Blame winpr/libwinpr/wtsapi/wtsapi_win32.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Windows Terminal Services API
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/io.h>
Packit 1fb8d4
#include <winpr/nt.h>
Packit 1fb8d4
#include <winpr/library.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/wtsapi.h>
Packit 1fb8d4
Packit 1fb8d4
#include "wtsapi_win32.h"
Packit 1fb8d4
Packit 1fb8d4
#include "../log.h"
Packit 1fb8d4
Packit Service 5a9772
#define WTSAPI_CHANNEL_MAGIC 0x44484356
Packit 1fb8d4
#define TAG WINPR_TAG("wtsapi")
Packit 1fb8d4
Packit 1fb8d4
struct _WTSAPI_CHANNEL
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 magic;
Packit 1fb8d4
	HANDLE hServer;
Packit 1fb8d4
	DWORD SessionId;
Packit 1fb8d4
	HANDLE hFile;
Packit 1fb8d4
	HANDLE hEvent;
Packit 1fb8d4
	char* VirtualName;
Packit 1fb8d4
Packit 1fb8d4
	DWORD flags;
Packit 1fb8d4
	BYTE* chunk;
Packit 1fb8d4
	BOOL dynamic;
Packit 1fb8d4
	BOOL readSync;
Packit 1fb8d4
	BOOL readAsync;
Packit 1fb8d4
	BOOL readDone;
Packit 1fb8d4
	UINT32 readSize;
Packit 1fb8d4
	UINT32 readOffset;
Packit 1fb8d4
	BYTE* readBuffer;
Packit 1fb8d4
	BOOL showProtocol;
Packit 1fb8d4
	BOOL waitObjectMode;
Packit 1fb8d4
	OVERLAPPED overlapped;
Packit 1fb8d4
	CHANNEL_PDU_HEADER* header;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _WTSAPI_CHANNEL WTSAPI_CHANNEL;
Packit 1fb8d4
Packit 1fb8d4
static BOOL g_Initialized = FALSE;
Packit 1fb8d4
static HMODULE g_WinStaModule = NULL;
Packit 1fb8d4
Packit Service 5a9772
typedef HANDLE(WINAPI* fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId,
Packit Service 5a9772
                                                LPSTR pVirtualName);
Packit Service 5a9772
typedef HANDLE(WINAPI* fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId,
Packit Service 5a9772
                                                  LPSTR pVirtualName, DWORD flags);
Packit 1fb8d4
Packit 1fb8d4
static fnWinStationVirtualOpen pfnWinStationVirtualOpen = NULL;
Packit 1fb8d4
static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = NULL;
Packit 1fb8d4
Packit 1fb8d4
BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel);
Packit 1fb8d4
Packit 1fb8d4
/**
Packit Service 5a9772
 * NOTE !!
Packit Service 5a9772
 * An application using the WinPR wtsapi frees memory via WTSFreeMemory, which
Packit Service 5a9772
 * might be mapped to Win32_WTSFreeMemory. Latter does not know if the passed
Packit Service 5a9772
 * pointer was allocated by a function in wtsapi32.dll or in some internal
Packit Service 5a9772
 * code below. The WTSFreeMemory implementation in all Windows wtsapi32.dll
Packit Service 5a9772
 * versions up to Windows 10 uses LocalFree since all its allocating functions
Packit Service 5a9772
 * use LocalAlloc() internally.
Packit Service 5a9772
 * For that reason we also have to use LocalAlloc() for any memory returned by
Packit Service 5a9772
 * our WinPR wtsapi functions.
Packit Service 5a9772
 *
Packit Service 5a9772
 * To be safe we only use the _wts_malloc, _wts_calloc, _wts_free wrappers
Packit Service 5a9772
 * for memory managment the code below.
Packit Service 5a9772
 */
Packit Service 5a9772
Packit Service 5a9772
static void* _wts_malloc(size_t size)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _UWP
Packit 1fb8d4
	return malloc(size);
Packit 1fb8d4
#else
Packit 1fb8d4
	return (PVOID)LocalAlloc(LMEM_FIXED, size);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void* _wts_calloc(size_t nmemb, size_t size)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _UWP
Packit 1fb8d4
	return calloc(nmemb, size);
Packit 1fb8d4
#else
Packit 1fb8d4
	return (PVOID)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, nmemb * size);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void _wts_free(void* ptr)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _UWP
