windows-nt/Source/XPSP1/NT/termsrv/drivers/termdd/ntload.c
2020-09-26 16:20:57 +08:00

346 lines
9.4 KiB
C

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
ntload.c
This module contains support for loading and unloading WD/PD/TD's as
standard NT drivers.
--*/
#include <precomp.h>
#pragma hdrstop
#if DBG
#define DBGPRINT(x) DbgPrint x
#else
#define DBGPRINT(x)
#endif
#define DEVICE_NAME_PREFIX L"\\Device\\"
#define SERVICE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
NTSTATUS
_IcaLoadSdWorker(
IN PDLLNAME SdName,
OUT PSDLOAD *ppSdLoad
)
/*++
Routine Description:
Replacement routine for Citrix _IcaLoadSdWorker that uses
standard NT driver loading.
Arguments:
SdName - Name of the stack driver to load
ppSdLoad - Pointer to return stack driver structure in.
Return Value:
NTSTATUS code.
Environment:
Kernel mode, DDK
--*/
{
PIRP Irp;
PKEVENT pEvent;
NTSTATUS Status;
PSDLOAD pSdLoad;
UNICODE_STRING DriverName;
UNICODE_STRING DeviceName;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
IO_STATUS_BLOCK Iosb;
PSD_MODULE_INIT pmi;
PIO_STACK_LOCATION IrpSp;
PWCHAR pDriverPath;
PWCHAR pDeviceName;
ULONG szDriverPath;
ULONG szDeviceName;
ASSERT( ExIsResourceAcquiredExclusiveLite( IcaSdLoadResource ) );
//
// Allocate a SDLOAD struct
//
pSdLoad = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pSdLoad) );
if ( pSdLoad == NULL )
return( STATUS_INSUFFICIENT_RESOURCES );
pEvent = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(KEVENT) );
if( pEvent == NULL ) {
ICA_FREE_POOL( pSdLoad );
return( STATUS_INSUFFICIENT_RESOURCES );
}
pmi = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(SD_MODULE_INIT) );
if( pmi == NULL ) {
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pSdLoad );
return( STATUS_INSUFFICIENT_RESOURCES );
}
szDeviceName = sizeof(DEVICE_NAME_PREFIX) + sizeof(pSdLoad->SdName) + sizeof(WCHAR);
pDeviceName = ICA_ALLOCATE_POOL( NonPagedPool, szDeviceName );
if( pDeviceName == NULL ) {
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pSdLoad );
return( STATUS_INSUFFICIENT_RESOURCES );
}
RtlZeroMemory( pmi, sizeof(*pmi) );
pSdLoad->RefCount = 1;
RtlCopyMemory( pSdLoad->SdName, SdName, sizeof( pSdLoad->SdName ) );
szDriverPath = sizeof(SERVICE_PATH) + sizeof(pSdLoad->SdName) + sizeof(WCHAR);
pDriverPath = ICA_ALLOCATE_POOL( NonPagedPool, szDriverPath );
if( pDriverPath == NULL ) {
ICA_FREE_POOL( pDeviceName );
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pSdLoad );
return( STATUS_INSUFFICIENT_RESOURCES );
}
wcscpy(pDriverPath, SERVICE_PATH);
wcscat(pDriverPath, pSdLoad->SdName);
RtlInitUnicodeString( &DriverName, pDriverPath );
wcscpy(pDeviceName, DEVICE_NAME_PREFIX);
wcscat(pDeviceName, pSdLoad->SdName);
pSdLoad->pUnloadWorkItem = NULL;
RtlInitUnicodeString( &DeviceName, pDeviceName );
KeInitializeEvent( pEvent, NotificationEvent, FALSE );
// Load the NT driver
Status = ZwLoadDriver( &DriverName );
if ( !NT_SUCCESS( Status ) && (Status != STATUS_IMAGE_ALREADY_LOADED)) {
DBGPRINT(("TermDD: ZwLoadDriver %wZ failed, 0x%x, 0x%x\n", &DriverName, Status, &DriverName ));
ICA_FREE_POOL( pDeviceName );
ICA_FREE_POOL( pDriverPath );
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pSdLoad );
return( Status );
}
//
// Now open the driver and get our stack driver pointers
//
Status = IoGetDeviceObjectPointer(
&DeviceName, // Device name is module name IE: \Device\TDTCP
GENERIC_ALL,
&FileObject,
&DeviceObject
);
if ( !NT_SUCCESS( Status ) ) {
DBGPRINT(( "TermDD: IoGetDeviceObjectPointer %wZ failed, 0x%x\n", &DeviceName, Status ));
ZwUnloadDriver( &DriverName );
ICA_FREE_POOL( pDeviceName );
ICA_FREE_POOL( pDriverPath );
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pSdLoad );
return( Status );
}
//
// Send the internal IOCTL_SD_MODULE_INIT to the device to
// get its stack interface pointers.
//
Irp = IoBuildDeviceIoControlRequest(
IOCTL_SD_MODULE_INIT,
DeviceObject,
NULL, // InputBuffer
0, // InputBufferLength
(PVOID)pmi, // OutputBuffer
sizeof(*pmi), // OutputBufferLength
TRUE, // Use IRP_MJ_INTERNAL_DEVICE_CONTROL
pEvent,
&Iosb
);
if( Irp == NULL ) {
ObDereferenceObject( FileObject );
ZwUnloadDriver( &DriverName );
ICA_FREE_POOL( pDeviceName );
ICA_FREE_POOL( pDriverPath );
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pSdLoad );
DBGPRINT(( "TermDD: Could not allocate IRP %S failed\n", SdName ));
return( Status );
}
ObReferenceObject( FileObject );
Irp->Tail.Overlay.OriginalFileObject = FileObject;
IrpSp = IoGetNextIrpStackLocation( Irp );
IrpSp->FileObject = FileObject;
Irp->Flags |= IRP_SYNCHRONOUS_API;
// Call the driver
Status = IoCallDriver( DeviceObject, Irp );
if( Status == STATUS_PENDING ) {
Status = KeWaitForSingleObject( pEvent, UserRequest, KernelMode, FALSE, NULL );
}
// Get the result from the actual I/O operation
if( Status == STATUS_SUCCESS ) {
Status = Iosb.Status;
}
if( NT_SUCCESS(Status) ) {
ASSERT( Iosb.Information == sizeof(*pmi) );
pSdLoad->DriverLoad = pmi->SdLoadProc;
pSdLoad->FileObject = FileObject;
pSdLoad->DeviceObject = DeviceObject;
InsertHeadList( &IcaSdLoadListHead, &pSdLoad->Links );
*ppSdLoad = pSdLoad;
}
else {
DBGPRINT(("TermDD: Error getting module pointers 0x%x\n",Status));
#if DBG
DbgBreakPoint();
#endif
ObDereferenceObject( FileObject );
ZwUnloadDriver( &DriverName );
ICA_FREE_POOL( pSdLoad );
ICA_FREE_POOL( pDeviceName );
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
ICA_FREE_POOL( pDriverPath );
return( Status );
}
// Cleanup
ICA_FREE_POOL( pDeviceName );
ICA_FREE_POOL( pDriverPath );
ICA_FREE_POOL( pmi );
ICA_FREE_POOL( pEvent );
return( Status );
}
NTSTATUS
_IcaUnloadSdWorker(
IN PSDLOAD pSdLoad
)
/*++
Replacement routine for Citrix _IcaUnloadSdWorker that uses
standard NT driver unloading.
Arguments:
SdName - Name of the stack driver to load
ppSdLoad - Pointer to return stack driver structure in.
Environment:
Kernel mode, DDK
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING DriverName;
WCHAR DriverPath[sizeof(SERVICE_PATH) +
sizeof(pSdLoad->SdName) +
sizeof(WCHAR)];
PSDLOAD pSdLoadInList;
PLIST_ENTRY Head, Next;
/*
* free the workitem
*/
ASSERT(pSdLoad->pUnloadWorkItem != NULL);
ICA_FREE_POOL(pSdLoad->pUnloadWorkItem);
pSdLoad->pUnloadWorkItem = NULL;
wcscpy(DriverPath, SERVICE_PATH);
wcscat(DriverPath, pSdLoad->SdName);
RtlInitUnicodeString(&DriverName, DriverPath);
/*
* Lock the ICA Resource exclusively to search the SdLoad list.
* Note when holding a resource we need to prevent APC calls, so
* use KeEnterCriticalRegion().
*/
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite( IcaSdLoadResource, TRUE );
/*
* Look for the requested SD. If found, and refcount is still 0, then
* unload it. If refcount is not zero then someone has referenced it since
* we have posted the workitem and we do not want to unload it anymore.
*
*/
Head = &IcaSdLoadListHead;
for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
pSdLoadInList = CONTAINING_RECORD( Next, SDLOAD, Links );
if ( !wcscmp( pSdLoad->SdName, pSdLoadInList->SdName ) ) {
ASSERT(pSdLoad == pSdLoadInList);
if (--pSdLoad->RefCount != 0) {
break;
}
/*
* We found the driver and Refcount is Zero let unload it
*/
Status = ZwUnloadDriver(&DriverName);
if (Status != STATUS_INVALID_DEVICE_REQUEST) {
RemoveEntryList(&pSdLoad->Links);
ObDereferenceObject (pSdLoad->FileObject);
ICA_FREE_POOL(pSdLoad);
}
else {
// If the driver unloading fails because of invalid request,
// we keep this pSdLoad around. It will get cleaned up
// either unload succeeds or the driver exits.
// TODO: termdd currently not cleanup all the memory it allocates
// It does not have unload correctly implemented. So, we didn't put
// cleanup for this in the unload function. That needs to be looked
// at it once unload function is hooked up.
DBGPRINT(("TermDD: ZwUnLoadDriver %wZ failed, 0x%x, 0x%x\n", &DriverName, Status, &DriverName ));
}
break;
}
}
/*
* We should always find the driver in the list
*/
ASSERT(Next != Head);
ExReleaseResourceLite( IcaSdLoadResource);
KeLeaveCriticalRegion();
return Status;
}