Example #1
0
NTSTATUS
NtQueryFullAttributesFile (
    __in POBJECT_ATTRIBUTES ObjectAttributes,
    __out PFILE_NETWORK_OPEN_INFORMATION FileInformation
    )

/*++

Routine Description:

    This service queries the network attributes information for a specified
    file.

Arguments:

    ObjectAttributes - Supplies the attributes to be used for file object (name,
        SECURITY_DESCRIPTOR, etc.)

    FileInformation - Supplies an output buffer to receive the returned file
        attributes information.

Return Value:

    The status returned is the final completion status of the operation.

--*/

{
    KPROCESSOR_MODE requestorMode;
    NTSTATUS status;
    OPEN_PACKET openPacket;
    DUMMY_FILE_OBJECT localFileObject;
    FILE_NETWORK_OPEN_INFORMATION networkInformation;
    HANDLE handle;

    PAGED_CODE();

    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    requestorMode = KeGetPreviousMode();

    if (requestorMode != KernelMode) {

        try {

            //
            // The caller's mode is not kernel, so probe the output buffer.
            //

            ProbeForWriteSmallStructure( FileInformation,
                                         sizeof( FILE_NETWORK_OPEN_INFORMATION ),
#if defined(_X86_)
                                         sizeof( LONG ));
#else
                                         sizeof( LONGLONG ));
#endif // defined(_X86_)

        } except(EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception was incurred while probing the caller's parameters.
            // Simply return an appropriate error status code.
            //

            return GetExceptionCode();
        }
    }

    //
    // Build a parse open packet that tells the parse method to open the file,
    // query the file's full attributes, and close the file.
    //

    RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) );

    openPacket.Type = IO_TYPE_OPEN_PACKET;
    openPacket.Size = sizeof( OPEN_PACKET );
    openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
    openPacket.Disposition = FILE_OPEN;
    openPacket.CreateOptions = FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT;
    openPacket.QueryOnly = TRUE;
    openPacket.FullAttributes = TRUE;
    openPacket.TraversedMountPoint = FALSE;
    openPacket.LocalFileObject = &localFileObject;
    if (requestorMode != KernelMode) {
        openPacket.NetworkInformation = &networkInformation;
    } else {
        openPacket.NetworkInformation = FileInformation;
    }

    //
    // Update the open count for this process.
    //

    IopUpdateOtherOperationCount();

    //
    // Open the object by its name.  Because of the special QueryOnly flag set
    // in the open packet, the parse routine will open the file, and then
    // realize that it is only performing a query.  It will therefore perform
    // the query, and immediately close the file.
    //

    status = ObOpenObjectByName( ObjectAttributes,
                                 (POBJECT_TYPE) NULL,
                                 requestorMode,
                                 NULL,
                                 FILE_READ_ATTRIBUTES,
                                 &openPacket,
                                 &handle );

    //
    // The operation is successful if the parse check field of the open packet
    // indicates that the parse routine was actually invoked, and the final
    // status field of the packet is set to success.
    //

    if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) {
        if (NT_SUCCESS(status)) {
            ZwClose(handle);
            status = STATUS_OBJECT_TYPE_MISMATCH;
        }
        return status;
    } else {
        status = openPacket.FinalStatus;
    }

    if (NT_SUCCESS( status )) {
        if (requestorMode != KernelMode) {
            try {

                //
                // The query worked, so copy the returned information to the
                // caller's output buffer.
                //

                RtlCopyMemory( FileInformation,
                               &networkInformation,
                               sizeof( FILE_NETWORK_OPEN_INFORMATION ) );

            } except(EXCEPTION_EXECUTE_HANDLER) {
                status = GetExceptionCode();
            }
        }
    }

    return status;
}
Example #2
0
NTSTATUS
NtCancelIoFile (
    __in HANDLE FileHandle,
    __out PIO_STATUS_BLOCK IoStatusBlock
    )

/*++

Routine Description:

    This service causes all pending I/O operations for the specified file to be
    marked as canceled.  Most types of operations can be canceled immediately,
    while others may continue toward completion before they are actually
    canceled and the caller is notified.

    Only those pending operations that were issued by the current thread using
    the specified handle are canceled.  Any operations issued for the file by
    any other thread or any other process continues normally.

Arguments:

    FileHandle - Supplies a handle to the file whose operations are to be
        canceled.

    IoStatusBlock - Address of the caller's I/O status block.

Return Value:

    The status returned is the final completion status of the operation.

--*/