Packit 1fb8d4
	free(ptr);
Packit 1fb8d4
#else
Packit 1fb8d4
	LocalFree((HLOCAL)ptr);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL Win32_WTSVirtualChannelReadAsync(WTSAPI_CHANNEL* pChannel)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status = TRUE;
Packit 1fb8d4
	DWORD numBytes = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (pChannel->readAsync)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	ZeroMemory(&(pChannel->overlapped), sizeof(OVERLAPPED));
Packit 1fb8d4
	pChannel->overlapped.hEvent = pChannel->hEvent;
Packit 1fb8d4
	ResetEvent(pChannel->hEvent);
Packit 1fb8d4
Packit 1fb8d4
	if (pChannel->showProtocol)
Packit 1fb8d4
	{
Packit 1fb8d4
		ZeroMemory(pChannel->header, sizeof(CHANNEL_PDU_HEADER));
Packit 1fb8d4
Packit Service 5a9772
		status = ReadFile(pChannel->hFile, pChannel->header, sizeof(CHANNEL_PDU_HEADER), &numBytes,
Packit Service 5a9772
		                  &(pChannel->overlapped));
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		status = ReadFile(pChannel->hFile, pChannel->chunk, CHANNEL_CHUNK_LENGTH, &numBytes,
Packit Service 5a9772
		                  &(pChannel->overlapped));
Packit 1fb8d4
Packit 1fb8d4
		if (status)
Packit 1fb8d4
		{
Packit 1fb8d4
			pChannel->readOffset = 0;
Packit 1fb8d4
			pChannel->header->length = numBytes;
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readDone = TRUE;
Packit 1fb8d4
			SetEvent(pChannel->hEvent);
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Unexpected ReadFile status: %" PRId32 " numBytes: %" PRIu32 "", status,
Packit Service 5a9772
		         numBytes);
Packit 1fb8d4
		return FALSE; /* ReadFile should return FALSE and set ERROR_IO_PENDING */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (GetLastError() != ERROR_IO_PENDING)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "ReadFile: GetLastError() = %" PRIu32 "", GetLastError());
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pChannel->readAsync = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
HANDLE WINAPI Win32_WTSVirtualChannelOpen_Internal(HANDLE hServer, DWORD SessionId,
Packit Service 5a9772
                                                   LPSTR pVirtualName, DWORD flags)
Packit 1fb8d4
{
Packit 1fb8d4
	HANDLE hFile;
Packit 1fb8d4
	HANDLE hChannel;
Packit 1fb8d4
	WTSAPI_CHANNEL* pChannel;
Packit 1fb8d4
	size_t virtualNameLen;
Packit 1fb8d4
Packit 1fb8d4
	virtualNameLen = pVirtualName ? strlen(pVirtualName) : 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!virtualNameLen)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!pfnWinStationVirtualOpenEx)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_FUNCTION);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	hFile = pfnWinStationVirtualOpenEx(hServer, SessionId, pVirtualName, flags);
