You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
572 lines
14 KiB
572 lines
14 KiB
/*++
|
|
|
|
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 );
|
|
|
|
}
|