20 #include <winpr/config.h>
22 #include <winpr/crt.h>
25 #include <winpr/library.h>
27 #include <winpr/wtsapi.h>
29 #include "wtsapi_win32.h"
35 #pragma comment(lib, "ntdll.lib")
37 #define WTSAPI_CHANNEL_MAGIC 0x44484356
38 #define TAG WINPR_TAG("wtsapi")
64 static BOOL g_Initialized = FALSE;
65 static HMODULE g_WinStaModule = NULL;
67 typedef HANDLE(WINAPI* fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId,
69 typedef HANDLE(WINAPI* fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId,
70 LPSTR pVirtualName, DWORD flags);
72 static fnWinStationVirtualOpen pfnWinStationVirtualOpen = NULL;
73 static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = NULL;
75 BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel);
92 static void* _wts_malloc(
size_t size)
97 return (PVOID)LocalAlloc(LMEM_FIXED, size);
101 static void* _wts_calloc(
size_t nmemb,
size_t size)
104 return calloc(nmemb, size);
106 return (PVOID)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, nmemb * size);
110 static void _wts_free(
void* ptr)
115 LocalFree((HLOCAL)ptr);
119 BOOL Win32_WTSVirtualChannelReadAsync(WTSAPI_CHANNEL* pChannel)
124 if (pChannel->readAsync)
127 ZeroMemory(&(pChannel->overlapped),
sizeof(
OVERLAPPED));
128 pChannel->overlapped.hEvent = pChannel->hEvent;
129 (void)ResetEvent(pChannel->hEvent);
131 if (pChannel->showProtocol)
135 status = ReadFile(pChannel->hFile, pChannel->header,
sizeof(
CHANNEL_PDU_HEADER), &numBytes,
136 &(pChannel->overlapped));
140 status = ReadFile(pChannel->hFile, pChannel->chunk, CHANNEL_CHUNK_LENGTH, &numBytes,
141 &(pChannel->overlapped));
145 pChannel->readOffset = 0;
146 pChannel->header->length = numBytes;
148 pChannel->readDone = TRUE;
149 (void)SetEvent(pChannel->hEvent);
157 WLog_ERR(TAG,
"Unexpected ReadFile status: %" PRId32
" numBytes: %" PRIu32
"", status,
162 if (GetLastError() != ERROR_IO_PENDING)
164 WLog_ERR(TAG,
"ReadFile: GetLastError() = %" PRIu32
"", GetLastError());
168 pChannel->readAsync = TRUE;
173 HANDLE WINAPI Win32_WTSVirtualChannelOpen_Internal(HANDLE hServer, DWORD SessionId,
174 LPSTR pVirtualName, DWORD flags)
178 WTSAPI_CHANNEL* pChannel;
179 size_t virtualNameLen;
181 virtualNameLen = pVirtualName ? strlen(pVirtualName) : 0;
185 SetLastError(ERROR_INVALID_PARAMETER);
189 if (!pfnWinStationVirtualOpenEx)
191 SetLastError(ERROR_INVALID_FUNCTION);
195 hFile = pfnWinStationVirtualOpenEx(hServer, SessionId, pVirtualName, flags);
200 pChannel = (WTSAPI_CHANNEL*)_wts_calloc(1,
sizeof(WTSAPI_CHANNEL));
204 (void)CloseHandle(hFile);
205 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
209 hChannel = (HANDLE)pChannel;
210 pChannel->magic = WTSAPI_CHANNEL_MAGIC;
211 pChannel->hServer = hServer;
212 pChannel->SessionId = SessionId;
213 pChannel->hFile = hFile;
214 pChannel->VirtualName = _wts_calloc(1, virtualNameLen + 1);
215 if (!pChannel->VirtualName)
217 (void)CloseHandle(hFile);
218 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
222 memcpy(pChannel->VirtualName, pVirtualName, virtualNameLen);
224 pChannel->flags = flags;
225 pChannel->dynamic = (flags & WTS_CHANNEL_OPTION_DYNAMIC) ? TRUE : FALSE;
227 pChannel->showProtocol = pChannel->dynamic;
229 pChannel->readSize = CHANNEL_PDU_LENGTH;
230 pChannel->readBuffer = (BYTE*)_wts_malloc(pChannel->readSize);
235 pChannel->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
236 pChannel->overlapped.hEvent = pChannel->hEvent;
238 if (!pChannel->hEvent || !pChannel->VirtualName || !pChannel->readBuffer)
240 Win32_WTSVirtualChannelClose(hChannel);
241 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
248 HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
250 return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
253 HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
255 return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
258 BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel)
261 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
263 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
265 SetLastError(ERROR_INVALID_PARAMETER);
271 if (pChannel->readAsync)
273 CancelIo(pChannel->hFile);
274 pChannel->readAsync = FALSE;
277 status = CloseHandle(pChannel->hFile);
278 pChannel->hFile = NULL;
281 if (pChannel->hEvent)
283 (void)CloseHandle(pChannel->hEvent);
284 pChannel->hEvent = NULL;
287 if (pChannel->VirtualName)
289 _wts_free(pChannel->VirtualName);
290 pChannel->VirtualName = NULL;
293 if (pChannel->readBuffer)
295 _wts_free(pChannel->readBuffer);
296 pChannel->readBuffer = NULL;
305 BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds,
306 LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
307 LPDWORD lpNumberOfBytesTransferred)
309 if (pChannel->readDone)
311 DWORD numBytesRead = 0;
312 DWORD numBytesToRead = 0;
314 *lpNumberOfBytesTransferred = 0;
316 numBytesToRead = nNumberOfBytesToRead;
318 if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
319 numBytesToRead = (pChannel->header->length - pChannel->readOffset);
321 CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead);
322 *lpNumberOfBytesTransferred += numBytesToRead;
323 pChannel->readOffset += numBytesToRead;
325 if (pChannel->readOffset != pChannel->header->length)
327 SetLastError(ERROR_MORE_DATA);
332 pChannel->readDone = FALSE;
333 Win32_WTSVirtualChannelReadAsync(pChannel);
338 else if (pChannel->readSync)
342 DWORD numBytesRead = 0;
343 DWORD numBytesToRead = 0;
345 *lpNumberOfBytesTransferred = 0;
347 numBytesToRead = nNumberOfBytesToRead;
349 if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
350 numBytesToRead = (pChannel->header->length - pChannel->readOffset);
352 if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
354 *lpNumberOfBytesTransferred += numBytesRead;
355 pChannel->readOffset += numBytesRead;
357 if (pChannel->readOffset != pChannel->header->length)
359 SetLastError(ERROR_MORE_DATA);
363 pChannel->readSync = FALSE;
364 Win32_WTSVirtualChannelReadAsync(pChannel);
369 if (GetLastError() != ERROR_IO_PENDING)
372 bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
377 *lpNumberOfBytesTransferred += numBytesRead;
378 pChannel->readOffset += numBytesRead;
380 if (pChannel->readOffset != pChannel->header->length)
382 SetLastError(ERROR_MORE_DATA);
386 pChannel->readSync = FALSE;
387 Win32_WTSVirtualChannelReadAsync(pChannel);
391 else if (pChannel->readAsync)
394 DWORD numBytesRead = 0;
395 DWORD numBytesToRead = 0;
397 *lpNumberOfBytesTransferred = 0;
399 if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
402 GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
404 pChannel->readOffset = 0;
405 pChannel->header->length = numBytesRead;
407 if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
410 numBytesToRead = nNumberOfBytesToRead;
412 if (numBytesRead < numBytesToRead)
414 numBytesToRead = numBytesRead;
415 nNumberOfBytesToRead = numBytesRead;
418 CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead);
419 *lpNumberOfBytesTransferred += numBytesToRead;
420 lpBuffer = (BYTE*)lpBuffer + numBytesToRead;
421 nNumberOfBytesToRead -= numBytesToRead;
422 pChannel->readOffset += numBytesToRead;
424 pChannel->readAsync = FALSE;
426 if (!nNumberOfBytesToRead)
428 Win32_WTSVirtualChannelReadAsync(pChannel);
432 pChannel->readSync = TRUE;
436 bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
437 nNumberOfBytesToRead, &numBytesRead);
439 *lpNumberOfBytesTransferred += numBytesRead;
444 SetLastError(ERROR_IO_INCOMPLETE);
452 BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds,
453 LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
454 LPDWORD lpNumberOfBytesTransferred)
456 if (pChannel->readSync)
460 DWORD numBytesRead = 0;
461 DWORD numBytesToRead = 0;
463 *lpNumberOfBytesTransferred = 0;
465 numBytesToRead = nNumberOfBytesToRead;
467 if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
468 numBytesToRead = (pChannel->header->length - pChannel->readOffset);
470 if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
472 *lpNumberOfBytesTransferred += numBytesRead;
473 pChannel->readOffset += numBytesRead;
475 if (pChannel->readOffset != pChannel->header->length)
477 SetLastError(ERROR_MORE_DATA);
481 pChannel->readSync = FALSE;
482 Win32_WTSVirtualChannelReadAsync(pChannel);
487 if (GetLastError() != ERROR_IO_PENDING)
490 bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
495 *lpNumberOfBytesTransferred += numBytesRead;
496 pChannel->readOffset += numBytesRead;
498 if (pChannel->readOffset != pChannel->header->length)
500 SetLastError(ERROR_MORE_DATA);
504 pChannel->readSync = FALSE;
505 Win32_WTSVirtualChannelReadAsync(pChannel);
509 else if (pChannel->readAsync)
512 DWORD numBytesRead = 0;
514 *lpNumberOfBytesTransferred = 0;
516 if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
519 GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
521 if (pChannel->showProtocol)
526 if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
529 CopyMemory(lpBuffer, pChannel->header, numBytesRead);
530 *lpNumberOfBytesTransferred += numBytesRead;
531 lpBuffer = (BYTE*)lpBuffer + numBytesRead;
532 nNumberOfBytesToRead -= numBytesRead;
535 pChannel->readAsync = FALSE;
537 if (!pChannel->header->length)
539 Win32_WTSVirtualChannelReadAsync(pChannel);
543 pChannel->readSync = TRUE;
544 pChannel->readOffset = 0;
546 if (!nNumberOfBytesToRead)
548 SetLastError(ERROR_MORE_DATA);
554 bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
555 nNumberOfBytesToRead, &numBytesRead);
557 *lpNumberOfBytesTransferred += numBytesRead;
562 SetLastError(ERROR_IO_INCOMPLETE);
570 BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds, LPVOID lpBuffer,
571 DWORD nNumberOfBytesToRead,
572 LPDWORD lpNumberOfBytesTransferred)
574 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
576 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
578 SetLastError(ERROR_INVALID_PARAMETER);
582 if (!pChannel->waitObjectMode)
586 if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred,
590 if (GetLastError() != ERROR_IO_PENDING)
595 CancelIo(pChannel->hFile);
596 *lpNumberOfBytesTransferred = 0;
600 if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT)
601 return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred,
604 CancelIo(pChannel->hFile);
605 SetLastError(ERROR_IO_INCOMPLETE);
611 if (pChannel->dynamic)
613 return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
614 nNumberOfBytesToRead,
615 lpNumberOfBytesTransferred);
619 return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
620 nNumberOfBytesToRead,
621 lpNumberOfBytesTransferred);
628 BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, LPCVOID lpBuffer,
629 DWORD nNumberOfBytesToWrite,
630 LPDWORD lpNumberOfBytesTransferred)
633 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
635 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
637 SetLastError(ERROR_INVALID_PARAMETER);
641 if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred,
645 if (GetLastError() == ERROR_IO_PENDING)
646 return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE);
651 #ifndef FILE_DEVICE_TERMSRV
652 #define FILE_DEVICE_TERMSRV 0x00000038
655 BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode)
660 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
662 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
664 SetLastError(ERROR_INVALID_PARAMETER);
669 NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
671 if (ntstatus == STATUS_PENDING)
673 ntstatus = NtWaitForSingleObject(pChannel->hFile, 0, 0);
676 ntstatus = ioStatusBlock.Status;
679 if (ntstatus == STATUS_BUFFER_OVERFLOW)
681 ntstatus = STATUS_BUFFER_TOO_SMALL;
682 error = RtlNtStatusToDosError(ntstatus);
689 error = RtlNtStatusToDosError(ntstatus);
697 BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
699 return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
700 (FILE_DEVICE_TERMSRV << 16) | 0x0107);
703 BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
705 return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
706 (FILE_DEVICE_TERMSRV << 16) | 0x010B);
709 BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
710 PVOID* ppBuffer, DWORD* pBytesReturned)
712 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
714 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
716 SetLastError(ERROR_INVALID_PARAMETER);
720 if (WtsVirtualClass == WTSVirtualClientData)
722 SetLastError(ERROR_INVALID_PARAMETER);
725 else if (WtsVirtualClass == WTSVirtualFileHandle)
727 *pBytesReturned =
sizeof(HANDLE);
728 *ppBuffer = _wts_calloc(1, *pBytesReturned);
730 if (*ppBuffer == NULL)
732 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
736 CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
738 else if (WtsVirtualClass == WTSVirtualEventHandle)
740 *pBytesReturned =
sizeof(HANDLE);
741 *ppBuffer = _wts_calloc(1, *pBytesReturned);
743 if (*ppBuffer == NULL)
745 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
749 CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
751 Win32_WTSVirtualChannelReadAsync(pChannel);
752 pChannel->waitObjectMode = TRUE;
756 SetLastError(ERROR_INVALID_PARAMETER);
763 VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
768 BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
769 ULONG NumberOfEntries)
774 BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
775 ULONG NumberOfEntries)
777 return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
782 g_WinStaModule = LoadLibraryA(
"winsta.dll");
787 pfnWinStationVirtualOpen =
788 GetProcAddressAs(g_WinStaModule,
"WinStationVirtualOpen", fnWinStationVirtualOpen);
789 pfnWinStationVirtualOpenEx =
790 GetProcAddressAs(g_WinStaModule,
"WinStationVirtualOpenEx", fnWinStationVirtualOpenEx);
792 if (!pfnWinStationVirtualOpen | !pfnWinStationVirtualOpenEx)
795 pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
796 pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
797 pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
798 pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
799 pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
800 pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
801 pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
802 pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
803 pWtsApi->pFreeMemory = Win32_WTSFreeMemory;