555 lines
14 KiB
C
555 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
minirdr.c
|
|
|
|
Abstract:
|
|
|
|
This module implements minirdr registration functions.
|
|
|
|
Author:
|
|
|
|
Joe Linn (JoeLinn) 2-2-95
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RxRegisterMinirdr)
|
|
#pragma alloc_text(PAGE, RxMakeLateDeviceAvailable)
|
|
#pragma alloc_text(PAGE, RxpUnregisterMinirdr)
|
|
#endif
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (0)
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#endif
|
|
|
|
// #define BBT_UPDATE 1
|
|
|
|
#ifdef BBT_UPDATE
|
|
extern VOID RxUpdate(PVOID pContext);
|
|
|
|
HANDLE RxHandle = INVALID_HANDLE_VALUE;
|
|
PETHREAD RxPointer = NULL;
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RxRegisterMinirdr(
|
|
OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
|
|
IN OUT PDRIVER_OBJECT DriverObject,
|
|
IN PMINIRDR_DISPATCH MrdrDispatch,
|
|
IN ULONG Controls,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN ULONG DeviceExtensionSize,
|
|
IN DEVICE_TYPE DeviceType,
|
|
IN ULONG DeviceCharacteristics
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine adds the registration information to the minirdr registration table. As well, it builds
|
|
a device object; the MUP registration is at start time. Also, we fill in the deviceobject so that we are catching
|
|
all the calls.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - where the created device object is to be stored
|
|
ProtocolMarker - a 4byte marker denoting the FileLevel Protocol
|
|
('LCL ', 'SMB ', 'NCP ', and 'NFS ') are used
|
|
MrdrDispatch - the dispatch table for finding the server/netroot discovery routines
|
|
Context - whatever PVOID the underlying guy wants
|
|
MupAction - whether/how the MUP registration is done
|
|
DeviceName,DeviceExtensionSize,DeviceType,DeviceCharacteristics
|
|
- the params for the device object that is to be built these are adjusted a bit
|
|
bfore they're passed to Io
|
|
|
|
Return Value:
|
|
|
|
--
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PRDBSS_DEVICE_OBJECT RxDeviceObject;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), (" RxRegisterMinirdr Name = %wZ", DeviceName) );
|
|
|
|
if (DeviceObject == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Create the device object.
|
|
//
|
|
|
|
Status = IoCreateDevice( DriverObject,
|
|
sizeof(RDBSS_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT) + DeviceExtensionSize,
|
|
DeviceName,
|
|
DeviceType,
|
|
DeviceCharacteristics,
|
|
FALSE,
|
|
(PDEVICE_OBJECT *)(&RxDeviceObject));
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if (RxData.DriverObject == NULL) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// If the Mini-Redir is being built in a monolithic fashion, then the
|
|
// device object "RxFileSystemDeviceObject" would not have been created
|
|
// in the RxDriverEntry function. Hence we set RxDeviceObject->RDBSSDeviceObject
|
|
// to NULL. When the "monolithic" Mini-Redir gets unloaded, a check is done
|
|
// to see if RxDeviceObject->RDBSSDeviceObject is NULL. If it is not NULL,
|
|
// then the device object is dereferenced. This happens in the function
|
|
// RxUnregisterMinirdr.
|
|
//
|
|
// Don't allow myself to be unloaded.
|
|
//
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
RxDeviceObject->RDBSSDeviceObject = (PDEVICE_OBJECT)RxFileSystemDeviceObject;
|
|
ObReferenceObject( (PDEVICE_OBJECT)RxFileSystemDeviceObject );
|
|
|
|
//
|
|
// Reset the Unload routine. This prevents rdbss from being unloaded individually
|
|
//
|
|
|
|
RxData.DriverObject->DriverUnload = NULL;
|
|
#else
|
|
RxDeviceObject->RDBSSDeviceObject = NULL;
|
|
RxFileSystemDeviceObject->ReferenceCount += 1;
|
|
#endif
|
|
|
|
*DeviceObject = RxDeviceObject;
|
|
|
|
RxDeviceObject->RdbssExports = &RxExports;
|
|
RxDeviceObject->Dispatch = MrdrDispatch;
|
|
RxDeviceObject->RegistrationControls = Controls;
|
|
RxDeviceObject->DeviceName = *DeviceName;
|
|
RxDeviceObject->RegisterUncProvider =
|
|
!BooleanFlagOn( Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS );
|
|
RxDeviceObject->RegisterMailSlotProvider =
|
|
!BooleanFlagOn( Controls, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS );
|
|
|
|
{
|
|
LONG Index;
|
|
|
|
for (Index = 0; Index < MaximumWorkQueue; Index++) {
|
|
InitializeListHead( &RxDeviceObject->OverflowQueue[Index] );
|
|
}
|
|
}
|
|
|
|
KeInitializeSpinLock( &RxDeviceObject->OverflowQueueSpinLock );
|
|
|
|
RxDeviceObject->NetworkProviderPriority = RxGetNetworkProviderPriority( DeviceName );
|
|
RxLog(( "RegMini %x %wZ\n", RxDeviceObject->NetworkProviderPriority, DeviceName ));
|
|
RxWmiLog( LOG,
|
|
RxRegisterMinirdr,
|
|
LOGULONG( RxDeviceObject->NetworkProviderPriority )
|
|
LOGUSTR( *DeviceName ) );
|
|
|
|
ExAcquireFastMutexUnsafe( &RxData.MinirdrRegistrationMutex );
|
|
|
|
InsertTailList( &RxData.RegisteredMiniRdrs, &RxDeviceObject->MiniRdrListLinks );
|
|
|
|
//
|
|
// no need for interlock.....we're inside the mutex
|
|
//
|
|
|
|
RxData.NumberOfMinirdrsRegistered += 1;
|
|
|
|
ExReleaseFastMutexUnsafe(&RxData.MinirdrRegistrationMutex);
|
|
|
|
if (!FlagOn( Controls, RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH )) {
|
|
RxInitializeMinirdrDispatchTable( DriverObject );
|
|
}
|
|
|
|
if (!FlagOn( Controls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER )) {
|
|
|
|
//
|
|
// Initialize the netname table
|
|
//
|
|
|
|
RxDeviceObject->pRxNetNameTable = &RxDeviceObject->RxNetNameTableInDeviceObject;
|
|
RxInitializePrefixTable( RxDeviceObject->pRxNetNameTable, 0, FALSE );
|
|
RxDeviceObject->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
|
|
|
|
//
|
|
// Initialize the scavenger data structures
|
|
//
|
|
|
|
RxDeviceObject->pRdbssScavenger = &RxDeviceObject->RdbssScavengerInDeviceObject;
|
|
RxInitializeRdbssScavenger( RxDeviceObject->pRdbssScavenger );
|
|
}
|
|
|
|
RxDeviceObject->pAsynchronousRequestsCompletionEvent = NULL;
|
|
|
|
#ifdef BBT_UPDATE
|
|
if (RxHandle == INVALID_HANDLE_VALUE) {
|
|
NTSTATUS Status;
|
|
|
|
Status = PsCreateSystemThread( &RxHandle,
|
|
PROCESS_ALL_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
RxUpdate,
|
|
NULL );
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
Status = ObReferenceObjectByHandle( RxHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode,
|
|
&RxPointer,
|
|
NULL );
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxPointer = NULL;
|
|
}
|
|
|
|
ZwClose( RxHandle );
|
|
} else {
|
|
RxHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
RxMakeLateDeviceAvailable (
|
|
IN PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine diddles the device object to make a "late device" available.
|
|
A late device is one that is not created in the driver's load routine.
|
|
Non-late devices are diddled by the driverload code in the io subsystem; but
|
|
for late devices we have to do this by hand. This is a routine instead of a
|
|
macro in order that other stuff might have to be done here....it's only
|
|
executed once per device object.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - where the created device object is to be stored
|
|
|
|
Return Value:
|
|
|
|
--
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
ClearFlag( RxDeviceObject->Flags, DO_DEVICE_INITIALIZING );
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
RxpUnregisterMinirdr (
|
|
IN PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), (" RxUnregisterMinirdr Name = %wZ\n",&RxDeviceObject->DeviceName) );
|
|
|
|
ExAcquireFastMutexUnsafe( &RxData.MinirdrRegistrationMutex );
|
|
|
|
RemoveEntryList(&RxDeviceObject->MiniRdrListLinks);
|
|
|
|
//
|
|
// no need for interlock.....we're inside the mutex
|
|
//
|
|
|
|
RxData.NumberOfMinirdrsRegistered -= 1;
|
|
|
|
if (RxData.NumberOfMinirdrsRegistered == 0) {
|
|
|
|
//
|
|
// Allow rdbss being unloaded after mini rdr driver is unregistered
|
|
//
|
|
|
|
RxData.DriverObject->DriverUnload = RxUnload;
|
|
}
|
|
|
|
ExReleaseFastMutexUnsafe( &RxData.MinirdrRegistrationMutex );
|
|
|
|
if (!FlagOn( RxDeviceObject->RegistrationControls, RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER )) {
|
|
|
|
RxForceNetTableFinalization( RxDeviceObject );
|
|
RxFinalizePrefixTable( &RxDeviceObject->RxNetNameTableInDeviceObject );
|
|
|
|
//
|
|
// no finalization is defined for scavenger structure
|
|
//
|
|
}
|
|
|
|
RxSpinDownOutstandingAsynchronousRequests( RxDeviceObject );
|
|
|
|
//
|
|
// Spin down any worker threads associated with this minirdr
|
|
//
|
|
|
|
RxSpinDownMRxDispatcher( RxDeviceObject );
|
|
|
|
IoDeleteDevice( &RxDeviceObject->DeviceObject );
|
|
|
|
#ifdef BBT_UPDATE
|
|
if (RxPointer != NULL) {
|
|
|
|
RxHandle = INVALID_HANDLE_VALUE;
|
|
KeWaitForSingleObject( RxPointer, Executive, KernelMode, FALSE, NULL );
|
|
|
|
ASSERT( PsIsThreadTerminating( RxPointer ) );
|
|
ObDereferenceObject( RxPointer );
|
|
|
|
RxPointer = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
RxSpinDownOutstandingAsynchronousRequests (
|
|
PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine spins down all the outstanding requests associated with a
|
|
mini redirector before it can be unloaded
|
|
|
|
Arguments:
|
|
|
|
RxDeviceObject -- the mini redirector's device object
|
|
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN WaitForSpinDown = FALSE;
|
|
KEVENT SpinDownEvent;
|
|
|
|
KeInitializeEvent( &SpinDownEvent, NotificationEvent, FALSE );
|
|
|
|
RxAcquireSerializationMutex();
|
|
|
|
ASSERT( RxDeviceObject->pAsynchronousRequestsCompletionEvent == NULL );
|
|
|
|
WaitForSpinDown = (RxDeviceObject->AsynchronousRequestsPending != 0);
|
|
|
|
RxDeviceObject->pAsynchronousRequestsCompletionEvent = &SpinDownEvent;
|
|
|
|
RxReleaseSerializationMutex();
|
|
|
|
if (WaitForSpinDown) {
|
|
|
|
KeWaitForSingleObject( &SpinDownEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxRegisterAsynchronousRequest (
|
|
PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine registers an asynchronous request. On successful completion
|
|
the mini redirector cannot be unloaded till the request completes
|
|
|
|
Arguments:
|
|
|
|
RxDeviceObject - the mini redirector device object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
RxAcquireSerializationMutex();
|
|
|
|
if (RxDeviceObject->pAsynchronousRequestsCompletionEvent == NULL) {
|
|
RxDeviceObject->AsynchronousRequestsPending += 1;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
RxReleaseSerializationMutex();
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
RxDeregisterAsynchronousRequest (
|
|
PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine signals the completion of an asynchronous request. It resumes
|
|
unloading if required.
|
|
|
|
Arguments:
|
|
|
|
RxDeviceObject - the mini redirector device object
|
|
|
|
--*/
|
|
{
|
|
PKEVENT Event = NULL;
|
|
|
|
RxAcquireSerializationMutex();
|
|
|
|
RxDeviceObject->AsynchronousRequestsPending -= 1;
|
|
|
|
if ((RxDeviceObject->AsynchronousRequestsPending == 0) &&
|
|
(RxDeviceObject->pAsynchronousRequestsCompletionEvent != NULL)) {
|
|
|
|
Event = RxDeviceObject->pAsynchronousRequestsCompletionEvent;
|
|
}
|
|
|
|
RxReleaseSerializationMutex();
|
|
|
|
if (Event != NULL) {
|
|
|
|
KeSetEvent( Event, IO_NO_INCREMENT, FALSE );
|
|
}
|
|
}
|
|
|
|
#ifdef BBT_UPDATE
|
|
WCHAR Request_Name[] = L"\\??\\UNC\\landyw-bear\\bbt\\bbt.txt";
|
|
|
|
VOID
|
|
RxUpdate(PVOID pContext)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING RequestName;
|
|
|
|
RequestName.Buffer = Request_Name;
|
|
RequestName.MaximumLength = wcslen( Request_Name ) * sizeof( WCHAR );
|
|
RequestName.Length = RequestName.MaximumLength;
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&RequestName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
for (;;) {
|
|
PHYSICAL_ADDRESS StartAddress;
|
|
LARGE_INTEGER NumberOfBytes;
|
|
HANDLE FileHandle;
|
|
|
|
struct {
|
|
LIST_ENTRY Link;
|
|
SIZE_T Size;
|
|
CHAR Data[];
|
|
} *Request;
|
|
|
|
NumberOfBytes.QuadPart = 0x2;
|
|
StartAddress.QuadPart = 0;
|
|
|
|
MmAddPhysicalMemory(
|
|
&StartAddress,
|
|
&NumberOfBytes);
|
|
|
|
Request = (PVOID)(StartAddress.QuadPart);
|
|
|
|
if (Request != NULL) {
|
|
|
|
Status = ZwCreateFile( &FileHandle,
|
|
FILE_APPEND_DATA | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
FILE_NO_INTERMEDIATE_BUFFERING,
|
|
NULL,
|
|
0 );
|
|
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
LARGE_INTEGER ByteOffset;
|
|
|
|
ByteOffset.QuadPart = -1;
|
|
|
|
Status = ZwWriteFile( FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
Request->Data,
|
|
(ULONG)Request->Size,
|
|
&ByteOffset,
|
|
NULL );
|
|
|
|
Status = ZwClose( FileHandle );
|
|
}
|
|
|
|
ExFreePool( Request );
|
|
}
|
|
|
|
|
|
if (RxHandle == INVALID_HANDLE_VALUE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
PsTerminateSystemThread( STATUS_SUCCESS );
|
|
}
|
|
#endif
|
|
|