////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Microsoft Windows                                                         //
//  Copyright (C) Microsoft Corporation, 1999.                                //
//                                                                            //
//  File:    rewrite.cxx                                                      //
//                                                                            //
//  Contents:    New marta rewrite functions.                                 //
//                                                                            //
//  History:    4/99    KedarD     Created                                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

#include <aclpch.hxx>
#pragma hdrstop

extern "C"
{
    #include <stdio.h>
    #include <permit.h>
    #include <dsgetdc.h>
    #include <lmapibuf.h>
    #include <wmistr.h>
    #include <ntprov.hxx>
    #include <strings.h>
    #include <seopaque.h>
    #include <sertlp.h>
    #include <tables.h>

}

#define MARTA_DEBUG_NO 0

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// STRUCTURES DEFINITIONS TO HOLD FUNCTION POINTERS START HERE                //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

typedef struct _MARTA_GET_FUNCTION_CONTEXT {
    FN_ADD_REF_CONTEXT     fAddRefContext;
    FN_CLOSE_CONTEXT       fCloseContext;
    FN_GET_DESIRED_ACCESS  fGetDesiredAccess;
    FN_GET_PARENT_CONTEXT  fGetParentContext;
    FN_GET_PROPERTIES      fGetProperties;
    FN_GET_TYPE_PROPERTIES fGetTypeProperties;
    FN_OPEN_NAMED_OBJECT   fOpenNamedObject;
    FN_OPEN_HANDLE_OBJECT  fOpenHandleObject;
    FN_GET_RIGHTS          fGetRights;
} MARTA_GET_FUNCTION_CONTEXT, *PMARTA_GET_FUNCTION_CONTEXT;

typedef struct _MARTA_SET_FUNCTION_CONTEXT {
    FN_ADD_REF_CONTEXT       fAddRefContext;
    FN_CLOSE_CONTEXT         fCloseContext;
    FN_FIND_FIRST            fFindFirst;
    FN_FIND_NEXT             fFindNext;
    FN_GET_DESIRED_ACCESS    fGetDesiredAccess;
    FN_GET_PARENT_CONTEXT    fGetParentContext;
    FN_GET_PROPERTIES        fGetProperties;
    FN_GET_TYPE_PROPERTIES   fGetTypeProperties;
    FN_GET_RIGHTS            fGetRights;
    FN_OPEN_NAMED_OBJECT     fOpenNamedObject;
    FN_OPEN_HANDLE_OBJECT    fOpenHandleObject;
    FN_SET_RIGHTS            fSetRights;
    FN_REOPEN_CONTEXT        fReopenContext;
    FN_REOPEN_ORIG_CONTEXT   fReopenOrigContext;
    FN_GET_NAME_FROM_CONTEXT fGetNameFromContext;
} MARTA_SET_FUNCTION_CONTEXT, *PMARTA_SET_FUNCTION_CONTEXT;

typedef struct _MARTA_INDEX_FUNCTION_CONTEXT {
    FN_OPEN_NAMED_OBJECT  fOpenNamedObject;
    FN_CLOSE_CONTEXT      fCloseContext;
    FN_GET_RIGHTS         fGetRights;
    FN_GET_PARENT_NAME    fGetParentName;
} MARTA_INDEX_FUNCTION_CONTEXT, *PMARTA_INDEX_FUNCTION_CONTEXT;

typedef struct _MARTA_RESET_FUNCTION_CONTEXT {
    FN_ADD_REF_CONTEXT     fAddRefContext;
    FN_CLOSE_CONTEXT       fCloseContext;
    FN_GET_DESIRED_ACCESS  fGetDesiredAccess;
    FN_GET_PARENT_CONTEXT  fGetParentContext;
    FN_GET_PROPERTIES      fGetProperties;
    FN_GET_TYPE_PROPERTIES fGetTypeProperties;
    FN_OPEN_NAMED_OBJECT   fOpenNamedObject;
    FN_GET_RIGHTS          fGetRights;
} MARTA_RESET_FUNCTION_CONTEXT, *PMARTA_RESET_FUNCTION_CONTEXT;
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// MACRO DEFINITIONS START HERE                                               //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

#define MARTA_DACL_NOT_PROTECTED(sd, si)                                       \
        (FLAG_ON((si), DACL_SECURITY_INFORMATION) &&                           \
         !FLAG_ON((sd)->Control, SE_DACL_PROTECTED))

#define MARTA_SACL_NOT_PROTECTED(sd, si)                                       \
        (FLAG_ON((si), SACL_SECURITY_INFORMATION) &&                           \
         !FLAG_ON((sd)->Control, SE_SACL_PROTECTED))

#define MARTA_SD_NOT_PROTECTED(sd, si)                                         \
        ((MARTA_DACL_NOT_PROTECTED((sd), (si))) ||                             \
         (MARTA_SACL_NOT_PROTECTED((sd), (si))))

#define MARTA_NT5_FLAGS_ON(c)                                                  \
        (FLAG_ON((c), (SE_SACL_AUTO_INHERITED   | SE_DACL_AUTO_INHERITED |     \
                       SE_DACL_PROTECTED        | SE_SACL_PROTECTED |          \
                       SE_DACL_AUTO_INHERIT_REQ | SE_SACL_AUTO_INHERIT_REQ)))


#if 1
#define MARTA_TURN_OFF_IMPERSONATION                                           \
        if (OpenThreadToken(                                                   \
                GetCurrentThread(),                                            \
                MAXIMUM_ALLOWED,                                               \
                TRUE,                                                          \
                &ThreadHandle                                                  \
                ))                                                             \
        { RevertToSelf(); }                                                    \
        else                                                                   \
        { ThreadHandle = NULL; }

#define MARTA_TURN_ON_IMPERSONATION                                            \
        if (ThreadHandle != NULL)                                              \
        {                                                                      \
            (VOID) SetThreadToken(NULL, ThreadHandle);                         \
            CloseHandle(ThreadHandle);                                         \
            ThreadHandle = NULL;                                               \
        }

#else

#define MARTA_TURN_ON_IMPERSONATION 
#define MARTA_TURN_OFF_IMPERSONATION 

#endif

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// FUNCTION PROTOTYPES START HERE                                             //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccRewriteSetHandleRights(
    IN     HANDLE               Handle,
    IN     SE_OBJECT_TYPE       ObjectType,
    IN     SECURITY_INFORMATION SecurityInfo,
    IN OUT PSECURITY_DESCRIPTOR pSecurityDescriptor
    );

DWORD
AccRewriteSetNamedRights(
    IN     LPWSTR               pObjectName,
    IN     SE_OBJECT_TYPE       ObjectType,
    IN     SECURITY_INFORMATION SecurityInfo,
    IN OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
    IN     BOOL                 bSkipInheritanceComputation
    );

VOID
MartaInitializeGetContext(
    IN  SE_OBJECT_TYPE              ObjectType,
    OUT PMARTA_GET_FUNCTION_CONTEXT pFunctionContext
    );

VOID
MartaInitializeIndexContext(
    IN  SE_OBJECT_TYPE                ObjectType,
    OUT PMARTA_INDEX_FUNCTION_CONTEXT pFunctionContext
    );

BOOL
MartaUpdateTree(
    IN SECURITY_INFORMATION        SecurityInfo,
    IN PSECURITY_DESCRIPTOR        pNewSD,
    IN PSECURITY_DESCRIPTOR        pOldSD,
    IN MARTA_CONTEXT               Context,
    IN HANDLE                      ProcessHandle,
    IN PMARTA_SET_FUNCTION_CONTEXT pMartaSetFunctionContext,
    IN PGENERIC_MAPPING            pGenMap
    );

BOOL
MartaResetTree(
    IN SECURITY_INFORMATION        SecurityInfo,
    IN SECURITY_INFORMATION        TmpSeInfo,
    IN PSECURITY_DESCRIPTOR        pNewSD,
    IN PSECURITY_DESCRIPTOR        pEmptySD,
    IN MARTA_CONTEXT               Context,
    IN HANDLE                      ProcessHandle,
    IN PMARTA_SET_FUNCTION_CONTEXT pMartaSetFunctionContext,
    IN PGENERIC_MAPPING            pGenMap,
    IN ACCESS_MASK                 MaxAccessMask,
    IN ACCESS_MASK                 AccessMask,
    IN ACCESS_MASK                 RetryAccessMask,
    IN OUT PPROG_INVOKE_SETTING    pOperation,
    IN FN_PROGRESS                 fnProgress,
    IN PVOID                       Args,
    IN BOOL                        KeepExplicit
    );

DWORD
MartaGetNT4NodeSD(
    IN     PSECURITY_DESCRIPTOR pOldSD,
    IN OUT PSECURITY_DESCRIPTOR pOldChildSD,
    IN     HANDLE               ProcessHandle,
    IN     BOOL                 bIsChildContainer,
    IN     PGENERIC_MAPPING     pGenMap,
    IN     SECURITY_INFORMATION SecurityInfo
    );

DWORD
MartaCompareAndMarkInheritedAces(
    IN  PACL    pParentAcl,
    IN  PACL    pChildAcl,
    IN  BOOL    bIsChildContainer,
    OUT PBOOL   pCompareStatus
    );

BOOL
MartaEqualAce(
    IN PACE_HEADER pParentAce,
    IN PACE_HEADER pChildAce,
    IN BOOL        bIsChildContainer
    );

DWORD
MartaManualPropagation(
    IN     MARTA_CONTEXT               Context,
    IN     SECURITY_INFORMATION        SecurityInfo,
    IN OUT PSECURITY_DESCRIPTOR        pSD,
    IN     PGENERIC_MAPPING            pGenMap,
    IN     BOOL                        bDoPropagate,
    IN     BOOL                        bReadOldProtectedBits,
    IN     PMARTA_SET_FUNCTION_CONTEXT pMartaSetFunctionContext,
    IN     BOOL                        bSkipInheritanceComputation
    );

VOID
MartaInitializeSetContext(
    IN  SE_OBJECT_TYPE              ObjectType,
    OUT PMARTA_SET_FUNCTION_CONTEXT pFunctionContext
    );

DWORD
AccRewriteGetHandleRights(
    IN  HANDLE                 Handle,
    IN  SE_OBJECT_TYPE         ObjectType,
    IN  SECURITY_INFORMATION   SecurityInfo,
    OUT PSID                 * ppSidOwner,
    OUT PSID                 * ppSidGroup,
    OUT PACL                 * ppDacl,
    OUT PACL                 * ppSacl,
    OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
    );

DWORD
AccRewriteGetNamedRights(
    IN  LPWSTR                 pObjectName,
    IN  SE_OBJECT_TYPE         ObjectType,
    IN  SECURITY_INFORMATION   SecurityInfo,
    OUT PSID                 * ppSidOwner,
    OUT PSID                 * ppSidGroup,
    OUT PACL                 * ppDacl,
    OUT PACL                 * ppSacl,
    OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
    );

DWORD
MartaGetRightsFromContext(
    IN  MARTA_CONTEXT               Context,
    IN  PMARTA_GET_FUNCTION_CONTEXT pGetFunctionContext,
    IN  SECURITY_INFORMATION        SecurityInfo,
    OUT PSID                      * ppSidOwner,
    OUT PSID                      * ppSidGroup,
    OUT PACL                      * ppDacl,
    OUT PACL                      * ppSacl,
    OUT PSECURITY_DESCRIPTOR      * ppSecurityDescriptor
    );

VOID
MartaGetSidsAndAclsFromSD(
    IN  SECURITY_INFORMATION   SecurityInfo,
    IN  PSECURITY_DESCRIPTOR   pSD,
    OUT PSID                 * ppSidOwner,
    OUT PSID                 * ppSidGroup,
    OUT PACL                 * ppDacl,
    OUT PACL                 * ppSacl,
    OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
    );

BOOL
MartaIsSDNT5Style(
    IN PSECURITY_DESCRIPTOR SD
    );

BOOL
MartaIsAclNt5Style(
    PACL pAcl
    );

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// FUNCTIONS START HERE                                                       //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaIsSDNT5Style                                                //
//                                                                            //
// Description: Determine if the Security Descriptor is NT5 style.            //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pSD]                    Security Descriptor                       //
//                                                                            //
// Returns:  TRUE if any of the following is true                             //
//               Presence of Protected/AutoInherited in the contol bits of SD //
//               Presence of INHERITED_ACE flag in DACL/SACL                  //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

