/*++ 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