{
    PIRP irp;
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    KPROCESSOR_MODE requestorMode;
    PETHREAD thread;
    BOOLEAN found = FALSE;
    PLIST_ENTRY header;
    PLIST_ENTRY entry;
    KIRQL irql;

    PAGED_CODE();


    //
    // Get the address of the current thread.  The thread contains a list of
    // the pending operations for this file.
    //

    thread = PsGetCurrentThread();

    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    requestorMode = KeGetPreviousModeByThread(&thread->Tcb);

    if (requestorMode != KernelMode) {

        //
        // The caller's access mode is user, so probe each of the arguments
        // and capture them as necessary.  If any failures occur, the condition
        // handler will be invoked to handle them.  It will simply cleanup and
        // return an access violation status code back to the system service
        // dispatcher.
        //

        try {

            //
            // The IoStatusBlock parameter must be writeable by the caller.
            //

            ProbeForWriteIoStatus( IoStatusBlock );

        } except(EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception was incurred attempting to probe the caller'
            // I/O status block.  Simply return an appropriate error status
            // code.
            //

            return GetExceptionCode();
        }
    }

    //
    // There were no blatant errors so far, so reference the file object so
    // the target device object can be found.  Note that if the handle does
    // not refer to a file object, or if the caller does not have the required
    // access to the file, then it will fail.
    //

    status = ObReferenceObjectByHandle( FileHandle,
                                        0,
                                        IoFileObjectType,
                                        requestorMode,
                                        (PVOID *) &fileObject,
                                        NULL );
    if (!NT_SUCCESS( status )) {
        return(status);
    }

    //
    // Note that here the I/O system would normally make a check to determine
    // whether or not the file was opened for synchronous I/O.  If it was, then
    // it would attempt to exclusively acquire the file object lock.  However,
    // since this service is attempting to cancel all of the I/O for the file,
    // it does not make much sense to wait until it has all completed before
    // attempting to cancel it.
    //


    //
    // Update the operation count statistic for the current process for
    // operations other than read and write.
    //

    IopUpdateOtherOperationCount();

    //
    // Walk the list of IRPs on the thread's pending I/O queue looking for IRPs
    // which specify the same file as the FileHandle refers to.  For each IRP
    // found, set its cancel flag.  If no IRPs are found, simply complete the
    // I/O here.  The only synchronization needed here is to block out all APCs
    // for this thread so that no I/O can complete and remove packets from the
    // queue.  No considerations need be made for multi-processing since this
    // thread can only be running on one processor at a time and this routine
    // has control of the thread for now.
    //

    KeRaiseIrql( APC_LEVEL, &irql );

    header = &thread->IrpList;
    entry = thread->IrpList.Flink;

    while (header != entry) {

        //
        // An IRP has been found for this thread.  If the IRP refers to the
        // appropriate file object, set its cancel flag and remember that it
        // was found;  otherwise, simply continue the loop.
        //

        irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
        if (irp->Tail.Overlay.OriginalFileObject == fileObject) {
            found = TRUE;
            IoCancelIrp( irp );
        }

        entry = entry->Flink;
    }

    //
    // Lower the IRQL back down to what it was on entry to this procedure.
    //

    KeLowerIrql( irql );

    if (found) {

        LARGE_INTEGER interval;

        //
        // Delay execution for a time and let the request
        // finish.  The delay time is 10ms.
        //

        interval.QuadPart = -10 * 1000 * 10;

        //
        // Wait for a while so the canceled requests can complete.
        //

        while (found) {

            (VOID) KeDelayExecutionThread( KernelMode, FALSE, &interval );

            found = FALSE;

            //
            // Raise the IRQL to prevent modification to the IRP list by the
            // thread's APC routine.
            //

            KeRaiseIrql( APC_LEVEL, &irql );

            //
            // Check the IRP list for requests which refer to the specified
            // file object.
            //

            entry = thread->IrpList.Flink;

            while (header != entry) {

                //
                // An IRP has been found for this thread.  If the IRP refers
                // to the appropriate file object,  remember that it
                // was found;  otherwise, simply continue the loop.
                //

                irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
                if (irp->Tail.Overlay.OriginalFileObject == fileObject) {
                    found = TRUE;
                    break;
                }

                entry = entry->Flink;
            }

            //
            // Lower the IRQL back down to what it was on entry to this procedure.
            //

            KeLowerIrql( irql );

        }
    }

    try {

        //
        // Write the status back to the user.
        //

        IoStatusBlock->Status = STATUS_SUCCESS;
        IoStatusBlock->Information = 0L;

    } except(EXCEPTION_EXECUTE_HANDLER) {

        //
        // An exception was incurred attempting to write the caller's
        // I/O status block; however, the service completed successfully so
        // just return success.
        //

    }

    //
    // Dereference the file object.
    //

    ObDereferenceObject( fileObject );

    return STATUS_SUCCESS;
}
Example #3
0
NTSTATUS
IopGetSetSecurityObject(
    IN PVOID Object,
    IN SECURITY_OPERATION_CODE OperationCode,
    IN PSECURITY_INFORMATION SecurityInformation,
    IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN OUT PULONG CapturedLength,
    IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    IN POOL_TYPE PoolType,
    IN PGENERIC_MAPPING GenericMapping
    )

