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.
562 lines
15 KiB
562 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
rdpdrpnp.c
|
|
|
|
Abstract:
|
|
|
|
This module includes routines for handling PnP and IO manager related IRP's
|
|
for RDP device redirection.
|
|
|
|
Don't forget to clean up the device object and the symbol link when
|
|
our driver is unloaded.
|
|
|
|
We should probably not expose a Win32 symbolic link. This might be a
|
|
security issue ... If this is the case, then I will have to do a better
|
|
job of researching overlapped I/O with NtCreateFile vs. CreateFile.
|
|
|
|
Need a check in IRP_MJ_CREATE to make sure that we are not being opened
|
|
2x by the same session. This shouldn't be allowed.
|
|
|
|
We may need to completely lock out access to the IRP queue on a cancel
|
|
request.
|
|
|
|
Where can I safely use PAGEDPOOL instead of NONPAGEDPOOL.
|
|
|
|
Make sure that we handle opens and all subsequent IRP's from bogus
|
|
user-mode apps.
|
|
|
|
Author:
|
|
|
|
tadb
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#define TRC_FILE "rdpdrpnp"
|
|
#include "trc.h"
|
|
|
|
#define DRIVER
|
|
|
|
#include "cfg.h"
|
|
#include "pnp.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local Prototypes
|
|
//
|
|
|
|
// This routine is called when the lower level driver completes an IRP.
|
|
NTSTATUS RDPDR_DeferIrpCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
// Adjust the dacl on the rdpdyn device object
|
|
NTSTATUS AdjustSecurityDescriptor(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
IN ULONG SecurityDescriptorLength);
|
|
|
|
//
|
|
// Externals. We cannot include ob.h or ntosp.h
|
|
// as it causes tons of conflicts.
|
|
//
|
|
|
|
extern "C" {
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlDeleteAce (
|
|
PACL Acl,
|
|
ULONG AceIndex
|
|
);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// Unique Port Name Counter defined in rdpdyn.c.
|
|
extern ULONG LastPortNumberUsed;
|
|
|
|
// The Physical Device Object that terminates our DO stack.
|
|
extern PDEVICE_OBJECT RDPDYN_PDO;
|
|
|
|
// Global Registry Path for RDPDR.SYS. This global is defined in rdpdr.c.
|
|
extern UNICODE_STRING DrRegistryPath;
|
|
|
|
// Global Dr admin SD and sd length
|
|
extern PSECURITY_DESCRIPTOR DrAdminSecurityDescriptor;
|
|
extern ULONG DrSecurityDescriptorLength;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// External Prototypes
|
|
//
|
|
|
|
// Just shove the typedefs in for the Power Management functions now because I can't
|
|
// get the header conflicts resolved.
|
|
NTKERNELAPI VOID PoStartNextPowerIrp(IN PIRP Irp);
|
|
NTKERNELAPI NTSTATUS PoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal Prototypes
|
|
//
|
|
|
|
NTSTATUS RDPDRPNP_HandleStartDeviceIRP(
|
|
PDEVICE_OBJECT StackDeviceObject,
|
|
PIO_STACK_LOCATION IoStackLocation,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles PnP Start Device IRP's.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for the class device.
|
|
|
|
Irp - Irp.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the operation.
|
|
|
|
--*/
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS ntStatus;
|
|
|
|
BEGIN_FN("RDPDRPNP_HandleStartDeviceIRP");
|
|
|
|
// Initialize this module.
|
|
ntStatus = RDPDYN_Initialize();
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
//
|
|
// Set up the IO completion routine because the lower level
|
|
// driver needs to handle this IRP before we can continue.
|
|
//
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,RDPDR_DeferIrpCompletion,&event,TRUE,TRUE,TRUE);
|
|
ntStatus = IoCallDriver(StackDeviceObject,Irp);
|
|
if (ntStatus == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL);
|
|
ntStatus = Irp->IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
// Finish the IRP.
|
|
Irp->IoStatus.Status = ntStatus;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS RDPDRPNP_HandleRemoveDeviceIRP(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
PDEVICE_OBJECT StackDeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles PnP Remove Device IRP's.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for the class device.
|
|
|
|
Irp - Irp.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
UNICODE_STRING symbolicLink;
|
|
|
|
BEGIN_FN("RDPDRPNP_HandleRemoveDeviceIRP");
|
|
|
|
//
|
|
// Remove the Win32 symbolic link name.
|
|
//
|
|
RtlInitUnicodeString(&symbolicLink, RDPDRDVMGR_W32DEVICE_PATH_U);
|
|
|
|
// Delete the existing link ... if it exists.
|
|
#if DBG
|
|
ntStatus = IoDeleteSymbolicLink(&symbolicLink);
|
|
if (ntStatus != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "IoDeleteSymbolicLink failed: %08X", ntStatus));
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "IoDeleteSymbolicLink succeeded"));
|
|
}
|
|
#else
|
|
IoDeleteSymbolicLink(&symbolicLink);
|
|
#endif
|
|
|
|
//
|
|
// Call the lower level driver.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
ntStatus = IoCallDriver(StackDeviceObject,Irp);
|
|
|
|
//
|
|
// Detach the FDO from the DO stack.
|
|
//
|
|
IoDetachDevice(StackDeviceObject);
|
|
|
|
//
|
|
// The device is now about to be deleted4 ... we might need to perform
|
|
// some cleanup for the device here before we remove it.
|
|
//
|
|
|
|
//
|
|
// Release the FDO.
|
|
//
|
|
IoDeleteDevice(DeviceObject);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS RDPDRPNP_PnPAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine should only be called one time to create the "dr"'s FDO
|
|
that sits on top of the PDO for the sole purpose of registering new
|
|
device interfaces.
|
|
|
|
This function is called by PnP to make the "dr" the function driver
|
|
for a root dev node that was created on install.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object for this instance of USBPRINT
|
|
|
|
PhysicalDeviceObject - pointer to a device object created by the bus
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_OBJECT fdo = NULL;
|
|
PRDPDYNDEVICE_EXTENSION deviceExtension;
|
|
UNICODE_STRING deviceName;
|
|
UNICODE_STRING symbolicLink;
|
|
|
|
BEGIN_FN("RDPDRPNP_PnPAddDevice");
|
|
|
|
// Initialize the device name.
|
|
RtlInitUnicodeString(&deviceName, RDPDRDVMGR_DEVICE_PATH_U);
|
|
|
|
//
|
|
// Create our FDO.
|
|
//
|
|
ntStatus = IoCreateDevice(DriverObject, sizeof(RDPDYNDEVICE_EXTENSION),
|
|
&deviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
//
|
|
// Adjust the default security descriptor on our device object
|
|
//
|
|
TRC_ASSERT(DrAdminSecurityDescriptor != NULL,
|
|
(TB, "DrAdminSecurityDescriptor != NULL"));
|
|
|
|
ntStatus = AdjustSecurityDescriptor(fdo, DrAdminSecurityDescriptor, DrSecurityDescriptorLength);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
TRC_ERR((TB, "AdjustSecurityDescriptor failed: %08X",
|
|
ntStatus));
|
|
IoDeleteDevice(fdo);
|
|
goto cleanup;
|
|
}
|
|
|
|
// We support buffered IO.
|
|
fdo->Flags |= DO_BUFFERED_IO;
|
|
|
|
//
|
|
// Add the Win32 symbolic link name.
|
|
//
|
|
RtlInitUnicodeString(&symbolicLink, RDPDRDVMGR_W32DEVICE_PATH_U);
|
|
|
|
// Delete the existing link ... in case it exists.
|
|
IoDeleteSymbolicLink(&symbolicLink);
|
|
|
|
// Create the new link.
|
|
ntStatus = IoCreateSymbolicLink(&symbolicLink, &deviceName);
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
TRC_ERR((TB, "IoCreateSymbolicLink failed: %08X",
|
|
ntStatus));
|
|
IoDeleteDevice(fdo);
|
|
}
|
|
else {
|
|
//
|
|
// Get the device extension.
|
|
//
|
|
deviceExtension = (PRDPDYNDEVICE_EXTENSION)(fdo->DeviceExtension);
|
|
|
|
//
|
|
// Attach to the PDO after recording the current top of the DO stack.
|
|
//
|
|
|
|
deviceExtension->TopOfStackDeviceObject=IoAttachDeviceToDeviceStack(
|
|
fdo,
|
|
PhysicalDeviceObject
|
|
);
|
|
if (deviceExtension->TopOfStackDeviceObject == NULL)
|
|
{
|
|
TRC_ERR((TB, "IoAttachDeviceToDeviceStack failed"));
|
|
IoDeleteDevice(fdo);
|
|
}
|
|
else
|
|
{
|
|
// Record the PDO to a global.
|
|
RDPDYN_PDO = PhysicalDeviceObject;
|
|
|
|
// We are done initializing our device.
|
|
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
}
|
|
}
|
|
|
|
} // end if creation of FDO succeeded.
|
|
|
|
cleanup:
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AdjustSecurityDescriptor(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
IN ULONG SecurityDescriptorLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Use the given security descriptor to give system-only access on the given device object
|
|
|
|
Arguments:
|
|
Device Object - Pointer to the device object to be modified
|
|
SecurityDescriptor - Pointer to a valid SECURITY_DESCRIPTOR structure
|
|
SecurityDescriptorLength - Length of the SecurityDescriptor
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - success/error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
BEGIN_FN("AdjustSecurityDescriptor");
|
|
//
|
|
// We set only the Dacl from the SD
|
|
//
|
|
SECURITY_INFORMATION SecurityInformation = DACL_SECURITY_INFORMATION;
|
|
NTSTATUS status;
|
|
|
|
|
|
PACE_HEADER AceHeader = NULL;
|
|
PSID AceSid;
|
|
PACL Dacl = NULL;
|
|
BOOLEAN DaclDefaulted;
|
|
BOOLEAN DaclPresent;
|
|
DWORD i;
|
|
PACL NewDacl = NULL;
|
|
SECURITY_DESCRIPTOR NewSD;
|
|
|
|
if (DeviceObject == NULL ||
|
|
SecurityDescriptor == NULL ||
|
|
SecurityDescriptorLength == 0) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Validate the security descriptor
|
|
//
|
|
if (SeValidSecurityDescriptor(SecurityDescriptorLength, SecurityDescriptor)) {
|
|
//
|
|
// Obtain the Dacl from the security descriptor
|
|
//
|
|
status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
|
|
&DaclPresent,
|
|
&Dacl,
|
|
&DaclDefaulted);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
TRC_ERR((TB, "RDPDRPNP:RtlGetDaclSecurityDescriptor failed: %08X",
|
|
status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
TRC_ASSERT(DaclPresent != FALSE,
|
|
(TB, "RDPDRPNP:Dacl not present"));
|
|
|
|
//
|
|
// Make a copy of the Dacl so that we can modify it.
|
|
//
|
|
|
|
NewDacl = (PACL)ExAllocatePoolWithTag(PagedPool, Dacl->AclSize, DR_POOLTAG);
|
|
|
|
if (NULL == NewDacl) {
|
|
status = STATUS_NO_MEMORY;
|
|
TRC_ERR((TB, "RDPDRPNP:Can't allocate memory for new dacl: %08X",
|
|
status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
RtlCopyMemory(NewDacl, Dacl, Dacl->AclSize);
|
|
|
|
//
|
|
// Loop through the DACL, removing any access allowed
|
|
// entries that aren't for SYSTEM
|
|
//
|
|
|
|
for (i = 0; i < NewDacl->AceCount; i++) {
|
|
//
|
|
// Get each ACE.
|
|
//
|
|
status = RtlGetAce(NewDacl, i, (PVOID*)&AceHeader);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if (ACCESS_ALLOWED_ACE_TYPE == AceHeader->AceType) {
|
|
|
|
AceSid = (PSID) &((ACCESS_ALLOWED_ACE*)AceHeader)->SidStart;
|
|
|
|
//
|
|
// Check if this is system sid.
|
|
//
|
|
if (!RtlEqualSid(AceSid, SeExports->SeLocalSystemSid)) {
|
|
//
|
|
// Not a system sid. Delete ace.
|
|
//
|
|
status = RtlDeleteAce(NewDacl, i);
|
|
if (NT_SUCCESS(status)) {
|
|
i -= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TRC_ASSERT(NewDacl->AceCount > 0,
|
|
(TB, "RDPDRPNP:AceCount is 0 in the new dacl"));
|
|
|
|
//
|
|
// Create a new security descriptor to hold the new Dacl.
|
|
//
|
|
|
|
status = RtlCreateSecurityDescriptor(&NewSD, SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
TRC_ERR((TB, "RDPDRPNP:RtlCreateSecurityDescriptor failed: %08X",
|
|
status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Place the new Dacl into the new SD
|
|
//
|
|
|
|
status = RtlSetDaclSecurityDescriptor(&NewSD, TRUE, NewDacl, FALSE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
TRC_ERR((TB, "RDPDRPNP:RtlSetDaclSecurityDescriptor failed: %08X",
|
|
status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the new SD into our device object.
|
|
//
|
|
status = ObSetSecurityObjectByPointer(
|
|
DeviceObject,
|
|
SecurityInformation,
|
|
&NewSD
|
|
);
|
|
}
|
|
else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
TRC_ERR((TB, "RDPDRPNP: Invalid security descriptor",
|
|
status));
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if (NULL != NewDacl) {
|
|
ExFreePool(NewDacl);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RDPDR_DeferIrpCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the lower level driver completes an IRP. It
|
|
simply sets an event to true, which allows the blocked thread to finish
|
|
whatever processing was pending.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for the class device.
|
|
|
|
Irp - Irp completed.
|
|
|
|
Context - Driver defined context.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the operation.
|
|
|
|
--*/
|
|
{
|
|
PKEVENT event = (PKEVENT)Context;
|
|
|
|
BEGIN_FN("RDPDR_DeferIrpCompletion");
|
|
|
|
KeSetEvent(event,
|
|
1,
|
|
FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|