//////////////////////////////////////////////////////////////////////////////// // // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999. // // // // File: rewrite.cxx // // // // Contents: New marta rewrite functions. // // // // History: 4/99 KedarD Created // // // //////////////////////////////////////////////////////////////////////////////// #include #pragma hdrstop extern "C" { #include #include #include #include #include #include #include #include #include #include } #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; }