/*++

Routine Description:

    This routine is invoked to either query or set the security descriptor
    for a file, directory, volume, or device.  It implements these functions
    by either performing an in-line check if the file is a device or a
    volume, or an I/O Request Packet (IRP) is generated and given to the
    driver to perform the operation.

Arguments:

    Object - Pointer to the file or device object representing the open object.

    SecurityInformation - Information about what is being done to or obtained
        from the object's security descriptor.

    SecurityDescriptor - Supplies the base security descriptor and returns
        the final security descriptor.  Note that if this buffer is coming
        from user space, it has already been probed by the object manager
        to length "CapturedLength", otherwise it points to kernel space and
        should not be probed.  It must, however, be referenced in a try
        clause.

    CapturedLength - For a query operation this specifies the size, in
        bytes, of the output security descriptor buffer and on return
        contains the number of bytes needed to store the complete security
        descriptor.  If the length needed is greater than the length
        supplied the operation will fail.  This parameter is ignored for
        the set and delete operations.  It is expected to point into
        system space, ie, it need not be probed and it will not change.

    ObjectsSecurityDescriptor - Supplies and returns the object's security
        descriptor.

    PoolType - Specifies from which type of pool memory is to be allocated.

    GenericMapping - Supplies the generic mapping for the object type.

Return Value:

    The final status of the operation is returned as the function value.

--*/

