/******************************************************************************* * virtual.c * * Published Terminal Server Virtual Channel APIs * * Copyright 1998, Citrix Systems Inc. * Copyright (C) 1997-1999 Microsoft Corp. ******************************************************************************/ #include #include #include #include #include #include #include #include #if(WINVER >= 0x0500) #include #include #include #else #include #include #include #endif #include #include #include #include /* * 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); } }