windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/infocomm/spuddrv/miscsvc.c
2020-09-26 16:20:57 +08:00

649 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
miscsvc.c
Abstract:
This module contains miscellaneous SPUD services.
Author:
Keith Moore (keithmo) 09-Feb-1998
Revision History:
--*/
#include "spudp.h"
//
// Private prototypes.
//
NTSTATUS
SpudpOpenSelfHandle(
OUT PHANDLE SelfHandle
);
NTSTATUS
SpudpCloseSelfHandle(
IN HANDLE SelfHandle
);
NTSTATUS
SpudpInitCompletionPort(
IN HANDLE CompletionPort
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SPUDInitialize )
#pragma alloc_text( PAGE, SPUDTerminate )
#pragma alloc_text( PAGE, SPUDCancel )
#pragma alloc_text( PAGE, SPUDGetCounts )
#pragma alloc_text( PAGE, SpudpOpenSelfHandle )
#pragma alloc_text( PAGE, SpudpCloseSelfHandle )
#endif
#if 0
NOT PAGEABLE -- SpudpInitCompletionPort
#endif
//
// Public functions.
//
NTSTATUS
SPUDInitialize(
ULONG Version,
HANDLE hPort
)
/*++
Routine Description:
Performs per-process SPUD initialization.
Arguments:
Version - The SPUD interface version the user-mode client is expecting.
hPort - The handle to the user-mode code's I/O completion port.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
HANDLE selfHandle;
//
// Sanity check.
//
PAGED_CODE();
status = SPUD_ENTER_SERVICE( "SPUDInitialize", FALSE );
if( !NT_SUCCESS(status) ) {
return status;
}
//
// Setup locals so we know how to cleanup on exit.
//
selfHandle = NULL;
//
// SPUD doesn't support kernel-mode callers. In fact, we don't
// even build the "system stubs" necessary to invoke SPUD from
// kernel-mode.
//
ASSERT( ExGetPreviousMode() == UserMode );
//
// Ensure we got the SPUD interface version number we're expecting.
//
if( Version != SPUD_VERSION ) {
status = STATUS_INVALID_PARAMETER;
}
//
// Open an exclusive handle to ourselves.
//
if( NT_SUCCESS(status) ) {
status = SpudpOpenSelfHandle( &selfHandle );
}
//
// Reference the I/O completion port handle so we can use the
// pointer directly in KeInsertQueue().
//
if( NT_SUCCESS(status) ) {
status = SpudpInitCompletionPort( hPort );
}
//
// Remember that we're initialized.
//
if( NT_SUCCESS(status) ) {
SpudSelfHandle = selfHandle;
} else {
//
// Fatal error, cleanup our self handle if we managed to
// open it.
//
if( selfHandle != NULL ) {
SpudpCloseSelfHandle( selfHandle );
}
}
SPUD_LEAVE_SERVICE( "SPUDInitialize", status, FALSE );
return status;
} // SPUDInitialize
NTSTATUS
SPUDTerminate(
VOID
)
/*++
Routine Description:
Performs per-process SPUD termination.
Arguments:
None.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
//
// Sanity check.
//
PAGED_CODE();
status = SPUD_ENTER_SERVICE( "SPUDTerminate", TRUE );
if( !NT_SUCCESS(status) ) {
return status;
}
//
// SPUD doesn't support kernel-mode callers. In fact, we don't
// even build the "system stubs" necessary to invoke SPUD from
// kernel-mode.
//
ASSERT( ExGetPreviousMode() == UserMode );
//
// Close the handle we opened to ourself. The IRP_MJ_CLOSE handler
// will dereference the completion port and reset the global variables.
//
ASSERT( SpudSelfHandle != NULL );
SpudpCloseSelfHandle( SpudSelfHandle );
SpudSelfHandle = NULL;
ASSERT( status == STATUS_SUCCESS );
SPUD_LEAVE_SERVICE( "SPUDTerminate", status, FALSE );
return status;
} // SPUDTerminate
NTSTATUS
SPUDCancel(
IN PSPUD_REQ_CONTEXT reqContext
)
/*++
Routine Description:
Cancels an outstanding XxxAndRecv() request.
Arguments:
reqContext - The user-mode context associated with the I/O request.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
PSPUD_AFD_REQ_CONTEXT SpudReqContext;
PIRP irp;
//
// Sanity check.
//
PAGED_CODE();
status = SPUD_ENTER_SERVICE( "SPUDCancel", TRUE );
if( !NT_SUCCESS(status) ) {
return status;
}
//
// SPUD doesn't support kernel-mode callers. In fact, we don't
// even build the "system stubs" necessary to invoke SPUD from
// kernel-mode.
//
ASSERT( ExGetPreviousMode() == UserMode );
try {
//
// Make sure we can write to reqContext
//
ProbeForRead(
reqContext,
sizeof(SPUD_REQ_CONTEXT),
sizeof(ULONG)
);
} except(EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
//
// Get the kernel-mode context from the user-mode context.
//
if( NT_SUCCESS(status) ) {
SpudReqContext = SpudGetRequestContext( reqContext );
if( SpudReqContext == NULL ) {
status = STATUS_INVALID_PARAMETER;
}
}
//
// Snag the IRP from the context & cancel the request.
//
if( NT_SUCCESS(status) ) {
irp = SpudReqContext->Irp;
if (irp) {
IoCancelIrp(irp);
}
}
SPUD_LEAVE_SERVICE( "SPUDCancel", status, FALSE );
return status;
} // SPUDCancel
NTSTATUS
SPUDGetCounts(
PSPUD_COUNTERS UserCounters
)
/*++
Routine Description:
Retrieves the SPUD activity counters.
Arguments:
UserCounters - Receives the counters.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
//
// Sanity check.
//
PAGED_CODE();
//
// N.B. We do not perform the usual driver initialization and
// exclusivity checks here. We *want* SPUDGetCounts to be callable
// by processes other than the server.
//
//
// SPUD doesn't support kernel-mode callers. In fact, we don't
// even build the "system stubs" necessary to invoke SPUD from
// kernel-mode.
//
ASSERT( ExGetPreviousMode() == UserMode );
try {
//
// The SpudCounters parameter must be writable.
//
ProbeForWrite( UserCounters, sizeof(*UserCounters), sizeof(ULONG) );
//
// Copy the counters to the user-mode buffer.
//
RtlCopyMemory(
UserCounters,
&SpudCounters,
sizeof(SpudCounters)
);
status = STATUS_SUCCESS;
} except( EXCEPTION_EXECUTE_HANDLER ) {
status = GetExceptionCode();
}
return status;
} // SPUDGetCounts
//
// Private prototypes.
//
NTSTATUS
SpudpOpenSelfHandle(
OUT PHANDLE SelfHandle
)
/*++
Routine Description:
Opens a handle to \Device\Spud and marks it so that it cannot be
closed.
Arguments:
SelfHandle - Pointer to a variable that receives the handle.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
HANDLE selfHandle;
UNICODE_STRING deviceName;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
//
// Sanity check.
//
PAGED_CODE();
//
// Open an exclusive handle to ourselves.
//
RtlInitUnicodeString(
&deviceName,
SPUD_DEVICE_NAME
);
InitializeObjectAttributes(
&objectAttributes, // ObjectAttributes
&deviceName, // ObjectName
OBJ_CASE_INSENSITIVE, // Attributes
NULL, // RootDirectory
NULL // SecurityDescriptor
);
status = IoCreateFile(
&selfHandle, // FileHandle
GENERIC_READ // DesiredAccess
| SYNCHRONIZE //
| FILE_READ_ATTRIBUTES, //
&objectAttributes, // ObjectAttributes
&ioStatusBlock, // IoStatusBlock
NULL, // AllocationSize
0L, // FileAttributes
0L, // ShareAccess
FILE_OPEN, // Disposition
0L, // CreateOptions
NULL, // EaBuffer
0, // EaLength
CreateFileTypeNone, // CreateFileType
NULL, // ExtraCreateParameters
IO_NO_PARAMETER_CHECKING // Options
);
if( !NT_SUCCESS(status) ) {
return status;
}
//
// Mark the handle so that those pesky user-mode applications
// can't close it. While we're at it, make the handle not
// inheritable.
//
handleInfo.ProtectFromClose = TRUE;
handleInfo.Inherit = FALSE;
status = ZwSetInformationObject(
selfHandle, // Handle
ObjectHandleFlagInformation, // ObjectInformationClass
&handleInfo, // ObjectInformation
sizeof(handleInfo) // ObjectInformationLength
);
//
// If all went well, then return the handle to the caller. Otherwise,
// carefully close the handle (avoiding an exception if the user-mode
// code has already closed it).
//
if( NT_SUCCESS(status) ) {
*SelfHandle = selfHandle;
} else {
if( selfHandle != NULL ) {
try {
NtClose( selfHandle );
} except( EXCEPTION_EXECUTE_HANDLER ) {
NOTHING;
}
}
}
return status;
} // SpudpOpenSelfHandle
NTSTATUS
SpudpCloseSelfHandle(
IN HANDLE SelfHandle
)
/*++
Routine Description:
Closes the handle opened by SpudpOpenSelfHandle().
Arguments:
SelfHandle - The handle to close.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
//
// Sanity check.
//
PAGED_CODE();
//
// Mark the handle so that we can close it.
//
handleInfo.ProtectFromClose = FALSE;
handleInfo.Inherit = FALSE;
status = ZwSetInformationObject(
SelfHandle, // Handle
ObjectHandleFlagInformation, // ObjectInformationClass
&handleInfo, // ObjectInformation
sizeof(handleInfo) // ObjectInformationLength
);
//
// Carefully close the handle, even if the above APIs failed.
//
try {
status = NtClose( SelfHandle );
} except( EXCEPTION_EXECUTE_HANDLER ) {
status = GetExceptionCode();
}
return status;
} // SpudpCloseSelfHandle
NTSTATUS
SpudpInitCompletionPort(
IN HANDLE CompletionPort
)
/*++
Routine Description:
References the specified completion port and sets our local reference
count.
N.B. This is a separate routine so that SPUDInitialize() can be pageable.
Arguments:
CompletionPort - The completion port handle.
Return Value:
NTSTATUS - Completion status.
--*/
{
NTSTATUS status;
KIRQL oldIrql;
PVOID completionPort;
//
// Reference the I/O completion port handle so we can use the
// pointer directly in KeInsertQueue().
//
status = ObReferenceObjectByHandle(
CompletionPort, // Handle
IO_COMPLETION_MODIFY_STATE, // DesiredAccess
NULL, // ObjectType
UserMode, // AccessMode
&completionPort, // Object
NULL // HandleInformation
);
//
// Remember that we're initialized.
//
if( NT_SUCCESS(status) ) {
TRACE_OB_REFERENCE( completionPort );
KeAcquireSpinLock(
&SpudCompletionPortLock,
&oldIrql
);
ASSERT( SpudCompletionPort == NULL );
ASSERT( SpudCompletionPortRefCount == 0 );
SpudCompletionPort = completionPort;
SpudCompletionPortRefCount = 1;
KeReleaseSpinLock(
&SpudCompletionPortLock,
oldIrql
);
}
return status;
} // SpudpInitCompletionPort