From 6a3eca32a6a89bf533d3075ac5cb3b24da1b1326 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Sun, 3 Mar 2013 23:10:51 -0500 Subject: [PATCH 1/1] Windows: CreateFile Reparse Point to File as File Apply the Reparse Point to File as File Policy to CreateFile. If the FILE_OPEN_REPARSE_POINT flag is specified to the CreateFile operation and AFSIgnoreReparsePointToFile() returns TRUE, evaluate the target object (if possible) and if the object is a FILE, then ignore the FILE_OPEN_REPARSE_POINT flag. Otherwise, re-evaluate the request to attempt to open a reparse point if it exists. Change-Id: Ia1a3d5f4c4d638d7d94209c9b4a9dfc2e8aa2005 Reviewed-on: http://gerrit.openafs.org/9343 Tested-by: BuildBot Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- src/WINNT/afsrdr/common/AFSRedirCommonDefines.h | 1 + src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp | 647 +++++++++++++++++++----- 2 files changed, 523 insertions(+), 125 deletions(-) diff --git a/src/WINNT/afsrdr/common/AFSRedirCommonDefines.h b/src/WINNT/afsrdr/common/AFSRedirCommonDefines.h index 816331d..bdd1740 100644 --- a/src/WINNT/afsrdr/common/AFSRedirCommonDefines.h +++ b/src/WINNT/afsrdr/common/AFSRedirCommonDefines.h @@ -91,6 +91,7 @@ #define AFS_NAME_BUFFER_EIGHT_TAG '8NFA' #define AFS_NAME_BUFFER_NINE_TAG '9NFA' #define AFS_NAME_BUFFER_TEN_TAG 'ANFA' +#define AFS_NAME_BUFFER_ELEVEN_TAG 'BNFA' #define AFS_SUBST_BUFFER_TAG 'SBFA' #define AFS_FILE_CREATE_BUFFER_TAG 'CFFA' #define AFS_RENAME_REQUEST_TAG 'RFFA' diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp index 81d9d8a..f12cc0c 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp @@ -425,193 +425,590 @@ AFSCommonCreate( IN PDEVICE_OBJECT DeviceObject, try_return( ntStatus); } - // - // Opening a reparse point directly? - // - ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME; - - if( BooleanFlagOn( ulOptions, FILE_OPEN_REPARSE_POINT)) + if ( !AFSIgnoreReparsePointToFile() || + !BooleanFlagOn( ulOptions, FILE_OPEN_REPARSE_POINT)) { - ulNameProcessingFlags |= (AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL | - AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL | - AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL); - } + // + // If there is no ReparsePointPolicy then the FILE_OPEN_REPARSE_POINT + // flag is applied if it is set. + // + // If the FILE_OPEN_REPARSE_POINT flag is not set, then there is + // no extra work to be done in any case. Use a single pass evaluation. + // + + ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME; + + // + // Opening a reparse point directly? + // + + if( BooleanFlagOn( ulOptions, FILE_OPEN_REPARSE_POINT)) + { + ulNameProcessingFlags |= (AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL); + } + + uniSubstitutedPathName = uniRootFileName; + + ntStatus = AFSLocateNameEntry( &stAuthGroup, + pFileObject, + &uniRootFileName, + &uniParsedFileName, + pNameArray, + ulNameProcessingFlags, + pVolumeCB, + pParentDirectoryCB, + &pNewVolumeCB, + &NewVolumeReferenceReason, + &pNewParentDirectoryCB, + &pDirectoryCB, + &uniComponentName); + + if ( pNewVolumeCB != NULL) + { + + // + // AFSLocateNameEntry returns pNewVolumeCB with a reference held + // even if pVolumeCB == pNewVolumeCB. It is always safe to release + // the reference on pVolumeCB that was held prior to the call. + // If pVolumeCB == pNewVolumeCB, the reference from AFSLocateNameEntry + // will be released second. + // + + lCount = AFSVolumeDecrement( pVolumeCB, + VolumeReferenceReason); + + AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate Decrement count on volume %p Reason %u Cnt %d\n", + pVolumeCB, + VolumeReferenceReason, + lCount)); + + pVolumeCB = pNewVolumeCB; + + pNewVolumeCB = NULL; + + VolumeReferenceReason = NewVolumeReferenceReason; + + NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID; + + bReleaseVolume = (pVolumeCB != NULL); + } + + // + // AFSLocateNameEntry does not alter the reference count of + // pParentDirectoryCB and it returns pNewParentDirectoryCB with + // a reference held. + // + + if ( bReleaseParentDir) + { + + lCount = InterlockedDecrement( &pParentDirectoryCB->DirOpenReferenceCount); + + AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate DecrementX count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + pCcb, + lCount)); + } + + pParentDirectoryCB = pNewParentDirectoryCB; + + pNewParentDirectoryCB = NULL; + + bReleaseParentDir = (pParentDirectoryCB != NULL); + + if ( pDirectoryCB) + { + + bReleaseDir = TRUE; + } + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { - uniSubstitutedPathName = uniRootFileName; + if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer) + { + uniSubstitutedPathName.Buffer = NULL; + } - ntStatus = AFSLocateNameEntry( &stAuthGroup, - pFileObject, - &uniRootFileName, - &uniParsedFileName, - pNameArray, - ulNameProcessingFlags, - pVolumeCB, - pParentDirectoryCB, - &pNewVolumeCB, - &NewVolumeReferenceReason, - &pNewParentDirectoryCB, - &pDirectoryCB, - &uniComponentName); + // + // AFSLocateNameEntry released the Parent while walking the + // branch + // - if ( pNewVolumeCB != NULL) - { + AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%p) Failed to locate name entry for %wZ Status %08lX\n", + Irp, + &uniFileName, + ntStatus)); - // - // AFSLocateNameEntry returns pNewVolumeCB with a reference held - // even if pVolumeCB == pNewVolumeCB. It is always safe to release - // the reference on pVolumeCB that was held prior to the call. - // If pVolumeCB == pNewVolumeCB, the reference from AFSLocateNameEntry - // will be released second. - // + try_return( ntStatus); + } - lCount = AFSVolumeDecrement( pVolumeCB, - VolumeReferenceReason); + // + // Check for STATUS_REPARSE + // - AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSCommonCreate Decrement count on volume %p Reason %u Cnt %d\n", - pVolumeCB, - VolumeReferenceReason, - lCount)); + if( ntStatus == STATUS_REPARSE) + { - pVolumeCB = pNewVolumeCB; + uniSubstitutedPathName.Buffer = NULL; - pNewVolumeCB = NULL; + // + // Update the information and return + // - VolumeReferenceReason = NewVolumeReferenceReason; + Irp->IoStatus.Information = IO_REPARSE; - NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID; + try_return( ntStatus); + } - bReleaseVolume = (pVolumeCB != NULL); - } + // + // If we re-allocated the name, then update our substitute name + // - // - // AFSLocateNameEntry does not alter the reference count of - // pParentDirectoryCB and it returns pNewParentDirectoryCB with - // a reference held. - // + if( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer) + { - if ( bReleaseParentDir) - { + uniSubstitutedPathName = uniRootFileName; + } + else + { - lCount = InterlockedDecrement( &pParentDirectoryCB->DirOpenReferenceCount); + uniSubstitutedPathName.Buffer = NULL; + } - AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSCommonCreate DecrementX count on %wZ DE %p Ccb %p Cnt %d\n", - &pParentDirectoryCB->NameInformation.FileName, - pParentDirectoryCB, - pCcb, - lCount)); - } + // + // Check for a symlink access + // - pParentDirectoryCB = pNewParentDirectoryCB; + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND && + pParentDirectoryCB != NULL) + { - pNewParentDirectoryCB = NULL; + // + // pParentDirectoryCB DirOpenReferenceCount is still held + // - bReleaseParentDir = (pParentDirectoryCB != NULL); + UNICODE_STRING uniFinalComponent; - if ( pDirectoryCB) - { + uniFinalComponent.Length = 0; + uniFinalComponent.MaximumLength = 0; + uniFinalComponent.Buffer = NULL; - bReleaseDir = TRUE; - } + AFSRetrieveFinalComponent( &uniFileName, + &uniFinalComponent); + + ntStatus = AFSCheckSymlinkAccess( pParentDirectoryCB, + &uniFinalComponent); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%p) Failing access to symlink %wZ Status %08lX\n", + Irp, + &uniFileName, + ntStatus)); - if( !NT_SUCCESS( ntStatus) && - ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + try_return( ntStatus); + } + } + } + else { + AFSNameArrayHdr *pNameArrayClone = NULL; + UNICODE_STRING uniRootFileNameClone; - if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer) - { - uniSubstitutedPathName.Buffer = NULL; - } + // + // The FILE_OPEN_REPARSE_POINT flag has been specified and a ReparsePointPolicy + // is in effect which conditionally applies depending on the type of the target + // object. Therefore, two lookup passes must be performed. + // 1. Evaluate the path as if the FILE_OPEN_REPARSE_POINT flag had + // not been specified. + // 2. If the target object type matches the policy, use it and ignore + // the FILE_OPEN_REPARSE_POINT flag. + // 3. If the target object type does not match the policy, perform + // a second pass that opens the reparse point. + // 4. If the target object cannot be evaluated, perform the second pass + // that opens the reparse point. + + + ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME; + + uniSubstitutedPathName = uniRootFileName; // - // AFSLocateNameEntry released the Parent while walking the - // branch + // Since we may need to replay the call with different options + // the values that might be altered need to be cloned: + // 1. uniRootFileName + // 2. pNameArray // - AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSCommonCreate (%p) Failed to locate name entry for %wZ Status %08lX\n", - Irp, - &uniFileName, - ntStatus)); + pNameArrayClone = AFSInitNameArray( NULL, 0); - try_return( ntStatus); - } + if ( pNameArrayClone == NULL) + { - // - // Check for STATUS_REPARSE - // + AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%p) Failed to initialize name array clone\n", + Irp)); - if( ntStatus == STATUS_REPARSE) - { + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } - uniSubstitutedPathName.Buffer = NULL; + ntStatus = AFSPopulateNameArrayFromRelatedArray( pNameArrayClone, + pNameArray, + NULL); - // - // Update the information and return - // + if ( !NT_SUCCESS(ntStatus)) + { - Irp->IoStatus.Information = IO_REPARSE; + AFSFreeNameArray( pNameArrayClone); - try_return( ntStatus); - } + try_return( ntStatus); + } - // - // If we re-allocated the name, then update our substitute name - // + uniRootFileNameClone = uniRootFileName; - if( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer) - { + uniRootFileNameClone.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniRootFileNameClone.MaximumLength, + AFS_NAME_BUFFER_ELEVEN_TAG); - uniSubstitutedPathName = uniRootFileName; - } - else - { + if( uniRootFileNameClone.Buffer == NULL) + { - uniSubstitutedPathName.Buffer = NULL; - } + AFSFreeNameArray( pNameArrayClone); - // - // Check for a symlink access - // + AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate (%p) Failed to allocate uniRootFileNameClone\n", + Irp)); - if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND && - pParentDirectoryCB != NULL) - { + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( uniRootFileNameClone.Buffer, + uniRootFileName.Buffer, + uniRootFileNameClone.Length); // - // pParentDirectoryCB DirOpenReferenceCount is still held + // Now that the data is saved perform the lookup to determine + // what the target resolves to. // - UNICODE_STRING uniFinalComponent; + ntStatus = AFSLocateNameEntry( &stAuthGroup, + pFileObject, + &uniRootFileName, + &uniParsedFileName, + pNameArray, + ulNameProcessingFlags, + pVolumeCB, + pParentDirectoryCB, + &pNewVolumeCB, + &NewVolumeReferenceReason, + &pNewParentDirectoryCB, + &pDirectoryCB, + &uniComponentName); + + if ( ntStatus == STATUS_SUCCESS || + ntStatus == STATUS_REPARSE || + ntStatus == STATUS_OBJECT_NAME_NOT_FOUND || + ntStatus == STATUS_ACCESS_DENIED) + { + // + // Decide what to do based upon the ReparsePointPolicy + // and the type of the target object. + // + + if ( ntStatus == STATUS_SUCCESS && + AFSIgnoreReparsePointToFile() && + pDirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_FILE) + { + + // + // We found an entity that matches the policy. + // Therefore, we are done. Cleanup the cloned data + // and clear the FILE_OPEN_REPARSE_FLAG so we do not + // later mark the CCB with CCB_FLAG_MASK_OPENED_REPARSE_POINT. + // + + AFSFreeNameArray( pNameArrayClone); + + pNameArrayClone = NULL; + + AFSExFreePoolWithTag( uniRootFileNameClone.Buffer, + AFS_NAME_BUFFER_ELEVEN_TAG); + + RtlZeroMemory( &uniRootFileNameClone, + sizeof( UNICODE_STRING)); + + ClearFlag( ulOptions, FILE_OPEN_REPARSE_POINT); + } + else + { + // + // There is no matching policy, so we need to cleanup the + // output values from AFSLocateNameEntry(), restore the + // cloned information, and re-issue the request attempting + // to open the reparse point (if any). + // + + if ( pNewVolumeCB != NULL) + { + + lCount = AFSVolumeDecrement( pNewVolumeCB, + NewVolumeReferenceReason); + + pNewVolumeCB = NULL; + + NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID; + } + + if ( pNewParentDirectoryCB) + { + + lCount = InterlockedDecrement( &pNewParentDirectoryCB->DirOpenReferenceCount); + + AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate DecrementY count on %wZ DE %p Ccb %p Cnt %d\n", + &pNewParentDirectoryCB->NameInformation.FileName, + pNewParentDirectoryCB, + pCcb, + lCount)); + + pNewParentDirectoryCB = NULL; + } + + if ( pDirectoryCB) + { + + lCount = InterlockedDecrement( &pDirectoryCB->DirOpenReferenceCount); + + AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate DecrementZ count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + pCcb, + lCount)); + + pDirectoryCB = NULL; + } + + RtlZeroMemory( &uniComponentName, + sizeof( UNICODE_STRING)); + + if ( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer) + { + + AFSExFreePoolWithTag( uniRootFileName.Buffer, 0); - uniFinalComponent.Length = 0; - uniFinalComponent.MaximumLength = 0; - uniFinalComponent.Buffer = NULL; + uniRootFileName = uniSubstitutedPathName; + } - AFSRetrieveFinalComponent( &uniFileName, - &uniFinalComponent); + AFSFreeNameArray( pNameArray); + + pNameArray = pNameArrayClone; + + pNameArrayClone = NULL; + + // + // Retry the lookup + // + + ulNameProcessingFlags |= (AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL); + + ntStatus = AFSLocateNameEntry( &stAuthGroup, + pFileObject, + &uniRootFileName, + &uniParsedFileName, + pNameArray, + ulNameProcessingFlags, + pVolumeCB, + pParentDirectoryCB, + &pNewVolumeCB, + &NewVolumeReferenceReason, + &pNewParentDirectoryCB, + &pDirectoryCB, + &uniComponentName); + } + } + + if ( pNewVolumeCB != NULL) + { + + // + // AFSLocateNameEntry returns pNewVolumeCB with a reference held + // even if pVolumeCB == pNewVolumeCB. It is always safe to release + // the reference on pVolumeCB that was held prior to the call. + // If pVolumeCB == pNewVolumeCB, the reference from AFSLocateNameEntry + // will be released second. + // + + lCount = AFSVolumeDecrement( pVolumeCB, + VolumeReferenceReason); + + AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate Decrement count on volume %p Reason %u Cnt %d\n", + pVolumeCB, + VolumeReferenceReason, + lCount)); + + pVolumeCB = pNewVolumeCB; + + pNewVolumeCB = NULL; + + VolumeReferenceReason = NewVolumeReferenceReason; + + NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID; + + bReleaseVolume = (pVolumeCB != NULL); + } + + // + // AFSLocateNameEntry does not alter the reference count of + // pParentDirectoryCB and it returns pNewParentDirectoryCB with + // a reference held. + // + + if ( bReleaseParentDir) + { + + lCount = InterlockedDecrement( &pParentDirectoryCB->DirOpenReferenceCount); + + AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate DecrementX count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + pCcb, + lCount)); + } - ntStatus = AFSCheckSymlinkAccess( pParentDirectoryCB, - &uniFinalComponent); + pParentDirectoryCB = pNewParentDirectoryCB; + + pNewParentDirectoryCB = NULL; + + bReleaseParentDir = (pParentDirectoryCB != NULL); + + if ( pDirectoryCB) + { + + bReleaseDir = TRUE; + } if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { + if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer) + { + uniSubstitutedPathName.Buffer = NULL; + } + + // + // AFSLocateNameEntry released the Parent while walking the + // branch + // + AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, - "AFSCommonCreate (%p) Failing access to symlink %wZ Status %08lX\n", + "AFSCommonCreate (%p) Failed to locate name entry for %wZ Status %08lX\n", Irp, &uniFileName, ntStatus)); try_return( ntStatus); } + + // + // Check for STATUS_REPARSE + // + + if( ntStatus == STATUS_REPARSE) + { + + uniSubstitutedPathName.Buffer = NULL; + + // + // Update the information and return + // + + Irp->IoStatus.Information = IO_REPARSE; + + try_return( ntStatus); + } + + // + // If we re-allocated the name, then update our substitute name + // + + if( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer) + { + + uniSubstitutedPathName = uniRootFileName; + } + else + { + + uniSubstitutedPathName.Buffer = NULL; + } + + // + // Check for a symlink access + // + + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND && + pParentDirectoryCB != NULL) + { + + // + // pParentDirectoryCB DirOpenReferenceCount is still held + // + + UNICODE_STRING uniFinalComponent; + + uniFinalComponent.Length = 0; + uniFinalComponent.MaximumLength = 0; + uniFinalComponent.Buffer = NULL; + + AFSRetrieveFinalComponent( &uniFileName, + &uniFinalComponent); + + ntStatus = AFSCheckSymlinkAccess( pParentDirectoryCB, + &uniFinalComponent); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%p) Failing access to symlink %wZ Status %08lX\n", + Irp, + &uniFileName, + ntStatus)); + + try_return( ntStatus); + } + } } } -- 1.9.4