Packit 1fb8d4
Packit 1fb8d4
	if (!hFile)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	pChannel = (WTSAPI_CHANNEL*)_wts_calloc(1, sizeof(WTSAPI_CHANNEL));
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel)
Packit 1fb8d4
	{
Packit 1fb8d4
		CloseHandle(hFile);
Packit 1fb8d4
		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	hChannel = (HANDLE)pChannel;
Packit 1fb8d4
	pChannel->magic = WTSAPI_CHANNEL_MAGIC;
Packit 1fb8d4
	pChannel->hServer = hServer;
Packit 1fb8d4
	pChannel->SessionId = SessionId;
Packit 1fb8d4
	pChannel->hFile = hFile;
Packit 1fb8d4
	pChannel->VirtualName = _wts_calloc(1, virtualNameLen + 1);
Packit 1fb8d4
	if (!pChannel->VirtualName)
Packit 1fb8d4
	{
Packit 1fb8d4
		CloseHandle(hFile);
Packit 1fb8d4
		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Packit 1fb8d4
		_wts_free(pChannel);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
	memcpy(pChannel->VirtualName, pVirtualName, virtualNameLen);
Packit 1fb8d4
Packit 1fb8d4
	pChannel->flags = flags;
Packit 1fb8d4
	pChannel->dynamic = (flags & WTS_CHANNEL_OPTION_DYNAMIC) ? TRUE : FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pChannel->showProtocol = pChannel->dynamic;
Packit 1fb8d4
Packit 1fb8d4
	pChannel->readSize = CHANNEL_PDU_LENGTH;
Packit Service 5a9772
	pChannel->readBuffer = (BYTE*)_wts_malloc(pChannel->readSize);
Packit 1fb8d4
Packit Service 5a9772
	pChannel->header = (CHANNEL_PDU_HEADER*)pChannel->readBuffer;
Packit 1fb8d4
	pChannel->chunk = &(pChannel->readBuffer[sizeof(CHANNEL_PDU_HEADER)]);
Packit 1fb8d4
Packit 1fb8d4
	pChannel->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit 1fb8d4
	pChannel->overlapped.hEvent = pChannel->hEvent;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel->hEvent || !pChannel->VirtualName || !pChannel->readBuffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		Win32_WTSVirtualChannelClose(hChannel);
Packit 1fb8d4
		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return hChannel;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
Packit 1fb8d4
{
Packit 1fb8d4
	return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
Packit 1fb8d4
{
Packit 1fb8d4
	return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status = TRUE;
Packit Service 5a9772
	WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pChannel->hFile)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (pChannel->readAsync)
Packit 1fb8d4
		{
Packit 1fb8d4
			CancelIo(pChannel->hFile);
Packit 1fb8d4
			pChannel->readAsync = FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		status = CloseHandle(pChannel->hFile);
Packit 1fb8d4
		pChannel->hFile = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pChannel->hEvent)
Packit 1fb8d4
	{
Packit 1fb8d4
		CloseHandle(pChannel->hEvent);
Packit 1fb8d4
		pChannel->hEvent = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pChannel->VirtualName)
Packit 1fb8d4
	{
Packit 1fb8d4
		_wts_free(pChannel->VirtualName);
Packit 1fb8d4
		pChannel->VirtualName = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pChannel->readBuffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		_wts_free(pChannel->readBuffer);
Packit 1fb8d4
		pChannel->readBuffer = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pChannel->magic = 0;
Packit 1fb8d4
	_wts_free(pChannel);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds,
Packit Service 5a9772
                                               LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
Packit Service 5a9772
                                               LPDWORD lpNumberOfBytesTransferred)
Packit 1fb8d4
{
Packit 1fb8d4
	if (pChannel->readDone)
Packit 1fb8d4
	{
Packit 1fb8d4
		DWORD numBytesRead = 0;
Packit 1fb8d4
		DWORD numBytesToRead = 0;
Packit Service 5a9772
Packit 1fb8d4
		*lpNumberOfBytesTransferred = 0;
Packit 1fb8d4
Packit 1fb8d4
		numBytesToRead = nNumberOfBytesToRead;
Packit 1fb8d4
Packit 1fb8d4
		if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
Packit 1fb8d4
			numBytesToRead = (pChannel->header->length - pChannel->readOffset);
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead);
Packit 1fb8d4
		*lpNumberOfBytesTransferred += numBytesToRead;
Packit 1fb8d4
		pChannel->readOffset += numBytesToRead;
Packit 1fb8d4
Packit 1fb8d4
		if (pChannel->readOffset != pChannel->header->length)
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_MORE_DATA);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			pChannel->readDone = FALSE;
Packit 1fb8d4
			Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pChannel->readSync)
Packit 1fb8d4
	{
Packit 1fb8d4
		BOOL bSuccess;
Packit 1fb8d4
		OVERLAPPED overlapped;
Packit 1fb8d4
		DWORD numBytesRead = 0;
Packit 1fb8d4
		DWORD numBytesToRead = 0;
Packit Service 5a9772
Packit 1fb8d4
		*lpNumberOfBytesTransferred = 0;
Packit 1fb8d4
Packit 1fb8d4
		ZeroMemory(&overlapped, sizeof(OVERLAPPED));
Packit 1fb8d4
Packit 1fb8d4
		numBytesToRead = nNumberOfBytesToRead;
Packit 1fb8d4
Packit 1fb8d4
		if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
Packit 1fb8d4
			numBytesToRead = (pChannel->header->length - pChannel->readOffset);
Packit 1fb8d4
Packit 1fb8d4
		if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
Packit 1fb8d4
		{
Packit 1fb8d4
			*lpNumberOfBytesTransferred += numBytesRead;
Packit 1fb8d4
			pChannel->readOffset += numBytesRead;
Packit 1fb8d4
Packit 1fb8d4
			if (pChannel->readOffset != pChannel->header->length)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_MORE_DATA);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readSync = FALSE;
Packit 1fb8d4
			Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (GetLastError() != ERROR_IO_PENDING)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
Packit 1fb8d4
Packit 1fb8d4
		if (!bSuccess)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		*lpNumberOfBytesTransferred += numBytesRead;
Packit 1fb8d4
		pChannel->readOffset += numBytesRead;
Packit 1fb8d4
Packit 1fb8d4
		if (pChannel->readOffset != pChannel->header->length)
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_MORE_DATA);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		pChannel->readSync = FALSE;
Packit 1fb8d4
		Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pChannel->readAsync)
Packit 1fb8d4
	{
Packit 1fb8d4
		BOOL bSuccess;
Packit 1fb8d4
		DWORD numBytesRead = 0;
Packit 1fb8d4
		DWORD numBytesToRead = 0;
Packit 1fb8d4
Packit 1fb8d4
		*lpNumberOfBytesTransferred = 0;
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
Packit 1fb8d4
		{
Packit Service 5a9772
			bSuccess =
Packit Service 5a9772
			    GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readOffset = 0;
Packit 1fb8d4
			pChannel->header->length = numBytesRead;
Packit 1fb8d4
Packit 1fb8d4
			if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			numBytesToRead = nNumberOfBytesToRead;
Packit 1fb8d4
Packit 1fb8d4
			if (numBytesRead < numBytesToRead)
Packit 1fb8d4
			{
Packit 1fb8d4
				numBytesToRead = numBytesRead;
Packit 1fb8d4
				nNumberOfBytesToRead = numBytesRead;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead);
Packit 1fb8d4
			*lpNumberOfBytesTransferred += numBytesToRead;
Packit Service 5a9772
			lpBuffer = (BYTE*)lpBuffer + numBytesToRead;
Packit 1fb8d4
			nNumberOfBytesToRead -= numBytesToRead;
Packit 1fb8d4
			pChannel->readOffset += numBytesToRead;
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readAsync = FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!nNumberOfBytesToRead)
Packit 1fb8d4
			{
Packit 1fb8d4
				Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
				return TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readSync = TRUE;
Packit 1fb8d4
Packit 1fb8d4
			numBytesRead = 0;
Packit 1fb8d4
Packit Service 5a9772
			bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
Packit Service 5a9772
			                                              nNumberOfBytesToRead, &numBytesRead);
Packit 1fb8d4
Packit 1fb8d4
			*lpNumberOfBytesTransferred += numBytesRead;
Packit 1fb8d4
			return bSuccess;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_IO_INCOMPLETE);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds,
Packit Service 5a9772
                                                LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
Packit Service 5a9772
                                                LPDWORD lpNumberOfBytesTransferred)
