|
|
////////////////////////////////////////////////////////////////////////////////
// //
// 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; }
|