NTSTATUS FsRtlRegisterUncProvider( __inout 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; }
/*++ * @name FsRtlRegisterUncProvider * @implemented * * FILLME * * @param Handle * FILLME * * @param RedirectorDeviceName * FILLME * * @param MailslotsSupported * FILLME * * @return None * * @remarks None * *--*/ NTSTATUS NTAPI FsRtlRegisterUncProvider(OUT PHANDLE Handle, IN PCUNICODE_STRING RedirectorDeviceName, IN BOOLEAN MailslotsSupported) { NTSTATUS Status; HANDLE DeviceHandle; UNICODE_STRING MupString; PAGED_CODE(); DPRINT1("FsRtlRegisterUncProvider(%p, %wZ, %u)\n", Handle, RedirectorDeviceName, MailslotsSupported); KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL); /* 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) { 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; } } /* In case no UNC provider was already registered, * We'll proceed without MUP and directly redirect * UNC to the provider. */ if (FsRtlpRedirs == 0) { /* 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); } 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; }