Packit 1fb8d4
{
Packit 1fb8d4
	if (pChannel->readSync)
Packit 1fb8d4
	{
Packit 1fb8d4
		BOOL bSuccess;
Packit 1fb8d4
		OVERLAPPED overlapped;
Packit 1fb8d4
		DWORD numBytesRead = 0;
Packit 1fb8d4
		DWORD numBytesToRead = 0;
Packit Service 5a9772
Packit 1fb8d4
		*lpNumberOfBytesTransferred = 0;
Packit 1fb8d4
Packit 1fb8d4
		ZeroMemory(&overlapped, sizeof(OVERLAPPED));
Packit 1fb8d4
Packit 1fb8d4
		numBytesToRead = nNumberOfBytesToRead;
Packit 1fb8d4
Packit 1fb8d4
		if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
Packit 1fb8d4
			numBytesToRead = (pChannel->header->length - pChannel->readOffset);
Packit 1fb8d4
Packit 1fb8d4
		if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
Packit 1fb8d4
		{
Packit 1fb8d4
			*lpNumberOfBytesTransferred += numBytesRead;
Packit 1fb8d4
			pChannel->readOffset += numBytesRead;
Packit 1fb8d4
Packit 1fb8d4
			if (pChannel->readOffset != pChannel->header->length)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_MORE_DATA);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readSync = FALSE;
Packit 1fb8d4
			Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (GetLastError() != ERROR_IO_PENDING)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
Packit 1fb8d4
Packit 1fb8d4
		if (!bSuccess)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		*lpNumberOfBytesTransferred += numBytesRead;
Packit 1fb8d4
		pChannel->readOffset += numBytesRead;
Packit 1fb8d4
Packit 1fb8d4
		if (pChannel->readOffset != pChannel->header->length)
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_MORE_DATA);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		pChannel->readSync = FALSE;
Packit 1fb8d4
		Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pChannel->readAsync)