BOOL
MartaIsSDNT5Style(
    IN PSECURITY_DESCRIPTOR pSD
    )
{
    BOOL                  bRetval = TRUE;
    PACL                  pAcl    = NULL;
    PISECURITY_DESCRIPTOR pISD    = (PISECURITY_DESCRIPTOR) pSD;

    if (MARTA_NT5_FLAGS_ON(pISD->Control))
    {
        return TRUE;
    }

    pAcl = RtlpDaclAddrSecurityDescriptor(pISD);

    if (NULL != pAcl)
    {
        bRetval = FALSE;

        if (MartaIsAclNt5Style(pAcl))
        {
            return TRUE;
        }
    }

    pAcl = RtlpSaclAddrSecurityDescriptor(pISD);

    if (NULL != pAcl)
    {
        bRetval = FALSE;

        if (MartaIsAclNt5Style(pAcl))
        {
            return TRUE;
        }
    }

    return bRetval;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaIsAclNT5Style                                               //
//                                                                            //
// Description: Determine if the Acl is NT5 style.                            //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pAcl]                    ACL                                      //
//                                                                            //
// Returns: TRUE if INHERITED_ACE flags exists in the AceFlags                //
//          FALSE otherwise                                                   //
////////////////////////////////////////////////////////////////////////////////

BOOL
MartaIsAclNt5Style(
    PACL pAcl
    )
{
    ULONG       i    = 0;
    PACE_HEADER pAce = (PACE_HEADER) FirstAce(pAcl);

    for (; i < pAcl->AceCount; i++, pAce = (PACE_HEADER) NextAce(pAce))
    {
        if (FLAG_ON(pAce->AceFlags, INHERITED_ACE))
        {
            return TRUE;
        }
    }

    return FALSE;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaInitializeGetContext                                        //
//                                                                            //
// Description: Initializes the function pointers based on object-type.       //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  ObjectType]        Type of the object                             //
//     [OUT pFunctionContext]  Structure to hold function pointers            //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

VOID
MartaInitializeGetContext(
    IN  SE_OBJECT_TYPE              ObjectType,
    OUT PMARTA_GET_FUNCTION_CONTEXT pFunctionContext
    )
{
    pFunctionContext->fAddRefContext     = MartaAddRefContext[ObjectType];
    pFunctionContext->fCloseContext      = MartaCloseContext[ObjectType];
    pFunctionContext->fOpenNamedObject   = MartaOpenNamedObject[ObjectType];
    pFunctionContext->fOpenHandleObject  = MartaOpenHandleObject[ObjectType];
    pFunctionContext->fGetRights         = MartaGetRights[ObjectType];
    pFunctionContext->fGetDesiredAccess  = MartaGetDesiredAccess[ObjectType];
    pFunctionContext->fGetParentContext  = MartaGetParentContext[ObjectType];
    pFunctionContext->fGetTypeProperties = MartaGetTypeProperties[ObjectType];
    pFunctionContext->fGetProperties     = MartaGetProperties[ObjectType];
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaGetSidsAndAclsFromSD                                        //
//                                                                            //
// Description: Fill in the fields requested by GetSecurity API.              //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  SecurityInfo]           Security Information requested            //
//     [IN  pSD]                    Security Descriptor from which the out    //
//                                  fields will be returned                   //
//                                                                            //
//     [OUT  ppSIdOwner]            To return the owner                       //
//     [OUT  ppSidGroup]            To return the group                       //
//     [OUT  ppDacl]                To return the Dacl                        //
//     [OUT  ppSacl]                To return the Sacl                        //
//     [OUT  ppSecurityDescriptor]  To return the Security Descriptor         //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

VOID
MartaGetSidsAndAclsFromSD(
    IN  SECURITY_INFORMATION   SecurityInfo,
    IN  PSECURITY_DESCRIPTOR   pSD,
    OUT PSID                 * ppSidOwner,
    OUT PSID                 * ppSidGroup,
    OUT PACL                 * ppDacl,
    OUT PACL                 * ppSacl,
    OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
    )
{
    PISECURITY_DESCRIPTOR pISD = (PISECURITY_DESCRIPTOR) pSD;

    if (FLAG_ON(SecurityInfo, OWNER_SECURITY_INFORMATION) && (NULL != ppSidOwner))
    {
        *ppSidOwner = RtlpOwnerAddrSecurityDescriptor(pISD);
    }

    if (FLAG_ON(SecurityInfo, GROUP_SECURITY_INFORMATION) && (NULL != ppSidGroup))
    {
        *ppSidGroup = RtlpGroupAddrSecurityDescriptor(pISD);
    }

    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION) && (NULL != ppDacl))
    {
       *ppDacl = RtlpDaclAddrSecurityDescriptor(pISD);
    }

    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION) && (ppSacl != NULL))
    {
        *ppSacl = RtlpSaclAddrSecurityDescriptor(pISD);
    }

    if (NULL != ppSecurityDescriptor)
    {
        *ppSecurityDescriptor = pSD;
    }
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaGetRightsFromContext                                        //
//                                                                            //
// Description: Get the security information requested given the Context.     //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  Context]                Context structure for the object          //
//     [IN  pGetFunctionContext]    Structure holding the function pointers   //
//     [IN  SecurityInfo]           Security Information requested            //
//                                                                            //
//     [OUT  ppSIdOwner]            To return the owner                       //
//     [OUT  ppSidGroup]            To return the group                       //
//     [OUT  ppDacl]                To return the Dacl                        //
//     [OUT  ppSacl]                To return the Sacl                        //
//     [OUT  ppSecurityDescriptor]  To return the Security Descriptor         //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
MartaGetRightsFromContext(
    IN  MARTA_CONTEXT               Context,
    IN  PMARTA_GET_FUNCTION_CONTEXT pGetFunctionContext,
    IN  SECURITY_INFORMATION        SecurityInfo,
    OUT PSID                      * ppSidOwner,
    OUT PSID                      * ppSidGroup,
    OUT PACL                      * ppDacl,
    OUT PACL                      * ppSacl,
    OUT PSECURITY_DESCRIPTOR      * ppSecurityDescriptor
    )
{
    DWORD                dwErr         = ERROR_SUCCESS;
    PSECURITY_DESCRIPTOR pSD           = NULL;
    PSECURITY_DESCRIPTOR pParentSD     = NULL;
    HANDLE               ProcessHandle = NULL;
    GENERIC_MAPPING      ZeroGenMap    = {0, 0, 0, 0};
    MARTA_CONTEXT        ParentContext = NULL_MARTA_CONTEXT;
    BOOL                 bIsContainer  = FALSE;

    MARTA_OBJECT_PROPERTIES      ObjectProperties;
    MARTA_OBJECT_TYPE_PROPERTIES ObjectTypeProperties;

    dwErr = (*(pGetFunctionContext->fGetRights))(
                   Context,
                   SecurityInfo,
                   &pSD
                   );

    CONDITIONAL_RETURN(dwErr);

    if (NULL == pSD)
    {
        goto End;
    }

    if (!FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
    {
        goto GetResults;
    }

    //
    // If the SD is NT4 && acl requested is not PROTECTED && ManualPropagation
    // is required then
    //     Get the ParentSD and convert the SD into NT5 style
    // else
    //     Goto GetResults
    //

    if (!MARTA_SD_NOT_PROTECTED((PISECURITY_DESCRIPTOR) pSD, SecurityInfo))
    {
        goto GetResults;
    }

    if (MartaIsSDNT5Style(pSD))
    {
        goto GetResults;
    }

    //
    // Get the "Type" properties for the object,
    //

    ObjectTypeProperties.cbSize  = sizeof(ObjectTypeProperties);
    ObjectTypeProperties.dwFlags = 0;
    ObjectTypeProperties.GenMap  = ZeroGenMap;

    dwErr = (*(pGetFunctionContext->fGetTypeProperties))(&ObjectTypeProperties);

    CONDITIONAL_EXIT(dwErr, End);

    if (!FLAG_ON(ObjectTypeProperties.dwFlags, MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG))
    {
        goto GetResults;
    }

    dwErr = (*(pGetFunctionContext->fGetParentContext))(
                Context,
                (*(pGetFunctionContext->fGetDesiredAccess))(READ_ACCESS_RIGHTS, FALSE, SecurityInfo),
                &ParentContext
                );

    CONDITIONAL_EXIT(dwErr, End);

    //
    // The SD is NT4 style. Read the parent SD to determine whether the aces are
    // the "same" on both the parent and the child.
    //

    if (NULL == ParentContext)
    {
        goto GetResults;
    }

    dwErr = (*(pGetFunctionContext->fGetRights))(
                   ParentContext,
                   SecurityInfo,
                   &pParentSD
                   );

    (VOID) (*(pGetFunctionContext->fCloseContext))(ParentContext);

    CONDITIONAL_EXIT(dwErr, End);

    if (NULL == pParentSD)
    {
        goto GetResults;
    }

    dwErr = GetCurrentToken(&ProcessHandle);

    CONDITIONAL_EXIT(dwErr, End);

    if (!((FLAG_ON(SecurityInfo, OWNER_SECURITY_INFORMATION)) &&
          (FLAG_ON(SecurityInfo, GROUP_SECURITY_INFORMATION))))
    {
        AccFree(pSD);
        pSD = NULL;

        dwErr = (*(pGetFunctionContext->fGetRights))(
                       Context,
                       (SecurityInfo | OWNER_SECURITY_INFORMATION |
                        GROUP_SECURITY_INFORMATION),
                       &pSD
                       );

        CONDITIONAL_EXIT(dwErr, End);
    }

    ObjectProperties.cbSize  = sizeof(ObjectProperties);
    ObjectProperties.dwFlags = 0;

    dwErr = (*(pGetFunctionContext->fGetProperties))(
                   Context,
                   &ObjectProperties
                   );

    CONDITIONAL_EXIT(dwErr, End);

    bIsContainer = FLAG_ON(ObjectProperties.dwFlags, MARTA_OBJECT_IS_CONTAINER);

    dwErr = MartaGetNT4NodeSD(
                pParentSD,
                pSD,
                ProcessHandle,
                bIsContainer,
                &(ObjectTypeProperties.GenMap),
                SecurityInfo
                );

    CONDITIONAL_EXIT(dwErr, End);

GetResults:

    MartaGetSidsAndAclsFromSD(
        SecurityInfo,
        pSD,
        ppSidOwner,
        ppSidGroup,
        ppDacl,
        ppSacl,
        ppSecurityDescriptor
        );

End:

    if (NULL != pParentSD)
    {
        AccFree(pParentSD);
    }

    if (NULL != ProcessHandle)
    {
        CloseHandle(ProcessHandle);
    }

    if (ERROR_SUCCESS != dwErr)
    {
        AccFree(pSD);
    }

    return dwErr;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: AccRewriteGetNamedRights                                         //
//                                                                            //
// Description: Get the security information requested given the object       //
//              name and information. This is the routine that is called by   //
//              advapi32.                                                     //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pObjectName]            Name of the Object                        //
//     [IN  ObjectType]             Type of the object                        //
//     [IN  SecurityInfo]           Security Information requested            //
//                                                                            //
//     [OUT  ppSIdOwner]            To return the owner                       //
//     [OUT  ppSidGroup]            To return the group                       //
//     [OUT  ppDacl]                To return the Dacl                        //
//     [OUT  ppSacl]                To return the Sacl                        //
//     [OUT  ppSecurityDescriptor]  To return the Security Descriptor         //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccRewriteGetNamedRights(
    IN  LPWSTR                 pObjectName,
    IN  SE_OBJECT_TYPE         ObjectType,
    IN  SECURITY_INFORMATION   SecurityInfo,
    OUT PSID                 * ppSidOwner,
    OUT PSID                 * ppSidGroup,
    OUT PACL                 * ppDacl,
    OUT PACL                 * ppSacl,
    OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
    )
{
    DWORD         dwErr   = ERROR_SUCCESS;
    MARTA_CONTEXT Context = NULL_MARTA_CONTEXT;

    MARTA_GET_FUNCTION_CONTEXT MartaGetFunctionContext;

    switch (ObjectType)
    {
    case SE_FILE_OBJECT:
    case SE_SERVICE:
    case SE_PRINTER:
    case SE_REGISTRY_KEY:
    case SE_REGISTRY_WOW64_32KEY:
    case SE_LMSHARE:
    case SE_KERNEL_OBJECT:
    case SE_WINDOW_OBJECT:
    case SE_WMIGUID_OBJECT:
    case SE_DS_OBJECT:
    case SE_DS_OBJECT_ALL:
        break;
    case SE_PROVIDER_DEFINED_OBJECT:
    case SE_UNKNOWN_OBJECT_TYPE:
    default:
        return ERROR_INVALID_PARAMETER;
    }

    MartaInitializeGetContext(ObjectType, &MartaGetFunctionContext);

    //
    // Open the object with permissions to read the object type as well. If that
    // fails, open the object with just read permissions. This has to be done in
    // order to accomodate NT4 SDs.
    //

    dwErr = (*(MartaGetFunctionContext.fOpenNamedObject))(
                   pObjectName,
                   (*(MartaGetFunctionContext.fGetDesiredAccess))(READ_ACCESS_RIGHTS, TRUE, SecurityInfo),
                   &Context
                   );

    if (ERROR_SUCCESS != dwErr)
    {
        dwErr = (*(MartaGetFunctionContext.fOpenNamedObject))(
                       pObjectName,
                       (*(MartaGetFunctionContext.fGetDesiredAccess))(READ_ACCESS_RIGHTS, FALSE, SecurityInfo),
                       &Context
                       );

        CONDITIONAL_EXIT(dwErr, End);
    }

    dwErr = MartaGetRightsFromContext(
                Context,
                &MartaGetFunctionContext,
                SecurityInfo,
                ppSidOwner,
                ppSidGroup,
                ppDacl,
                ppSacl,
                ppSecurityDescriptor
                );

    (VOID) (*(MartaGetFunctionContext.fCloseContext))(Context);

End:
    return dwErr;

}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: AccRewriteGetHandleRights                                        //
//                                                                            //
// Description: Get the security information requested given the object       //
//              handle and information. This is the routine that is called by //
//              advapi32.                                                     //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  Handle]                 Handle to the Object                      //
//     [IN  pGetFunctionContext]    Structure holding the function pointers   //
//     [IN  SecurityInfo]           Security Information requested            //
//                                                                            //
//     [OUT  ppSIdOwner]            To return the owner                       //
//     [OUT  ppSidGroup]            To return the group                       //
//     [OUT  ppDacl]                To return the Dacl                        //
//     [OUT  ppSacl]                To return the Sacl                        //
//     [OUT  ppSecurityDescriptor]  To return the Security Descriptor         //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccRewriteGetHandleRights(
    IN  HANDLE                 Handle,
    IN  SE_OBJECT_TYPE         ObjectType,
    IN  SECURITY_INFORMATION   SecurityInfo,
    OUT PSID                 * ppSidOwner,
    OUT PSID                 * ppSidGroup,
    OUT PACL                 * ppDacl,
    OUT PACL                 * ppSacl,
    OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
    )
{
    DWORD         dwErr   = ERROR_SUCCESS;
    MARTA_CONTEXT Context = NULL_MARTA_CONTEXT;

    MARTA_GET_FUNCTION_CONTEXT MartaGetFunctionContext;

    switch (ObjectType)
    {
    case SE_FILE_OBJECT:
    case SE_SERVICE:
    case SE_PRINTER:
    case SE_REGISTRY_KEY:
    case SE_LMSHARE:
    case SE_KERNEL_OBJECT:
    case SE_WINDOW_OBJECT:
    case SE_WMIGUID_OBJECT:
        break;
    case SE_DS_OBJECT:
    case SE_DS_OBJECT_ALL:
    case SE_PROVIDER_DEFINED_OBJECT:
    case SE_UNKNOWN_OBJECT_TYPE:
    default:
        return ERROR_INVALID_PARAMETER;
    }

    MartaInitializeGetContext(ObjectType, &MartaGetFunctionContext);

    //
    // Open the object with permissions to read the object type as well. If that
    // fails, open the object with just read permissions. This has to be done in
    // order to accomodate NT4 SDs.
    //

    dwErr = (*(MartaGetFunctionContext.fOpenHandleObject))(
                   Handle,
                   (*(MartaGetFunctionContext.fGetDesiredAccess))(READ_ACCESS_RIGHTS, TRUE, SecurityInfo),
                   &Context
                   );

    if (ERROR_SUCCESS != dwErr)
    {
        dwErr = (*(MartaGetFunctionContext.fOpenHandleObject))(
                       Handle,
                       (*(MartaGetFunctionContext.fGetDesiredAccess))(READ_ACCESS_RIGHTS, FALSE, SecurityInfo),
                       &Context
                       );

        CONDITIONAL_EXIT(dwErr, End);
    }

    dwErr = MartaGetRightsFromContext(
                Context,
                &MartaGetFunctionContext,
                SecurityInfo,
                ppSidOwner,
                ppSidGroup,
                ppDacl,
                ppSacl,
                ppSecurityDescriptor
                );

    (VOID) (*(MartaGetFunctionContext.fCloseContext))(Context);

End:
    return dwErr;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaInitializeSetContext                                        //
//                                                                            //
// Description: Initializes the function pointers based on object-type.       //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  ObjectType]        Type of the object                             //
//     [OUT pFunctionContext]  Structure to hold function pointers            //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////


VOID
MartaInitializeSetContext(
    IN  SE_OBJECT_TYPE              ObjectType,
    OUT PMARTA_SET_FUNCTION_CONTEXT pFunctionContext
    )
{
    pFunctionContext->fAddRefContext      = MartaAddRefContext[ObjectType];
    pFunctionContext->fCloseContext       = MartaCloseContext[ObjectType];
    pFunctionContext->fFindFirst          = MartaFindFirst[ObjectType];
    pFunctionContext->fFindNext           = MartaFindNext[ObjectType];
    pFunctionContext->fGetParentContext   = MartaGetParentContext[ObjectType];
    pFunctionContext->fGetProperties      = MartaGetProperties[ObjectType];
    pFunctionContext->fGetTypeProperties  = MartaGetTypeProperties[ObjectType];
    pFunctionContext->fGetRights          = MartaGetRights[ObjectType];
    pFunctionContext->fOpenNamedObject    = MartaOpenNamedObject[ObjectType];
    pFunctionContext->fOpenHandleObject   = MartaOpenHandleObject[ObjectType];
    pFunctionContext->fSetRights          = MartaSetRights[ObjectType];
    pFunctionContext->fGetDesiredAccess   = MartaGetDesiredAccess[ObjectType];
    pFunctionContext->fReopenContext      = MartaReopenContext[ObjectType];
    pFunctionContext->fReopenOrigContext  = MartaReopenOrigContext[ObjectType];
    pFunctionContext->fGetNameFromContext = MartaGetNameFromContext[ObjectType];
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaManualPropagation                                           //
//                                                                            //
// Description: Stamp the security descriptor on the object referred by the   //
//              context and propagate the inheritable aces to its children.   //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  Context]                Context structure for the object          //
//     [IN  SecurityInfo]           Security Information requested            //
//     [IN  OUT pSD]                Security Descriptor to be stamped on the  //
//                                  object in absolute format.                //
//     [IN  pGenMap]                Generic mapping of the object rights      //
//     [IN  bDoPropagate]           Whether propagation _can_ be done         //
//     [IN  bReadOldProtectedBits]  Whether to read existing protection info  //
//     [IN  pSetFunctionContext]    Structure holding the function pointers   //
//     [IN  bSkipInheritanceComputation]  Whether to compute inherited aces   //
//                                        from the parent
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
MartaManualPropagation(
    IN     MARTA_CONTEXT               Context,
    IN     SECURITY_INFORMATION        SecurityInfo,
    IN OUT PSECURITY_DESCRIPTOR        pSD,
    IN     PGENERIC_MAPPING            pGenMap,
    IN     BOOL                        bDoPropagate,
    IN     BOOL                        bReadOldProtectedBits,
    IN     PMARTA_SET_FUNCTION_CONTEXT pMartaSetFunctionContext,
    IN     BOOL                        bSkipInheritanceComputation
    )
{
    DWORD                       dwErr             = ERROR_SUCCESS;
    BOOL                        bProtected        = TRUE;
    BOOL                        bIsChildContainer = FALSE;
    BOOL                        bRetryPropagation = FALSE;
    PSECURITY_DESCRIPTOR        pParentSD         = NULL;
    PSECURITY_DESCRIPTOR        pOldSD            = NULL;
    PSECURITY_DESCRIPTOR        pNewSD            = NULL;
    PSID                        pSidOwner         = NULL;
    HANDLE                      ProcessHandle     = NULL;
    HANDLE                      ThreadHandle      = NULL;
    MARTA_CONTEXT               ParentContext     = NULL_MARTA_CONTEXT;
    SECURITY_DESCRIPTOR_CONTROL LocalControl      = (SECURITY_DESCRIPTOR_CONTROL) 0;

    MARTA_OBJECT_PROPERTIES ObjectProperties;

    //
    // Check if manual propagation should be done. Propagation is not tried if
    // any errors are encountered.
    //

    ObjectProperties.cbSize  = sizeof(ObjectProperties);
    ObjectProperties.dwFlags = 0;

    dwErr = (*(pMartaSetFunctionContext->fGetProperties))(
                   Context,
                   &ObjectProperties
                   );

    CONDITIONAL_EXIT(dwErr, End);

    bIsChildContainer = FLAG_ON(ObjectProperties.dwFlags, MARTA_OBJECT_IS_CONTAINER);

    dwErr = GetCurrentToken(&ProcessHandle);

    CONDITIONAL_EXIT(dwErr, End);

    //
    // Compute inherited aces if the caller has not already. This is the usual
    // case.
    //

    if (FALSE == bSkipInheritanceComputation)
    {
        //
        // Read the parent ACL only if xACL is to be stamped on is not protected.
        //

        if (MARTA_SD_NOT_PROTECTED((PISECURITY_DESCRIPTOR) pSD, SecurityInfo))
        {
            bProtected = FALSE;

            dwErr = (*(pMartaSetFunctionContext->fGetParentContext))(
                        Context,
                        (*(pMartaSetFunctionContext->fGetDesiredAccess))(READ_ACCESS_RIGHTS, FALSE, SecurityInfo),
                        &ParentContext
                        );

            CONDITIONAL_EXIT(dwErr, End);

            if (NULL != ParentContext)
            {
                dwErr = (*(pMartaSetFunctionContext->fGetRights))(
                               ParentContext,
                               SecurityInfo,
                               &pParentSD
                               );

                (VOID) (*(pMartaSetFunctionContext->fCloseContext))(ParentContext);

                CONDITIONAL_EXIT(dwErr, End);

                if (NULL != pParentSD)
                {
                    if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
                    {
                        ((PISECURITY_DESCRIPTOR) pParentSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
                    }

                    if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
                    {
                        ((PISECURITY_DESCRIPTOR) pParentSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
                    }
                }
            }
        }

        //
        // Read the old security descriptor on the child if xAcl is not protected
        // and is to be stamped on the child.
        // To take case of creator-owner/group aces, read in Owner/Group info as
        // well and set it in the SD passed in if it is not already present.
        //

        if (FALSE == bProtected)
        {
            SECURITY_INFORMATION LocalSeInfo = SecurityInfo;

            if (NULL == RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD))
            {
                LocalSeInfo |= OWNER_SECURITY_INFORMATION;
            }

            if (NULL == RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD))
            {
                LocalSeInfo |= GROUP_SECURITY_INFORMATION;
            }

            dwErr = (*(pMartaSetFunctionContext->fGetRights))(
                           Context,
                           LocalSeInfo,
                           &pOldSD
                           );

            CONDITIONAL_EXIT(dwErr, End);

            if (NULL == RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD))
            {
                if (FALSE == SetSecurityDescriptorOwner(
                                 pSD,
                                 RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldSD),
                                 FALSE))
                {
                    dwErr = GetLastError();
                }

                CONDITIONAL_EXIT(dwErr, End);
            }

            if (NULL == RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD))
            {
                if (FALSE == SetSecurityDescriptorGroup(
                                 pSD,
                                 RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldSD),
                                 FALSE))
                {
                    dwErr = GetLastError();
                }

                CONDITIONAL_EXIT(dwErr, End);
            }

        }

        //
        // Read the old security descriptor on the child if xAcl it is a container.
        //

        else if (bIsChildContainer || bReadOldProtectedBits)
        {
            dwErr = (*(pMartaSetFunctionContext->fGetRights))(
                           Context,
                           SecurityInfo,
                           &pOldSD
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }

        //
        // If none of the PROTECTED flags are passed in then do the "right" thing.
        // Read the PROTECTED bit from the existing security descriptor and set it
        // in the new one.
        //

        if (bReadOldProtectedBits && (NULL != pOldSD))
        {
            if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
            {
                if (!FLAG_ON(SecurityInfo, (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)))
                {
                    ((PISECURITY_DESCRIPTOR) pSD)->Control |= ((PISECURITY_DESCRIPTOR) pOldSD)->Control & SE_DACL_PROTECTED;
                }
            }

            if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
            {
                if (!FLAG_ON(SecurityInfo, (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION)))
                {
                    ((PISECURITY_DESCRIPTOR) pSD)->Control |= ((PISECURITY_DESCRIPTOR) pOldSD)->Control & SE_SACL_PROTECTED;
                }
            }
        }

        //
        // Merge the SD with the parent SD whether or not it is protected.
        // This is done to lose the inherited aces if the child is protected.
        //

        MARTA_TURN_OFF_IMPERSONATION;

        if (FALSE == CreatePrivateObjectSecurityEx(
                         pParentSD,
                         pSD,
                         &pNewSD,
                         NULL,
                         bIsChildContainer,
                         (SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT | SEF_AVOID_OWNER_CHECK | SEF_AVOID_PRIVILEGE_CHECK),
                         ProcessHandle,
                         pGenMap
                         ))
        {
            dwErr = GetLastError();
        }

        MARTA_TURN_ON_IMPERSONATION;

        CONDITIONAL_EXIT(dwErr, End);
    }
    else
    {
        //
        // Stamp the security descriptor as prvided by the caller. The only
        // caller of this is SCE.
        //

        pNewSD = pSD;

        //
        // Read the old security descriptor on the child if xAcl it is a container.
        //

        if (bIsChildContainer)
        {
            dwErr = (*(pMartaSetFunctionContext->fGetRights))(
                           Context,
                           (SecurityInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)),
                           &pOldSD
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }
    }

    //
    // If the child is a container then update the subtree underneath it.
    //

    if (bIsChildContainer)
    {
        if (bDoPropagate)
        {
            bRetryPropagation = MartaUpdateTree(
                                    SecurityInfo,
                                    pNewSD,
                                    pOldSD,
                                    Context,
                                    ProcessHandle,
                                    pMartaSetFunctionContext,
                                    pGenMap
                                    );
        }
        else
        {
            bRetryPropagation = TRUE;
        }
    }

    //
    // Stamp NewNodeSD on the node
    //

    if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {
        ((PISECURITY_DESCRIPTOR) pNewSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
    }

    if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        ((PISECURITY_DESCRIPTOR) pNewSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
    }

    dwErr = (*(pMartaSetFunctionContext->fSetRights))(
                   Context,
                   SecurityInfo,
                   pNewSD
                   );

    CONDITIONAL_EXIT(dwErr, End);

    //
    // If propagation had failed in the first attept then try again. This is to
    // cover the case when the container can be enumerated after setting the new
    // security.

    if (bRetryPropagation && (SecurityInfo & DACL_SECURITY_INFORMATION))
    {
        ACCESS_MASK Access = (*(pMartaSetFunctionContext->fGetDesiredAccess))(
                                    NO_ACCESS_RIGHTS,
                                    TRUE,
                                    SecurityInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)
                                    );

        DWORD lErr = (*(pMartaSetFunctionContext->fReopenOrigContext))(
                       Context,
                       Access
                       );

        CONDITIONAL_EXIT(lErr, End);

        (VOID) MartaUpdateTree(
                   SecurityInfo,
                   pNewSD,
                   pOldSD,
                   Context,
                   ProcessHandle,
                   pMartaSetFunctionContext,
                   pGenMap
                   );
    }