{
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    PDEVICE_OBJECT deviceObject;
    PDEVICE_OBJECT devicePDO = NULL;
    BOOLEAN synchronousIo;

    UNREFERENCED_PARAMETER( ObjectsSecurityDescriptor );
    UNREFERENCED_PARAMETER( PoolType );

    PAGED_CODE();


    //
    // Begin by determining whether the security operation is to be performed
    // in this routine or by the driver.  This is based upon whether the
    // object represents a device object, or it represents a file object
    // to a device, or a file on the device. If the open is a direct device
    // open then use the device object.
    //

    if (((PDEVICE_OBJECT) (Object))->Type == IO_TYPE_DEVICE) {
        deviceObject = (PDEVICE_OBJECT) Object;
        fileObject = (PFILE_OBJECT) NULL;
    } else {
        fileObject = (PFILE_OBJECT) Object;
        if (fileObject->Flags & FO_DIRECT_DEVICE_OPEN) {
            deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
        }
        else {
                deviceObject = fileObject->DeviceObject;
        }
    }

    if (!fileObject ||
        (!fileObject->FileName.Length && !fileObject->RelatedFileObject) ||
        (fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {

        //
        // This security operation is for the device itself, either through
        // a file object, or directly to the device object.  For the latter
        // case, assignment operations are also possible.  Also note that
        // this may be a stream file object, which do not have security.
        // The security for a stream file is actually represented by the
        // security descriptor on the file itself, or the volume, or the
        // device.
        //

        if (OperationCode == AssignSecurityDescriptor) {

            //
            // Simply assign the security descriptor to the device object,
            // if this is a device object.
            //

            if (fileObject == NULL || !(fileObject->Flags & FO_STREAM_FILE)) {
                KeEnterCriticalRegion();
                ExAcquireResourceExclusive( &IopSecurityResource, TRUE );
                deviceObject->SecurityDescriptor = SecurityDescriptor;
                ExReleaseResource( &IopSecurityResource );
                KeLeaveCriticalRegion();
            }
            status = STATUS_SUCCESS;

        } else if (OperationCode == SetSecurityDescriptor) {

            //
            // This is a set operation.  The SecurityInformation parameter
            // determines what part of the SecurityDescriptor is going to
            // be applied to the ObjectsSecurityDescriptor.
            //

            //
            // if this deviceObject is attached to a PDO then we want
            // to modify the security on the PDO and apply it up the
            // device chain
            //
            if (fileObject == NULL || !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
                //
                // see if there is a PDO for this object, and obtain it
                //
                devicePDO = IopGetDevicePDO(deviceObject);
            } else {
                devicePDO = NULL;
            }
            if (devicePDO) {
                //
                // set PDO and all attached device objects
                //
                status = IopSetDeviceSecurityDescriptors(devicePDO,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,TRUE);
                ObDereferenceObject( devicePDO );
            } else {
                //
                // set this device object only
                //
                status = IopSetDeviceSecurityDescriptors(deviceObject,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,FALSE);
            }

        } else if (OperationCode == QuerySecurityDescriptor) {

            //
            // This is a get operation.  The SecurityInformation parameter
            // determines what part of the SecurityDescriptor is going to
            // be returned from the ObjectsSecurityDescriptor.
            //

            KeEnterCriticalRegion();
            ExAcquireResourceShared( &IopSecurityResource, TRUE );
            status = SeQuerySecurityDescriptorInfo( SecurityInformation,
                                                    SecurityDescriptor,
                                                    CapturedLength,
                                                    &deviceObject->SecurityDescriptor );
            ExReleaseResource( &IopSecurityResource );
            KeLeaveCriticalRegion();

        } else {

            //
            // This is a delete operation.  Simply indicate that everything
            // worked just fine.
            //

            status = STATUS_SUCCESS;

        }

    } else if (OperationCode == DeleteSecurityDescriptor) {

        //
        // This is a delete operation for the security descriptor on a file
        // object.  This function will be performed by the file system once
        // the FCB itself is deleted.  Simply indicate that the operation
        // was successful.
        //

        status = STATUS_SUCCESS;

    } else {

        PIRP irp;
        IO_STATUS_BLOCK localIoStatus;
        KEVENT event;
        PIO_STACK_LOCATION irpSp;
        KPROCESSOR_MODE requestorMode;

        //
        // This file object does not refer to the device itself.  Rather, it
        // refers to either a file or a directory on the device.  This means
        // that the request must be passed to the file system for processing.
        // Note that the only requests that are passed through in this manner
        // are SET or QUERY security operations.  DELETE operations have
        // already been taken care of above since the file system which just
        // drop the storage on the floor when it really needs to, and ASSIGN
        // operations are irrelevant to file systems since they never
        // generate one because they never assign the security descriptor
        // to the object in the first place, they just assign it to the FCB.
        //

        requestorMode = KeGetPreviousMode();

        //
        // Begin by referencing the object by pointer.   Note that the object
        // handle has already been checked for the appropriate access by the
        // object system caller.  This reference must be performed because
        // standard I/O completion will dereference the object.
        //

        ObReferenceObject( fileObject );

        //
        // Make a special check here to determine whether this is a synchronous
        // I/O operation.  If it is, then wait here until the file is owned by
        // the current thread.  If this is not a (serialized) synchronous I/O
        // operation, then initialize the local event.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

            BOOLEAN interrupted;

            if (!IopAcquireFastLock( fileObject )) {
                status = IopAcquireFileObjectLock( fileObject,
                                                   requestorMode,
                                                   (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
                                                   &interrupted );
                if (interrupted) {
                    ObDereferenceObject( fileObject );
                    return status;
                }
            }
            synchronousIo = TRUE;
        } else {
            KeInitializeEvent( &event, SynchronizationEvent, FALSE );
            synchronousIo = FALSE;
        }

        //
        // Set the file object to the Not-Signaled state.
        //

        KeClearEvent( &fileObject->Event );

        //
        // Get the address of the target device object.
        //

        deviceObject = IoGetRelatedDeviceObject( fileObject );

        //
        // Allocate and initialize the I/O Request Packet (IRP) for this
        // operation.  The allocation is performed with an exception handler
        // in case the caller does not have enough quota to allocate the packet.

        irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
        if (!irp) {

            //
            // An IRP could not be allocated.  Cleanup and return an
            // appropriate error status code.
            //

            IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );

            return STATUS_INSUFFICIENT_RESOURCES;
        }
        irp->Tail.Overlay.OriginalFileObject = fileObject;
        irp->Tail.Overlay.Thread = PsGetCurrentThread();
        irp->RequestorMode = requestorMode;

        //
        // Fill in the service independent parameters in the IRP.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
            irp->UserEvent = (PKEVENT) NULL;
        } else {
            irp->UserEvent = &event;
            irp->Flags = IRP_SYNCHRONOUS_API;
        }
        irp->UserIosb = &localIoStatus;
        irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;

        //
        // Get a pointer to the stack location for the first driver.  This will
        // be used to pass the original function codes and parameters.
        //

        irpSp = IoGetNextIrpStackLocation( irp );

        //
        // Now determine whether this is a set or a query operation.
        //

        if (OperationCode == QuerySecurityDescriptor) {

            //
            // This is a query operation.  Fill in the appropriate fields in
            // the stack location for the packet, as well as the fixed part
            // of the packet.  Note that each of these parameters has been
            // captured as well, so there is no need to perform any probing.
            // The only exception is the UserBuffer memory may change, but
            // that is the file system's responsibility to check.  Note that
            // it has already been probed, so the pointer is at least not
            // in an address space that the caller should not be accessing
            // because of mode.
            //

            irpSp->MajorFunction = IRP_MJ_QUERY_SECURITY;
            irpSp->Parameters.QuerySecurity.SecurityInformation = *SecurityInformation;
            irpSp->Parameters.QuerySecurity.Length = *CapturedLength;
            irp->UserBuffer = SecurityDescriptor;

        } else {

            //
            // This is a set operation.  Fill in the appropriate fields in
            // the stack location for the packet.  Note that access to the
            // SecurityInformation parameter is safe, as the parameter was
            // captured by the caller.  Likewise, the SecurityDescriptor
            // refers to a captured copy of the descriptor.
            //

            irpSp->MajorFunction = IRP_MJ_SET_SECURITY;
            irpSp->Parameters.SetSecurity.SecurityInformation = *SecurityInformation;
            irpSp->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor;

        }

        irpSp->FileObject = fileObject;

        //
        // Insert the packet at the head of the IRP list for the thread.
        //

        IopQueueThreadIrp( irp );

        //
        // Update the operation count statistic for the current process for
        // operations other than read and write.
        //

        IopUpdateOtherOperationCount();

        //
        // Everything has been properly set up, so simply invoke the driver.
        //

        status = IoCallDriver( deviceObject, irp );

        //
        // If this operation was a synchronous I/O operation, check the return
        // status to determine whether or not to wait on the file object.  If
        // the file object is to be waited on, wait for the operation to be
        // completed and obtain the final status from the file object itself.
        //

        if (synchronousIo) {
            if (status == STATUS_PENDING) {
                (VOID) KeWaitForSingleObject( &fileObject->Event,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              (PLARGE_INTEGER) NULL );
                status = fileObject->FinalStatus;
            }
            IopReleaseFileObjectLock( fileObject );

        } else {

            //
            // This is a normal synchronous I/O operation, as opposed to a
            // serialized synchronous I/O operation.  For this case, wait
            // for the local event and return the final status information
            // back to the caller.
            //

            if (status == STATUS_PENDING) {
                (VOID) KeWaitForSingleObject( &event,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              (PLARGE_INTEGER) NULL );
                status = localIoStatus.Status;
            }
        }

        //
        // If this operation was just attempted on a file system or a device
        // driver of some kind that does not implement security, then return
        // a normal null security descriptor.
        //

        if (status == STATUS_INVALID_DEVICE_REQUEST) {

            //
            // The file system does not implement a security policy.  Determine
            // what type of operation this was and implement the correct
            // semantics for the file system.
            //

            if (OperationCode == QuerySecurityDescriptor) {

                //
                // The operation is a query.  If the caller's buffer is too
                // small, then indicate that this is the case and let him know
                // what size buffer is required.  Otherwise, attempt to return
                // a null security descriptor.
                //

               try {
                    status = SeAssignWorldSecurityDescriptor(
                                 SecurityDescriptor,
                                 CapturedLength,
                                 SecurityInformation
                                 );

                } except( EXCEPTION_EXECUTE_HANDLER ) {

                    //
                    // An exception was incurred while attempting to
                    // access the caller's buffer.  Clean everything
                    // up and return an appropriate status code.
                    //

                    status = GetExceptionCode();
                }

            } else {

                //
                // This was an operation other than a query.  Simply indicate
                // that the operation was successful.
                //

                status = STATUS_SUCCESS;
            }

        } else if (OperationCode == QuerySecurityDescriptor) {
Example #4
0
NTSTATUS
NtDeleteFile (
    __in POBJECT_ATTRIBUTES ObjectAttributes
    )

/*++

Routine Description:

    This service deletes the specified file.

Arguments:

    ObjectAttributes - Supplies the attributes to be used for file object (name,
        SECURITY_DESCRIPTOR, etc.)

Return Value:

    The status returned is the final completion status of the operation.

--*/

{
    KPROCESSOR_MODE requestorMode;
    NTSTATUS status;
    OPEN_PACKET openPacket;
    DUMMY_FILE_OBJECT localFileObject;
    HANDLE handle;

    PAGED_CODE();

    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    requestorMode = KeGetPreviousMode();

    //
    // Build a parse open packet that tells the parse method to open the file
    // for open for delete access w/the delete bit set, and then close it.
    //

    RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) );

    openPacket.Type = IO_TYPE_OPEN_PACKET;
    openPacket.Size = sizeof( OPEN_PACKET );
    openPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
    openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
    openPacket.Disposition = FILE_OPEN;
    openPacket.DeleteOnly = TRUE;
    openPacket.TraversedMountPoint = FALSE;
    openPacket.LocalFileObject = &localFileObject;

    //
    // Update the open count for this process.
    //

    IopUpdateOtherOperationCount();

    //
    // Open the object by its name.  Because of the special DeleteOnly flag
    // set in the open packet, the parse routine will open the file, and
    // then realize that it is only deleting the file, and will therefore
    // immediately dereference the file.  This will cause the cleanup and
    // the close to be sent to the file system, thus causing the file to
    // be deleted.
    //

    status = ObOpenObjectByName( ObjectAttributes,
                                 (POBJECT_TYPE) NULL,
                                 requestorMode,
                                 NULL,
                                 DELETE,
                                 &openPacket,
                                 &handle );

    //
    // The operation is successful if the parse check field of the open packet
    // indicates that the parse routine was actually invoked, and the final
    // status field of the packet is set to success.
    //

    if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) {
        return status;
    } else {
        return openPacket.FinalStatus;
    }
}
Example #5
0
VOID
IopCloseFile(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ULONG GrantedAccess,
    IN ULONG ProcessHandleCount,
    IN ULONG SystemHandleCount
    )