Packit 1fb8d4
	{
Packit 1fb8d4
		BOOL bSuccess;
Packit 1fb8d4
		DWORD numBytesRead = 0;
Packit 1fb8d4
Packit 1fb8d4
		*lpNumberOfBytesTransferred = 0;
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
Packit 1fb8d4
		{
Packit Service 5a9772
			bSuccess =
Packit Service 5a9772
			    GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
Packit 1fb8d4
Packit 1fb8d4
			if (pChannel->showProtocol)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (numBytesRead != sizeof(CHANNEL_PDU_HEADER))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				CopyMemory(lpBuffer, pChannel->header, numBytesRead);
Packit 1fb8d4
				*lpNumberOfBytesTransferred += numBytesRead;
Packit Service 5a9772
				lpBuffer = (BYTE*)lpBuffer + numBytesRead;
Packit 1fb8d4
				nNumberOfBytesToRead -= numBytesRead;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readAsync = FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (!pChannel->header->length)
Packit 1fb8d4
			{
Packit 1fb8d4
				Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
				return TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pChannel->readSync = TRUE;
Packit 1fb8d4
			pChannel->readOffset = 0;
Packit 1fb8d4
Packit 1fb8d4
			if (!nNumberOfBytesToRead)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_MORE_DATA);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			numBytesRead = 0;
Packit 1fb8d4
Packit Service 5a9772
			bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
Packit Service 5a9772
			                                               nNumberOfBytesToRead, &numBytesRead);
Packit 1fb8d4
Packit 1fb8d4
			*lpNumberOfBytesTransferred += numBytesRead;
Packit 1fb8d4
			return bSuccess;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_IO_INCOMPLETE);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds, LPVOID lpBuffer,
Packit Service 5a9772
                                        DWORD nNumberOfBytesToRead,
Packit Service 5a9772
                                        LPDWORD lpNumberOfBytesTransferred)
Packit 1fb8d4
{
Packit Service 5a9772
	WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel->waitObjectMode)
Packit 1fb8d4
	{
Packit 1fb8d4
		OVERLAPPED overlapped;
Packit Service 5a9772
Packit 1fb8d4
		ZeroMemory(&overlapped, sizeof(OVERLAPPED));
Packit 1fb8d4
Packit Service 5a9772
		if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred,
Packit Service 5a9772
		             &overlapped))
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
Packit 1fb8d4
		if (GetLastError() != ERROR_IO_PENDING)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		if (!dwMilliseconds)
Packit 1fb8d4
		{
Packit 1fb8d4
			CancelIo(pChannel->hFile);
Packit 1fb8d4
			*lpNumberOfBytesTransferred = 0;
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT)
Packit Service 5a9772
			return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred,
Packit Service 5a9772
			                           FALSE);
Packit 1fb8d4
Packit 1fb8d4
		CancelIo(pChannel->hFile);
Packit 1fb8d4
		SetLastError(ERROR_IO_INCOMPLETE);
Packit 1fb8d4
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (pChannel->dynamic)
Packit 1fb8d4
		{
Packit Service 5a9772
			return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
Packit Service 5a9772
			                                           nNumberOfBytesToRead,
Packit Service 5a9772
			                                           lpNumberOfBytesTransferred);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit Service 5a9772
			return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
Packit Service 5a9772
			                                          nNumberOfBytesToRead,
Packit Service 5a9772
			                                          lpNumberOfBytesTransferred);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, LPCVOID lpBuffer,
Packit Service 5a9772
                                         DWORD nNumberOfBytesToWrite,
Packit Service 5a9772
                                         LPDWORD lpNumberOfBytesTransferred)
Packit 1fb8d4
{
Packit 1fb8d4
	OVERLAPPED overlapped;
Packit Service 5a9772
	WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ZeroMemory(&overlapped, sizeof(OVERLAPPED));
Packit 1fb8d4
Packit Service 5a9772
	if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred,
Packit Service 5a9772
	              &overlapped))
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (GetLastError() == ERROR_IO_PENDING)
Packit 1fb8d4
		return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE);
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifndef FILE_DEVICE_TERMSRV
Packit Service 5a9772
#define FILE_DEVICE_TERMSRV 0x00000038
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD error;
Packit 1fb8d4
	NTSTATUS ntstatus;
