535 lines
15 KiB
C
535 lines
15 KiB
C
|
/*******************************************************************************
|
||
|
* virtual.c
|
||
|
*
|
||
|
* Published Terminal Server Virtual Channel APIs
|
||
|
*
|
||
|
* Copyright 1998, Citrix Systems Inc.
|
||
|
* Copyright (C) 1997-1999 Microsoft Corp.
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <ntddkbd.h>
|
||
|
#include <ntddmou.h>
|
||
|
#include <windows.h>
|
||
|
#include <winbase.h>
|
||
|
#include <winerror.h>
|
||
|
|
||
|
#if(WINVER >= 0x0500)
|
||
|
#include <ntstatus.h>
|
||
|
#include <winsta.h>
|
||
|
#include <icadd.h>
|
||
|
#else
|
||
|
#include <citrix\cxstatus.h>
|
||
|
#include <citrix\winsta.h>
|
||
|
#include <citrix\icadd.h>
|
||
|
#endif
|
||
|
#include <utildll.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
#include <wtsapi32.h>
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Virtual Channel Name
|
||
|
*/
|
||
|
#define VIRTUALNAME_LENGTH 7
|
||
|
|
||
|
typedef CHAR VIRTUALNAME[ VIRTUALNAME_LENGTH + 1 ]; // includes null
|
||
|
typedef CHAR * PVIRTUALNAME;
|
||
|
|
||
|
|
||
|
|
||
|
// Handle structure used internally
|
||
|
typedef struct _VCHANDLE {
|
||
|
ULONG Signature;
|
||
|
HANDLE hServer;
|
||
|
DWORD SessionId;
|
||
|
HANDLE hChannel;
|
||
|
VIRTUALNAME VirtualName;
|
||
|
} VCHANDLE, *PVCHANDLE;
|
||
|
|
||
|
#define VCHANDLE_SIGNATURE ('V' | ('C' << 8) | ('H' << 16) | ('D' << 24))
|
||
|
#define ValidVCHandle(hVC) ((hVC) && ((hVC)->Signature == VCHANDLE_SIGNATURE))
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelOpen
|
||
|
*
|
||
|
* Open the specified virtual channel
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* hServer (input)
|
||
|
* Terminal Server handle (or WTS_CURRENT_SERVER)
|
||
|
* SessionId (input)
|
||
|
* Server Session Id (or WTS_CURRENT_SESSION)
|
||
|
* pVirtualName (input)
|
||
|
* Pointer to virtual channel name
|
||
|
*
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Handle to specified virtual channel (NULL on error)
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
HANDLE
|
||
|
WINAPI
|
||
|
WTSVirtualChannelOpen(
|
||
|
IN HANDLE hServer,
|
||
|
IN DWORD SessionId,
|
||
|
IN LPSTR pVirtualName /* ascii name */
|
||
|
)
|
||
|
{
|
||
|
PVCHANDLE pChannelHandle;
|
||
|
HANDLE hChannel;
|
||
|
|
||
|
if (hChannel = WinStationVirtualOpen( hServer, SessionId, pVirtualName)) {
|
||
|
|
||
|
// Allocate the Handle
|
||
|
if (!(pChannelHandle = (PVCHANDLE) LocalAlloc(LPTR,
|
||
|
sizeof(VCHANDLE)))) {
|
||
|
CloseHandle(hChannel);
|
||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
pChannelHandle->Signature = VCHANDLE_SIGNATURE;
|
||
|
pChannelHandle->hServer = hServer;
|
||
|
pChannelHandle->SessionId = SessionId;
|
||
|
pChannelHandle->hChannel = hChannel;
|
||
|
memcpy(pChannelHandle->VirtualName, pVirtualName, sizeof(VIRTUALNAME));
|
||
|
return((HANDLE)pChannelHandle);
|
||
|
}
|
||
|
return(NULL);
|
||
|
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelClose
|
||
|
*
|
||
|
* Close the specified virtual channel
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* hChannel (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful otherwise FALSE.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
WTSVirtualChannelClose(HANDLE hChannel)
|
||
|
{
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE) hChannel;
|
||
|
BOOL RetVal = FALSE;
|
||
|
|
||
|
if(!hChannel || IsBadReadPtr(hChannel,sizeof(HANDLE)))
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!ValidVCHandle(VCHandle)) {
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
goto BadParam;
|
||
|
}
|
||
|
|
||
|
if (CloseHandle(VCHandle->hChannel))
|
||
|
RetVal = TRUE;
|
||
|
|
||
|
VCHandle->Signature = 0;
|
||
|
LocalFree(VCHandle);
|
||
|
|
||
|
BadParam:
|
||
|
return(RetVal);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelWrite
|
||
|
*
|
||
|
* Write data to a virtual channel
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* ChannelHandle (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
* Buffer (input)
|
||
|
* Buffer containing data to write.
|
||
|
* Length (input)
|
||
|
* Length of data to write (bytes)
|
||
|
* pBytesWritten (output)
|
||
|
* Returns the amount of data written.
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful otherwise FALSE.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
WTSVirtualChannelWrite(HANDLE hChannel, PCHAR pBuffer, ULONG Length, PULONG pBytesWritten)
|
||
|
{
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE)hChannel;
|
||
|
OVERLAPPED Overlapped;
|
||
|
|
||
|
if (!ValidVCHandle(VCHandle)) {
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
Overlapped.hEvent = NULL;
|
||
|
Overlapped.Offset = 0;
|
||
|
Overlapped.OffsetHigh = 0;
|
||
|
|
||
|
if (!WriteFile(VCHandle->hChannel,
|
||
|
pBuffer,
|
||
|
Length,
|
||
|
pBytesWritten,
|
||
|
&Overlapped)) {
|
||
|
|
||
|
if (GetLastError() == ERROR_IO_PENDING)
|
||
|
// check on the results of the asynchronous write
|
||
|
return (GetOverlappedResult(VCHandle->hChannel,
|
||
|
&Overlapped,
|
||
|
pBytesWritten,
|
||
|
TRUE));
|
||
|
else
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelRead
|
||
|
*
|
||
|
* Read data from a virtual channel
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* ChannelHandle (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
* Timeout (input)
|
||
|
* The amount of time to wait for the read to complete.
|
||
|
* Buffer (input)
|
||
|
* Buffer which receive the data read.
|
||
|
* BufferLength (input)
|
||
|
* Length of the read buffer.
|
||
|
* pBytesRead (output)
|
||
|
* Returns the amount of data read.
|
||
|
*
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful otherwise FALSE.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
WTSVirtualChannelRead(HANDLE hChannel, ULONG Timeout, PCHAR pBuffer, ULONG BufferLength, PULONG pBytesRead)
|
||
|
{
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE)hChannel;
|
||
|
OVERLAPPED Overlapped;
|
||
|
|
||
|
if (!ValidVCHandle(VCHandle)) {
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
Overlapped.hEvent = NULL;
|
||
|
Overlapped.Offset = 0;
|
||
|
Overlapped.OffsetHigh = 0;
|
||
|
|
||
|
if (!ReadFile(VCHandle->hChannel,
|
||
|
pBuffer,
|
||
|
BufferLength,
|
||
|
pBytesRead,
|
||
|
&Overlapped)) {
|
||
|
if (GetLastError() == ERROR_IO_PENDING) {
|
||
|
if (!Timeout) {
|
||
|
// Read with no timeout - cancel IO and return success.
|
||
|
// This matches the behavior in WTS 1.7. This is required for
|
||
|
// Wyse firmware download software.
|
||
|
CancelIo(VCHandle->hChannel);
|
||
|
*pBytesRead = 0;
|
||
|
return(TRUE);
|
||
|
}
|
||
|
if (WaitForSingleObject(VCHandle->hChannel, Timeout) == WAIT_TIMEOUT) {
|
||
|
CancelIo(VCHandle->hChannel);
|
||
|
SetLastError(ERROR_IO_INCOMPLETE);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
// check on the results of the asynchronous read
|
||
|
return(GetOverlappedResult(VCHandle->hChannel,
|
||
|
&Overlapped,
|
||
|
pBytesRead,
|
||
|
FALSE));
|
||
|
} else {
|
||
|
return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* VirtualChannelIoctl
|
||
|
*
|
||
|
* Issues an Ioctl to a virtual channel. This routine was replicated from
|
||
|
* icaapi so that OEMs don't need to link with icaapi.dll.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* hChannelHandle (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
* IoctlCode (input)
|
||
|
* The type of ioctl to do.
|
||
|
* pInBuf (input)
|
||
|
* Input data required for the Ioctl.
|
||
|
* InBufLength (input)
|
||
|
* Length of input data.
|
||
|
*
|
||
|
* pOutBuf (output)
|
||
|
* Buffer to receive output data.
|
||
|
* OutBufLength (input)
|
||
|
* Length of the output buffer.
|
||
|
* pBytesReturned (output)
|
||
|
* Number of bytes returned in OutputBuffer.
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful, otherwise FALSE.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
VirtualChannelIoctl (HANDLE hChannel,
|
||
|
ULONG IoctlCode,
|
||
|
PCHAR pInBuf,
|
||
|
ULONG InBufLength,
|
||
|
PCHAR pOutBuf,
|
||
|
ULONG OutBufLength,
|
||
|
PULONG pBytesReturned)
|
||
|
{
|
||
|
IO_STATUS_BLOCK Iosb;
|
||
|
NTSTATUS Status;
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE)hChannel;
|
||
|
|
||
|
if (!ValidVCHandle(VCHandle)) {
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Issue ioctl
|
||
|
*/
|
||
|
Status = NtDeviceIoControlFile( VCHandle->hChannel,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&Iosb,
|
||
|
IoctlCode,
|
||
|
pInBuf,
|
||
|
InBufLength,
|
||
|
pOutBuf,
|
||
|
OutBufLength );
|
||
|
|
||
|
/*
|
||
|
* Wait for ioctl to complete
|
||
|
*/
|
||
|
if ( Status == STATUS_PENDING ) {
|
||
|
Status = NtWaitForSingleObject( VCHandle->hChannel, FALSE, NULL );
|
||
|
if ( NT_SUCCESS(Status))
|
||
|
Status = Iosb.Status;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Convert warning into error
|
||
|
*/
|
||
|
if ( Status == STATUS_BUFFER_OVERFLOW )
|
||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
|
||
|
/*
|
||
|
* Initialize bytes returned
|
||
|
*/
|
||
|
if ( pBytesReturned )
|
||
|
*pBytesReturned = (ULONG)Iosb.Information;
|
||
|
|
||
|
/* Return success/failure indication */
|
||
|
if (NT_SUCCESS(Status)) {
|
||
|
return(TRUE);
|
||
|
} else {
|
||
|
SetLastError(RtlNtStatusToDosError(Status));
|
||
|
return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelPurgeInput
|
||
|
*
|
||
|
* Purge all queued input data on a virtual channel.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* ChannelHandle (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
*
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful otherwise FALSE.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
WTSVirtualChannelPurgeInput(IN HANDLE hChannelHandle)
|
||
|
{
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE) hChannelHandle;
|
||
|
|
||
|
return(VirtualChannelIoctl(VCHandle,
|
||
|
IOCTL_ICA_VIRTUAL_CANCEL_INPUT,
|
||
|
(PCHAR) NULL,
|
||
|
0,
|
||
|
(PCHAR) NULL,
|
||
|
0,
|
||
|
(PULONG) NULL));
|
||
|
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelPurgeOutput
|
||
|
*
|
||
|
* Purge all queued output data on a virtual channel.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* ChannelHandle (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
*
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful otherwise FALSE.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
WTSVirtualChannelPurgeOutput(IN HANDLE hChannelHandle)
|
||
|
{
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE)hChannelHandle;
|
||
|
|
||
|
return(VirtualChannelIoctl(VCHandle,
|
||
|
IOCTL_ICA_VIRTUAL_CANCEL_OUTPUT,
|
||
|
(PCHAR) NULL,
|
||
|
0,
|
||
|
(PCHAR) NULL,
|
||
|
0,
|
||
|
(PULONG) NULL));
|
||
|
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* WTSVirtualChannelQuery
|
||
|
*
|
||
|
* Query data related to a virtual channel.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* hChannelHandle (input)
|
||
|
* Virtual Channel handle previously returned by WTSVirtualChannelOpen.
|
||
|
* VirtualClass (input)
|
||
|
* The type of information requested.
|
||
|
* ppBuffer (output)
|
||
|
* Pointer to a buffer pointer, which is allocated upon successful
|
||
|
* return.
|
||
|
* pBytesReturned (output)
|
||
|
* Pointer to a DWORD which is updated with the length of the data
|
||
|
* returned in the allocated buffer upon successful return.
|
||
|
* EXIT:
|
||
|
*
|
||
|
* Returns TRUE if successful otherwise FALSE.
|
||
|
* If successful, the caller is responsible for deallocating the
|
||
|
* buffer returned.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
WTSVirtualChannelQuery(IN HANDLE hChannelHandle,IN WTS_VIRTUAL_CLASS VirtualClass,
|
||
|
OUT PVOID *ppBuffer,OUT DWORD *pBytesReturned)
|
||
|
{
|
||
|
PVCHANDLE VCHandle = (PVCHANDLE) hChannelHandle;
|
||
|
PVOID DataBuffer;
|
||
|
DWORD DataBufferLen;
|
||
|
|
||
|
if (!hChannelHandle || IsBadReadPtr(hChannelHandle,sizeof(HANDLE)))
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
if (!ValidVCHandle(VCHandle)) {
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
if (!ppBuffer || IsBadWritePtr(ppBuffer, sizeof(PVOID)))
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
if (!pBytesReturned || IsBadWritePtr(pBytesReturned, sizeof(DWORD)))
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
switch (VirtualClass) {
|
||
|
case WTSVirtualFileHandle:
|
||
|
DataBuffer = LocalAlloc( LPTR, sizeof(HANDLE) );
|
||
|
if ( DataBuffer == NULL ) {
|
||
|
return(FALSE);
|
||
|
}
|
||
|
memcpy(DataBuffer, &VCHandle->hChannel, sizeof(HANDLE) );
|
||
|
*ppBuffer = DataBuffer;
|
||
|
*pBytesReturned = sizeof(HANDLE);
|
||
|
return(TRUE);
|
||
|
break;
|
||
|
case WTSVirtualClientData:
|
||
|
DataBufferLen = sizeof(VIRTUALNAME) + 1024;
|
||
|
for (;;) {
|
||
|
|
||
|
DataBuffer = LocalAlloc( LPTR, DataBufferLen );
|
||
|
if ( DataBuffer == NULL ) {
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
memcpy( DataBuffer,VCHandle->VirtualName,sizeof(VIRTUALNAME));
|
||
|
|
||
|
if (WinStationQueryInformationW( VCHandle->hServer,
|
||
|
VCHandle->SessionId,
|
||
|
WinStationVirtualData,
|
||
|
DataBuffer,
|
||
|
DataBufferLen,
|
||
|
&DataBufferLen)) {
|
||
|
*ppBuffer = DataBuffer;
|
||
|
*pBytesReturned = DataBufferLen;
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
|
||
|
(DataBufferLen < sizeof(VIRTUALNAME))) {
|
||
|
LocalFree(DataBuffer);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
LocalFree(DataBuffer);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|