BOOLEAN AFSIs64BitProcess( IN ULONGLONG ProcessId) { NTSTATUS ntStatus = STATUS_SUCCESS; BOOLEAN bIs64Bit = FALSE; AFSProcessCB *pProcessCB = NULL; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; __Enter { AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSIs64BitProcess Acquiring Control ProcessTree.TreeLock lock %p SHARED %08lX\n", pDeviceExt->Specific.Control.ProcessTree.TreeLock, PsGetCurrentThread())); AFSAcquireShared( pDeviceExt->Specific.Control.ProcessTree.TreeLock, TRUE); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, (ULONGLONG)ProcessId, (AFSBTreeEntry **)&pProcessCB); if( pProcessCB != NULL) { bIs64Bit = BooleanFlagOn( pProcessCB->Flags, AFS_PROCESS_FLAG_IS_64BIT); } AFSReleaseResource( pDeviceExt->Specific.Control.ProcessTree.TreeLock); } return bIs64Bit; }
NTSTATUS AFSInitVolume( IN GUID *AuthGroup, IN AFSFileID *RootFid, OUT AFSVolumeCB **VolumeCB) { NTSTATUS ntStatus = STATUS_SUCCESS; IO_STATUS_BLOCK stIoStatus = {0,0}; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; AFSNonPagedVolumeCB *pNonPagedVcb = NULL; AFSVolumeCB *pVolumeCB = NULL; AFSNonPagedObjectInfoCB *pNonPagedObject = NULL; ULONGLONG ullIndex = 0; BOOLEAN bReleaseLocks = FALSE; AFSVolumeInfoCB stVolumeInformation; AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL; __Enter { // // Before grabbing any locks ask the service for the volume information // This may be a waste but we need to get this information prior to // taking any volume tree locks. Don't do this for any 'reserved' cell entries // if( RootFid->Cell != 0) { RtlZeroMemory( &stVolumeInformation, sizeof( AFSVolumeInfoCB)); ntStatus = AFSRetrieveVolumeInformation( AuthGroup, RootFid, &stVolumeInformation); if( !NT_SUCCESS( ntStatus)) { AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSInitVolume AFSRetrieveVolumeInformation(RootFid) failure %08lX\n", ntStatus); try_return( ntStatus); } // // Grab our tree locks and see if we raced with someone else // AFSAcquireExcl( pDeviceExt->Specific.RDR.VolumeTree.TreeLock, TRUE); AFSAcquireExcl( &pDeviceExt->Specific.RDR.VolumeListLock, TRUE); bReleaseLocks = TRUE; ullIndex = AFSCreateHighIndex( RootFid); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.RDR.VolumeTree.TreeHead, ullIndex, (AFSBTreeEntry **)&pVolumeCB); if( NT_SUCCESS( ntStatus) && pVolumeCB != NULL) { // // So we don't lock with an invalidation call ... // InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); AFSReleaseResource( pDeviceExt->Specific.RDR.VolumeTree.TreeLock); AFSReleaseResource( &pDeviceExt->Specific.RDR.VolumeListLock); bReleaseLocks = FALSE; AFSAcquireExcl( pVolumeCB->VolumeLock, TRUE); InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); *VolumeCB = pVolumeCB; try_return( ntStatus); } // // Revert our status from the above call back to success. // ntStatus = STATUS_SUCCESS; } // // For the global root we allocate out volume node and insert it // into the volume tree ... // pVolumeCB = (AFSVolumeCB *)AFSExAllocatePoolWithTag( NonPagedPool, sizeof( AFSVolumeCB), AFS_VCB_ALLOCATION_TAG); if( pVolumeCB == NULL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSInitVolume Failed to allocate the root volume cb\n"); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pVolumeCB, sizeof( AFSVolumeCB)); // // The non paged portion // pNonPagedVcb = (AFSNonPagedVolumeCB *)AFSExAllocatePoolWithTag( NonPagedPool, sizeof( AFSNonPagedVolumeCB), AFS_VCB_ALLOCATION_TAG); if( pNonPagedVcb == NULL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSInitVolume Failed to allocate the root non paged volume cb\n"); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pNonPagedVcb, sizeof( AFSNonPagedVolumeCB)); ExInitializeResourceLite( &pNonPagedVcb->VolumeLock); ExInitializeResourceLite( &pNonPagedVcb->ObjectInfoTreeLock); pNonPagedObject = (AFSNonPagedObjectInfoCB *)AFSExAllocatePoolWithTag( NonPagedPool, sizeof( AFSNonPagedObjectInfoCB), AFS_VCB_ALLOCATION_TAG); if( pNonPagedObject == NULL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSInitVolume Failed to allocate the root non paged object cb\n"); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pNonPagedObject, sizeof( AFSNonPagedObjectInfoCB)); ExInitializeResourceLite( &pNonPagedObject->DirectoryNodeHdrLock); pVolumeCB->NonPagedVcb = pNonPagedVcb; pVolumeCB->ObjectInformation.NonPagedInfo = pNonPagedObject; pVolumeCB->VolumeLock = &pNonPagedVcb->VolumeLock; pVolumeCB->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock = &pNonPagedObject->DirectoryNodeHdrLock; pVolumeCB->ObjectInfoTree.TreeLock = &pNonPagedVcb->ObjectInfoTreeLock; // // Bias our reference by 1 // AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSInitVolume Initializing count (1) on volume %08lX\n", pVolumeCB); pVolumeCB->VolumeReferenceCount = 1; AFSAcquireExcl( pVolumeCB->VolumeLock, TRUE); pVolumeCB->DirectoryCB = (AFSDirectoryCB *)AFSExAllocatePoolWithTag( PagedPool, sizeof( AFSDirectoryCB) + sizeof( WCHAR), AFS_DIR_ENTRY_TAG); if( pVolumeCB->DirectoryCB == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSExAllocatePoolWithTag( NonPagedPool, sizeof( AFSNonPagedDirectoryCB), AFS_DIR_ENTRY_NP_TAG); if( pNonPagedDirEntry == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pVolumeCB->DirectoryCB, sizeof( AFSDirectoryCB) + sizeof( WCHAR)); RtlZeroMemory( pNonPagedDirEntry, sizeof( AFSNonPagedDirectoryCB)); ExInitializeResourceLite( &pNonPagedDirEntry->Lock); pVolumeCB->DirectoryCB->NonPaged = pNonPagedDirEntry; // // Initialize the non-paged portion of the directory entry // KeQuerySystemTime( &pVolumeCB->ObjectInformation.CreationTime); KeQuerySystemTime( &pVolumeCB->ObjectInformation.LastWriteTime); KeQuerySystemTime( &pVolumeCB->ObjectInformation.LastAccessTime); pVolumeCB->ObjectInformation.FileType = AFS_FILE_TYPE_DIRECTORY; SetFlag( pVolumeCB->ObjectInformation.Flags, AFS_OBJECT_ROOT_VOLUME); pVolumeCB->ObjectInformation.FileId.Cell = RootFid->Cell; pVolumeCB->ObjectInformation.FileId.Volume = RootFid->Volume; pVolumeCB->ObjectInformation.FileId.Vnode = RootFid->Vnode; pVolumeCB->ObjectInformation.FileId.Unique = RootFid->Unique; pVolumeCB->ObjectInformation.FileId.Hash = RootFid->Hash; pVolumeCB->ObjectInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; pVolumeCB->DirectoryCB->NameInformation.FileName.Length = sizeof( WCHAR); pVolumeCB->DirectoryCB->NameInformation.FileName.MaximumLength = pVolumeCB->DirectoryCB->NameInformation.FileName.Length; pVolumeCB->DirectoryCB->NameInformation.FileName.Buffer = (WCHAR *)((char *)pVolumeCB->DirectoryCB + sizeof( AFSDirectoryCB)); RtlCopyMemory( pVolumeCB->DirectoryCB->NameInformation.FileName.Buffer, L"\\", sizeof( WCHAR)); // // Copy in the volume information retrieved above // RtlCopyMemory( &pVolumeCB->VolumeInformation, &stVolumeInformation, sizeof( AFSVolumeInfoCB)); // // Setup pointers // pVolumeCB->DirectoryCB->ObjectInformation = &pVolumeCB->ObjectInformation; pVolumeCB->DirectoryCB->ObjectInformation->VolumeCB = pVolumeCB; // // Insert the volume into our volume tree. Don't insert any reserved entries // if( RootFid->Cell != 0) { pVolumeCB->TreeEntry.HashIndex = ullIndex; if( pDeviceExt->Specific.RDR.VolumeTree.TreeHead == NULL) { pDeviceExt->Specific.RDR.VolumeTree.TreeHead = &pVolumeCB->TreeEntry; SetFlag( pVolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE); } else { if ( NT_SUCCESS( AFSInsertHashEntry( pDeviceExt->Specific.RDR.VolumeTree.TreeHead, &pVolumeCB->TreeEntry))) { SetFlag( pVolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE); } } if( pDeviceExt->Specific.RDR.VolumeListHead == NULL) { pDeviceExt->Specific.RDR.VolumeListHead = pVolumeCB; } else { pDeviceExt->Specific.RDR.VolumeListTail->ListEntry.fLink = (void *)pVolumeCB; pVolumeCB->ListEntry.bLink = pDeviceExt->Specific.RDR.VolumeListTail; } pDeviceExt->Specific.RDR.VolumeListTail = pVolumeCB; } *VolumeCB = pVolumeCB; try_exit: if( !NT_SUCCESS( ntStatus)) { if( pNonPagedVcb != NULL) { AFSReleaseResource( pVolumeCB->VolumeLock); ExDeleteResourceLite( &pNonPagedVcb->VolumeLock); ExDeleteResourceLite( &pNonPagedVcb->ObjectInfoTreeLock); AFSExFreePool( pNonPagedVcb); } if( pNonPagedObject != NULL) { ExDeleteResourceLite( &pNonPagedObject->DirectoryNodeHdrLock); AFSExFreePool( pNonPagedObject); } if( pVolumeCB != NULL) { if( pVolumeCB->DirectoryCB != NULL) { AFSExFreePool( pVolumeCB->DirectoryCB); } AFSExFreePool( pVolumeCB); } if( pNonPagedDirEntry != NULL) { ExDeleteResourceLite( &pNonPagedDirEntry->Lock); AFSExFreePool( pNonPagedDirEntry); } } if( bReleaseLocks) { AFSReleaseResource( pDeviceExt->Specific.RDR.VolumeTree.TreeLock); AFSReleaseResource( &pDeviceExt->Specific.RDR.VolumeListLock); } } return ntStatus; }
NTSTATUS AFSProcessUserFsRequest( IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG ulFsControlCode; AFSFcb *pFcb = NULL; PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp ); AFSCcb *pCcb = NULL; ULONG ulOutputBufferLen, ulInputBufferLen; __Enter { ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode; pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; if( pFcb == NULL || pCcb == NULL || pCcb->DirectoryCB == NULL) { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Invalid Fcb\n")); try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); } if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) { ntStatus = AFSProcessShareFsCtrl( Irp, pFcb, pCcb); try_return( ntStatus); } ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength; ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength; // // Process the request // switch( ulFsControlCode ) { case FSCTL_REQUEST_OPLOCK_LEVEL_1: case FSCTL_REQUEST_OPLOCK_LEVEL_2: case FSCTL_REQUEST_BATCH_OPLOCK: case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: case FSCTL_OPBATCH_ACK_CLOSE_PENDING: case FSCTL_OPLOCK_BREAK_NOTIFY: case FSCTL_OPLOCK_BREAK_ACK_NO_2: case FSCTL_REQUEST_FILTER_OPLOCK : { // // Note that implementing this call will probably need us // to call the server as well as adding code in read and // write and caching. Also that it is unlikely that // anyone will ever call us at this point - RDR doesn't // allow it // ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_LOCK_VOLUME: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n")); ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_UNLOCK_VOLUME: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n")); ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_DISMOUNT_VOLUME: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n")); ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_MARK_VOLUME_DIRTY: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n")); ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_IS_VOLUME_DIRTY: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n")); ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_IS_VOLUME_MOUNTED: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n")); ntStatus = STATUS_NOT_IMPLEMENTED; break; } case FSCTL_IS_PATHNAME_VALID: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n")); ntStatus = STATUS_SUCCESS; break; } #ifndef FSCTL_CSC_INTERNAL #define FSCTL_CSC_INTERNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, FILE_ANY_ACCESS) #endif case FSCTL_CSC_INTERNAL: { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_CSC_INTERNAL request\n")); ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } case FSCTL_GET_REPARSE_POINT: { REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; REPARSE_DATA_BUFFER *pMSFTReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; ULONG ulRemainingLen = ulOutputBufferLen; AFSReparseTagInfo *pReparseInfo = NULL; BOOLEAN bRelative = FALSE; BOOLEAN bDriveLetter = FALSE; WCHAR * PathBuffer = NULL; AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileType, pFcb->ObjectInformation->FileAttributes)); // // Check if we have the reparse entry set on the entry // if( !BooleanFlagOn( pFcb->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) { ntStatus = STATUS_NOT_A_REPARSE_POINT; break; } switch ( pFcb->ObjectInformation->FileType) { case AFS_FILE_TYPE_MOUNTPOINT: if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer); break; } ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer); break; default: if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer); break; } ulRemainingLen -= FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer); break; } // // Populate the data in the reparse buffer // pReparseBuffer->ReparseDataLength = 0; AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock, TRUE); if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) { // // We'll reset the DV to ensure we validate the metadata content // pFcb->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1; SetFlag( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY); AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileId.Cell, pFcb->ObjectInformation->FileId.Volume, pFcb->ObjectInformation->FileId.Vnode, pFcb->ObjectInformation->FileId.Unique)); ntStatus = AFSVerifyEntry( &pCcb->AuthGroup, pCcb->DirectoryCB, FALSE); if( !NT_SUCCESS( ntStatus)) { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileId.Cell, pFcb->ObjectInformation->FileId.Volume, pFcb->ObjectInformation->FileId.Vnode, pFcb->ObjectInformation->FileId.Unique, ntStatus)); AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock); break; } } pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0]; switch( pFcb->ObjectInformation->FileType) { case AFS_FILE_TYPE_SYMLINK: { if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) { ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED; break; } bRelative = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName); if ( bRelative) { if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length; break; } pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0; PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength; } else { if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + /* Display Name */ pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) + /* Substitute Name */ pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR)) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) + pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR); break; } pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR); pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR); pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0; PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer; /* Display Name */ *PathBuffer++ = L'\\'; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR); /* Substitute Name */ *PathBuffer++ = L'\\'; *PathBuffer++ = L'?'; *PathBuffer++ = L'?'; *PathBuffer++ = L'\\'; *PathBuffer++ = L'U'; *PathBuffer++ = L'N'; *PathBuffer++ = L'C'; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength; } break; } case AFS_FILE_TYPE_MOUNTPOINT: { UNICODE_STRING Cell, Volume; USHORT Type; if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) { ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED; break; } if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName, &Type, &Volume, &Cell)) { ntStatus = STATUS_INVALID_PARAMETER; break; } if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length; break; } pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT; pReparseInfo->AFSMountPoint.Type = Type; pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length; pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length; RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer, Cell.Buffer, Cell.Length); RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)], Volume.Buffer, Volume.Length); pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length); break; } case AFS_FILE_TYPE_DFSLINK: { if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) { ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED; break; } bRelative = ( pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\'); bDriveLetter = (bRelative == FALSE && pCcb->DirectoryCB->NameInformation.TargetName.Buffer[1] == L':'); if ( bRelative) { if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length; break; } pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0; PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength; } else if ( bDriveLetter) { if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + /* Display Name */ pCcb->DirectoryCB->NameInformation.TargetName.Length + /* Substitute Name */ pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR)) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length + pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR); break; } pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR); pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0; PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer; /* Display Name */ RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR); /* Substitute Name */ *PathBuffer++ = L'\\'; *PathBuffer++ = L'?'; *PathBuffer++ = L'?'; *PathBuffer++ = L'\\'; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength; } else { if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + /* Display Name */ pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) + /* Substitute Name */ pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR)) { ntStatus = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) + pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR); break; } pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR); pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR); pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength; pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0; PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer; /* Display Name */ *PathBuffer++ = L'\\'; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR); /* Substitute Name */ *PathBuffer++ = L'\\'; *PathBuffer++ = L'?'; *PathBuffer++ = L'?'; *PathBuffer++ = L'\\'; *PathBuffer++ = L'U'; *PathBuffer++ = L'N'; *PathBuffer++ = L'C'; RtlCopyMemory( PathBuffer, pCcb->DirectoryCB->NameInformation.TargetName.Buffer, pCcb->DirectoryCB->NameInformation.TargetName.Length); pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength; } break; } default: ntStatus = STATUS_NOT_A_REPARSE_POINT; break; } if ( ntStatus == STATUS_SUCCESS) { ulRemainingLen -= pReparseBuffer->ReparseDataLength; if ( pFcb->ObjectInformation->FileType == AFS_FILE_TYPE_MOUNTPOINT) { pReparseBuffer->ReparseTag = IO_REPARSE_TAG_SURROGATE|IO_REPARSE_TAG_OPENAFS_DFS; RtlCopyMemory( &pReparseBuffer->ReparseGuid, &GUID_AFS_REPARSE_GUID, sizeof( GUID)); Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pReparseBuffer->ReparseDataLength; } else { pReparseBuffer->ReparseTag = IO_REPARSE_TAG_SYMLINK; Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + pReparseBuffer->ReparseDataLength; } } AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock); break; } case FSCTL_SET_REPARSE_POINT: { REPARSE_GUID_DATA_BUFFER *pReparseGUIDBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; REPARSE_DATA_BUFFER *pReparseBuffer = NULL; AFSReparseTagInfo *pReparseInfo = NULL; AFSObjectInfoCB *pParentObjectInfo = NULL; UNICODE_STRING uniTargetName; ULONGLONG ullIndex = 0; LONG lCount; AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileType, pFcb->ObjectInformation->FileAttributes)); if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) { ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } if( (pReparseGUIDBuffer->ReparseTag & 0x0000FFFF) == IO_REPARSE_TAG_OPENAFS_DFS) { if( RtlCompareMemory( &pReparseGUIDBuffer->ReparseGuid, &GUID_AFS_REPARSE_GUID, sizeof( GUID)) != sizeof( GUID)) { ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT; break; } if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + sizeof( AFSReparseTagInfo)) { ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } pReparseInfo = (AFSReparseTagInfo *)pReparseGUIDBuffer->GenericReparseBuffer.DataBuffer; switch( pReparseInfo->SubTag) { case OPENAFS_SUBTAG_SYMLINK: { if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pReparseInfo->AFSSymLink.SymLinkTargetLength)) { ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } uniTargetName.Length = pReparseInfo->AFSSymLink.SymLinkTargetLength; uniTargetName.MaximumLength = uniTargetName.Length; uniTargetName.Buffer = (WCHAR *)pReparseInfo->AFSSymLink.Buffer; break; } case OPENAFS_SUBTAG_UNC: { if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pReparseInfo->UNCReferral.UNCTargetLength)) { ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } uniTargetName.Length = pReparseInfo->UNCReferral.UNCTargetLength; uniTargetName.MaximumLength = uniTargetName.Length; uniTargetName.Buffer = (WCHAR *)pReparseInfo->UNCReferral.Buffer; break; } case OPENAFS_SUBTAG_MOUNTPOINT: // // Not yet handled // default: { ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } } } else { // // Handle Microsoft Reparse Tags // switch( pReparseGUIDBuffer->ReparseTag) { case IO_REPARSE_TAG_MOUNT_POINT: { pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; uniTargetName.Length = pReparseBuffer->MountPointReparseBuffer.PrintNameLength; uniTargetName.MaximumLength = uniTargetName.Length; uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->MountPointReparseBuffer.PathBuffer + pReparseBuffer->MountPointReparseBuffer.PrintNameOffset); AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest IO_REPARSE_TAG_MOUNT_POINT request %wZ\n", &uniTargetName)); ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } case IO_REPARSE_TAG_SYMLINK: { pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; uniTargetName.Length = pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength; uniTargetName.MaximumLength = uniTargetName.Length; uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer + pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset); AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest IO_REPARSE_TAG_SYMLINK request %wZ\n", &uniTargetName)); break; } default: { ntStatus = STATUS_IO_REPARSE_DATA_INVALID; break; } } } if( !NT_SUCCESS( ntStatus)) { break; } // // First thing is to locate/create our object information block // for this entry // AFSAcquireExcl( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock, TRUE); if ( AFSIsVolumeFID( &pFcb->ObjectInformation->ParentFileId)) { pParentObjectInfo = &pFcb->ObjectInformation->VolumeCB->ObjectInformation; } else { ullIndex = AFSCreateLowIndex( &pFcb->ObjectInformation->ParentFileId); ntStatus = AFSLocateHashEntry( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead, ullIndex, (AFSBTreeEntry **)&pParentObjectInfo); } if ( NT_SUCCESS( ntStatus)) { lCount = AFSObjectInfoIncrement( pParentObjectInfo, AFS_OBJECT_REFERENCE_FS_REQ); AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSProcessUserFsRequest Increment count on object %p Cnt %d\n", pParentObjectInfo, lCount)); KeQueryTickCount( &pParentObjectInfo->LastAccessCount); } AFSReleaseResource( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock); if ( NT_SUCCESS( ntStatus)) { // // Extract out the information to the call to the service // ntStatus = AFSCreateSymlink( &pCcb->AuthGroup, pParentObjectInfo, &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation, &uniTargetName); AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processed FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x Status %08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileType, pFcb->ObjectInformation->FileAttributes, ntStatus)); AFSAcquireShared( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock, TRUE); lCount = AFSObjectInfoDecrement( pParentObjectInfo, AFS_OBJECT_REFERENCE_FS_REQ); AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSProcessUserFsRequest Decrement count on object %p Cnt %d\n", pParentObjectInfo, lCount)); AFSReleaseResource( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock); } break; } case FSCTL_DELETE_REPARSE_POINT: { REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileType, pFcb->ObjectInformation->FileAttributes)); // // Check if we have the reparse entry set on the entry // if( !BooleanFlagOn( pFcb->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) { ntStatus = STATUS_NOT_A_REPARSE_POINT; break; } if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) { ntStatus = STATUS_INVALID_PARAMETER; break; } if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != IO_REPARSE_TAG_OPENAFS_DFS) { ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH; break; } if( RtlCompareMemory( &pReparseBuffer->ReparseGuid, &GUID_AFS_REPARSE_GUID, sizeof( GUID)) != sizeof( GUID)) { ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT; break; } // // Claim success. The typical usage is setting delete on close // as the next operation on the reparse point before closing // the handle. // ntStatus = STATUS_SUCCESS; break; } #ifndef FSCTL_SET_PURGE_FAILURE_MODE #define FSCTL_SET_PURGE_FAILURE_MODE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 156, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif case FSCTL_SET_PURGE_FAILURE_MODE: { // // For the time being just succeed this call // ntStatus = STATUS_SUCCESS; break; } default : { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode)); ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } } try_exit: NOTHING; } return ntStatus; }
GUID * AFSValidateProcessEntry( IN HANDLE ProcessId, IN BOOLEAN bProcessTreeLocked) { GUID *pAuthGroup = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; AFSProcessCB *pProcessCB = NULL, *pParentProcessCB = NULL; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; ULONGLONG ullProcessID = (ULONGLONG)ProcessId; UNICODE_STRING uniSIDString; ULONG ulSIDHash = 0; AFSSIDEntryCB *pSIDEntryCB = NULL; ULONG ulSessionId = 0; ULONGLONG ullTableHash = 0; AFSThreadCB *pParentThreadCB = NULL; UNICODE_STRING uniGUID; BOOLEAN bImpersonation = FALSE; __Enter { uniSIDString.Length = 0; uniSIDString.MaximumLength = 0; uniSIDString.Buffer = NULL; if ( !bProcessTreeLocked) { AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSValidateProcessEntry Acquiring Control ProcessTree.TreeLock lock %p SHARED %08lX\n", pDeviceExt->Specific.Control.ProcessTree.TreeLock, PsGetCurrentThread())); AFSAcquireShared( pDeviceExt->Specific.Control.ProcessTree.TreeLock, TRUE); } AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Entry for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, ullProcessID, (AFSBTreeEntry **)&pProcessCB); if( !NT_SUCCESS( ntStatus) || pProcessCB == NULL) { if ( !bProcessTreeLocked) { AFSReleaseResource( pDeviceExt->Specific.Control.ProcessTree.TreeLock); AFSAcquireExcl( pDeviceExt->Specific.Control.ProcessTree.TreeLock, TRUE); } ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, ullProcessID, (AFSBTreeEntry **)&pProcessCB); if( !NT_SUCCESS( ntStatus) || pProcessCB == NULL) { AFSProcessCreate( 0, ProcessId, 0, 0); } if( !NT_SUCCESS( ntStatus) || pProcessCB == NULL) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to locate process entry for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); try_return( ntStatus = STATUS_UNSUCCESSFUL); } if ( !bProcessTreeLocked) { AFSConvertToShared( pDeviceExt->Specific.Control.ProcessTree.TreeLock); } } // // Locate and lock the ParentProcessCB if we have one // if( pProcessCB->ParentProcessId != 0) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Locating process entry for Parent ProcessID %I64X\n", __FUNCTION__, pProcessCB->ParentProcessId)); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, (ULONGLONG)pProcessCB->ParentProcessId, (AFSBTreeEntry **)&pParentProcessCB); if( NT_SUCCESS( ntStatus) && pParentProcessCB != NULL) { AFSAcquireExcl( &pParentProcessCB->Lock, TRUE); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Located process entry for Parent ProcessID %I64X\n", __FUNCTION__, pProcessCB->ParentProcessId)); } } else { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s No parent ID for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); } AFSAcquireExcl( &pProcessCB->Lock, TRUE); #if defined(_WIN64) // // Mark the process as 64-bit if it is. // if( !IoIs32bitProcess( NULL)) { SetFlag( pProcessCB->Flags, AFS_PROCESS_FLAG_IS_64BIT); } else { ClearFlag( pProcessCB->Flags, AFS_PROCESS_FLAG_IS_64BIT); } #endif // // Locate the SID for the caller // ntStatus = AFSGetCallerSID( &uniSIDString, &bImpersonation); if( !NT_SUCCESS( ntStatus)) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to locate callers SID for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); try_return( ntStatus); } ulSessionId = AFSGetSessionId( (HANDLE)ullProcessID, &bImpersonation); if( ulSessionId == (ULONG)-1) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to retrieve session ID for ProcessID %I64X\n", __FUNCTION__, ullProcessID)); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Retrieved callers SID %wZ for ProcessID %I64X Session %08lX\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId)); // // If there is an Auth Group for the current process, // our job is finished. // if ( bImpersonation == FALSE) { pAuthGroup = pProcessCB->ActiveAuthGroup; if( pAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pAuthGroup)) { uniGUID.Buffer = NULL; RtlStringFromGUID( *pAuthGroup, &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Located valid AuthGroup GUID %wZ for SID %wZ ProcessID %I64X Session %08lX\n", __FUNCTION__, &uniGUID, &uniSIDString, ullProcessID, ulSessionId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } try_return( ntStatus = STATUS_SUCCESS); } // // The current process does not yet have an Auth Group. Try to inherit // one from the parent process thread that created this process. // if( pParentProcessCB != NULL) { for ( pParentThreadCB = pParentProcessCB->ThreadList; pParentThreadCB != NULL; pParentThreadCB = pParentThreadCB->Next) { if( pParentThreadCB->ThreadId == pProcessCB->CreatingThreadId) { break; } } // // If the creating thread was found and it has a thread specific // Auth Group, use that even if it is the No PAG // if( pParentThreadCB != NULL && pParentThreadCB->ActiveAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pParentThreadCB->ActiveAuthGroup)) { pProcessCB->ActiveAuthGroup = pParentThreadCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s PID %I64X Session %08lX inherited Active AuthGroup %wZ from thread %I64X\n", __FUNCTION__, ullProcessID, ulSessionId, &uniGUID, pParentThreadCB->ThreadId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } } // // If the parent thread was not found or does not have an auth group // else if( pParentProcessCB->ActiveAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pParentProcessCB->ActiveAuthGroup)) { pProcessCB->ActiveAuthGroup = pParentProcessCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s PID %I64X Session %08lX inherited Active AuthGroup %wZ from parent PID %I64X\n", __FUNCTION__, ullProcessID, ulSessionId, &uniGUID, pParentProcessCB->TreeEntry.HashIndex)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } } // // If an Auth Group was inherited, set it to be the active group // if( pProcessCB->ActiveAuthGroup != NULL && !AFSIsNoPAGAuthGroup( pParentProcessCB->ActiveAuthGroup)) { pAuthGroup = pProcessCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Returning(1) Active AuthGroup %wZ for SID %wZ PID %I64X Session %08lX\n", __FUNCTION__, &uniGUID, &uniSIDString, ullProcessID, ulSessionId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } try_return( ntStatus); } } } // // If no Auth Group was inherited, assign one based upon the Session and SID // ntStatus = RtlHashUnicodeString( &uniSIDString, TRUE, HASH_STRING_ALGORITHM_DEFAULT, &ulSIDHash); if( !NT_SUCCESS( ntStatus)) { AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_ERROR, "%s Failed to hash SID %wZ for PID %I64X Session %08lX Status %08lX\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId, ntStatus)); try_return( ntStatus); } ullTableHash = ( ((ULONGLONG)ulSessionId << 32) | ulSIDHash); AFSAcquireShared( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock, TRUE); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead, (ULONGLONG)ullTableHash, (AFSBTreeEntry **)&pSIDEntryCB); if( !NT_SUCCESS( ntStatus) || pSIDEntryCB == NULL) { AFSReleaseResource( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); AFSAcquireExcl( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock, TRUE); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead, (ULONGLONG)ullTableHash, (AFSBTreeEntry **)&pSIDEntryCB); if( !NT_SUCCESS( ntStatus) || pSIDEntryCB == NULL) { pSIDEntryCB = (AFSSIDEntryCB *)AFSExAllocatePoolWithTag( NonPagedPool, sizeof( AFSSIDEntryCB), AFS_AG_ENTRY_CB_TAG); if( pSIDEntryCB == NULL) { AFSReleaseResource( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pSIDEntryCB, sizeof( AFSSIDEntryCB)); pSIDEntryCB->TreeEntry.HashIndex = (ULONGLONG)ullTableHash; while( ExUuidCreate( &pSIDEntryCB->AuthGroup) == STATUS_RETRY); uniGUID.Buffer = NULL; RtlStringFromGUID( pSIDEntryCB->AuthGroup, &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s SID %wZ PID %I64X Session %08lX generated NEW AG %wZ\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId, &uniGUID)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } if( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead == NULL) { pDeviceExt->Specific.Control.AuthGroupTree.TreeHead = (AFSBTreeEntry *)pSIDEntryCB; } else { AFSInsertHashEntry( pDeviceExt->Specific.Control.AuthGroupTree.TreeHead, &pSIDEntryCB->TreeEntry); } } AFSConvertToShared( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); } AFSReleaseResource( pDeviceExt->Specific.Control.AuthGroupTree.TreeLock); // // Store the auth group into the process cb // pProcessCB->ActiveAuthGroup = &pSIDEntryCB->AuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( pSIDEntryCB->AuthGroup, &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s SID %wZ PID %I64X Session %08lX assigned AG %wZ\n", __FUNCTION__, &uniSIDString, ullProcessID, ulSessionId, &uniGUID)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } // // Set the AFS_PROCESS_LOCAL_SYSTEM_AUTH flag if the process SID // is LOCAL_SYSTEM // if( AFSIsLocalSystemSID( &uniSIDString)) { SetFlag( pProcessCB->Flags, AFS_PROCESS_LOCAL_SYSTEM_AUTH); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Setting PID %I64X Session %08lX with LOCAL SYSTEM AUTHORITY\n", __FUNCTION__, ullProcessID, ulSessionId)); } // // Return the auth group // pAuthGroup = pProcessCB->ActiveAuthGroup; uniGUID.Buffer = NULL; RtlStringFromGUID( *(pProcessCB->ActiveAuthGroup), &uniGUID); AFSDbgTrace(( AFS_SUBSYSTEM_AUTHGROUP_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "%s Returning(2) Active AuthGroup %wZ for SID %wZ PID %I64X Session %08lX\n", __FUNCTION__, &uniGUID, &uniSIDString, ullProcessID, ulSessionId)); if( uniGUID.Buffer != NULL) { RtlFreeUnicodeString( &uniGUID); } try_exit: if( pProcessCB != NULL) { if( bImpersonation == FALSE && !BooleanFlagOn( pProcessCB->Flags, AFS_PROCESS_FLAG_ACE_SET) && NT_SUCCESS( ntStatus)) { ntStatus = AFSProcessSetProcessDacl( pProcessCB); if( !NT_SUCCESS( ntStatus)) { pAuthGroup = NULL; } else { SetFlag( pProcessCB->Flags, AFS_PROCESS_FLAG_ACE_SET); } } AFSReleaseResource( &pProcessCB->Lock); } if( pParentProcessCB != NULL) { AFSReleaseResource( &pParentProcessCB->Lock); } if( uniSIDString.Length > 0) { RtlFreeUnicodeString( &uniSIDString); } if ( !bProcessTreeLocked) { AFSReleaseResource( pDeviceExt->Specific.Control.ProcessTree.TreeLock); } } return pAuthGroup; }
void AFSProcessDestroy( IN HANDLE ProcessId) { NTSTATUS ntStatus = STATUS_SUCCESS; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; AFSProcessCB *pProcessCB = NULL; AFSProcessAuthGroupCB *pProcessAuthGroup = NULL, *pLastAuthGroup = NULL; AFSThreadCB *pThreadCB = NULL, *pNextThreadCB = NULL; __Enter { AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSProcessDestroy Acquiring Control ProcessTree.TreeLock lock %p EXCL %08lX\n", pDeviceExt->Specific.Control.ProcessTree.TreeLock, PsGetCurrentThreadId())); AFSAcquireExcl( pDeviceExt->Specific.Control.ProcessTree.TreeLock, TRUE); // // It's a remove so pull the entry // AFSDbgTrace(( AFS_SUBSYSTEM_PROCESS_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSProcessDestroy Process %08lX %08lX\n", ProcessId, PsGetCurrentThread())); ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.Control.ProcessTree.TreeHead, (ULONGLONG)ProcessId, (AFSBTreeEntry **)&pProcessCB); if( NT_SUCCESS( ntStatus) && pProcessCB != NULL) { AFSRemoveHashEntry( &pDeviceExt->Specific.Control.ProcessTree.TreeHead, (AFSBTreeEntry *)pProcessCB); pProcessAuthGroup = pProcessCB->AuthGroupList; while( pProcessAuthGroup != NULL) { pLastAuthGroup = pProcessAuthGroup->Next; ExFreePool( pProcessAuthGroup); pProcessAuthGroup = pLastAuthGroup; } pThreadCB = pProcessCB->ThreadList; while( pThreadCB != NULL) { pNextThreadCB = pThreadCB->Next; ExFreePool( pThreadCB); pThreadCB = pNextThreadCB; } ExDeleteResourceLite( &pProcessCB->Lock); ExFreePool( pProcessCB); } else { AFSDbgTrace(( AFS_SUBSYSTEM_PROCESS_PROCESSING, AFS_TRACE_LEVEL_WARNING, "AFSProcessDestroy Process %08lX not found in ProcessTree Status %08lX %08lX\n", ProcessId, ntStatus, PsGetCurrentThread())); } AFSReleaseResource( pDeviceExt->Specific.Control.ProcessTree.TreeLock); } return; }