|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
unc.c
Abstract:
This file contains functions to support multiple UNC providers on a single NT machine.
Author:
Manny Weiser [MannyW] 20-Dec-1991
Revision History:
Isaac Heizer [IsaacHe] 16-Nov-1994 Defer loading the MUP Rewrite
Milan Shah [MilanS] 7-Mar-1996 Check for Dfs client status before loading the MUP
--*/
#include "fsrtlp.h"
#include <zwapi.h>
#include <ntddmup.h>
#include <ntddnull.h>
#define MupRegKey L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup"
#define UNCSymbolicLink L"\\DosDevices\\UNC"
#define DevNull L"\\Device\\Null"
#define DevMup DD_MUP_DEVICE_NAME
//
// Define a tag for general pool allocations from this module
//
#undef MODULE_POOL_TAG
#define MODULE_POOL_TAG ('nuSF')
//
// Local prototypes
//
NTSTATUS FsRtlpRegisterProviderWithMUP ( IN HANDLE mupHandle, IN PUNICODE_STRING RedirDevName, IN BOOLEAN MailslotsSupported );
NTSTATUS FsRtlpOpenDev( IN OUT PHANDLE Handle, IN LPWSTR DevNameStr );
VOID FsRtlpSetSymbolicLink( IN PUNICODE_STRING DevName OPTIONAL );
BOOLEAN FsRtlpIsDfsEnabled();
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FsRtlpRegisterProviderWithMUP)
#pragma alloc_text(PAGE, FsRtlpOpenDev)
#pragma alloc_text(PAGE, FsRtlpSetSymbolicLink)
#pragma alloc_text(PAGE, FsRtlRegisterUncProvider)
#pragma alloc_text(PAGE, FsRtlDeregisterUncProvider)
#pragma alloc_text(PAGE, FsRtlpIsDfsEnabled)
#endif
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
//
// We defer calling the MUP with the registration data until
// the second redir loads and Dfs is disabled. This structure holds the
// data necessary to make that call.
//
struct { HANDLE MupHandle; HANDLE ReturnedHandle; UNICODE_STRING RedirDevName; BOOLEAN MailslotsSupported; } FsRtlpDRD = {0};
//
// Number of times we've loaded redirs.
//
ULONG FsRtlpRedirs = 0; #ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif
//
// Resource protection
//
KSEMAPHORE FsRtlpUncSemaphore;
NTSTATUS FsRtlpRegisterProviderWithMUP ( IN HANDLE mupHandle, IN PUNICODE_STRING RedirDevName, IN BOOLEAN MailslotsSupported ) /*++
Routine Description:
This private routine does the FSCTL to the MUP to tell it about a new redir
Arguments:
mupHandle - Handle to the MUP
RedirDevName - The device name of the redir.
MailslotsSupported - If TRUE, this redir supports mailslots.
Return Value:
NTSTATUS - The status of the operation.
--*/ { NTSTATUS status; IO_STATUS_BLOCK ioStatusBlock; ULONG paramLength; PREDIRECTOR_REGISTRATION params;
PAGED_CODE();
paramLength = sizeof( REDIRECTOR_REGISTRATION ) + RedirDevName->Length;
params = ExAllocatePoolWithTag( NonPagedPool, paramLength, MODULE_POOL_TAG ); if( params == NULL ) return STATUS_INSUFFICIENT_RESOURCES;
params->DeviceNameOffset = sizeof( REDIRECTOR_REGISTRATION ); params->DeviceNameLength = RedirDevName->Length; params->MailslotsSupported = MailslotsSupported;
RtlCopyMemory( (PCHAR)params + params->DeviceNameOffset, RedirDevName->Buffer, RedirDevName->Length );
status = NtFsControlFile( mupHandle, 0, NULL, NULL, &ioStatusBlock, FSCTL_MUP_REGISTER_UNC_PROVIDER, params, paramLength, NULL, 0 );
if ( status == STATUS_PENDING ) { status = NtWaitForSingleObject( mupHandle, TRUE, NULL ); }
if ( NT_SUCCESS( status ) ) { status = ioStatusBlock.Status; }
ASSERT( NT_SUCCESS( status ) );
ExFreePool( params );
return status; }
NTSTATUS FsRtlpOpenDev( IN OUT PHANDLE Handle, IN LPWSTR DevNameStr ) { NTSTATUS status; UNICODE_STRING DevName; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock;
PAGED_CODE();
RtlInitUnicodeString( &DevName, DevNameStr );
InitializeObjectAttributes( &objectAttributes, &DevName, 0, 0, NULL );
status = ZwCreateFile( Handle, GENERIC_WRITE, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0 );
if ( NT_SUCCESS( status ) ) { status = ioStatusBlock.Status; }
if( !NT_SUCCESS( status ) ) { *Handle = (HANDLE)-1; }
return status; }
VOID FsRtlpSetSymbolicLink( IN PUNICODE_STRING DevName OPTIONAL ) { NTSTATUS status; UNICODE_STRING UncSymbolicName;
PAGED_CODE();
RtlInitUnicodeString( &UncSymbolicName, UNCSymbolicLink ); (VOID)IoDeleteSymbolicLink( &UncSymbolicName ); if( ARGUMENT_PRESENT( DevName ) ) { status = IoCreateSymbolicLink( &UncSymbolicName, DevName ); ASSERT( NT_SUCCESS( status ) ); } }
NTSTATUS FsRtlRegisterUncProvider( IN OUT PHANDLE MupHandle, IN PUNICODE_STRING RedirDevName, IN BOOLEAN MailslotsSupported ) /*++
Routine Description:
This routine registers a redir as a UNC provider.
Arguments:
Handle - Pointer to a handle. The handle is returned by the routine to be used when calling FsRtlDeregisterUncProvider. It is valid only if the routines returns STATUS_SUCCESS.
RedirDevName - The device name of the redir.
MailslotsSupported - If TRUE, this redir supports mailslots.
Return Value:
NTSTATUS - The status of the operation.
--*/ { NTSTATUS status; HANDLE mupHandle = (HANDLE)-1; UNICODE_STRING mupDriverName; BOOLEAN dfsEnabled;
PAGED_CODE();
KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL );
if (FsRtlpRedirs == 0) {
dfsEnabled = FsRtlpIsDfsEnabled();
if (dfsEnabled) { FsRtlpRedirs = 1; RtlZeroMemory((PVOID) &FsRtlpDRD, sizeof(FsRtlpDRD)); }
}
switch( FsRtlpRedirs ) { case 0: //
// Ok, the MUP isn't there and we don't need to use the
// MUP for the first redir.
//
// We need to return a handle, but we're not really using the MUP yet.
// And we may never use it (if there's only 1 redir). Return
// a handle to the NULL device object, since we're committed to returning
// a handle to our caller. Our caller isn't supposed to do anything with
// the handle except to call FsRtlDeregisterUncProvider() with it.
//
status = FsRtlpOpenDev( &mupHandle, DevNull );
if( !NT_SUCCESS( status ) ) break;
//
// Save up enough state to allow us to call the MUP later with
// this registration info if necessary.
//
FsRtlpDRD.RedirDevName.Buffer = ExAllocatePoolWithTag( NonPagedPool, RedirDevName->MaximumLength, MODULE_POOL_TAG );
if( FsRtlpDRD.RedirDevName.Buffer == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; break; }
FsRtlpDRD.RedirDevName.Length = RedirDevName->Length; FsRtlpDRD.RedirDevName.MaximumLength = RedirDevName->MaximumLength;
RtlCopyMemory( (PCHAR)FsRtlpDRD.RedirDevName.Buffer, RedirDevName->Buffer, RedirDevName->MaximumLength );
FsRtlpDRD.MailslotsSupported = MailslotsSupported; FsRtlpDRD.ReturnedHandle = mupHandle; FsRtlpDRD.MupHandle = (HANDLE)-1;
//
// Set the UNC symbolic link to point to the redir we just loaded
//
FsRtlpSetSymbolicLink( RedirDevName );
break;
default: //
// This is the second or later redir load -- MUST use the MUP
//
status = FsRtlpOpenDev( &mupHandle, DevMup );
if( !NT_SUCCESS( status ) ) {
RtlInitUnicodeString( &mupDriverName, MupRegKey );
(VOID)ZwLoadDriver( &mupDriverName );
status = FsRtlpOpenDev( &mupHandle, DevMup ); if( !NT_SUCCESS( status ) ) break; }
//
// See if we need to tell the MUP about the first redir that registered
//
if( FsRtlpDRD.RedirDevName.Buffer ) {
status = FsRtlpRegisterProviderWithMUP( mupHandle, &FsRtlpDRD.RedirDevName, FsRtlpDRD.MailslotsSupported );
if( !NT_SUCCESS( status ) ) break;
FsRtlpDRD.MupHandle = mupHandle;
ExFreePool( FsRtlpDRD.RedirDevName.Buffer ); FsRtlpDRD.RedirDevName.Buffer = NULL;
//
// Set the UNC symbolic link to point to the MUP
//
RtlInitUnicodeString( &mupDriverName, DevMup ); FsRtlpSetSymbolicLink( &mupDriverName );
status = FsRtlpOpenDev( &mupHandle, DevMup );
if( !NT_SUCCESS( status ) ) break; }
//
// Pass the request to the MUP for this redir
//
status = FsRtlpRegisterProviderWithMUP( mupHandle, RedirDevName, MailslotsSupported ); break;
}
if( NT_SUCCESS( status ) ) { FsRtlpRedirs++; *MupHandle = mupHandle;
} else { if( mupHandle != (HANDLE)-1 && mupHandle != NULL ) { ZwClose( mupHandle ); }
*MupHandle = (HANDLE)-1; }
KeReleaseSemaphore(&FsRtlpUncSemaphore, 0, 1, FALSE ); return status; }
VOID FsRtlDeregisterUncProvider( IN HANDLE Handle )
/*++
Routine Description:
This routine deregisters a redir as a UNC provider.
Arguments:
Handle - A handle to the Multiple UNC router, returned by the registration call.
Return Value:
None.
--*/
{ NTSTATUS status;
PAGED_CODE();
if( Handle == (HANDLE)-1 || Handle == NULL ) return;
status = ZwClose( Handle );
if( !NT_SUCCESS( status ) ) { return; }
KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL );
ASSERT( FsRtlpRedirs > 0 );
if( Handle == FsRtlpDRD.ReturnedHandle ) {
//
// The first redir in the system is closing. Release the state we saved
// for it, and pass the close on to the MUP if necessary
//
if( FsRtlpDRD.RedirDevName.Buffer != NULL ) { ExFreePool( FsRtlpDRD.RedirDevName.Buffer ); FsRtlpDRD.RedirDevName.Buffer = NULL; }
if( FsRtlpDRD.MupHandle != (HANDLE)-1 ) { ZwClose( FsRtlpDRD.MupHandle ); FsRtlpDRD.MupHandle = (HANDLE)-1; }
FsRtlpDRD.ReturnedHandle = (HANDLE)-1;
}
if( --FsRtlpRedirs == 0 ) { FsRtlpSetSymbolicLink( (PUNICODE_STRING)NULL ); }
KeReleaseSemaphore(&FsRtlpUncSemaphore, 0, 1, FALSE ); }
BOOLEAN FsRtlpIsDfsEnabled()
/*++
Routine Description:
This routine checks a registry key to see if the Dfs client is enabled. The client is assumed to be enabled by default, and disabled only if there is a registry value indicating that it should be disabled.
Arguments:
None
Return Value:
TRUE if Dfs client is enabled, FALSE otherwise.
--*/
{ NTSTATUS status; HANDLE mupRegHandle; OBJECT_ATTRIBUTES objectAttributes; ULONG valueSize; BOOLEAN dfsEnabled = TRUE;
UNICODE_STRING mupRegKey = { sizeof(MupRegKey) - sizeof(WCHAR), sizeof(MupRegKey), MupRegKey};
#define DISABLE_DFS_VALUE_NAME L"DisableDfs"
UNICODE_STRING disableDfs = { sizeof(DISABLE_DFS_VALUE_NAME) - sizeof(WCHAR), sizeof(DISABLE_DFS_VALUE_NAME), DISABLE_DFS_VALUE_NAME};
struct { KEY_VALUE_PARTIAL_INFORMATION Info; ULONG Buffer; } disableDfsValue;
InitializeObjectAttributes( &objectAttributes, &mupRegKey, OBJ_CASE_INSENSITIVE, 0, NULL );
status = ZwOpenKey(&mupRegHandle, KEY_READ, &objectAttributes);
if (NT_SUCCESS(status)) {
status = ZwQueryValueKey( mupRegHandle, &disableDfs, KeyValuePartialInformation, (PVOID) &disableDfsValue, sizeof(disableDfsValue), &valueSize);
if (NT_SUCCESS(status) && disableDfsValue.Info.Type == REG_DWORD) {
if ( (*((PULONG) disableDfsValue.Info.Data)) == 1 ) dfsEnabled = FALSE;
}
ZwClose( mupRegHandle );
}
return( dfsEnabled );
}
|