Packit 1fb8d4
	IO_STATUS_BLOCK ioStatusBlock;
Packit Service 5a9772
	WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	ntstatus =
Packit Service 5a9772
	    _NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (ntstatus == STATUS_PENDING)
Packit 1fb8d4
	{
Packit 1fb8d4
		ntstatus = _NtWaitForSingleObject(pChannel->hFile, 0, 0);
Packit 1fb8d4
Packit 1fb8d4
		if (ntstatus >= 0)
Packit 1fb8d4
			ntstatus = ioStatusBlock.Status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (ntstatus == STATUS_BUFFER_OVERFLOW)
Packit 1fb8d4
	{
Packit 1fb8d4
		ntstatus = STATUS_BUFFER_TOO_SMALL;
Packit 1fb8d4
		error = _RtlNtStatusToDosError(ntstatus);
Packit 1fb8d4
		SetLastError(error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (ntstatus < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		error = _RtlNtStatusToDosError(ntstatus);
Packit 1fb8d4
		SetLastError(error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
Packit 1fb8d4
{
Packit Service 5a9772
	return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
Packit Service 5a9772
	                                             (FILE_DEVICE_TERMSRV << 16) | 0x0107);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
Packit 1fb8d4
{
Packit Service 5a9772
	return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
Packit Service 5a9772
	                                             (FILE_DEVICE_TERMSRV << 16) | 0x010B);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
Packit Service 5a9772
                                         PVOID* ppBuffer, DWORD* pBytesReturned)
Packit 1fb8d4
{
Packit Service 5a9772
	WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (WtsVirtualClass == WTSVirtualClientData)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (WtsVirtualClass == WTSVirtualFileHandle)
Packit 1fb8d4
	{
Packit 1fb8d4
		*pBytesReturned = sizeof(HANDLE);
Packit 1fb8d4
		*ppBuffer = _wts_calloc(1, *pBytesReturned);
Packit 1fb8d4
Packit 1fb8d4
		if (*ppBuffer == NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (WtsVirtualClass == WTSVirtualEventHandle)
Packit 1fb8d4
	{
Packit 1fb8d4
		*pBytesReturned = sizeof(HANDLE);
Packit 1fb8d4
		*ppBuffer = _wts_calloc(1, *pBytesReturned);
Packit 1fb8d4
Packit 1fb8d4
		if (*ppBuffer == NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
Packit 1fb8d4
Packit 1fb8d4
		Win32_WTSVirtualChannelReadAsync(pChannel);
Packit 1fb8d4
		pChannel->waitObjectMode = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_PARAMETER);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
Packit 1fb8d4
{
Packit 1fb8d4
	_wts_free(pMemory);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
Packit Service 5a9772
                                   ULONG NumberOfEntries)
Packit 1fb8d4
{
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
Packit Service 5a9772
                                   ULONG NumberOfEntries)
Packit 1fb8d4
{
Packit 1fb8d4
	return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi)
Packit 1fb8d4
{
Packit 1fb8d4
	g_WinStaModule = LoadLibraryA("winsta.dll");
Packit 1fb8d4
Packit 1fb8d4
	if (!g_WinStaModule)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	pfnWinStationVirtualOpen =
Packit Service 5a9772
	    (fnWinStationVirtualOpen)GetProcAddress(g_WinStaModule, "WinStationVirtualOpen");
Packit Service 5a9772
	pfnWinStationVirtualOpenEx =
Packit Service 5a9772
	    (fnWinStationVirtualOpenEx)GetProcAddress(g_WinStaModule, "WinStationVirtualOpenEx");
Packit 1fb8d4
Packit 1fb8d4
	if (!pfnWinStationVirtualOpen | !pfnWinStationVirtualOpenEx)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
Packit 1fb8d4
	pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
Packit 1fb8d4
	pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
Packit 1fb8d4
	pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
Packit 1fb8d4
	pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
Packit 1fb8d4
	pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
Packit 1fb8d4
	pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
Packit 1fb8d4
	pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
Packit 1fb8d4
	pWtsApi->pFreeMemory = Win32_WTSFreeMemory;
Packit Service 5a9772
	// pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW;
Packit Service 5a9772
	// pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}