windows-nt/Source/XPSP1/NT/ds/security/ntmarta/newsrc/rewrite.cxx

5006 lines
162 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
////////////////////////////////////////////////////////////////////////////////
// //
// 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;
}