/*++

Routine Description:

    This routine is invoked whenever a handle to a file is deleted.  If the
    handle being deleted is the last handle to the file (the ProcessHandleCount
    parameter is one), then all locks for the file owned by the specified
    process must be released.

    Likewise, if the SystemHandleCount is one then this is the last handle
    for this for file object across all processes.  For this case, the file
    system is notified so that it can perform any necessary cleanup on the
    file.

Arguments:

    Process - A pointer to the process that closed the handle.

    Object - A pointer to the file object that the handle referenced.

    GrantedAccess - Access that was granted to the object through the handle.

    ProcessHandleCount - Count of handles outstanding to the object for the
        process specified by the Process argument.  If the count is one
        then this is the last handle to this file by that process.

    SystemHandleCount - Count of handles outstanding to the object for the
        entire system.  If the count is one then this is the last handle
        to this file in the system.

Return Value:

    None.

--*/

{
    PIRP irp;
    PIO_STACK_LOCATION irpSp;
    PDEVICE_OBJECT deviceObject;
    PFAST_IO_DISPATCH fastIoDispatch;
    NTSTATUS status;
    KEVENT event;
    PFILE_OBJECT fileObject;
    KIRQL irql;

    UNREFERENCED_PARAMETER( Process );
    UNREFERENCED_PARAMETER( GrantedAccess );

    PAGED_CODE();

    //
    // If the handle count is not one then this is not the last close of
    // this file for the specified process so there is nothing to do.
    //

    if (ProcessHandleCount != 1) {
        return;
    }

    fileObject = (PFILE_OBJECT) Object;

    if (fileObject->LockOperation && SystemHandleCount != 1) {

        IO_STATUS_BLOCK localIoStatus;

        //
        // This is the last handle for the specified process and the process
        // called the NtLockFile or NtUnlockFile system services at least once.
        // Also, this is not the last handle for this file object system-wide
        // so unlock all of the pending locks for this process.  Note that
        // this check causes an optimization so that if this is the last
        // system-wide handle to this file object the cleanup code will take
        // care of releasing any locks on the file rather than having to
        // send the file system two different packets to get them shut down.

        //
        // Get the address of the target device object and the Fast I/O dispatch
        //

        if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
            deviceObject = IoGetRelatedDeviceObject( fileObject );
        } else {
            deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
        }
        fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;

        //
        // If this file is open for synchronous I/O, wait until this thread
        // owns it exclusively since there may still be a thread using it.
        // This occurs when a system service owns the file because it owns
        // the semaphore, but the I/O completion code has already dereferenced
        // the file object itself.  Without waiting here for the same semaphore
        // there would be a race condition in the service who owns it now. The
        // service needs to be able to access the object w/o it going away after
        // its wait for the file event is satisfied.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

            BOOLEAN interrupted;

            if (!IopAcquireFastLock( fileObject )) {
                (VOID) IopAcquireFileObjectLock( fileObject,
                                                 KernelMode,
                                                 FALSE,
                                                 &interrupted );
            }
        }

        //
        // Turbo unlock support.  If the fast Io Dispatch specifies a fast lock
        // routine then we'll first try and calling it with the specified lock
        // parameters.  If this is all successful then we do not need to do
        // the Irp based unlock all call.
        //

        if (fastIoDispatch &&
            fastIoDispatch->FastIoUnlockAll &&
            fastIoDispatch->FastIoUnlockAll( fileObject,
                                             PsGetCurrentProcess(),
                                             &localIoStatus,
                                             deviceObject )) {

            NOTHING;

        } else {

            //
            // Initialize the local event that will be used to synchronize access
            // to the driver completing this I/O operation.
            //

            KeInitializeEvent( &event, SynchronizationEvent, FALSE );

            //
            // Reset the event in the file object.
            //

            KeClearEvent( &fileObject->Event );

            //
            // Allocate and initialize the I/O Request Packet (IRP) for this
            // operation.
            //

            irp = IopAllocateIrpMustSucceed( deviceObject->StackSize );
            irp->Tail.Overlay.OriginalFileObject = fileObject;
            irp->Tail.Overlay.Thread = PsGetCurrentThread();
            irp->RequestorMode = KernelMode;

            //
            // Fill in the service independent parameters in the IRP.
            //

            irp->UserEvent = &event;
            irp->UserIosb = &irp->IoStatus;
            irp->Flags = IRP_SYNCHRONOUS_API;
            irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;

            //
            // Get a pointer to the stack location for the first driver.  This will
            // be used to pass the original function codes and parameters.  No
            // function-specific parameters are required for this operation.
            //

            irpSp = IoGetNextIrpStackLocation( irp );
            irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
            irpSp->MinorFunction = IRP_MN_UNLOCK_ALL;
            irpSp->FileObject = fileObject;

            //
            //  Reference the fileobject again for the IRP (cleared on completion)
            //

            ObReferenceObject( fileObject );

            //
            // Insert the packet at the head of the IRP list for the thread.
            //

            IopQueueThreadIrp( irp );

            //
            // Invoke the driver at its appropriate dispatch entry with the IRP.
            //

            status = IoCallDriver( deviceObject, irp );

            //
            // If no error was incurred, wait for the I/O operation to complete.
            //

            if (status == STATUS_PENDING) {
                (VOID) KeWaitForSingleObject( &event,
                                              UserRequest,
                                              KernelMode,
                                              FALSE,
                                              (PLARGE_INTEGER) NULL );
            }
        }

        //
        // If this operation was a synchronous I/O operation, release the
        // semaphore so that the file can be used by other threads.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
            IopReleaseFileObjectLock( fileObject );
        }
    }

    if (SystemHandleCount == 1) {

        //
        // The last handle to this file object for all of the processes in the
        // system has just been closed, so invoke the driver's "cleanup" handler
        // for this file.  This is the file system's opportunity to remove any
        // share access information for the file, to indicate that if the file
        // is opened for a caching operation and this is the last file object
        // to the file, then it can do whatever it needs with memory management
        // to cleanup any information.
        //
        // Begin by getting the address of the target device object.
        //

        if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
            deviceObject = IoGetRelatedDeviceObject( fileObject );
        } else {
            deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
        }

        //
        // Ensure that the I/O system believes that this file has a handle
        // associated with it in case it doesn't actually get one from the
        // Object Manager.  This is done because sometimes the Object Manager
        // actually creates a handle, but the I/O system never finds out
        // about it so it attempts to send two cleanups for the same file.
        //

        fileObject->Flags |= FO_HANDLE_CREATED;

        //
        // If this file is open for synchronous I/O, wait until this thread
        // owns it exclusively since there may still be a thread using it.
        // This occurs when a system service owns the file because it owns
        // the semaphore, but the I/O completion code has already dereferenced
        // the file object itself.  Without waiting here for the same semaphore
        // there would be a race condition in the service who owns it now. The
        // service needs to be able to access the object w/o it going away after
        // its wait for the file event is satisfied.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

            BOOLEAN interrupted;

            if (!IopAcquireFastLock( fileObject )) {
                (VOID) IopAcquireFileObjectLock( fileObject,
                                                 KernelMode,
                                                 FALSE,
                                                 &interrupted );
            }
        }

        //
        // Initialize the local event that will be used to synchronize access
        // to the driver completing this I/O operation.
        //

        KeInitializeEvent( &event, SynchronizationEvent, FALSE );

        //
        // Reset the event in the file object.
        //

        KeClearEvent( &fileObject->Event );

        //
        // Allocate and initialize the I/O Request Packet (IRP) for this
        // operation.
        //

        irp = IopAllocateIrpMustSucceed( deviceObject->StackSize );
        irp->Tail.Overlay.OriginalFileObject = fileObject;
        irp->Tail.Overlay.Thread = PsGetCurrentThread();
        irp->RequestorMode = KernelMode;

        //
        // Fill in the service independent parameters in the IRP.
        //

        irp->UserEvent = &event;
        irp->UserIosb = &irp->IoStatus;
        irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
        irp->Flags = IRP_SYNCHRONOUS_API | IRP_CLOSE_OPERATION;

        //
        // Get a pointer to the stack location for the first driver.  This will
        // be used to pass the original function codes and parameters.  No
        // function-specific parameters are required for this operation.
        //

        irpSp = IoGetNextIrpStackLocation( irp );
        irpSp->MajorFunction = IRP_MJ_CLEANUP;
        irpSp->FileObject = fileObject;

        //
        // Insert the packet at the head of the IRP list for the thread.
        //

        IopQueueThreadIrp( irp );

        //
        // Update the operation count statistic for the current process for
        // operations other than read and write.
        //

        IopUpdateOtherOperationCount();

        //
        // Invoke the driver at its appropriate dispatch entry with the IRP.
        //

        status = IoCallDriver( deviceObject, irp );

        //
        // If no error was incurred, wait for the I/O operation to complete.
        //

        if (status == STATUS_PENDING) {
            (VOID) KeWaitForSingleObject( &event,
                                          UserRequest,
                                          KernelMode,
                                          FALSE,
                                          (PLARGE_INTEGER) NULL );
        }

        //
        // The following code tears down the IRP by hand since it may not
        // either be possible to it to be completed (because this code was
        // invoked as APC_LEVEL in the first place - or because the reference
        // count on the object cannot be incremented due to this routine
        // being invoked by the delete file procedure below).  Cleanup IRPs
        // therefore use close sematics (the close operation flag is set
        // in the IRP) so that the I/O complete request routine itself sets
        // the event to the Signaled state.
        //

        KeRaiseIrql( APC_LEVEL, &irql );
        IopDequeueThreadIrp( irp );
        KeLowerIrql( irql );

        //
        // Also, free the IRP.
        //

        IoFreeIrp( irp );

        //
        // If this operation was a synchronous I/O operation, release the
        // semaphore so that the file can be used by other threads.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
            IopReleaseFileObjectLock( fileObject );
        }
    }

    return;
}