End:

    if (NULL != ProcessHandle)
    {
        CloseHandle(ProcessHandle);
    }

    if (NULL != pOldSD)
    {
        AccFree(pOldSD);
    }

    if (NULL != pParentSD)
    {
        AccFree(pParentSD);
    }

    if ((NULL != pNewSD) && (pNewSD != pSD))
    {
        DestroyPrivateObjectSecurity(&pNewSD);
    }

    return dwErr;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaEqualAce                                                    //
//                                                                            //
// Description: Compare an ace from child to an ace from parent to determine  //
//              if the child ace has been inherited from its parent.          //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pParentAce]          The ace for the parent object                //
//     [IN  pChildAce]           The ace for the child object                 //
//     [IN  bIsChildContainer]   Whether the child object is a Container      //
//                                                                            //
// Returns: TRUE    if the two aces are equal                                 //
//          FALSE   otherwise                                                 //
//                                                                            //
// Notes: No ace should contain generic bits and the parent ace should not    //
//        have INHERIT_ONLY bit.                                              //
//        Inherit flags are ignored.                                          //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

BOOL
MartaEqualAce(
    IN PACE_HEADER pParentAce,
    IN PACE_HEADER pChildAce,
    IN BOOL        bIsChildContainer
    )
{
    PSID        pSid1   = NULL;
    PSID        pSid2   = NULL;
    ACCESS_MASK Access1 = 0;
    ACCESS_MASK Access2 = 0;
    ULONG       Length1 = 0;
    ULONG       Length2 = 0;

    if ((NULL == pParentAce) || (NULL == pChildAce))
    {
        return FALSE;
    }

    //
    // Compare ACE type.
    //

    if (pParentAce->AceType != pChildAce->AceType)
    {
        return FALSE;
    }

    if ((pParentAce->AceFlags & ~INHERITED_ACE) != (pChildAce->AceFlags))
    {
        return FALSE;
    }

    if (bIsChildContainer)
    {
        //
        // Note: the flag shouldn't be compared because
        // it will be different even for the "equal" ace
        //
        // then we have a bug here, for example
        //      parentSD is Admin CI F
        //      childSD is Admin CIOI F
        // these two SDs should be marked as "different" but from
        // this routine, it will mark them "equal".
        //
    }

    //
    // Get access mask and SID pointer.
    //

    switch (pParentAce->AceType) {
    case ACCESS_ALLOWED_ACE_TYPE:
    case ACCESS_DENIED_ACE_TYPE:
    case SYSTEM_AUDIT_ACE_TYPE:
    case SYSTEM_ALARM_ACE_TYPE:

        pSid1   = (PSID) &((PKNOWN_ACE) pParentAce)->SidStart;
        pSid2   = (PSID) &((PKNOWN_ACE) pChildAce)->SidStart;
        Access1 = ((PKNOWN_ACE) pParentAce)->Mask;
        Access2 = ((PKNOWN_ACE) pChildAce)->Mask;
        break;

    case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
    case ACCESS_DENIED_OBJECT_ACE_TYPE:
    case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
    case SYSTEM_ALARM_OBJECT_ACE_TYPE:

        if (((PKNOWN_OBJECT_ACE) pParentAce)->Flags !=
             ((PKNOWN_OBJECT_ACE) pChildAce)->Flags )
        {
            return FALSE;
        }

        if (((PKNOWN_OBJECT_ACE) pParentAce)->Flags & ACE_OBJECT_TYPE_PRESENT)
        {
            if (!RtlpIsEqualGuid(
                     RtlObjectAceObjectType(pParentAce),
                     RtlObjectAceObjectType(pChildAce)))
            {
                return FALSE;
            }
        }

        if (((PKNOWN_OBJECT_ACE) pParentAce)->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
        {
            if (!RtlpIsEqualGuid(
                     RtlObjectAceInheritedObjectType(pParentAce),
                     RtlObjectAceInheritedObjectType(pChildAce)))
            {
                return FALSE;
            }
        }

        pSid1 = RtlObjectAceSid(pParentAce);
        pSid2 = RtlObjectAceSid(pChildAce);

        Access1 = ((PKNOWN_OBJECT_ACE) pParentAce)->Mask;
        Access2 = ((PKNOWN_OBJECT_ACE) pChildAce)->Mask;

        break;

    case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:

        if (((PKNOWN_COMPOUND_ACE) pParentAce)->CompoundAceType !=
            ((PKNOWN_COMPOUND_ACE) pChildAce)->CompoundAceType)
        {
            return FALSE;
        }

        pSid1 = (PSID) &((PKNOWN_COMPOUND_ACE) pParentAce)->SidStart;
        pSid2 = (PSID) &((PKNOWN_COMPOUND_ACE) pParentAce)->SidStart;

        if ((!RtlValidSid(pSid1)) || (!RtlValidSid(pSid2)))
        {
            return FALSE;
        }

        if (!RtlEqualSid(pSid1, pSid2))
        {
            return FALSE;
        }

        Length1 = RtlLengthSid(pSid1);
        Length2 = RtlLengthSid(pSid2);

        pSid1 = (PSID) (((PUCHAR) pSid1) + Length1);
        pSid2 = (PSID) (((PUCHAR) pSid2) + Length2);

        Access1 = ((PKNOWN_COMPOUND_ACE) pParentAce)->Mask;
        Access2 = ((PKNOWN_COMPOUND_ACE) pChildAce)->Mask;
        break;

    default:
        return FALSE;
    }

    //
    // Compare access mask. There should be no generic mask and both the parent
    // object and the child object should have the same object type.
    //

    if (Access1 != Access2) {
        return FALSE;
    }

    //
    // Compare the Sids.
    //

    if ((!RtlValidSid(pSid1)) || (!RtlValidSid(pSid2)))
    {
        return FALSE;
    }

    if (!RtlEqualSid(pSid1, pSid2))
    {
        return FALSE;
    }

    return TRUE;

}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: CompareAndMarkInheritedAces                                      //
//                                                                            //
// Description: Compare the parent acl with the child. If all the effective   //
//              aces from parent are present in the child then mark those     //
//              aces in the child with INHERITED_ACE bit.                     //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pParentAcl]          The acl for the parent object                //
//     [IN  OUT pChildAcl]       The acl for the child object                 //
//     [IN  bIsChildContainer]   Whether the child object is a Container      //
//                                                                            //
//     [OUT  pCompareStatus]  To return the Security Descriptor               //
//                                                                            //
// Returns: TRUE    if the all effective parent aces are present in the child //
//          FALSE   otherwise                                                 //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
MartaCompareAndMarkInheritedAces(
    IN      PACL    pParentAcl,
    IN  OUT PACL    pChildAcl,
    IN      BOOL    bIsChildContainer,
    OUT     PBOOL   pCompareStatus
    )
{
    DWORD       dwErr                 = ERROR_SUCCESS;
    LONG        ParentAceCnt          = 0;
    LONG        ChildAceCnt           = 0;
    LONG        i                     = 0;
    LONG        j                     = 0;
    LONG        LastDenyAce           = -1;
    LONG        LastExplicitAce       = -1;
    LONG        LastInheritedDenyAce  = -1;
    LONG        FirstAllowAce         = ChildAceCnt;
    LONG        FirstInheritedAce     = ChildAceCnt;
    LONG        FirstExplicitAllowAce = ChildAceCnt;
    PACE_HEADER pParentAce            = NULL;
    PACE_HEADER pChildAce             = NULL;
    PBOOL       Flags                 = NULL;
    PUCHAR      Buffer                = NULL;
    PUCHAR      CurrentBuffer         = NULL;

    //
    // If the ChildAcl is NULL then it is a superset of the parent ACL.
    //

    if (NULL == pChildAcl)
    {
        *pCompareStatus = FALSE;
        goto End;
    }

    //
    // If the ParentAcl is NULL then it is a superset of the child ACL.
    // Since Child Acl is non-null at this point return TRUE.
    //

    if (NULL == pParentAcl)
    {
        *pCompareStatus = TRUE;
        goto End;
    }

    //
    // If the parent has no aces that could have been inherited then all the
    // child aces must be explicit.
    //

    ParentAceCnt = pParentAcl->AceCount;

    if (0 == ParentAceCnt)
    {
        *pCompareStatus = TRUE;
        goto End;
    }

    //
    // If the parent has one/more inheritable aces but the child has none then
    // the acl must be protected.
    //

    ChildAceCnt  = pChildAcl->AceCount;

    if (0 == ChildAceCnt)
    {
        *pCompareStatus = FALSE;
        goto End;
    }

    Flags = (PBOOL) AccAlloc(sizeof(BOOL) * ChildAceCnt);

    if (NULL == Flags)
    {
        dwErr = ERROR_NOT_ENOUGH_MEMORY;
        goto End;
    }

    for (i = 0; i < ChildAceCnt; i++)
    {
        Flags[i] = FALSE;
    }

    //
    // For all aces present in ParentAcl
    //     If the ace is not present in ChildAcl
    //         return FALSE
    //     else
    //         Mark the position of the this ace in Child Acl in fFlags.
    //         These will later be marked as INHERITED if the acl can be
    //         rearranged to be canonical.
    //

    i = 0;
    pParentAce = (PACE_HEADER) FirstAce(pParentAcl);

    for (; i < ParentAceCnt; i++, pParentAce = (PACE_HEADER) NextAce(pParentAce))
    {
        j = 0;
        pChildAce = (PACE_HEADER) FirstAce(pChildAcl);

        for (; j < ChildAceCnt; j++, pChildAce = (PACE_HEADER) NextAce(pChildAce))
        {
            if (TRUE == MartaEqualAce(pParentAce, pChildAce, bIsChildContainer))
            {
                Flags[j] = TRUE;
                break;
            }
        }

        if (ChildAceCnt == j)
        {
            *pCompareStatus = FALSE;
            goto End;
        }
    }

    //
    // Mark all the aces that we had marked as INHERITED.
    // This will make sure that they are not DUPLICATED.
    //

    LastDenyAce           = -1;
    LastExplicitAce       = -1;
    LastInheritedDenyAce  = -1;

    FirstAllowAce         = ChildAceCnt;
    FirstInheritedAce     = ChildAceCnt;
    FirstExplicitAllowAce = ChildAceCnt;

    //
    // Run thru the acl and mark the positions of aces. These will be later used
    // to dtermine what should be done with the acl.
    //

    j = 0;
    pChildAce = (PACE_HEADER) FirstAce(pChildAcl);

    for (; j < ChildAceCnt; j++, pChildAce = (PACE_HEADER) NextAce(pChildAce))
    {
        switch (pChildAce->AceType)
        {
        case ACCESS_ALLOWED_ACE_TYPE:
        case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
        case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:

            if (FALSE == Flags[j])
            {
                if (ChildAceCnt == FirstExplicitAllowAce)
                {
                    FirstExplicitAllowAce = j;
                }
            }

            if (ChildAceCnt == FirstAllowAce)
            {
                FirstAllowAce = j;
            }

            break;

        case ACCESS_DENIED_ACE_TYPE:
        case ACCESS_DENIED_OBJECT_ACE_TYPE:

            if (TRUE == Flags[j])
            {
                LastInheritedDenyAce = j;
            }

            LastDenyAce = j;

            break;

        default:
            break;
        }

        if (FALSE == Flags[j])
        {
            LastExplicitAce = j;
        }
        else
        {
            if (ChildAceCnt == FirstInheritedAce)
            {
                FirstInheritedAce = j;
            }
        }
    }

    //
    // This a non-canonical acl. Do not try to correct it.
    //

    if ((ChildAceCnt != FirstAllowAce) && (LastDenyAce > FirstAllowAce))
    {
        *pCompareStatus = FALSE;
        goto End;
    }

    //
    // Do not try to rearrange the acl if
    //     1. an inherited deny ace exists AND
    //     2. an explicit allow ace exists.
    //

    if ((-1 != LastInheritedDenyAce) && (ChildAceCnt != FirstExplicitAllowAce))
    {
        *pCompareStatus = FALSE;
        goto End;
    }

    //
    // The acl need not be rearranged since all the explicit aces are ahead of
    // the inherited ones.
    //

    if (LastExplicitAce < FirstInheritedAce)
    {
        j = 0;
        pChildAce = (PACE_HEADER) FirstAce(pChildAcl);

        for (; j < ChildAceCnt; j++, pChildAce = (PACE_HEADER) NextAce(pChildAce))
        {
            if (TRUE == Flags[j])
            {
                pChildAce->AceFlags |= INHERITED_ACE;
            }
        }
    }

    //
    // At least one inherited ace exists before an explicit one.
    // Rearrange the acl to get it in canonical form.
    //

    else
    {
        Buffer = (PUCHAR) AccAlloc(pChildAcl->AclSize - sizeof(ACL));
        CurrentBuffer = Buffer;

        if (NULL == Buffer)
        {
            dwErr = ERROR_NOT_ENOUGH_MEMORY;
            goto End;
        }

        j = 0;
        pChildAce = (PACE_HEADER) FirstAce(pChildAcl);

        for (; j <= LastExplicitAce; j++, pChildAce = (PACE_HEADER) NextAce(pChildAce))
        {
            if (FALSE == Flags[j])
            {
                memcpy(CurrentBuffer, (PUCHAR) pChildAce, pChildAce->AceSize);
                CurrentBuffer += pChildAce->AceSize;
            }
        }

        j = 0;
        pChildAce = (PACE_HEADER) FirstAce(pChildAcl);

        for (; j < ChildAceCnt; j++, pChildAce = (PACE_HEADER) NextAce(pChildAce))
        {
            if (TRUE == Flags[j])
            {
                memcpy(CurrentBuffer, (PUCHAR) pChildAce, pChildAce->AceSize);
                ((PACE_HEADER) CurrentBuffer)->AceFlags |= INHERITED_ACE;
                CurrentBuffer += pChildAce->AceSize;
            }
        }

        memcpy(
            ((PUCHAR) pChildAcl) + sizeof(ACL),
            Buffer,
            pChildAcl->AclSize - sizeof(ACL)
            );
    }

    *pCompareStatus = TRUE;

End:

    if (NULL != Flags)
    {
        AccFree(Flags);
    }

    if (NULL != Buffer)
    {
        AccFree(Buffer);
    }

    return dwErr;;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaGetNT4NodeSD                                                //
//                                                                            //
// Description: Converts the child security descriptor NT4 ACL into NT5 ACL   //
//              by comparing it to the parent ACL.                            //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pOldSD]              Old parent security descriptor               //
//     [IN  OUT pOldChildSD]     Old child security descriptor                //
//     [IN  Processhandle]       Process Handle                               //
//     [IN  bIsChildContainer]   Whether the child object is a Container      //
//     [IN  pGenMap]             Generic mapping of the object rights         //
//     [IN  SecurityInfo]        Security Information requested               //
//                                                                            //
// Algorithm:                                                                 //
//     if child acl and parent acl differ then                                //
//         mark the child acl PROTECTED                                       //
//                                                                            //
// Returns: ERROR_SUCCESS on successful completion of the routine             //
//          ERROR_XXXX    Otherwise                                           //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
MartaGetNT4NodeSD(
    IN     PSECURITY_DESCRIPTOR pOldSD,
    IN OUT PSECURITY_DESCRIPTOR pOldChildSD,
    IN     HANDLE               ProcessHandle,
    IN     BOOL                 bIsChildContainer,
    IN     PGENERIC_MAPPING     pGenMap,
    IN     SECURITY_INFORMATION SecurityInfo
    )
{
    SECURITY_DESCRIPTOR  NullSD;

    DWORD                dwErr         = ERROR_SUCCESS;
    BOOL                 CompareStatus = FALSE;
    PACL                 pChildAcl     = NULL;
    PACL                 pParentAcl    = NULL;
    HANDLE               ThreadHandle  = NULL;
    PSECURITY_DESCRIPTOR pTmpSD        = NULL;
    UCHAR                Buffer[2 * sizeof(ACL)];
    PACL                 pDacl         = (PACL) Buffer;
    PACL                 pSacl         = (PACL) (Buffer + sizeof(ACL));

    if (!FLAG_ON(SecurityInfo, (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)))
    {
        return ERROR_SUCCESS;
    }

    InitializeSecurityDescriptor(&NullSD, SECURITY_DESCRIPTOR_REVISION);

    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {
        if (FALSE == InitializeAcl(pDacl, sizeof(ACL), ACL_REVISION))
        {
            return ERROR_ACCESS_DENIED;
        }

        if (FALSE == SetSecurityDescriptorDacl(
                         &NullSD,
                         TRUE,
                         pDacl,
                         FALSE))
        {
            return GetLastError();
        }
    }

    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        if (FALSE == InitializeAcl(pSacl, sizeof(ACL), ACL_REVISION))
        {
            return ERROR_ACCESS_DENIED;
        }

        if (FALSE == SetSecurityDescriptorSacl(
                         &NullSD,
                         TRUE,
                         pSacl,
                         FALSE))
        {
            return GetLastError();
        }
    }

    if (FALSE == SetSecurityDescriptorOwner(
                     &NullSD,
                     RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD),
                     FALSE))
    {
        return GetLastError();
    }

    if (FALSE == SetSecurityDescriptorGroup(
                     &NullSD,
                     RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD),
                     FALSE))
    {
        return GetLastError();
    }

    MARTA_TURN_OFF_IMPERSONATION;

    if (FALSE == CreatePrivateObjectSecurityEx(
                     pOldSD,
                     &NullSD,
                     &pTmpSD,
                     NULL,
                     bIsChildContainer,
                     (SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT | SEF_AVOID_OWNER_CHECK | SEF_AVOID_PRIVILEGE_CHECK),
                     ProcessHandle,
                     pGenMap
                     ))
    {
        dwErr = GetLastError();
    }

    MARTA_TURN_ON_IMPERSONATION;

    CONDITIONAL_EXIT(dwErr, End);

    //
    // Mark the aces from the child DACL, which are present in the parent.
    //

    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {
        pChildAcl  = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD);
        pParentAcl = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pTmpSD);

        dwErr = MartaCompareAndMarkInheritedAces(
                    pParentAcl,
                    pChildAcl,
                    bIsChildContainer,
                    &CompareStatus
                    );

        CONDITIONAL_EXIT(dwErr, End);

        if (FALSE == CompareStatus)
        {
            ((PISECURITY_DESCRIPTOR) pOldChildSD)->Control |= SE_DACL_PROTECTED;

        }
    }

    //
    // Mark the aces from the child SACL, which are present in the parent.
    //

    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        pChildAcl  = RtlpSaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD);
        pParentAcl = RtlpSaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pTmpSD);

        dwErr = MartaCompareAndMarkInheritedAces(
                    pParentAcl,
                    pChildAcl,
                    bIsChildContainer,
                    &CompareStatus
                    );

        CONDITIONAL_EXIT(dwErr, End);

        if (FALSE == CompareStatus)
        {
            ((PISECURITY_DESCRIPTOR) pOldChildSD)->Control |= SE_SACL_PROTECTED;

        }

        CONDITIONAL_EXIT(dwErr, End);
    }

End:
    if (NULL != pTmpSD)
    {
        DestroyPrivateObjectSecurity(&pTmpSD);
    }

    return dwErr;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaUpdateTree                                                  //
//                                                                            //
// Description: Propagate the inheritable aces to the children.               //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  SecurityInfo]           Security Information requested            //
//     [IN  pNewSD]                 New parent security descriptor            //
//     [IN  pOldSD]                 Old parent security descriptor            //
//     [IN  Context]                Context structure for the object          //
//     [IN  Processhandle]          Process Handle                            //
//     [IN  pSetFunctionContext]    Structure holding the function pointers   //
//     [IN  pGenMap]                Generic mapping of the object rights      //
//                                                                            //
// Algorithm:                                                                 //
//     For all children that are not "Protected"                              //
//         if OldChildSD = NT4 style                                          //
//            Convert it into NT5 style                                       //
//         NewChildSD = Merge(ParentSD, OldChildSD)                           //
//         UpdateTree(Child)                                                  //
//         Stamp NewChildSD on Child                                          //
//                                                                            //
// Note: An error in the propagation is ignored.                              //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

BOOL
MartaUpdateTree(
    IN SECURITY_INFORMATION        SecurityInfo,
    IN PSECURITY_DESCRIPTOR        pNewSD,
    IN PSECURITY_DESCRIPTOR        pOldSD,
    IN MARTA_CONTEXT               Context,
    IN HANDLE                      ProcessHandle,
    IN PMARTA_SET_FUNCTION_CONTEXT pMartaSetFunctionContext,
    IN PGENERIC_MAPPING            pGenMap
    )
{
    MARTA_OBJECT_PROPERTIES ObjectProperties;

    DWORD                dwErr             = ERROR_SUCCESS;
    BOOL                 bIsChildContainer = FALSE;
    BOOL                 bRetryPropagation = FALSE;
    BOOL                 bDoPropagate      = TRUE;
    HANDLE               ThreadHandle      = NULL;
    PSECURITY_DESCRIPTOR pOldChildSD       = NULL;
    PSECURITY_DESCRIPTOR pNewChildSD       = NULL;
    MARTA_CONTEXT        ChildContext      = NULL_MARTA_CONTEXT;

    //
    // Get the first child to update.
    //

    dwErr = (*(pMartaSetFunctionContext->fFindFirst))(
                   Context,
                   (*(pMartaSetFunctionContext->fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, TRUE, SecurityInfo),
                   &ChildContext
                   );

    if (ERROR_SUCCESS != dwErr)
    {
        if (NULL == ChildContext)
        {
            dwErr = (*(pMartaSetFunctionContext->fFindFirst))(
                           Context,
                           (*(pMartaSetFunctionContext->fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &ChildContext
                           );
        }
        else
        {
            dwErr = (*(pMartaSetFunctionContext->fReopenContext))(
                           ChildContext,
                           (*(pMartaSetFunctionContext->fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo)
                           );
        }

        bDoPropagate = FALSE;
    }

    if (NULL == ChildContext)
    {
        return TRUE;
    }

    CONDITIONAL_EXIT(dwErr, EndOfWhile);

    //
    // Note: On any intermediate error the current child is skipped.
    //

    while (ChildContext)
    {

        ObjectProperties.cbSize  = sizeof(ObjectProperties);
        ObjectProperties.dwFlags = 0;

        dwErr = (*(pMartaSetFunctionContext->fGetProperties))(
                       ChildContext,
                       &ObjectProperties
                       );

        CONDITIONAL_EXIT(dwErr, EndOfWhile);

        bIsChildContainer = FLAG_ON(ObjectProperties.dwFlags, MARTA_OBJECT_IS_CONTAINER);

        dwErr = (*(pMartaSetFunctionContext->fGetRights))(
                       ChildContext,
                       (SecurityInfo | OWNER_SECURITY_INFORMATION |
                        GROUP_SECURITY_INFORMATION),
                       &pOldChildSD
                       );

        CONDITIONAL_EXIT(dwErr, EndOfWhile);

        //
        // Skip the children that are protected.
        //

        if (!MARTA_SD_NOT_PROTECTED((PISECURITY_DESCRIPTOR) pOldChildSD, SecurityInfo))
        {
            goto EndOfWhile;

        }

        //
        // Convert NT4 SD to NT5 style.
        //

        if (FALSE == MartaIsSDNT5Style(pOldChildSD))
        {
            //
            // Note that this modifies OldChildSD in one of the two ways:
            //     1. If any of the inheritable aces from the OldSD are missing
            //        from OldChild then
            //            Mark the acl PROTECTED.
            //     2. else
            //            Mark the common aces in ChildSD as INHERITED.
            //

            dwErr = MartaGetNT4NodeSD(
                        pOldSD,
                        pOldChildSD,
                        ProcessHandle,
                        bIsChildContainer,
                        pGenMap,
                        SecurityInfo
                        );

            CONDITIONAL_EXIT(dwErr, EndOfWhile);
        }

        MARTA_TURN_OFF_IMPERSONATION;

        //
        // Merge the NewParentSD and the OldChildSD to create NewChildSD.
        //

        if (FALSE == CreatePrivateObjectSecurityEx(
                         pNewSD,
                         pOldChildSD,
                         &pNewChildSD,
                         NULL,
                         bIsChildContainer,
                         (SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT |
                          SEF_AVOID_OWNER_CHECK | SEF_AVOID_PRIVILEGE_CHECK),
                         ProcessHandle,
                         pGenMap
                         ))
        {
            dwErr = GetLastError();
        }

        MARTA_TURN_ON_IMPERSONATION;

        CONDITIONAL_EXIT(dwErr, EndOfWhile);

        //
        // Update the subtree undrneath this child.
        //

        if (bIsChildContainer)
        {
            if (bDoPropagate)
            {
                bRetryPropagation = MartaUpdateTree(
                                        SecurityInfo,
                                        pNewChildSD,
                                        pOldChildSD,
                                        ChildContext,
                                        ProcessHandle,
                                        pMartaSetFunctionContext,
                                        pGenMap
                                        );
            }
            else
            {
                bRetryPropagation = TRUE;
            }
        }

        //
        // Stamp NewChildSD on child.
        //

        if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pNewChildSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
        }

        if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pNewChildSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
        }

        dwErr = (*(pMartaSetFunctionContext->fSetRights))(
                       ChildContext,
                       SecurityInfo,
                       pNewChildSD
                       );

        CONDITIONAL_EXIT(dwErr, EndOfWhile);

        //
        // If propagation had failed in the first attept then try again. This is to
        // cover the case when the container can be enumerated after setting the new
        // security.

        if (bRetryPropagation && (SecurityInfo & DACL_SECURITY_INFORMATION))
        {
            ACCESS_MASK Access = (*(pMartaSetFunctionContext->fGetDesiredAccess))(
                                        NO_ACCESS_RIGHTS,
                                        TRUE,
                                        SecurityInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)
                                        );

            dwErr = (*(pMartaSetFunctionContext->fReopenContext))(
                           ChildContext,
                           Access
                           );

            CONDITIONAL_EXIT(dwErr, EndOfWhile);

            (VOID) MartaUpdateTree(
                       SecurityInfo,
                       pNewChildSD,
                       pOldChildSD,
                       ChildContext,
                       ProcessHandle,
                       pMartaSetFunctionContext,
                       pGenMap
                       );
        }

EndOfWhile:

        bRetryPropagation = FALSE;

        if (NULL != pOldChildSD)
        {
            AccFree(pOldChildSD);
            pOldChildSD = NULL;
        }

        if (NULL != pNewChildSD)
        {
            DestroyPrivateObjectSecurity(&pNewChildSD);
            pNewChildSD = NULL;
        }

        //
        // Get the next child.
        //

        do {

            dwErr = (*(pMartaSetFunctionContext->fFindNext))(
                           ChildContext,
                           (*(pMartaSetFunctionContext->fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, TRUE, SecurityInfo),
                           &ChildContext
                           );

            if (ERROR_SUCCESS != dwErr)
            {
                dwErr = (*(pMartaSetFunctionContext->fReopenContext))(
                               ChildContext,
                               (*(pMartaSetFunctionContext->fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo)
                               );

                bDoPropagate = FALSE;
            }
            else
            {
                bDoPropagate = TRUE;
            }

        } while ((ERROR_SUCCESS != dwErr) && (NULL != ChildContext));
    }

    return FALSE;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: AccRewriteSetNamedRights                                         //
//                                                                            //
// Description: Set the security descriptor passed in on the object passed in //
//              by Name.                                                      //
//              This routine is exported by ntmarta and called by advapi32.   //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pObjectName]            Name of the Object                        //
//     [IN  ObjectType]             Type of the object                        //
//     [IN  SecurityInfo]           Security Information to be stamped        //
//     [IN  pSecurityDescriptor]    Security descriptor to be stamped         //
//     [IN  bSkipInheritanceComputation]  Whether to compute inherited aces   //
//                                        from the parent
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccRewriteSetNamedRights(
    IN     LPWSTR               pObjectName,
    IN     SE_OBJECT_TYPE       ObjectType,
    IN     SECURITY_INFORMATION SecurityInfo,
    IN OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
    IN     BOOL                 bSkipInheritanceComputation
    )
{
    DWORD         dwErr                 = ERROR_SUCCESS;
    MARTA_CONTEXT Context               = NULL_MARTA_CONTEXT;
    BOOL          bDoPropagate          = FALSE;
    BOOL          bReadOldProtectedBits = FALSE;

    MARTA_OBJECT_TYPE_PROPERTIES ObjectTypeProperties;
    MARTA_SET_FUNCTION_CONTEXT   MartaSetFunctionContext;

    GENERIC_MAPPING      ZeroGenMap        = {0, 0, 0, 0};
    SECURITY_INFORMATION LocalSecurityInfo = (SECURITY_INFORMATION) 0;
    PSECURITY_DESCRIPTOR pOldSD            = NULL;

    //
    // Named calls are not valid only for the following object types.
    //

    switch (ObjectType)
    {
    case SE_FILE_OBJECT:
    case SE_SERVICE:
    case SE_PRINTER:
    case SE_REGISTRY_KEY:
    case SE_REGISTRY_WOW64_32KEY:
    case SE_LMSHARE:
    case SE_KERNEL_OBJECT:
    case SE_WINDOW_OBJECT:
    case SE_WMIGUID_OBJECT:
    case SE_DS_OBJECT:
    case SE_DS_OBJECT_ALL:
        break;
    case SE_PROVIDER_DEFINED_OBJECT:
    case SE_UNKNOWN_OBJECT_TYPE:
    default:
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Initialize the structure to hold the function pointers.
    //

    MartaInitializeSetContext(ObjectType, &MartaSetFunctionContext);


    //
    // Get the "Type" properties for the object,
    //

    ObjectTypeProperties.cbSize  = sizeof(ObjectTypeProperties);
    ObjectTypeProperties.dwFlags = 0;
    ObjectTypeProperties.GenMap  = ZeroGenMap;

    dwErr = (*(MartaSetFunctionContext.fGetTypeProperties))(&ObjectTypeProperties);

    CONDITIONAL_EXIT(dwErr, End);

    //
    // To make sure that NT4 applications do not wipe out PROTECTED bits, make a
    // note whether the caller knows what he is doing i.e. has passed in the
    // appropriate PROTECTED flags.
    //

    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {
        if (!FLAG_ON(SecurityInfo, (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)))
        {
            bReadOldProtectedBits  = TRUE;
            LocalSecurityInfo     |= DACL_SECURITY_INFORMATION;
        }
    }

    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        if (!FLAG_ON(SecurityInfo, (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION)))
        {
            bReadOldProtectedBits  = TRUE;
            LocalSecurityInfo     |= SACL_SECURITY_INFORMATION;
        }
    }

    //
    // Even for objects like Files/RegistryKeys manual propagation is required
    // only if DACl/SACL is to be set.
    //

    if ((FLAG_ON(ObjectTypeProperties.dwFlags, MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG)) &&
        (FLAG_ON(SecurityInfo, (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))))
    {
        dwErr = (*(MartaSetFunctionContext.fOpenNamedObject))(
                       pObjectName,
                       (*(MartaSetFunctionContext.fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, TRUE, SecurityInfo),
                       &Context
                       );

        if (ERROR_SUCCESS != dwErr)
        {
            bDoPropagate = FALSE;

            dwErr = (*(MartaSetFunctionContext.fOpenNamedObject))(
                           pObjectName,
                           (*(MartaSetFunctionContext.fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &Context
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }
        else
        {
            bDoPropagate = TRUE;
        }

        dwErr = MartaManualPropagation(
                    Context,
                    SecurityInfo,
                    pSecurityDescriptor,
                    &(ObjectTypeProperties.GenMap),
                    bDoPropagate,
                    bReadOldProtectedBits,
                    &MartaSetFunctionContext,
                    bSkipInheritanceComputation
                    );

        CONDITIONAL_EXIT(dwErr, End);
    }

    //
    // For object for which manual propagation is not required, stamp the SD
    // on the object.
    //

    else
    {
        if ((FLAG_ON(ObjectTypeProperties.dwFlags, MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG)) &&
            bReadOldProtectedBits)
        {
            dwErr = (*(MartaSetFunctionContext.fOpenNamedObject))(
                           pObjectName,
                           (*(MartaSetFunctionContext.fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &Context
                           );

            CONDITIONAL_EXIT(dwErr, End);

            dwErr = (*(MartaSetFunctionContext.fGetRights))(
                           Context,
                           LocalSecurityInfo,
                           &pOldSD
                           );

            CONDITIONAL_EXIT(dwErr, End);

            //
            // If none of the PROTECTED flags are passed in then do the "right" thing.
            // Read the PROTECTED bit from the existing security descriptor and set it
            // in the new one.
            //

            if (NULL != pOldSD)
            {
                if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
                {
                    if (!FLAG_ON(SecurityInfo, (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)))
                    {
                        ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= ((PISECURITY_DESCRIPTOR) pOldSD)->Control & SE_DACL_PROTECTED;

                    }
                }

                if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
                {
                    if (!FLAG_ON(SecurityInfo, (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION)))
                    {
                        ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= ((PISECURITY_DESCRIPTOR) pOldSD)->Control & SE_SACL_PROTECTED;
                    }
                }
            }
        }
        else
        {
            dwErr = (*(MartaSetFunctionContext.fOpenNamedObject))(
                           pObjectName,
                           (*(MartaSetFunctionContext.fGetDesiredAccess))(WRITE_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &Context
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }

        if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= SE_DACL_AUTO_INHERIT_REQ;
        }

        if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= SE_SACL_AUTO_INHERIT_REQ;
        }

        dwErr = (*(MartaSetFunctionContext.fSetRights))(
                       Context,
                       SecurityInfo,
                       pSecurityDescriptor
                       );

        CONDITIONAL_EXIT(dwErr, End);
    }

End:

    if (NULL != Context)
    {
        (VOID) (*(MartaSetFunctionContext.fCloseContext))(Context);
    }

    if (NULL != pOldSD)
    {
        AccFree(pOldSD);
    }

    return dwErr;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: AccRewriteSetHandleRights                                        //
//                                                                            //
// Description: Set the security descriptor passed in on the object passed in //
//              as Handle.                                                    //
//              This routine is exported by ntmarta and called by advapi32.   //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  Handle]                 Handle to the Object                      //
//     [IN  ObjectType]             Type of the object                        //
//     [IN  SecurityInfo]           Security Information to be stamped        //
//     [IN  pSecurityDescriptor]    Security descriptor to be stamped         //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccRewriteSetHandleRights(
    IN     HANDLE               Handle,
    IN     SE_OBJECT_TYPE       ObjectType,
    IN     SECURITY_INFORMATION SecurityInfo,
    IN OUT PSECURITY_DESCRIPTOR pSecurityDescriptor
    )
{
    DWORD         dwErr                 = ERROR_SUCCESS;
    MARTA_CONTEXT Context               = NULL_MARTA_CONTEXT;
    BOOL          bDoPropagate          = FALSE;
    BOOL          bReadOldProtectedBits = FALSE;

    MARTA_OBJECT_TYPE_PROPERTIES ObjectTypeProperties;
    MARTA_SET_FUNCTION_CONTEXT   MartaSetFunctionContext;

    GENERIC_MAPPING      ZeroGenMap        = {0, 0, 0, 0};
    SECURITY_INFORMATION LocalSecurityInfo = (SECURITY_INFORMATION) 0;
    PSECURITY_DESCRIPTOR pOldSD            = NULL;

    //
    // Handle calls are not valid for all object types.
    //

    switch (ObjectType)
    {
    case SE_FILE_OBJECT:
    case SE_SERVICE:
    case SE_PRINTER:
    case SE_REGISTRY_KEY:
    case SE_LMSHARE:
    case SE_KERNEL_OBJECT:
    case SE_WINDOW_OBJECT:
    case SE_WMIGUID_OBJECT:
        break;
    case SE_DS_OBJECT:
    case SE_DS_OBJECT_ALL:
    case SE_PROVIDER_DEFINED_OBJECT:
    case SE_UNKNOWN_OBJECT_TYPE:
    default:
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Initialize the structure to hold the function pointers.
    //

    MartaInitializeSetContext(ObjectType, &MartaSetFunctionContext);

    //
    // Get the "Type" properties for the object,
    //

    ObjectTypeProperties.cbSize  = sizeof(ObjectTypeProperties);
    ObjectTypeProperties.dwFlags = 0;
    ObjectTypeProperties.GenMap  = ZeroGenMap;

    dwErr = (*(MartaSetFunctionContext.fGetTypeProperties))(&ObjectTypeProperties);

    CONDITIONAL_EXIT(dwErr, End);

    //
    // To make sure that NT4 applications do not wipe out PROTECTED bits, make a
    // note whether the caller knows what he is doing i.e. has passed in the
    // appropriate PROTECTED flags.
    //

    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {
        if (!FLAG_ON(SecurityInfo, (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)))
        {
            bReadOldProtectedBits  = TRUE;
            LocalSecurityInfo     |= DACL_SECURITY_INFORMATION;
        }
    }

    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        if (!FLAG_ON(SecurityInfo, (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION)))
        {
            bReadOldProtectedBits  = TRUE;
            LocalSecurityInfo     |= SACL_SECURITY_INFORMATION;
        }
    }

    //
    // Even for objects like Files/RegistryKeys manual propagation is required
    // only if DACl/SACL is to be set.
    //

    if ((FLAG_ON(ObjectTypeProperties.dwFlags, MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG)) &&
        (FLAG_ON(SecurityInfo, (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))))
    {
        dwErr = (*(MartaSetFunctionContext.fOpenHandleObject))(
                       Handle,
                       (*(MartaSetFunctionContext.fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, TRUE, SecurityInfo),
                       &Context
                       );

        if (ERROR_SUCCESS != dwErr)
        {
            bDoPropagate = FALSE;

            dwErr = (*(MartaSetFunctionContext.fOpenHandleObject))(
                           Handle,
                           (*(MartaSetFunctionContext.fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &Context
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }
        else
        {
            bDoPropagate = TRUE;
        }

        dwErr = MartaManualPropagation(
                    Context,
                    SecurityInfo,
                    pSecurityDescriptor,
                    &(ObjectTypeProperties.GenMap),
                    bDoPropagate,
                    bReadOldProtectedBits,
                    &MartaSetFunctionContext,
                    FALSE  // Do not skip inheritance computation
                    );

        CONDITIONAL_EXIT(dwErr, End);
    }

    //
    // For object for which manual propagation is not required, stamp the SD
    // on the object.
    //

    else
    {
        if ((FLAG_ON(ObjectTypeProperties.dwFlags, MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG)) &&
            bReadOldProtectedBits)
        {
            dwErr = (*(MartaSetFunctionContext.fOpenHandleObject))(
                           Handle,
                           (*(MartaSetFunctionContext.fGetDesiredAccess))(MODIFY_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &Context
                           );

            CONDITIONAL_EXIT(dwErr, End);

            dwErr = (*(MartaSetFunctionContext.fGetRights))(
                           Context,
                           LocalSecurityInfo,
                           &pOldSD
                           );

            CONDITIONAL_EXIT(dwErr, End);

            //
            // If none of the PROTECTED flags are passed in then do the "right" thing.
            // Read the PROTECTED bit from the existing security descriptor and set it
            // in the new one.
            //

            if (NULL != pOldSD)
            {
                if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
                {
                    if (!FLAG_ON(SecurityInfo, (PROTECTED_DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION)))
                    {
                        ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= ((PISECURITY_DESCRIPTOR) pOldSD)->Control & SE_DACL_PROTECTED;
                    }
                }

                if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
                {
                    if (!FLAG_ON(SecurityInfo, (PROTECTED_SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION)))
                    {
                        ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= ((PISECURITY_DESCRIPTOR) pOldSD)->Control & SE_SACL_PROTECTED;
                    }
                }
            }
        }
        else
        {
            dwErr = (*(MartaSetFunctionContext.fOpenHandleObject))(
                           Handle,
                           (*(MartaSetFunctionContext.fGetDesiredAccess))(WRITE_ACCESS_RIGHTS, FALSE, SecurityInfo),
                           &Context
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }

        if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= SE_DACL_AUTO_INHERIT_REQ;
        }

        if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pSecurityDescriptor)->Control |= SE_SACL_AUTO_INHERIT_REQ;
        }

        dwErr = (*(MartaSetFunctionContext.fSetRights))(
                       Context,
                       SecurityInfo,
                       pSecurityDescriptor
                       );

        CONDITIONAL_EXIT(dwErr, End);
    }

End:
    if (NULL != Context)
    {
        (VOID) (*(MartaSetFunctionContext.fCloseContext))(Context);
    }

    if (NULL != pOldSD)
    {
        AccFree(pOldSD);
    }

    return dwErr;
}

typedef struct _FN_OBJECT_FUNCTIONS
{
    ULONG Flags;
} FN_OBJECT_FUNCTIONS, *PFN_OBJECT_FUNCTIONS;

#define MARTA_NO_PARENT    (LONG) -1
#define MARTA_EXPLICIT_ACE  0

VOID
MartaInitializeIndexContext(
    IN  SE_OBJECT_TYPE                ObjectType,
    OUT PMARTA_INDEX_FUNCTION_CONTEXT pFunctionContext
    )
{
    pFunctionContext->fCloseContext    = MartaCloseContext[ObjectType];
    pFunctionContext->fOpenNamedObject = MartaOpenNamedObject[ObjectType];
    pFunctionContext->fGetRights       = MartaGetRights[ObjectType];
    pFunctionContext->fGetParentName   = MartaGetParentName[ObjectType];
}

typedef DWORD (*PFN_FREE) (IN PVOID Mem);

DWORD
AccFreeIndexArray(
    IN OUT PINHERITED_FROMW pInheritArray,
    IN USHORT AceCnt,
    IN PFN_FREE pfnFree
    );

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: AccGetInheritanceSource                                          //
//                                                                            //
// Description: Get the source of every inherited ace in the gicen acl.       //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN pObjectName]      Name of the object                               //
//     [IN ObjecType]        Type of the object ex. File/Reg/DS               //
//     [IN SecurityInfo]     Whether DACL/SACL                                //
//     [IN Container]        Whether Object or Container                      //
//     [IN ObjecTypeGuid]    Type of the object (for DS objects)              //
//     [IN pAcl]             DACL or SACL depending on SecurityInfo           //
//     [IN pGenericMapping]  GenericMapping for the object type               //
//     [IN pfnArray]         Function pointers when we support non-DS/FS/Reg  //
//     [OUT pInheritArray]    To return the results                           //
//                                                                            //
//                                                                            //
// Algorithm:                                                                 //
//     Initialize the output structure.                                       //
//     Read the Owner/Group info needed for CreatePrivateObjectSecurityEx.    // 
//     while (unmarked inherited aces exist)                                  //
//         Get the parent at the next level.                                  //
//         if we are at the root,                                             //
//             break                                                          //
//         Get the xAcl for the parent.                                       //
//         for ancestors other than the immediate parent                      //
//             Mask off inheritance flags for ACES with NP or ID              //
//         for immediate parent                                               //
//             Mask off inheritance flags for ACES with ID                    //
//         Call CreatePrivateObjectSecurityEx with the empty SD and ParentSD  // 
//             to get ExpectedSD                                              //
//         From the input xAcl,                                               //
//             mark unmarked common inherited aces                            //
//             Update count                                                   //
//         If the parent xAcl was protected,                                  //
//             break                                                          //
//                                                                            //
// Returns: ERROR_SUCCESS on successful completion of the routine             //
//          ERROR_XXXX    Otherwise                                           //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccGetInheritanceSource(
    IN  LPWSTR                   pObjectName,
    IN  SE_OBJECT_TYPE           ObjectType,
    IN  SECURITY_INFORMATION     SecurityInfo,
    IN  BOOL                     Container,
    IN  GUID                  ** pObjectTypeGuid OPTIONAL,
    IN  DWORD                    GuidCount,
    IN  PACL                     pAcl,
    IN  PGENERIC_MAPPING         pGenericMapping,
    IN  PFN_OBJECT_MGR_FUNCTS    pfnArray OPTIONAL,
    OUT PINHERITED_FROMW         pInheritArray
    )
{
    SECURITY_DESCRIPTOR  EmptySD;
    MARTA_INDEX_FUNCTION_CONTEXT MartaIndexFunctionContext;

    USHORT               i               = 0;
    USHORT               j               = 0;
    USHORT               AceCnt          = 0;
    USHORT               ParentAceCnt    = 0;
    USHORT               ExpectedAceCnt  = 0;
    USHORT               InheritedAceCnt = 0;
    USHORT               ParentIndex     = 0;
    ULONG                ProtectedBit    = 0;
    UCHAR                FlagsToKeep     = 0;
    DWORD                dwErr           = ERROR_SUCCESS;
    BOOL                 bKnownObject    = FALSE;
    BOOL                 Match           = TRUE;
    BOOL                 ProtectedParent = FALSE;
    LPWSTR               ParentName      = NULL;
    LPWSTR               OldName         = NULL;
    PACL                 pParentAcl      = NULL;
    PACL                 pExpectedAcl    = NULL;
    PACE_HEADER          pAce            = NULL;
    PACE_HEADER          pParentAce      = NULL;
    PACE_HEADER          pExpectedAce    = NULL;
    PSECURITY_DESCRIPTOR pSD             = NULL;
    PSECURITY_DESCRIPTOR pNewSD          = NULL;
    PSECURITY_DESCRIPTOR pParentSD       = NULL;
    MARTA_CONTEXT        Context         = NULL_MARTA_CONTEXT;

    //
    // Simple error checks to make sure that the input is valid.
    //

    if ((NULL == pAcl) || (!RtlValidAcl(pAcl)))
    {
        return ERROR_INVALID_PARAMETER;
    }

    if ((NULL == pObjectName) || (NULL == pInheritArray) || (NULL == pGenericMapping))
    {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Make sure that the caller requested for either the SACL or the DACL and
    // nothing else.
    // Record the corresponding protected flag. This will be used later on.
    //

    switch (SecurityInfo)
    {
    case DACL_SECURITY_INFORMATION:
        ProtectedBit = SE_DACL_PROTECTED;
        break;
    case SACL_SECURITY_INFORMATION:
        ProtectedBit = SE_SACL_PROTECTED;
        break;
    default:
        return ERROR_INVALID_PARAMETER;
    }

    //
    // The function is supported for just files, registry, and DS objects.
    //

    switch (ObjectType)
    {
    case SE_FILE_OBJECT:
    case SE_REGISTRY_KEY:
    case SE_DS_OBJECT:
    case SE_DS_OBJECT_ALL:

        bKnownObject = TRUE;
        MartaInitializeIndexContext(ObjectType, &MartaIndexFunctionContext);
        break;

    default:
        return ERROR_INVALID_PARAMETER;
    }

    AceCnt = pAcl->AceCount;

    //
    // Return for an empty acl.
    //

    if (0 == AceCnt)
    {
        return ERROR_SUCCESS;
    }

    //
    // We need to mask off certain aceflags for ancestors other than the parent.
    //

    if (Container)
    {
        FlagsToKeep = ~(OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
    }
    else
    {
        FlagsToKeep = ~OBJECT_INHERIT_ACE;
    }

    //
    // Run thru the acl and mark the aces as either INHERITED or EXPLICIT.
    // Keep a count of inherited aces and set return values to default.
    //

    pAce = (PACE_HEADER) FirstAce(pAcl);
    for (i = 0; i < AceCnt; pAce = (PACE_HEADER) NextAce(pAce), i++)
    {
        if (FLAG_ON(pAce->AceFlags, INHERITED_ACE))
        {
            pInheritArray[i].GenerationGap = MARTA_NO_PARENT;
            InheritedAceCnt++;
        }
        else
        {
            pInheritArray[i].GenerationGap = MARTA_EXPLICIT_ACE;
        }

        pInheritArray[i].AncestorName = NULL;
    }

    //
    // Return for an acl with no inherited aces.
    //

    if (0 == InheritedAceCnt)
    {
        return ERROR_SUCCESS;
    }

    InitializeSecurityDescriptor(&EmptySD, SECURITY_DESCRIPTOR_REVISION);

    if (bKnownObject)
    {
        //
        // Read the owner and group information on the object.
        //

        dwErr = (*(MartaIndexFunctionContext.fOpenNamedObject))(
                       pObjectName,
                       READ_CONTROL,
                       &Context
                       );

        CONDITIONAL_EXIT(dwErr, End);

        dwErr = (*(MartaIndexFunctionContext.fGetRights))(
                       Context,
                       OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
                       &pSD
                       );

        // Note: This has to be freed immediately!!

        (VOID) (*(MartaIndexFunctionContext.fCloseContext))(Context);

        CONDITIONAL_EXIT(dwErr, End);
    }
    else
    {
        //
        // Get the owner and group information.
        //
    }

    //
    // Set the owner and group information in pSD.
    //

    if (!SetSecurityDescriptorOwner(
             &EmptySD,
             RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD),
             FALSE))
    {
        dwErr = GetLastError();
        goto End;
    }

    if (!SetSecurityDescriptorGroup(
             &EmptySD,
             RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD),
             FALSE))
    {
        dwErr = GetLastError();
        goto End;
    }


    if (bKnownObject)
    {
        dwErr = (*(MartaIndexFunctionContext.fGetParentName))(
                       pObjectName,
                       &ParentName
                       );

        CONDITIONAL_EXIT(dwErr, End);

        //
        // A null parent name means we have hit the root of the hierarchy.
        //

        if (NULL == ParentName)
        {
            goto End;
        }
    }
    else
    {
    }

    OldName = ParentName;

    //
    // Run thru the list of ancestors as long as
    //     1. we have inherited aces whose ancestor is yet to be found AND
    //     2. we have not yet hit an ancestor that is PROTECTED.
    //

    for (ParentIndex = 1; InheritedAceCnt > 0 && !ProtectedParent; ParentIndex++)
    {
        if (bKnownObject)
        {
#ifdef MARTA_DEBUG
            wprintf(L"\n\nParentIndex = %d, ParentName = %s\n", ParentIndex, ParentName);
#endif

            //
            // Get parent security descriptor
            //

            dwErr = AccRewriteGetNamedRights(
                        ParentName,
                        ObjectType,
                        SecurityInfo,
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &pParentSD
                        );

            CONDITIONAL_EXIT(dwErr, End);

        }
        else
        {
            // Get the ParentName and ParentSD
        }

        //
        // This might happen if we were to extend the API to support new object
        // types.
        //

        if (NULL == pParentSD)
        {
            dwErr = ERROR_ACCESS_DENIED;
            goto End;
        }

        //
        // Get the Acl
        //

        if (DACL_SECURITY_INFORMATION == SecurityInfo)
        {
            pParentAcl = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pParentSD);
        }
        else
        {
            pParentAcl = RtlpSaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pParentSD);
        }

        //
        // Null acls are really protected.
        //

        if (NULL == pParentAcl)
        {
            break;
        }

        ParentAceCnt = pParentAcl->AceCount;

        if (ParentIndex > 1)
        {
            //
            // This is an ancestor other then the immediate parent. Mask off its
            // inheritable inherited aces as well as those with NP flag in them.
            // Now we will not see them in the inherited part of the acl after
            // calling CreatePrivateObjectSecurityEx.
            // We save on multiple calls to CreatePrivateObjectSecurityEx by
            // masking off the NP aces.
            //

            pParentAce = (PACE_HEADER) FirstAce(pParentAcl);
            for (i = 0; i < ParentAceCnt; pParentAce = (PACE_HEADER) NextAce(pParentAce), i++)
            {
                if (FLAG_ON(pParentAce->AceFlags, INHERITED_ACE) ||
                    FLAG_ON(pParentAce->AceFlags, NO_PROPAGATE_INHERIT_ACE))
                {
                    pParentAce->AceFlags &= FlagsToKeep;
                }
            }
        }
        else
        {
            //
            // This is the immediate parent. Mask off its inheritable inherited
            // aces so that we will not see them in the inherited part of the
            // acl after calling CreatePrivateObjectSecurityEx.
            //

            pParentAce = (PACE_HEADER) FirstAce(pParentAcl);
            for (i = 0; i < ParentAceCnt; pParentAce = (PACE_HEADER) NextAce(pParentAce), i++)
            {
                if (FLAG_ON(pParentAce->AceFlags, INHERITED_ACE))
                {
                    pParentAce->AceFlags &= FlagsToKeep;
                }
            }
        }

        //
        // Merge the Empty SD with the modified parent SD.
        //

        if (!CreatePrivateObjectSecurityWithMultipleInheritance(
                 pParentSD,
                 &EmptySD,
                 &pNewSD,
                 pObjectTypeGuid,
                 GuidCount,
                 Container,
                 (SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT | SEF_AVOID_OWNER_CHECK | SEF_AVOID_PRIVILEGE_CHECK),
                 NULL,
                 pGenericMapping
                 ))
        {
            dwErr = GetLastError();
            goto End;
        }

        //
        // Get the ChildAcl
        //

        if (DACL_SECURITY_INFORMATION == SecurityInfo)
        {
            pExpectedAcl = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pNewSD);
        }
        else
        {
            pExpectedAcl = RtlpSaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pNewSD);
        }

        if (NULL == pExpectedAcl)
        {
#ifdef MARTA_DEBUG
        wprintf(L"ExpectedAcl is NULL!!!\n\n");
#endif
            pExpectedAce = NULL;
            ExpectedAceCnt = 0;
        }
        else
        {
            pExpectedAce = (PACE_HEADER) FirstAce(pExpectedAcl);
            ExpectedAceCnt = pExpectedAcl->AceCount;
        }

        Match = FALSE;

#ifdef MARTA_DEBUG
        wprintf(L"ExpectedAceCnt = %d, AceCnt = %d\n", ExpectedAceCnt, AceCnt);
#endif

        //
        // for all expected inherited aces
        //   if there's a match with an "avaliable" ace in the supplied ACL
        //     Record the name and the level of the ancestor in the output array
        //

        for (i = 0; i < ExpectedAceCnt; pExpectedAce = (PACE_HEADER) NextAce(pExpectedAce), i++)
        {
            pAce = (PACE_HEADER) FirstAce(pAcl);
            for (j = 0; j < AceCnt; pAce = (PACE_HEADER) NextAce(pAce), j++)
            {
                //
                // Skip aces whose ancestor has already been determined.
                //

                if (MARTA_NO_PARENT != pInheritArray[j].GenerationGap)
                {
#ifdef MARTA_DEBUG
                    wprintf(L"Ace %d taken by level %d, name = %s\n", j,
                            pInheritArray[j].GenerationGap, pInheritArray[j].AncestorName);
#endif

                    continue;
                }

#ifdef MARTA_DEBUG
                wprintf(L"Ace matching i = %d, j = %d, Parent = %s\n", i, j, ParentName);
#endif

                //
                // Check if the aces match.
                //

                if ((pAce->AceSize == pExpectedAce->AceSize) &&
                    !memcmp(pAce, pExpectedAce, pAce->AceSize))
                {
#ifdef MARTA_DEBUG
                    wprintf(L"Ace match found i = %d, j = %d, left = %d, Parent = %s\n",
                            i, j, InheritedAceCnt, ParentName);
#endif

                    //
                    // Record the name and level of the parent.
                    //

                    pInheritArray[j].GenerationGap = ParentIndex;
                    pInheritArray[j].AncestorName = ParentName;

                    //
                    // A match has been found.
                    //

                    Match = TRUE;

                    //
                    // Decrement the "available" ace count.
                    //

                    InheritedAceCnt--;

                    break;
                }
            }

        }

        //
        // Check if the ancestor is protected. The loop stops after we have
        // processed a protected ancestor.
        //

        ProtectedParent = FLAG_ON(((PISECURITY_DESCRIPTOR) pParentSD)->Control, ProtectedBit);

        if (NULL != pParentSD)
        {
            if (bKnownObject)
            {
                LocalFree(pParentSD);
            }
            else
            {
            }

            pParentSD = NULL;
        }

        ParentName = NULL;

        //
        // Get the name of the next ancestor only if we still need to continue.
        //

        if (InheritedAceCnt > 0 && !ProtectedParent)
        {
            dwErr = (*(MartaIndexFunctionContext.fGetParentName))(
                           OldName,
                           &ParentName
                           );

        }

        //
        // Free the ancestor name if no aces were inherited from it.
        //

        if (!Match)
        {
            if (bKnownObject)
            {
                LocalFree(OldName);
            }
            else
            {
            }
        }

        OldName = NULL;

        CONDITIONAL_EXIT(dwErr, End);

        //
        // A null parent name means we have hit the root of the hierarchy.
        //

        if (NULL == ParentName)
        {
            break;
        }

        OldName = ParentName;
    }

End:

    if (bKnownObject)
    {
        if (ERROR_SUCCESS != dwErr)
        {
            AccFreeIndexArray(pInheritArray, AceCnt, NULL);
        }

        if (NULL != pSD)
        {
            LocalFree(pSD);
        }

        if (NULL != OldName)
        {
            LocalFree(OldName);
        }

        if (NULL != pParentSD)
        {
            LocalFree(pParentSD);
        }
    }
    else
    {
    }

    return dwErr;
}


#ifdef MAX_INDEX_LEVEL
#undef MAX_INDEX_LEVEL
#endif

#define MAX_INDEX_LEVEL 10

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: AccFreeIndexArray                                              //
//                                                                            //
// Description: Free the strings allocated and stored in the array.           //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN OUT pInheritArray]    Array to free results from                   //
//     [IN AceCnt]               Number of elements in the array              //
//     [IN pfnFree]              Function to use for freeing                  //
//                                                                            //
// Algorithm:                                                                 //
//     Note that there is a single allocated string for all nodes at the same //
//     level.                                                                 //
//     In (1, p1), (2, p2), (3, p3), (1, p1) (1, p1) (2, p2)                  //
//         we free just three strings p1, p2 and p3.                          //
//     Initialize the boolean 'freed' array to TRUE                           //
//     For all elements of the array,                                         //
//         if (InheritedAce AND Ancestor name non-NULL AND Not already freed) //
//             Mark as Freed and free the string.                             //
//                                                                            //
// Returns: ERROR_SUCCESS on successful completion of the routine             //
//          ERROR_XXXX    Otherwise                                           //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccFreeIndexArray(
    IN OUT PINHERITED_FROMW pInheritArray,
    IN USHORT AceCnt,
    IN PFN_FREE pfnFree
    )
{
    USHORT i = 0;
    LONG MaxLevel = 0;
    BOOL LevelBuffer[MAX_INDEX_LEVEL + 1];
    PBOOL pLevelStatus = (PBOOL) LevelBuffer;

    for (i = 0; i < AceCnt; i++)
    {
        if (pInheritArray[i].GenerationGap > MaxLevel)
        {
            MaxLevel = pInheritArray[i].GenerationGap;
        }
    }

    if (MaxLevel <= 0)
    {
        return ERROR_SUCCESS;
    }

    if (MaxLevel > MAX_INDEX_LEVEL)
    {
        pLevelStatus = (PBOOL) AccAlloc(sizeof(BOOL) * (MaxLevel + 1));

        if (NULL == pLevelStatus)
        {
            return ERROR_NOT_ENOUGH_MEMORY;
        }
    }

    for (i = 0; i <= MaxLevel; i++)
    {
        pLevelStatus[i] = TRUE;
    }

    for (i = 0; i < AceCnt; i++)
    {
        if ((pInheritArray[i].GenerationGap > 0) &&
            (NULL != pInheritArray[i].AncestorName) &&
            (pLevelStatus[pInheritArray[i].GenerationGap]))
        {
            pLevelStatus[pInheritArray[i].GenerationGap] = FALSE;
            if (NULL == pfnFree)
            {
                AccFree(pInheritArray[i].AncestorName);
            }
            else
            {
                pfnFree(pInheritArray[i].AncestorName);
            }
        }
    }

    if (pLevelStatus != (PBOOL) LevelBuffer)
    {
        AccFree(pLevelStatus);
    }

    return ERROR_SUCCESS;
}


////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaResetTree                                                    //
//                                                                            //
// Description: Reset permissions on the subtree starting at pObjectName.     //
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  pObjectName]    Name of the Object                                //
//     [IN  ObjectType]     Type of the object                                //
//     [IN  SecurityInfo]   Security info to reset                            //
//     [IN  pOwner]         Owner sid to reset                                //
//     [IN  pGroup]         Group sid to reset                                //
//     [IN  pDacl]          Dacl to reset                                     //
//     [IN  pSacl]          Sacl to reset                                     //
//     [IN  KeepExplicit]   if TRUE, retain explicit aces on the subtree, not //
//                          including the object.                             //
//     [IN  fnProgress]     Caller supplied callback function                 //
//     [IN  pOperation]     To determine if callback should be invoked.       //
//                                     callback function.                     //
//     [IN  Args]                      Arguments supplied by the caller       //
//                                                                            //
// Returns:  TRUE if reset succeeded.                                         //
//           FALSE o/w                                                        //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

DWORD
AccTreeResetNamedSecurityInfo(
    IN LPWSTR               pObjectName,
    IN SE_OBJECT_TYPE       ObjectType,
    IN SECURITY_INFORMATION SecurityInfo,
    IN PSID                 pOwner OPTIONAL,
    IN PSID                 pGroup OPTIONAL,
    IN PACL                 pDacl OPTIONAL,
    IN PACL                 pSacl OPTIONAL,
    IN BOOL                 KeepExplicit,
    IN FN_PROGRESS          fnProgress OPTIONAL,
    IN PROG_INVOKE_SETTING  ProgressInvokeSetting,
    IN PVOID                Args OPTIONAL
    )
{
    MARTA_OBJECT_TYPE_PROPERTIES ObjectTypeProperties;
    MARTA_SET_FUNCTION_CONTEXT   MartaSetFunctionContext;
    MARTA_OBJECT_PROPERTIES      ObjectProperties;
    SECURITY_DESCRIPTOR          TmpSD;
    UCHAR                        Buffer[2 * sizeof(ACL)];
    ACL                          EmptyDacl;
    ACL                          EmptySacl;

    SECURITY_INFORMATION LocalSeInfo     = 0;
    PSID                 LocalGroup      = pGroup;
    PSID                 LocalOwner      = pOwner;
    ACCESS_MASK          LocalAccessMask = 0;
    MARTA_CONTEXT        Context         = NULL_MARTA_CONTEXT;
    MARTA_CONTEXT        ParentContext   = NULL_MARTA_CONTEXT;
    GENERIC_MAPPING      ZeroGenMap      = {0, 0, 0, 0};
    PSECURITY_DESCRIPTOR pOldSD          = NULL;
    PSECURITY_DESCRIPTOR pParentSD       = NULL;
    PSECURITY_DESCRIPTOR pNewSD          = NULL;
    DWORD                dwErr           = ERROR_SUCCESS;
    BOOL                 bIsContainer    = FALSE;
    HANDLE               ProcessHandle   = NULL;
    HANDLE               ThreadHandle    = NULL;
    ACCESS_MASK          AccessMask      = 0;
    ACCESS_MASK          RetryAccessMask = 0;
    ACCESS_MASK          MaxAccessMask   = 0;
    BOOL                 bRetry          = FALSE;
    BOOL                 bSetWorked      = FALSE;
    PROG_INVOKE_SETTING  Operation       = ProgressInvokeSetting;
    SECURITY_INFORMATION TmpSeInfo       = (OWNER_SECURITY_INFORMATION |
                                            GROUP_SECURITY_INFORMATION );

    LPWSTR               NewObjectName   = NULL;


    //
    // Convert the file object name into a dos name.
    // For all other objects, use the name as supplied.
    //

    if (SE_FILE_OBJECT == ObjectType) 
    {
        UNICODE_STRING FileName;
        RTL_RELATIVE_NAME RelativeName;

        if (!RtlDosPathNameToNtPathName_U(
                 pObjectName,
                 &FileName,
                 NULL,
                 &RelativeName
                 ))
        {
            return ERROR_INVALID_NAME;
        }

        if (RelativeName.RelativeName.Length) 
        {
            FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
        }

        NewObjectName = FileName.Buffer;

    }
    else
    {
        NewObjectName = pObjectName;
    }

    //
    // TmpSeInfo records whether Owner + Group sids have been supplied by the
    // caller.
    //

    TmpSeInfo = (SecurityInfo & TmpSeInfo) ^ TmpSeInfo;

    //
    // Initialize the dummy security descriptor. This may be changed by the
    // recursive calls.
    //

    InitializeSecurityDescriptor(&TmpSD, SECURITY_DESCRIPTOR_REVISION);

    //
    // Initialize the function pointers based on the object type.
    //

    MartaInitializeSetContext(ObjectType, &MartaSetFunctionContext);

    //
    // Basic error checks for owner and group.
    //

    if (FLAG_ON(SecurityInfo, OWNER_SECURITY_INFORMATION))
    {
        if ((NULL == pOwner) || !RtlValidSid(pOwner))
        {
            return ERROR_INVALID_SID;
        }
    }

    if (FLAG_ON(SecurityInfo, GROUP_SECURITY_INFORMATION))
    {
        if ((NULL == pGroup) || !RtlValidSid(pGroup))
        {
            return ERROR_INVALID_SID;
        }
    }

    //
    // For both DACL and SACL:
    //   If the caller requested for inheritance blocking
    //     set the appropriate bit in TmpSD
    //   else
    //     note that the parent Acl should be read for computing inherited aces
    //   Do basic error checks on the Acl.
    //

    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {

        if (FLAG_ON(SecurityInfo, PROTECTED_DACL_SECURITY_INFORMATION))
        {
            TmpSD.Control |= SE_DACL_PROTECTED;
        }
        else
        {
            LocalSeInfo |= DACL_SECURITY_INFORMATION;
        }

        if ((NULL == pDacl) || !RtlValidAcl(pDacl))
        {
            return ERROR_INVALID_ACL;
        }

        if (FALSE == SetSecurityDescriptorDacl(&TmpSD, TRUE, pDacl, FALSE))
        {
            return GetLastError();
        }
    }

    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        if (FLAG_ON(SecurityInfo, PROTECTED_SACL_SECURITY_INFORMATION))
        {
            TmpSD.Control |= SE_SACL_PROTECTED;
        }
        else
        {
            LocalSeInfo |= SACL_SECURITY_INFORMATION;
        }

        if ((NULL == pSacl) || !RtlValidAcl(pSacl))
        {
            return ERROR_INVALID_ACL;
        }

        if (FALSE == SetSecurityDescriptorSacl(&TmpSD, TRUE, pSacl, FALSE))
        {
            return GetLastError();
        }
    }

    if (FLAG_ON(SecurityInfo, (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)))
    {
        //
        // We need read as well as write access to take care of CO/CG.
        //

        MaxAccessMask = (*(MartaSetFunctionContext.fGetDesiredAccess))(
                               MODIFY_ACCESS_RIGHTS,
                               TRUE,
                               SecurityInfo
                               );

        AccessMask = (*(MartaSetFunctionContext.fGetDesiredAccess))(
                            MODIFY_ACCESS_RIGHTS,
                            FALSE,
                            SecurityInfo
                            );
    }
    else
    {
        //
        // We only need WRITE access if we are not setting any ACL.
        //

        MaxAccessMask = (*(MartaSetFunctionContext.fGetDesiredAccess))(
                               WRITE_ACCESS_RIGHTS,
                               TRUE,
                               SecurityInfo
                               );

        AccessMask = (*(MartaSetFunctionContext.fGetDesiredAccess))(
                            WRITE_ACCESS_RIGHTS,
                            FALSE,
                            SecurityInfo
                            );
    }

    RetryAccessMask = (*(MartaSetFunctionContext.fGetDesiredAccess))(
                             NO_ACCESS_RIGHTS,
                             TRUE,
                             SecurityInfo
                             );

    //
    // Open the object for maximum access that may be needed for computing
    // new SD, setting it on the object and Listing the subtree below this node.
    //

    dwErr = (*(MartaSetFunctionContext.fOpenNamedObject))(
                   pObjectName,
                   MaxAccessMask,
                   &Context
                   );

    if (ERROR_SUCCESS != dwErr)
    {
        //
        // We did not have List permission. Open the object for computing the
        // new SD and setting it on the object.
        //

        dwErr = (*(MartaSetFunctionContext.fOpenNamedObject))(
                       pObjectName,
                       AccessMask,
                       &Context
                       );

        CONDITIONAL_EXIT(dwErr, End);

        //
        // Note that we must retry List and propagate on the subtree.
        //

        bRetry = TRUE;
    }

    //
    // Read the object atributes to figure out whether the object is a container.
    //

    ObjectProperties.cbSize  = sizeof(ObjectProperties);
    ObjectProperties.dwFlags = 0;

    dwErr = (*(MartaSetFunctionContext.fGetProperties))(
                   Context,
                   &ObjectProperties
                   );

    CONDITIONAL_EXIT(dwErr, End);

    bIsContainer = FLAG_ON(ObjectProperties.dwFlags, MARTA_OBJECT_IS_CONTAINER);

    //
    // LocalSeInfo != corresponds to
    //     Resetting ACL(s) in LocalSeInfo and they should not be PROTECTED.
    //
    // Read the existing ACL(s) on the parent.
    //

    if (0 != LocalSeInfo)
    {
        LocalAccessMask = (*(MartaSetFunctionContext.fGetDesiredAccess))(
                                 READ_ACCESS_RIGHTS,
                                 FALSE,
                                 LocalSeInfo
                                 );

        dwErr = (*(MartaSetFunctionContext.fGetParentContext))(
                       Context,
                       LocalAccessMask,
                       &ParentContext
                       );

        CONDITIONAL_EXIT(dwErr, End);

        if (NULL != ParentContext)
        {
            dwErr = (*(MartaSetFunctionContext.fGetRights))(
                           ParentContext,
                           SecurityInfo,
                           &pParentSD
                           );

            (VOID) (*(MartaSetFunctionContext.fCloseContext))(ParentContext);

            CONDITIONAL_EXIT(dwErr, End);
        }
    }

    if (FLAG_ON(SecurityInfo, (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)))
    {
        //
        // Read the owner and group info from the object if it has not been
        // supplied by the caller.
        //

        if (!((FLAG_ON(SecurityInfo, OWNER_SECURITY_INFORMATION)) &&
             (FLAG_ON(SecurityInfo, GROUP_SECURITY_INFORMATION))))
        {
            dwErr = (*(MartaSetFunctionContext.fGetRights))(
                           Context,
                           TmpSeInfo,
                           &pOldSD
                           );

            CONDITIONAL_EXIT(dwErr, End);
        }

        //
        // If Owner sid has not been provided by the caller, pick it up from the
        // existing security descriptor.
        //

        LocalOwner = pOwner;

        if (NULL == LocalOwner)
        {
            LocalOwner = RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldSD);
        }

        //
        // Set the owner sid in the TmpSd.
        //

        if (FALSE == SetSecurityDescriptorOwner(
                         &TmpSD,
                         LocalOwner,
                         FALSE))
        {
            dwErr = GetLastError();

            CONDITIONAL_EXIT(dwErr, End);
        }

        //
        // If Group sid has not been provided by the caller, pick it up from the
        // existing security descriptor.
        //

        if (NULL == LocalGroup)
        {
            LocalGroup = RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldSD);
        }

        //
        // Set the group sid in the TmpSd.
        //

        if (FALSE == SetSecurityDescriptorGroup(
                         &TmpSD,
                         LocalGroup,
                         FALSE))
        {
            dwErr = GetLastError();

            CONDITIONAL_EXIT(dwErr, End);
        }

        dwErr = GetCurrentToken(&ProcessHandle);

        CONDITIONAL_EXIT(dwErr, End);

        ObjectTypeProperties.cbSize  = sizeof(ObjectTypeProperties);
        ObjectTypeProperties.dwFlags = 0;
        ObjectTypeProperties.GenMap  = ZeroGenMap;

        //
        // Get information regarding the object type.
        //

        dwErr = (*(MartaSetFunctionContext.fGetTypeProperties))(&ObjectTypeProperties);

        CONDITIONAL_EXIT(dwErr, End);

        MARTA_TURN_OFF_IMPERSONATION;

        //
        // Compute the new security descriptor.
        //

        if (FALSE == CreatePrivateObjectSecurityEx(
                         pParentSD,
                         &TmpSD,
                         &pNewSD,
                         NULL,
                         bIsContainer,
                         (SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT | SEF_AVOID_OWNER_CHECK | SEF_AVOID_PRIVILEGE_CHECK),
                         ProcessHandle,
                         &ObjectTypeProperties.GenMap
                         ))
        {
            dwErr = GetLastError();
        }

        MARTA_TURN_ON_IMPERSONATION;

        CONDITIONAL_EXIT(dwErr, End);

        //
        // Set the owner and the group fields in TmpSD to NULL if the caller
        // did not want to set these.
        //

        if (NULL == pOwner)
        {
            if (FALSE == SetSecurityDescriptorOwner(
                             &TmpSD,
                             NULL,
                             FALSE))
            {
                dwErr = GetLastError();
            }

            CONDITIONAL_EXIT(dwErr, End);
        }

        if (NULL == pGroup)
        {
            if (FALSE == SetSecurityDescriptorGroup(
                             &TmpSD,
                             NULL,
                             FALSE))
            {
                dwErr = GetLastError();
            }

            CONDITIONAL_EXIT(dwErr, End);
        }

        //
        // Set the DACL to Empty if the caller requested for resetting the DACL.
        //

        if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
        {
            if (FALSE == InitializeAcl(&EmptyDacl, sizeof(ACL), ACL_REVISION))
            {
                return ERROR_ACCESS_DENIED;
            }

            if (FALSE == SetSecurityDescriptorDacl(
                             &TmpSD,
                             TRUE,
                             &EmptyDacl,
                             FALSE))
            {
                return GetLastError();
            }
        }

        //
        // Set the SACL to Empty if the caller requested for resetting the SACL.
        //

        if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
        {
            if (FALSE == InitializeAcl(&EmptySacl, sizeof(ACL), ACL_REVISION))
            {
                return ERROR_ACCESS_DENIED;
            }

            if (FALSE == SetSecurityDescriptorSacl(
                             &TmpSD,
                             TRUE,
                             &EmptySacl,
                             FALSE))
            {
                return GetLastError();
            }
        }

        //
        // We now have TmpSD with
        //     Owner Sid     if SecurityInfo contains OWNER_SECURITY_INFORMATION
        //     Group Sid     if SecurityInfo contains GROUP_SECURITY_INFORMATION
        //     Empty DACL    if SecurityInfo contains DACL_SECURITY_INFORMATION
        //     Empty SACL    if SecurityInfo contains SACL_SECURITY_INFORMATION
        //

    }
    else
    {
        //
        // The caller requested for resetting owner and/or group.
        // Set these in the TmpSD which will be passed to the recursive routine.
        //

        if (FLAG_ON(SecurityInfo, OWNER_SECURITY_INFORMATION))
        {
            if (FALSE == SetSecurityDescriptorOwner(
                             &TmpSD,
                             LocalOwner,
                             FALSE))
            {
                dwErr = GetLastError();
            }

            CONDITIONAL_EXIT(dwErr, End);
        }

        if (FLAG_ON(SecurityInfo, GROUP_SECURITY_INFORMATION))
        {
            if (FALSE == SetSecurityDescriptorGroup(
                             &TmpSD,
                             LocalGroup,
                             FALSE))
            {
                dwErr = GetLastError();
            }

            CONDITIONAL_EXIT(dwErr, End);
        }

        //
        // This is also out New SD to set on the object.
        //

        pNewSD = &TmpSD;
    }

    //
    // If the child is a container then update the subtree underneath it.
    //

    if (bIsContainer)
    {
        TmpSD.Control &= ~(SE_DACL_PROTECTED | SE_SACL_PROTECTED);

        if (!bRetry)
        {
            bRetry = MartaResetTree(
                         SecurityInfo,
                         TmpSeInfo,
                         pNewSD,
                         &TmpSD,
                         Context,
                         ProcessHandle,
                         &MartaSetFunctionContext,
                         &ObjectTypeProperties.GenMap,
                         MaxAccessMask,
                         AccessMask,
                         RetryAccessMask,
                         &Operation,
                         fnProgress,
                         Args,
                         KeepExplicit
                         );
        }
    }
    else
    {
        bRetry = FALSE;
    }

    //
    // Set the computed security descriptor on the object.
    //

    if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
    {
        ((PISECURITY_DESCRIPTOR) pNewSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
    }

    if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
    {
        ((PISECURITY_DESCRIPTOR) pNewSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
    }

    dwErr = (*(MartaSetFunctionContext.fSetRights))(
                   Context,
                   SecurityInfo,
                   pNewSD
                   );

    CONDITIONAL_EXIT(dwErr, End);

    //
    // Note that the set operation on the object is successful.
    //

    bSetWorked = TRUE;

    //
    // Abort if the progress function requested a "Cancel" in the subtree
    // below this node. The value is propagated all the way to the root as
    // the stack unwinds.
    //

    if (ProgressCancelOperation == Operation)
    {
        goto End;
    }

    //
    // If propagation had failed in the first attept then try again. This is to
    // cover the case when the container can be enumerated after setting the new
    // security.
    //

    if (bRetry && bIsContainer && (SecurityInfo & DACL_SECURITY_INFORMATION))
    {

Retry:

         bRetry = FALSE;

        //
        // Reopen the object for List and retry on the subtree. Note that for
        // file objects this is just a dummy routine. The actual reopen happens
        // in FindFirst.
        //

        dwErr = (*(MartaSetFunctionContext.fReopenOrigContext))(
                            Context,
                            RetryAccessMask
                            );

        CONDITIONAL_EXIT(dwErr, End);

        bRetry = MartaResetTree(
                     SecurityInfo,
                     TmpSeInfo,
                     pNewSD,
                     &TmpSD,
                     Context,
                     ProcessHandle,
                     &MartaSetFunctionContext,
                     &ObjectTypeProperties.GenMap,
                     MaxAccessMask,
                     AccessMask,
                     RetryAccessMask,
                     &Operation,
                     fnProgress,
                     Args,
                     KeepExplicit
                     );

        //
        // Retry failed. We should give a callback stating enum failed.
        //

        if (bRetry)
        {
            switch (Operation)
            {
            case ProgressInvokeNever:
                break;

            case ProgressInvokeOnError:

                if (ERROR_SUCCESS == dwErr)
                {
                    break;
                }

                //
                // Fallthrough is intended!!
                //

            case ProgressInvokeEveryObject:

                if (NULL != fnProgress)
                {
                    fnProgress(
                        NewObjectName,
                        ERROR_ACCESS_DENIED,
                        &Operation,
                        Args,
                        TRUE
                        );

                    //
                    // This was the latest feature request by HiteshR. At this
                    // point, retry has failed, but the caller has made some
                    // changes and expects retry to work okay now.
                    //

                    if (ProgressRetryOperation == Operation)
                    {
                        Operation = ProgressInvokeEveryObject;
                        goto Retry;
                    }
                }

                break;

            default:
                break;
            }
        }
    }
End:

    if (bRetry && bIsContainer) 
    {
        dwErr = ERROR_ACCESS_DENIED;
    }

    switch (Operation)
    {
    case ProgressInvokeNever:
        break;

    case ProgressInvokeOnError:

        if (ERROR_SUCCESS == dwErr)
        {
            break;
        }

        //
        // Fallthrough is intended!!
        //

    case ProgressInvokeEveryObject:

        if (NULL != fnProgress)
        {
            fnProgress(
                NewObjectName,
                dwErr,
                &Operation,
                Args,
                bSetWorked
                );

            //
            // This was the latest feature request by HiteshR. At this
            // point, retry has failed, but the caller has made some
            // changes and expects retry to work okay now.
            //

            if (ProgressRetryOperation == Operation)
            {
                Operation = ProgressInvokeEveryObject;
                goto Retry;
            }
        }

        break;

    default:
        break;
    }

    if (NULL != ProcessHandle)
    {
        CloseHandle(ProcessHandle);
    }

    if (NULL != pOldSD)
    {
        AccFree(pOldSD);
    }

    if (NULL != pParentSD)
    {
        AccFree(pParentSD);
    }

    if ((NULL != pNewSD) && (&TmpSD != pNewSD))
    {
        DestroyPrivateObjectSecurity(&pNewSD);
    }

    if (NULL != Context)
    {
        (VOID) (*(MartaSetFunctionContext.fCloseContext))(Context);
    }

    if (NewObjectName != pObjectName) 
    {
        RtlFreeHeap(RtlProcessHeap(), 0, NewObjectName);
    }

    return dwErr;
}

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Function: MartaResetTree                                                    //
//                                                                            //
// Description: Reset permissions on the subtree below the node represented   //
//              by Context.
//                                                                            //
// Arguments:                                                                 //
//                                                                            //
//     [IN  SecurityInfo]              Security info to reset                 //
//     [IN  TmpSeInfo]                 Info that needs to be read from the    //
//                                     object                                 //
//     [IN  pNewSD]                    New security Descriptor on the parent  //
//     [IN  pEmptySD]                  Security Descriptor with owner/group   //
//     [IN  Context]                   Context for the root of the subtree    //
//     [IN  ProcessHandle]             Handle to the process token            //
//     [IN  pMartaSetFunctionContext]  Struct holding function pointers       //
//     [IN  pGenMap]                   Generic mapping for the object         //
//     [IN  MaxAccessMask]             Desired access mask for R, W, List     //
//     [IN  AccessMask]                Desired access mask for W              //
//     [IN  RetryMask]                 Desired access mask for List           //
//     [IN  OUT pOperation]            To determine if callback should be     //
//                                     invoked. Value may be changed by the   //
//                                     callback function.                     //
//     [IN  Args]                      Arguments supplied by the caller       //
//     [IN  fnProgress]                Caller supplied callback function      //
//     [IN  KeepExplicit]              if TRUE, retain explicit aces          //
//                                                                            //
//                                                                            //
// Algorithm:                                                                 //
//     Open the first child for R, W, List                                    //
//     if open failed                                                         //
//         Try again for just R, W and note that a retry is needed.           //
//     Return TRUE if no children exist.                                      //
//     Return FALSE if we can not list                                        //
//     for all children                                                       //
//       If resetting xAcl (and maybe owner/group)                            //
//         if KeepExplicit                                                    //
//           read old xAcl and (owner/group if not provided by the caller)    //
//         else                                                               //
//           read owner/group if not provided by the caller)                  //
//         Compute NewChildSD using this computed info and new parent SD      //
//       else                                                                 //
//         NewChildSD = EmptySD                                               //
//       Invoke callback depending on the flag.                               //
//       Retry propagation if it failed the first time.                       //
//       If at any time, the callback function requests a cancel              //
//           Abort.                                                           //
//
// Returns:  TRUE if propagation succeeded                                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

BOOL
MartaResetTree(
    IN SECURITY_INFORMATION        SecurityInfo,
    IN SECURITY_INFORMATION        TmpSeInfo,
    IN PSECURITY_DESCRIPTOR        pNewSD,
    IN PSECURITY_DESCRIPTOR        pEmptySD,
    IN MARTA_CONTEXT               Context,
    IN HANDLE                      ProcessHandle,
    IN PMARTA_SET_FUNCTION_CONTEXT pMartaSetFunctionContext,
    IN PGENERIC_MAPPING            pGenMap,
    IN ACCESS_MASK                 MaxAccessMask,
    IN ACCESS_MASK                 AccessMask,
    IN ACCESS_MASK                 RetryAccessMask,
    IN OUT PPROG_INVOKE_SETTING    pOperation,
    IN FN_PROGRESS                 fnProgress,
    IN PVOID                       Args,
    IN BOOL                        KeepExplicit
    )
{
    MARTA_OBJECT_PROPERTIES      ObjectProperties;

    MARTA_CONTEXT        ChildContext  = NULL_MARTA_CONTEXT;
    PSECURITY_DESCRIPTOR pNewChildSD   = NULL;
    PSECURITY_DESCRIPTOR pOldChildSD   = NULL;
    DWORD                dwErr         = ERROR_SUCCESS;
    BOOL                 bIsContainer  = FALSE;
    HANDLE               ThreadHandle  = NULL;
    BOOL                 bRetry        = FALSE;
    BOOL                 bSetWorked    = FALSE;

    //
    // Get the first child of this container. In the first attempt try to open
    // the child with read/write as well as list.
    //

    dwErr = (*(pMartaSetFunctionContext->fFindFirst))(
                   Context,
                   MaxAccessMask,
                   &ChildContext
                   );

    if (ERROR_SUCCESS != dwErr)
    {

#ifdef MARTA_DEBUG
            wprintf(L"FindFirst failed\n");
#endif

        if (NULL == ChildContext)
        {
            //
            // This should never happen. A NULL ChildContext represents no
            // more children. We have this code path just in case some resource
            // manager cannot open the object for list.
            //

            dwErr = (*(pMartaSetFunctionContext->fFindFirst))(
                           Context,
                           AccessMask,
                           &ChildContext
                           );
        }
        else
        {
            //
            // Try opening the child again, this time with permissions sufficent
            // for computing security info to set and setting it.
            //

            dwErr = (*(pMartaSetFunctionContext->fReopenContext))(
                           ChildContext,
                           AccessMask
                           );
        }

        //
        // We failed to open the object for list. Record this failure and open
        // the child again if it is a container.
        //

        bRetry = TRUE;
    }
    else
    {
#ifdef MARTA_DEBUG
            wprintf(L"FindFirst succeeded\n");
#endif
    }

    if (NULL == ChildContext)
    {
        //
        // The parent does not have any children.
        //

        if (ERROR_SUCCESS == dwErr)
        {

#ifdef MARTA_DEBUG
            wprintf(L"The container does not have any children\n");
#endif

            return FALSE;
        }

#ifdef MARTA_DEBUG
        wprintf(L"Can not list objects in the current container. Retry needed\n");
#endif

        //
        // We need a propagation retry for the parent.
        //

        return TRUE;
    }

    CONDITIONAL_EXIT(dwErr, EndOfWhile);

    //
    // Child context becomes NULL when there are no more children.
    //

    while (ChildContext)
    {
        ObjectProperties.cbSize  = sizeof(ObjectProperties);
        ObjectProperties.dwFlags = 0;

        //
        // Get information about the current child. We need to know whether
        // it is a container.
        //
        //

        dwErr = (*(pMartaSetFunctionContext->fGetProperties))(
                       ChildContext,
                       &ObjectProperties
                       );

        CONDITIONAL_EXIT(dwErr, EndOfWhile);

#ifdef MARTA_DEBUG
        wprintf(L"GetProperties succeeded\n");
#endif

        bIsContainer = FLAG_ON(ObjectProperties.dwFlags, MARTA_OBJECT_IS_CONTAINER);

        //
        // If we are setting any of the ACLs then the security descriptor must
        // be recomputed.
        //

        if (FLAG_ON(SecurityInfo, (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)))
        {
            //
            // TmpSeInfo is ZERO if the caller is resetting both OWNER and GROUP
            // as well.
            // We have to read the old ACLs if the caller wants to retain explicit
            // aces.
            //

            if (KeepExplicit)
            {
                TmpSeInfo |= (SecurityInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION));
            }

            //
            // Read the existing security on the child.
            //

            if (0 != TmpSeInfo)
            {
                dwErr = (*(pMartaSetFunctionContext->fGetRights))(
                               ChildContext,
                               TmpSeInfo,
                               &pOldChildSD
                               );

                CONDITIONAL_EXIT(dwErr, EndOfWhile);

                //
                // Set the existing owner information in the empty security descriptor
                // if the caller has not provided an Owner sid to set.
                //

                if (!FLAG_ON(SecurityInfo, OWNER_SECURITY_INFORMATION))
                {
                    if (FALSE == SetSecurityDescriptorOwner(
                                     pEmptySD,
                                     RtlpOwnerAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD),
                                     FALSE))
                    {
                        dwErr = GetLastError();

                        CONDITIONAL_EXIT(dwErr, EndOfWhile);
                    }
                }

                if (KeepExplicit)
                {
                    //
                    // Set the ACLs in the EmptySD to existing ones in order to
                    // retain explicit aces.
                    //

                    if (FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
                    {
                        if (FALSE == SetSecurityDescriptorDacl(
                                         pEmptySD,
                                         TRUE,
                                         RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD),
                                         FALSE))
                        {
                            dwErr = GetLastError();

                            CONDITIONAL_EXIT(dwErr, EndOfWhile);
                        }
                    }

                    if (FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
                    {
                        if (FALSE == SetSecurityDescriptorSacl(
                                         pEmptySD,
                                         TRUE,
                                         RtlpSaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD),
                                         FALSE))
                        {
                            dwErr = GetLastError();

                            CONDITIONAL_EXIT(dwErr, EndOfWhile);
                        }
                    }
                }

                //
                // Set the existing group information in the empty security descriptor
                // if the caller has not provided a group sid to set.
                //

                if (!FLAG_ON(SecurityInfo, GROUP_SECURITY_INFORMATION))
                {
                    if (FALSE == SetSecurityDescriptorGroup(
                                     pEmptySD,
                                     RtlpGroupAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pOldChildSD),
                                     FALSE))
                    {
                        dwErr = GetLastError();

                        CONDITIONAL_EXIT(dwErr, EndOfWhile);
                    }
                }
            }

            MARTA_TURN_OFF_IMPERSONATION;

            //
            // Merge the NewParentSD and the OldChildSD to create NewChildSD.
            //

            if (FALSE == CreatePrivateObjectSecurityEx(
                             pNewSD,
                             pEmptySD,
                             &pNewChildSD,
                             NULL,
                             bIsContainer,
                             (SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT |
                              SEF_AVOID_OWNER_CHECK | SEF_AVOID_PRIVILEGE_CHECK),
                             ProcessHandle,
                             pGenMap
                             ))
            {
                dwErr = GetLastError();
            }

            MARTA_TURN_ON_IMPERSONATION;

            CONDITIONAL_EXIT(dwErr, EndOfWhile);
        }
        else
        {
            //
            // The new ChildSD does not have to computed. We only want to set
            // Owner/Group information.
            //

            pNewChildSD = pEmptySD;
        }

        //
        // Update the subtree undrneath this child.
        //

        if (bIsContainer)
        {

            if (!bRetry)
            {

#ifdef MARTA_DEBUG
        wprintf(L"Trying reset \n");
#endif

                bRetry = MartaResetTree(
                           SecurityInfo,
                           TmpSeInfo,
                           pNewChildSD,
                           pEmptySD,
                           ChildContext,
                           ProcessHandle,
                           pMartaSetFunctionContext,
                           pGenMap,
                           MaxAccessMask,
                           AccessMask,
                           RetryAccessMask,
                           pOperation,
                           fnProgress,
                           Args,
                           KeepExplicit
                           );
            }
        }
        else
        {
            bRetry = FALSE;
        }

        //
        // Stamp NewChildSD on child.
        //

        if(FLAG_ON(SecurityInfo, DACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pNewChildSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
        }

        if(FLAG_ON(SecurityInfo, SACL_SECURITY_INFORMATION))
        {
            ((PISECURITY_DESCRIPTOR) pNewChildSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
        }

        dwErr = (*(pMartaSetFunctionContext->fSetRights))(
                       ChildContext,
                       SecurityInfo,
                       pNewChildSD
                       );

        CONDITIONAL_EXIT(dwErr, EndOfWhile);

#ifdef MARTA_DEBUG
        wprintf(L"Set right succeeded\n");
#endif

        //
        // Note down that we were able to set security on this object.
        //

        bSetWorked = TRUE;

        //
        // Abort if the progress function requested a "Cancel" in the subtree
        // below this node. The value is propagated all the way to the root as
        // the stack unwinds.
        //

        if (ProgressCancelOperation == *pOperation)
        {
            goto EndOfWhile;
        }

        //
        // If propagation had failed in the first attept then try again. This is to
        // cover the case when the container can be enumerated after setting the new
        // security.
        //

        if (bRetry && bIsContainer && (SecurityInfo & DACL_SECURITY_INFORMATION))
        {

Retry:

            bRetry = FALSE;

            //
            // Reopen the object for List and retry on the subtree.
            //

            dwErr = (*(pMartaSetFunctionContext->fReopenContext))(
                           ChildContext,
                           RetryAccessMask
                           );

            CONDITIONAL_EXIT(dwErr, EndOfWhile);

            bRetry = MartaResetTree(
                       SecurityInfo,
                       TmpSeInfo,
                       pNewSD,
                       pEmptySD,
                       ChildContext,
                       ProcessHandle,
                       pMartaSetFunctionContext,
                       pGenMap,
                       MaxAccessMask,
                       AccessMask,
                       RetryAccessMask,
                       pOperation,
                       fnProgress,
                       Args,
                       KeepExplicit
                       );
        }

EndOfWhile:

        if (bRetry && bIsContainer) 
        {
            dwErr = ERROR_ACCESS_DENIED;
        }

        switch (*pOperation)
        {

        case ProgressInvokeNever:

            break;

        case ProgressInvokeOnError:

            if (ERROR_SUCCESS == dwErr)
            {
                break;
            }

            //
            // Fallthough is intended!!
            //

        case ProgressInvokeEveryObject:

            if (NULL != fnProgress)
            {
                LPWSTR Name = NULL;

                //
                // Get the name of the current object from the context and call
                // the progress function with the arguments provided by the
                // caller of ResetTree API.
                //

                DWORD Error = (*(pMartaSetFunctionContext->fGetNameFromContext))(
                                     ChildContext,
                                     &Name
                                     );

                if (ERROR_SUCCESS == Error)
                {
                    fnProgress(
                        Name,
                        dwErr,
                        pOperation,
                        Args,
                        bSetWorked
                        );

                    LocalFree(Name);

                    //
                    // This was the latest feature request by HiteshR. At this
                    // point, retry has failed, but the caller has made some
                    // changes and expects retry to work okay now.
                    //

                    if (ProgressRetryOperation == *pOperation)
                    {
                        *pOperation = ProgressInvokeEveryObject;
                        goto Retry;
                    }
                }
            }

            break;

        default:
            break;
        }

        bSetWorked = bRetry = FALSE;

        if ((NULL != pNewChildSD) && (pEmptySD != pNewChildSD))
        {
            DestroyPrivateObjectSecurity(&pNewChildSD);
            pNewChildSD = NULL;
        }

        if (NULL != pOldChildSD)
        {
            LocalFree(pOldChildSD);
            pOldChildSD = NULL;
        }

        //
        // Abort if the progress function requested a "Cancel".
        //

        if (ProgressCancelOperation == *pOperation)
        {
            (*(pMartaSetFunctionContext->fCloseContext)) (ChildContext);
            return TRUE;
        }

        //
        // Get the next child.
        //

        do {

            dwErr = (*(pMartaSetFunctionContext->fFindNext))(
                           ChildContext,
                           MaxAccessMask,
                           &ChildContext
                           );

            if (ERROR_SUCCESS != dwErr)
            {

#ifdef MARTA_DEBUG
                wprintf(L"FindNext failed\n");
#endif

                dwErr = (*(pMartaSetFunctionContext->fReopenContext))(
                               ChildContext,
                               AccessMask
                               );

#ifdef MARTA_DEBUG
                if (dwErr == ERROR_SUCCESS)
                {
                    wprintf(L"FindNext failed\n");
                }
#endif

                bRetry = TRUE;
            }
            else
            {
#ifdef MARTA_DEBUG
                wprintf(L"Findnext succeeded\n");
#endif
            }

            switch (*pOperation)
            {

            case ProgressInvokeNever:
            case ProgressInvokeEveryObject:

                break;

            case ProgressInvokeOnError:

                //
                // If we encountered an error in FindNext then report it to the
                // caller.
                //

                if (ERROR_SUCCESS == dwErr)
                {
                    break;
                }

                if (NULL != fnProgress)
                {
                    LPWSTR Name = NULL;

                    //
                    // Get the name of the current object.
                    //

                    DWORD Error = (*(pMartaSetFunctionContext->fGetNameFromContext))(
                                         ChildContext,
                                         &Name
                                         );

                    if (ERROR_SUCCESS == Error)
                    {
                        fnProgress(
                            Name,
                            dwErr,
                            pOperation,
                            Args,
                            bSetWorked
                            );

                        LocalFree(Name);

                    }
                }

                break;

            default:
                break;
            }

            //
            // Abort if the progress function requested a "Cancel".
            //

            if (ProgressCancelOperation == *pOperation)
            {
                (*(pMartaSetFunctionContext->fCloseContext)) (ChildContext);
                return TRUE;
            }

        } while ((ERROR_SUCCESS != dwErr) && (NULL != ChildContext));
    }

    return FALSE;
}