Leaked source code of windows server 2003
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

/*++
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;
}