557 lines
12 KiB
C
557 lines
12 KiB
C
/*++
|
||
|
||
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>
|
||
|
||
static WCHAR MupRegKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
|
||
static WCHAR UNCSymbolicLink[] = L"\\DosDevices\\UNC";
|
||
static WCHAR DevNull[] = L"\\Device\\Null";
|
||
static WCHAR DevMup[] = DD_MUP_DEVICE_NAME;
|
||
|
||
//
|
||
// 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, FsRtlDeregisterUncProvider)
|
||
#pragma alloc_text(PAGE, FsRtlRegisterUncProvider)
|
||
#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};
|
||
|
||
//
|
||
// Resource protection
|
||
//
|
||
KSEMAPHORE FsRtlpUncSemaphore;
|
||
|
||
//
|
||
// Number of times we've loaded redirs.
|
||
//
|
||
ULONG FsRtlpRedirs = 0;
|
||
|
||
|
||
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 = ExAllocatePool( NonPagedPool, paramLength );
|
||
if( params == NULL )
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
params->DeviceNameOffset = sizeof( REDIRECTOR_REGISTRATION );
|
||
params->DeviceNameLength = RedirDevName->Length;
|
||
params->MailslotsSupported = MailslotsSupported;
|
||
|
||
RtlMoveMemory(
|
||
(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 =
|
||
ExAllocatePool( NonPagedPool, RedirDevName->MaximumLength );
|
||
|
||
if( FsRtlpDRD.RedirDevName.Buffer == NULL ) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
FsRtlpDRD.RedirDevName.Length = RedirDevName->Length;
|
||
FsRtlpDRD.RedirDevName.MaximumLength = RedirDevName->MaximumLength;
|
||
|
||
RtlMoveMemory(
|
||
(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 );
|
||
|
||
}
|