mirror of
https://github.com/reactos/reactos.git
synced 2024-12-31 19:42:51 +00:00
[FSRTL]
Rewrite FsRtlRegisterUncProvider() and FsRtlDeregisterUncProvider() so that they can support MUP in case it's required They also support DFS svn path=/trunk/; revision=68759
This commit is contained in:
parent
05244f7905
commit
4c1d3954cd
1 changed files with 349 additions and 62 deletions
|
@ -3,7 +3,7 @@
|
|||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/fsrtl/unc.c
|
||||
* PURPOSE: Manages UNC support routines for file system drivers.
|
||||
* PROGRAMMERS: None.
|
||||
* PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
@ -12,11 +12,182 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define TAG_UNC 'nuSF'
|
||||
|
||||
KSEMAPHORE FsRtlpUncSemaphore;
|
||||
|
||||
ULONG FsRtlpRedirs = 0;
|
||||
|
||||
struct
|
||||
{
|
||||
HANDLE MupHandle;
|
||||
HANDLE NullHandle;
|
||||
UNICODE_STRING RedirectorDeviceName;
|
||||
BOOLEAN MailslotsSupported;
|
||||
} FsRtlpDRD;
|
||||
|
||||
BOOLEAN
|
||||
FsRtlpIsDfsEnabled(VOID)
|
||||
{
|
||||
HANDLE Key;
|
||||
ULONG Length;
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING KeyName;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
struct
|
||||
{
|
||||
KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
|
||||
ULONG KeyValue;
|
||||
} KeyQueryOutput;
|
||||
|
||||
/* You recognize MuppIsDfsEnabled()! Congratz :-) */
|
||||
KeyName.Buffer = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
|
||||
KeyName.Length = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL);
|
||||
KeyName.MaximumLength = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
|
||||
|
||||
/* Simply query registry to get whether DFS is disabled.
|
||||
* If DFS isn't disabled from registry side, assume it is enabled
|
||||
* and go through MUP.
|
||||
* MUP itself might disable it, but that's not our concern
|
||||
* any longer
|
||||
*/
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
KeyName.Buffer = L"DisableDfs";
|
||||
KeyName.Length = sizeof(L"DisableDfs") - sizeof(UNICODE_NULL);
|
||||
KeyName.MaximumLength = sizeof(L"DisableDfs");
|
||||
|
||||
Status = ZwQueryValueKey(Key, &KeyName, KeyValuePartialInformation, &KeyQueryOutput, sizeof(KeyQueryOutput), &Length);
|
||||
ZwClose(Key);
|
||||
if (!NT_SUCCESS(Status) || KeyQueryOutput.KeyInfo.Type != REG_DWORD)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return ((ULONG)KeyQueryOutput.KeyInfo.Data != 1);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FsRtlpOpenDev(OUT PHANDLE DeviceHandle,
|
||||
IN PCWSTR DeviceName)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING StrDeviceName;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Just open the device and return the obtained handle */
|
||||
RtlInitUnicodeString(&StrDeviceName, DeviceName);
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&StrDeviceName,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateFile(DeviceHandle,
|
||||
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))
|
||||
{
|
||||
*DeviceHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FsRtlpSetSymbolicLink(IN PUNICODE_STRING DeviceName)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING UncDevice;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Delete the old link, and set the new one if we have a name */
|
||||
RtlInitUnicodeString(&UncDevice, L"\\DosDevices\\UNC");
|
||||
IoDeleteSymbolicLink(&UncDevice);
|
||||
if (DeviceName != NULL)
|
||||
{
|
||||
Status = IoCreateSymbolicLink(&UncDevice, DeviceName);
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FsRtlpRegisterProviderWithMUP(IN HANDLE MupHandle,
|
||||
IN PUNICODE_STRING RedirectorDeviceName,
|
||||
IN BOOLEAN MailslotsSupported)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG BufferSize;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
PMUP_PROVIDER_REGISTRATION_INFO RegistrationInfo;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT1("FsRtlpRegisterProviderWithMUP(%p, %wZ, %u)\n", (PVOID)MupHandle, RedirectorDeviceName, MailslotsSupported);
|
||||
|
||||
/* We have to be able to store the name and the registration information */
|
||||
BufferSize = RedirectorDeviceName->Length + sizeof(MUP_PROVIDER_REGISTRATION_INFO);
|
||||
RegistrationInfo = ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG_UNC);
|
||||
if (RegistrationInfo == NULL)
|
||||
{
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* Set the information about the provider (including its name) */
|
||||
RegistrationInfo->RedirectorDeviceNameOffset = sizeof(MUP_PROVIDER_REGISTRATION_INFO);
|
||||
RegistrationInfo->RedirectorDeviceNameLength = RedirectorDeviceName->Length;
|
||||
RegistrationInfo->MailslotsSupported = MailslotsSupported;
|
||||
RtlCopyMemory((PWSTR)((ULONG_PTR)RegistrationInfo + RegistrationInfo->RedirectorDeviceNameOffset),
|
||||
RedirectorDeviceName->Buffer, RedirectorDeviceName->Length);
|
||||
|
||||
/* Call MUP with the registration FSCTL */
|
||||
Status = NtFsControlFile(MupHandle, NULL, NULL, NULL,
|
||||
&IoStatusBlock, FSCTL_MUP_REGISTER_PROVIDER,
|
||||
RegistrationInfo, BufferSize, NULL, 0);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
Status = NtWaitForSingleObject(MupHandle, TRUE, NULL);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
/* And we're done! */
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
ExFreePoolWithTag(RegistrationInfo, TAG_UNC);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*++
|
||||
* @name FsRtlDeregisterUncProvider
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -32,23 +203,63 @@ VOID
|
|||
NTAPI
|
||||
FsRtlDeregisterUncProvider(IN HANDLE Handle)
|
||||
{
|
||||
UNICODE_STRING DosDevicesUNC = RTL_CONSTANT_STRING(L"\\DosDevices\\UNC");
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT("FsRtlDeregisterUncProvider: Handle=%p\n", Handle);
|
||||
//
|
||||
// Normal implementation should look like:
|
||||
// - notify mup.sys?
|
||||
// - at last deregistration, destroy \DosDevices\UNC symbolic link
|
||||
//
|
||||
/* We won't work on invalid input */
|
||||
if (Handle == INVALID_HANDLE_VALUE || Handle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ZwClose(Handle);
|
||||
KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
IoDeleteSymbolicLink(&DosDevicesUNC);
|
||||
/* Sanity check: we need to have providers */
|
||||
ASSERT(FsRtlpRedirs > 0);
|
||||
|
||||
/* At that point, we had only one provider at a time */
|
||||
if (Handle == (HANDLE)FsRtlpDRD.NullHandle)
|
||||
{
|
||||
/* Free its name if possible (it might have been overtaken in case of
|
||||
* registration of other UNC provider */
|
||||
if (FsRtlpDRD.RedirectorDeviceName.Buffer != NULL)
|
||||
{
|
||||
ExFreePoolWithTag(FsRtlpDRD.RedirectorDeviceName.Buffer, TAG_UNC);
|
||||
FsRtlpDRD.RedirectorDeviceName.Buffer = NULL;
|
||||
}
|
||||
|
||||
/* Close the handle to MUP */
|
||||
if (FsRtlpDRD.MupHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ZwClose(FsRtlpDRD.MupHandle);
|
||||
FsRtlpDRD.MupHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* Last handle isn't required anymore */
|
||||
FsRtlpDRD.NullHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* One less provider */
|
||||
--FsRtlpRedirs;
|
||||
|
||||
/* In case we reach no provider anylonger, reset the symbolic link */
|
||||
if (FsRtlpRedirs == 0)
|
||||
{
|
||||
FsRtlpSetSymbolicLink(NULL);
|
||||
}
|
||||
|
||||
KeReleaseSemaphore(&FsRtlpUncSemaphore, IO_NO_INCREMENT, 1, FALSE);
|
||||
|
||||
/* Final note:
|
||||
* NULL device handle and 'normal' MUP device handle are not closed by
|
||||
* FsRtl. It's up to the user to close them afterwards.
|
||||
* If the handle is leaked, MUP will never be notified about the
|
||||
* unregistration.
|
||||
*/
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name FsRtlRegisterUncProvider
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -59,6 +270,7 @@ FsRtlDeregisterUncProvider(IN HANDLE Handle)
|
|||
* FILLME
|
||||
*
|
||||
* @param MailslotsSupported
|
||||
* FILLME
|
||||
*
|
||||
* @return None
|
||||
*
|
||||
|
@ -67,68 +279,143 @@ FsRtlDeregisterUncProvider(IN HANDLE Handle)
|
|||
*--*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
FsRtlRegisterUncProvider(IN OUT PHANDLE Handle,
|
||||
FsRtlRegisterUncProvider(OUT PHANDLE Handle,
|
||||
IN PUNICODE_STRING RedirectorDeviceName,
|
||||
IN BOOLEAN MailslotsSupported)
|
||||
{
|
||||
UNICODE_STRING DevNull = RTL_CONSTANT_STRING(L"\\Device\\Null");
|
||||
UNICODE_STRING DosDevicesUNC = RTL_CONSTANT_STRING(L"\\DosDevices\\UNC");
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
HANDLE FileHandle;
|
||||
NTSTATUS Status;
|
||||
HANDLE DeviceHandle;
|
||||
UNICODE_STRING MupString;
|
||||
|
||||
DPRINT("FsRtlRegisterUncProvider: Redirector=%wZ MailslotsSupported=%d\n",
|
||||
RedirectorDeviceName, MailslotsSupported);
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Current implementation is a hack, as it only supports one UNC provider.
|
||||
// However, it doesn't require to have a functional mup.sys driver.
|
||||
//
|
||||
DPRINT1("FsRtlRegisterUncProvider(%p, %wZ, %u)\n", Handle, RedirectorDeviceName, MailslotsSupported);
|
||||
|
||||
//
|
||||
// Normal implementation should look like:
|
||||
// - at registration 1, creates symlink \DosDevices\UNC to new provider;
|
||||
// returns handle to \Device\Null
|
||||
// - at registration 2, load mup.sys, register both providers to mup.sys
|
||||
// and change \DosDevices\UNC to DD_MUP_DEVICE_NAME;
|
||||
// returns handle to new provider
|
||||
// - at next registrations, register provider to mup.sys;
|
||||
// returns handle to new provider
|
||||
//
|
||||
KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
*Handle = (HANDLE)-1;
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&DevNull,
|
||||
OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateFile(&FileHandle,
|
||||
GENERIC_WRITE,
|
||||
&ObjectAttributes,
|
||||
&Iosb,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
/* In case no provider was registered yet, check for DFS present.
|
||||
* If DFS is present, we need to go with MUP, whatever the case
|
||||
*/
|
||||
if (FsRtlpRedirs == 0)
|
||||
{
|
||||
DPRINT("Failed to open %wZ\n", &DevNull);
|
||||
return Status;
|
||||
if (FsRtlpIsDfsEnabled())
|
||||
{
|
||||
DPRINT1("DFS is not disabled. Going through MUP\n");
|
||||
|
||||
/* We've to go with MUP, make sure our internal structure doesn't
|
||||
* contain any leftover data and raise redirs to one, to make sure
|
||||
* we use MUP.
|
||||
*/
|
||||
RtlZeroMemory(&FsRtlpDRD, sizeof(FsRtlpDRD));
|
||||
FsRtlpRedirs = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Status = IoCreateSymbolicLink(&DosDevicesUNC, RedirectorDeviceName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
/* In case no UNC provider was already registered,
|
||||
* We'll proceed without MUP and directly redirect
|
||||
* UNC to the provider.
|
||||
*/
|
||||
if (FsRtlpRedirs == 0)
|
||||
{
|
||||
DPRINT("Failed to create symbolic link %wZ -> %wZ\n", &DosDevicesUNC, RedirectorDeviceName);
|
||||
DPRINT1("FIXME: multiple unc provider registered?\n");
|
||||
ZwClose(FileHandle);
|
||||
return Status;
|
||||
/* As we don't provide MUP, just give a handle to NULL device */
|
||||
Status = FsRtlpOpenDev(&DeviceHandle, L"\\Device\\Null");
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Allocate a buffer big enough to keep a local copy of UNC provider device */
|
||||
FsRtlpDRD.RedirectorDeviceName.Buffer = ExAllocatePoolWithTag(NonPagedPool, RedirectorDeviceName->MaximumLength, TAG_UNC);
|
||||
if (FsRtlpDRD.RedirectorDeviceName.Buffer == NULL)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
FsRtlpDRD.RedirectorDeviceName.Length = RedirectorDeviceName->Length;
|
||||
FsRtlpDRD.RedirectorDeviceName.MaximumLength = RedirectorDeviceName->MaximumLength;
|
||||
RtlCopyMemory(FsRtlpDRD.RedirectorDeviceName.Buffer, RedirectorDeviceName->Buffer, RedirectorDeviceName->MaximumLength);
|
||||
|
||||
/* We don't have MUP, and copy provider information */
|
||||
FsRtlpDRD.MupHandle = INVALID_HANDLE_VALUE;
|
||||
FsRtlpDRD.MailslotsSupported = MailslotsSupported;
|
||||
FsRtlpDRD.NullHandle = DeviceHandle;
|
||||
|
||||
/* Set DOS device UNC to use provider device */
|
||||
FsRtlpSetSymbolicLink(RedirectorDeviceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We (will) have several providers, MUP is required */
|
||||
Status = FsRtlpOpenDev(&DeviceHandle, L"\\Device\\Mup");
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Opening MUP may have failed because the driver was not loaded, so load it and retry */
|
||||
RtlInitUnicodeString(&MupString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
|
||||
ZwLoadDriver(&MupString);
|
||||
Status = FsRtlpOpenDev(&DeviceHandle, L"\\Device\\Mup");
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case we had a single provider till now, we have to forward the old provider to MUP
|
||||
* And then, register the new one to MUP as well
|
||||
*/
|
||||
if (FsRtlpDRD.RedirectorDeviceName.Buffer != NULL)
|
||||
{
|
||||
/* We will only continue if we can register previous provider in MUP */
|
||||
Status = FsRtlpRegisterProviderWithMUP(DeviceHandle, &FsRtlpDRD.RedirectorDeviceName, FsRtlpDRD.MailslotsSupported);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Save our Mup handle for later usage */
|
||||
FsRtlpDRD.MupHandle = DeviceHandle;
|
||||
|
||||
/* Release information about previous provider */
|
||||
ExFreePoolWithTag(FsRtlpDRD.RedirectorDeviceName.Buffer, TAG_UNC);
|
||||
FsRtlpDRD.RedirectorDeviceName.Buffer = NULL;
|
||||
|
||||
/* Re-open MUP to have a handle to give back to the user */
|
||||
Status = FsRtlpOpenDev(&DeviceHandle, L"\\Device\\Mup");
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Redirect UNC DOS device to MUP */
|
||||
RtlInitUnicodeString(&MupString, L"\\Device\\Mup");
|
||||
FsRtlpSetSymbolicLink(&MupString);
|
||||
|
||||
/* Register new provider */
|
||||
Status = FsRtlpRegisterProviderWithMUP(DeviceHandle, RedirectorDeviceName, MailslotsSupported);
|
||||
}
|
||||
|
||||
*Handle = FileHandle;
|
||||
return STATUS_SUCCESS;
|
||||
Cleanup:
|
||||
|
||||
/* In case of success, increment number of providers and return handle
|
||||
* to the device pointed by UNC DOS device
|
||||
*/
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
++FsRtlpRedirs;
|
||||
*Handle = DeviceHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cleanup in case of failure */
|
||||
if (DeviceHandle != INVALID_HANDLE_VALUE && DeviceHandle != 0)
|
||||
{
|
||||
ZwClose(DeviceHandle);
|
||||
}
|
||||
|
||||
*Handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
KeReleaseSemaphore(&FsRtlpUncSemaphore, IO_NO_INCREMENT, 1, FALSE);
|
||||
return Status;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue