FreeRDP
Loading...
Searching...
No Matches
libfreerdp/core/server.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdint.h>
28
29#include <winpr/atexit.h>
30#include <winpr/wtypes.h>
31#include <winpr/crt.h>
32#include <winpr/synch.h>
33#include <winpr/stream.h>
34#include <winpr/assert.h>
35#include <winpr/cast.h>
36
37#include <freerdp/log.h>
38#include <freerdp/constants.h>
39#include <freerdp/server/channels.h>
40#include <freerdp/channels/drdynvc.h>
41#include <freerdp/utils/drdynvc.h>
42
43#include "rdp.h"
44
45#include "server.h"
46
47#define TAG FREERDP_TAG("core.server")
48#ifdef WITH_DEBUG_DVC
49#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__)
50#else
51#define DEBUG_DVC(...) \
52 do \
53 { \
54 } while (0)
55#endif
56
57#define DVC_MAX_DATA_PDU_SIZE 1600
58
59typedef struct
60{
61 UINT16 channelId;
62 UINT16 reserved;
63 UINT32 length;
64 UINT32 offset;
65} wtsChannelMessage;
66
67static const DWORD g_err_oom = WINPR_CXX_COMPAT_CAST(DWORD, E_OUTOFMEMORY);
68
69static DWORD g_SessionId = 1;
70static wHashTable* g_ServerHandles = nullptr;
71static INIT_ONCE g_HandleInitializer = INIT_ONCE_STATIC_INIT;
72
73static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, UINT32 ChannelId)
74{
75 WINPR_ASSERT(vcm);
76 return HashTable_GetItemValue(vcm->dynamicVirtualChannels, &ChannelId);
77}
78
79static BOOL wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* Buffer1, size_t Length1,
80 const BYTE* Buffer2, size_t Length2)
81{
82 WINPR_ASSERT(channel);
83
84 if (Length1 > UINT32_MAX - sizeof(wtsChannelMessage))
85 return FALSE;
86 if (Length2 > UINT32_MAX - sizeof(wtsChannelMessage) - Length1)
87 return FALSE;
88 const size_t len = Length1 + Length2;
89 const size_t tlen = sizeof(wtsChannelMessage) + len;
90 wtsChannelMessage* messageCtx = (wtsChannelMessage*)malloc(tlen);
91 if (!messageCtx)
92 return FALSE;
93
94 WINPR_ASSERT(channel->channelId <= UINT16_MAX);
95 messageCtx->channelId = WINPR_ASSERTING_INT_CAST(UINT16, channel->channelId);
96 messageCtx->length = WINPR_ASSERTING_INT_CAST(UINT32, len);
97 messageCtx->offset = 0;
98 BYTE* buffer = (BYTE*)(&messageCtx[1]);
99 CopyMemory(buffer, Buffer1, Length1);
100
101 WINPR_ASSERT(Buffer2 || (Length2 == 0));
102 buffer += Length1;
103 if (Buffer2)
104 CopyMemory(buffer, Buffer2, Length2);
105
106 return MessageQueue_Post(channel->queue, messageCtx, 0, nullptr, nullptr);
107}
108
109static BOOL wts_queue_send_item(rdpPeerChannel* channel, BYTE* Buffer, UINT32 Length)
110{
111 BYTE* buffer = nullptr;
112 UINT32 length = 0;
113
114 WINPR_ASSERT(channel);
115 WINPR_ASSERT(channel->vcm);
116 buffer = Buffer;
117 length = Length;
118
119 WINPR_ASSERT(channel->channelId <= UINT16_MAX);
120 const UINT16 channelId = (UINT16)channel->channelId;
121 return MessageQueue_Post(channel->vcm->queue, (void*)(UINT_PTR)channelId, 0, (void*)buffer,
122 (void*)(UINT_PTR)length);
123}
124
125static unsigned wts_read_variable_uint(wStream* s, int cbLen, UINT32* val)
126{
127 WINPR_ASSERT(s);
128 WINPR_ASSERT(val);
129 switch (cbLen)
130 {
131 case 0:
132 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
133 return 0;
134
135 Stream_Read_UINT8(s, *val);
136 return 1;
137
138 case 1:
139 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
140 return 0;
141
142 Stream_Read_UINT16(s, *val);
143 return 2;
144
145 case 2:
146 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
147 return 0;
148
149 Stream_Read_UINT32(s, *val);
150 return 4;
151
152 default:
153 WLog_ERR(TAG, "invalid wts variable uint len %d", cbLen);
154 return 0;
155 }
156}
157
158static BOOL wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, wStream* s)
159{
160 UINT16 Version = 0;
161
162 WINPR_ASSERT(channel);
163 WINPR_ASSERT(channel->vcm);
164 const size_t length = Stream_GetRemainingLength(s);
165 if (length < 3)
166 return FALSE;
167
168 Stream_Seek_UINT8(s); /* Pad (1 byte) */
169 Stream_Read_UINT16(s, Version);
170 DEBUG_DVC("Version: %" PRIu16 "", Version);
171
172 if (Version < 1)
173 {
174 WLog_ERR(TAG, "invalid version %" PRIu16 " for DRDYNVC", Version);
175 return FALSE;
176 }
177
178 WTSVirtualChannelManager* vcm = channel->vcm;
179 vcm->drdynvc_state = DRDYNVC_STATE_READY;
180
181 /* we only support version 1 for now (no compression yet) */
182 vcm->dvc_spoken_version = MAX(Version, 1);
183
184 return SetEvent(MessageQueue_Event(vcm->queue));
185}
186
187static BOOL wts_read_drdynvc_create_response(rdpPeerChannel* channel, wStream* s)
188{
189 UINT32 CreationStatus = 0;
190 BOOL status = TRUE;
191
192 WINPR_ASSERT(channel);
193 WINPR_ASSERT(s);
194 const size_t length = Stream_GetRemainingLength(s);
195 if ((length < 4) || (length > UINT32_MAX))
196 return FALSE;
197
198 Stream_Read_UINT32(s, CreationStatus);
199
200 if ((INT32)CreationStatus < 0)
201 {
202 DEBUG_DVC("ChannelId %" PRIu32 " creation failed (%" PRId32 ")", channel->channelId,
203 (INT32)CreationStatus);
204 channel->dvc_open_state = DVC_OPEN_STATE_FAILED;
205 }
206 else
207 {
208 DEBUG_DVC("ChannelId %" PRIu32 " creation succeeded", channel->channelId);
209 channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED;
210 }
211
212 channel->creationStatus = (INT32)CreationStatus;
213 IFCALLRET(channel->vcm->dvc_creation_status, status, channel->vcm->dvc_creation_status_userdata,
214 channel->channelId, (INT32)CreationStatus);
215 if (!status)
216 WLog_ERR(TAG, "vcm->dvc_creation_status failed!");
217
218 return status;
219}
220
221static BOOL wts_read_drdynvc_data_first(rdpPeerChannel* channel, wStream* s, int cbLen)
222{
223 WINPR_ASSERT(channel);
224 WINPR_ASSERT(s);
225
226 const UINT32 value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length);
227
228 if (value == 0)
229 return FALSE;
230
231 const size_t length = Stream_GetRemainingLength(s);
232 if (length > channel->dvc_total_length)
233 return FALSE;
234
235 Stream_ResetPosition(channel->receiveData);
236
237 if (!Stream_EnsureRemainingCapacity(channel->receiveData, length))
238 return FALSE;
239
240 Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
241 return TRUE;
242}
243
244static BOOL wts_read_drdynvc_data(rdpPeerChannel* channel, wStream* s)
245{
246 BOOL ret = FALSE;
247
248 WINPR_ASSERT(channel);
249 WINPR_ASSERT(s);
250
251 const size_t length = Stream_GetRemainingLength(s);
252 if (channel->dvc_total_length > 0)
253 {
254 const size_t pos = Stream_GetPosition(channel->receiveData);
255 if (pos > SIZE_MAX - length)
256 return FALSE;
257
258 if (pos + length > channel->dvc_total_length)
259 {
260 channel->dvc_total_length = 0;
261 WLog_ERR(TAG, "incorrect fragment data, discarded.");
262 return FALSE;
263 }
264
265 if (!Stream_EnsureRemainingCapacity(channel->receiveData, length))
266 return FALSE;
267
268 Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
269
270 if (Stream_GetPosition(channel->receiveData) >= channel->dvc_total_length)
271 {
272 ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
273 channel->dvc_total_length, nullptr, 0);
274 channel->dvc_total_length = 0;
275 }
276 else
277 ret = TRUE;
278 }
279 else
280 {
281 ret = wts_queue_receive_data(channel, Stream_ConstPointer(s), length, nullptr, 0);
282 }
283
284 return ret;
285}
286
287static void wts_read_drdynvc_close_response(rdpPeerChannel* channel)
288{
289 WINPR_ASSERT(channel);
290 DEBUG_DVC("ChannelId %" PRIu32 " close response", channel->channelId);
291 channel->dvc_open_state = DVC_OPEN_STATE_CLOSED;
292 MessageQueue_PostQuit(channel->queue, 0);
293}
294
295WINPR_ATTR_NODISCARD
296static BOOL wts_read_drdynvc_pdu_ready_guarded(wStream* s, UINT8 Cmd, UINT8 Sp, UINT32 ChannelId,
297 rdpPeerChannel* dvc)
298{
299 switch (Cmd)
300 {
301 case CREATE_REQUEST_PDU:
302 return wts_read_drdynvc_create_response(dvc, s);
303
304 case DATA_FIRST_PDU:
305 if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED)
306 {
307 WLog_ERR(TAG,
308 "ChannelId %" PRIu32 " did not open successfully. "
309 "Ignoring DYNVC_DATA_FIRST PDU",
310 ChannelId);
311 return TRUE;
312 }
313
314 return wts_read_drdynvc_data_first(dvc, s, Sp);
315
316 case DATA_PDU:
317 if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED)
318 {
319 WLog_ERR(TAG,
320 "ChannelId %" PRIu32 " did not open successfully. "
321 "Ignoring DYNVC_DATA PDU",
322 ChannelId);
323 return TRUE;
324 }
325
326 return wts_read_drdynvc_data(dvc, s);
327
328 case CLOSE_REQUEST_PDU:
329 wts_read_drdynvc_close_response(dvc);
330 break;
331
332 case DATA_FIRST_COMPRESSED_PDU:
333 case DATA_COMPRESSED_PDU:
334 WLog_ERR(TAG, "Compressed data not handled");
335 break;
336
337 case SOFT_SYNC_RESPONSE_PDU:
338 WLog_ERR(TAG, "SoftSync response not handled yet(and rather strange to receive "
339 "that packet as our code doesn't send SoftSync requests");
340 break;
341
342 case SOFT_SYNC_REQUEST_PDU:
343 WLog_ERR(TAG, "Not expecting a SoftSyncRequest on the server");
344 return FALSE;
345
346 default:
347 WLog_ERR(TAG, "Cmd %d not recognized.", Cmd);
348 break;
349 }
350 return TRUE;
351}
352
353WINPR_ATTR_NODISCARD
354static BOOL wts_read_drdynvc_pdu_ready(rdpPeerChannel* channel, wStream* s, UINT8 Cmd, UINT8 Sp,
355 UINT8 cbChId)
356{
357 WINPR_ASSERT(channel);
358
359 BOOL haveChannelId = 0;
360 switch (Cmd)
361 {
362 case SOFT_SYNC_REQUEST_PDU:
363 case SOFT_SYNC_RESPONSE_PDU:
364 haveChannelId = FALSE;
365 break;
366 default:
367 haveChannelId = TRUE;
368 break;
369 }
370
371 UINT32 ChannelId = 0;
372 rdpPeerChannel* dvc = nullptr;
373 wHashTable* table = nullptr;
374 if (haveChannelId)
375 {
376 const unsigned val = wts_read_variable_uint(s, cbChId, &ChannelId);
377 if (val == 0)
378 return FALSE;
379
380 DEBUG_DVC("Cmd %s ChannelId %" PRIu32 " length %" PRIuz "", drdynvc_get_packet_type(Cmd),
381 ChannelId, Stream_GetRemainingLength(s));
382 table = channel->vcm->dynamicVirtualChannels;
383 if (!table)
384 return FALSE;
385 HashTable_Lock(table);
386 dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId);
387 if (!dvc)
388 {
389 DEBUG_DVC("ChannelId %" PRIu32 " does not exist.", ChannelId);
390 HashTable_Unlock(table);
391 return TRUE;
392 }
393 }
394
395 const BOOL rc = wts_read_drdynvc_pdu_ready_guarded(s, Cmd, Sp, ChannelId, dvc);
396 if (table)
397 HashTable_Unlock(table);
398 return rc;
399}
400
401WINPR_ATTR_NODISCARD
402static BOOL wts_read_drdynvc_pdu(rdpPeerChannel* channel)
403{
404 WINPR_ASSERT(channel);
405 WINPR_ASSERT(channel->vcm);
406
407 const size_t slength = Stream_GetPosition(channel->receiveData);
408 if ((slength < 1) || (slength > UINT32_MAX))
409 return FALSE;
410
411 Stream_ResetPosition(channel->receiveData);
412 wStream buffer = WINPR_C_ARRAY_INIT;
413 wStream* s = Stream_StaticConstInit(&buffer, Stream_Buffer(channel->receiveData), slength);
414 const UINT8 value = Stream_Get_UINT8(s);
415 const UINT8 Cmd = (value & 0xf0) >> 4;
416 const UINT8 Sp = (value & 0x0c) >> 2;
417 const UINT8 cbChId = (value & 0x03) >> 0;
418
419 if (Cmd == CAPABILITY_REQUEST_PDU)
420 return wts_read_drdynvc_capabilities_response(channel, s);
421
422 if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY)
423 return wts_read_drdynvc_pdu_ready(channel, s, Cmd, Sp, cbChId);
424 else
425 WLog_ERR(TAG, "received Cmd %d but channel is not ready.", Cmd);
426
427 return TRUE;
428}
429
430static int wts_write_variable_uint(wStream* s, UINT32 val)
431{
432 int cb = 0;
433
434 WINPR_ASSERT(s);
435 if (val <= 0xFF)
436 {
437 cb = 0;
438 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, val));
439 }
440 else if (val <= 0xFFFF)
441 {
442 cb = 1;
443 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, val));
444 }
445 else
446 {
447 cb = 2;
448 Stream_Write_UINT32(s, val);
449 }
450
451 return cb;
452}
453
454static void wts_write_drdynvc_header(wStream* s, BYTE Cmd, UINT32 ChannelId)
455{
456 WINPR_ASSERT(s);
457
458 BYTE* bm = Stream_PointerAs(s, BYTE);
459 Stream_Seek_UINT8(s);
460 const int cbChId = wts_write_variable_uint(s, ChannelId);
461 *bm = (((Cmd & 0x0F) << 4) | cbChId) & 0xFF;
462}
463
464static BOOL wts_write_drdynvc_create_request(wStream* s, UINT32 ChannelId, const char* ChannelName)
465{
466 size_t len = 0;
467
468 WINPR_ASSERT(s);
469 WINPR_ASSERT(ChannelName);
470
471 wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId);
472 len = strlen(ChannelName) + 1;
473
474 if (!Stream_EnsureRemainingCapacity(s, len))
475 return FALSE;
476
477 Stream_Write(s, ChannelName, len);
478 return TRUE;
479}
480
481static BOOL WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId, const BYTE* data,
482 size_t s, UINT32 flags, size_t t)
483{
484 BOOL ret = TRUE;
485 size_t size = s;
486 const size_t totalSize = t;
487
488 WINPR_ASSERT(channel);
489 WINPR_ASSERT(channel->vcm);
490 WINPR_UNUSED(channelId);
491
492 if (channel->channelFlags & CHANNEL_OPTION_SHOW_PROTOCOL)
493 {
494 BOOL firstPass = TRUE;
495
496 while (size)
497 {
498 const UINT32 payloadLen = (size > CHANNEL_CHUNK_LENGTH)
499 ? CHANNEL_CHUNK_LENGTH
500 : WINPR_ASSERTING_INT_CAST(UINT32, size);
501 size -= payloadLen;
502
503 /* here we skip other flags than CHANNEL_FLAG_FIRST and CHANNEL_FLAG_LAST
504 * as it's the only ones treated by ChannelPduTracker.
505 */
506 UINT32 newFlags = 0;
507 if (firstPass)
508 {
509 firstPass = FALSE;
510 if (flags & CHANNEL_FLAG_FIRST)
511 newFlags = CHANNEL_FLAG_FIRST;
512 }
513
514 if (!size && (flags & CHANNEL_FLAG_LAST))
515 newFlags |= CHANNEL_FLAG_LAST;
516
517 const CHANNEL_PDU_HEADER header = {
518 .length = payloadLen,
519 .flags = newFlags,
520 };
521
522 if (!wts_queue_receive_data(channel, (const BYTE*)&header, sizeof(header), data,
523 payloadLen))
524 return FALSE;
525
526 data += payloadLen;
527 }
528 return TRUE;
529 }
530
531 if ((flags & CHANNEL_FLAG_FIRST) != 0)
532 {
533 Stream_ResetPosition(channel->receiveData);
534 }
535
536 if (!Stream_EnsureRemainingCapacity(channel->receiveData, size))
537 return FALSE;
538
539 Stream_Write(channel->receiveData, data, size);
540
541 if ((flags & CHANNEL_FLAG_LAST) != 0)
542 {
543 if (Stream_GetPosition(channel->receiveData) != totalSize)
544 return FALSE;
545
546 if (channel == channel->vcm->drdynvc_channel)
547 {
548 ret = wts_read_drdynvc_pdu(channel);
549 }
550 else
551 {
552 const size_t pos = Stream_GetPosition(channel->receiveData);
553 if (pos > UINT32_MAX)
554 ret = FALSE;
555 else
556 ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData), pos,
557 nullptr, 0);
558 }
559
560 Stream_ResetPosition(channel->receiveData);
561 }
562 else if (Stream_GetPosition(channel->receiveData) >= totalSize)
563 return FALSE;
564
565 return ret;
566}
567
568static BOOL WTSReceiveChannelData(freerdp_peer* client, UINT16 channelId, const BYTE* data,
569 size_t size, UINT32 flags, size_t totalSize)
570{
571 rdpMcs* mcs = nullptr;
572
573 WINPR_ASSERT(client);
574 WINPR_ASSERT(client->context);
575 WINPR_ASSERT(client->context->rdp);
576
577 mcs = client->context->rdp->mcs;
578 WINPR_ASSERT(mcs);
579
580 for (UINT32 i = 0; i < mcs->channelCount; i++)
581 {
582 rdpMcsChannel* cur = &mcs->channels[i];
583 if (cur->ChannelId == channelId)
584 {
585 rdpPeerChannel* channel = (rdpPeerChannel*)cur->handle;
586
587 if (channel)
588 return WTSProcessChannelData(channel, channelId, data, size, flags, totalSize);
589 }
590 }
591
592 WLog_WARN(TAG, "unknown channelId %" PRIu16 " ignored", channelId);
593
594 return TRUE;
595}
596
597#if defined(WITH_FREERDP_DEPRECATED)
598void WTSVirtualChannelManagerGetFileDescriptor(HANDLE hServer, void** fds, int* fds_count)
599{
600 void* fd = nullptr;
602 WINPR_ASSERT(vcm);
603 WINPR_ASSERT(fds);
604 WINPR_ASSERT(fds_count);
605
606 fd = GetEventWaitObject(MessageQueue_Event(vcm->queue));
607
608 if (fd)
609 {
610 fds[*fds_count] = fd;
611 (*fds_count)++;
612 }
613
614#if 0
615
616 if (vcm->drdynvc_channel)
617 {
618 fd = GetEventWaitObject(vcm->drdynvc_channel->receiveEvent);
619
620 if (fd)
621 {
622 fds[*fds_count] = fd;
623 (*fds_count)++;
624 }
625 }
626
627#endif
628}
629#endif
630
631BOOL WTSVirtualChannelManagerOpen(HANDLE hServer)
632{
634
635 if (!vcm)
636 return FALSE;
637
638 if (vcm->drdynvc_state == DRDYNVC_STATE_NONE)
639 {
640 rdpPeerChannel* channel = nullptr;
641
642 /* Initialize drdynvc channel once and only once. */
643 vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
644 channel = (rdpPeerChannel*)WTSVirtualChannelOpen((HANDLE)vcm, WTS_CURRENT_SESSION,
645 DRDYNVC_SVC_CHANNEL_NAME);
646
647 if (channel)
648 {
649 BYTE capaBuffer[12] = WINPR_C_ARRAY_INIT;
650 wStream staticS = WINPR_C_ARRAY_INIT;
651 wStream* s = Stream_StaticInit(&staticS, capaBuffer, sizeof(capaBuffer));
652
653 vcm->drdynvc_channel = channel;
654 vcm->dvc_spoken_version = 1;
655 Stream_Write_UINT8(s, 0x50); /* Cmd=5 sp=0 cbId=0 */
656 Stream_Write_UINT8(s, 0x00); /* Pad */
657 Stream_Write_UINT16(s, 0x0001); /* Version */
658
659 /* TODO: shall implement version 2 and 3 */
660
661 const size_t pos = Stream_GetPosition(s);
662 WINPR_ASSERT(pos <= UINT32_MAX);
663 ULONG written = 0;
664 if (!WTSVirtualChannelWrite(channel, (PCHAR)capaBuffer, (UINT32)pos, &written))
665 return FALSE;
666 }
667 }
668
669 return TRUE;
670}
671
672BOOL WTSVirtualChannelManagerCheckFileDescriptorEx(HANDLE hServer, BOOL autoOpen)
673{
674 wMessage message = WINPR_C_ARRAY_INIT;
675 BOOL status = TRUE;
676 WTSVirtualChannelManager* vcm = nullptr;
677
678 if (!hServer || hServer == INVALID_HANDLE_VALUE)
679 return FALSE;
680
681 vcm = (WTSVirtualChannelManager*)hServer;
682
683 if (autoOpen)
684 {
685 if (!WTSVirtualChannelManagerOpen(hServer))
686 return FALSE;
687 }
688
689 while (MessageQueue_Peek(vcm->queue, &message, TRUE))
690 {
691 BYTE* buffer = nullptr;
692 UINT32 length = 0;
693 UINT16 channelId = 0;
694 channelId = (UINT16)(UINT_PTR)message.context;
695 buffer = (BYTE*)message.wParam;
696 length = (UINT32)(UINT_PTR)message.lParam;
697
698 WINPR_ASSERT(vcm->client);
699 WINPR_ASSERT(vcm->client->SendChannelData);
700 if (!vcm->client->SendChannelData(vcm->client, channelId, buffer, length))
701 {
702 status = FALSE;
703 }
704
705 free(buffer);
706
707 if (!status)
708 break;
709 }
710
711 return status;
712}
713
714BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer)
715{
716 return WTSVirtualChannelManagerCheckFileDescriptorEx(hServer, TRUE);
717}
718
719HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer)
720{
722 WINPR_ASSERT(vcm);
723 return MessageQueue_Event(vcm->queue);
724}
725
726static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs, const char* channel_name)
727{
728 if (!mcs || !channel_name || !strnlen(channel_name, CHANNEL_NAME_LEN + 1))
729 return nullptr;
730
731 for (UINT32 index = 0; index < mcs->channelCount; index++)
732 {
733 rdpMcsChannel* mchannel = &mcs->channels[index];
734 if (mchannel->joined)
735 {
736 if (_strnicmp(mchannel->Name, channel_name, CHANNEL_NAME_LEN + 1) == 0)
737 return mchannel;
738 }
739 }
740
741 return nullptr;
742}
743
744static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs, const UINT16 channel_id)
745{
746 if (!mcs || !channel_id)
747 return nullptr;
748
749 WINPR_ASSERT(mcs->channels);
750 for (UINT32 index = 0; index < mcs->channelCount; index++)
751 {
752 rdpMcsChannel* mchannel = &mcs->channels[index];
753 if (mchannel->joined)
754 {
755 if (mchannel->ChannelId == channel_id)
756 return &mcs->channels[index];
757 }
758 }
759
760 return nullptr;
761}
762
763BOOL WTSIsChannelJoinedByName(freerdp_peer* client, const char* channel_name)
764{
765 if (!client || !client->context || !client->context->rdp)
766 return FALSE;
767
768 return (wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) != nullptr);
769}
770
771BOOL WTSIsChannelJoinedById(freerdp_peer* client, UINT16 channel_id)
772{
773 if (!client || !client->context || !client->context->rdp)
774 return FALSE;
775
776 return (wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id) != nullptr);
777}
778
779BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name)
780{
782
783 if (!vcm || !vcm->rdp)
784 return FALSE;
785
786 return (wts_get_joined_channel_by_name(vcm->rdp->mcs, name) != nullptr);
787}
788
789BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer)
790{
792 WINPR_ASSERT(vcm);
793 return vcm->drdynvc_state;
794}
795
796void WTSVirtualChannelManagerSetDVCCreationCallback(HANDLE hServer, psDVCCreationStatusCallback cb,
797 void* userdata)
798{
799 WTSVirtualChannelManager* vcm = hServer;
800
801 WINPR_ASSERT(vcm);
802
803 vcm->dvc_creation_status = cb;
804 vcm->dvc_creation_status_userdata = userdata;
805}
806
807UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name)
808{
809 rdpMcsChannel* channel = nullptr;
810
811 WINPR_ASSERT(channel_name);
812 if (!client || !client->context || !client->context->rdp)
813 return 0;
814
815 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
816
817 if (!channel)
818 return 0;
819
820 return channel->ChannelId;
821}
822
823UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle)
824{
825 rdpPeerChannel* channel = hChannelHandle;
826
827 WINPR_ASSERT(channel);
828
829 return channel->channelId;
830}
831
832BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle)
833{
834 rdpMcsChannel* channel = nullptr;
835
836 WINPR_ASSERT(channel_name);
837 if (!client || !client->context || !client->context->rdp)
838 return FALSE;
839
840 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
841
842 if (!channel)
843 return FALSE;
844
845 channel->handle = handle;
846 return TRUE;
847}
848
849BOOL WTSChannelSetHandleById(freerdp_peer* client, UINT16 channel_id, void* handle)
850{
851 rdpMcsChannel* channel = nullptr;
852
853 if (!client || !client->context || !client->context->rdp)
854 return FALSE;
855
856 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
857
858 if (!channel)
859 return FALSE;
860
861 channel->handle = handle;
862 return TRUE;
863}
864
865void* WTSChannelGetHandleByName(freerdp_peer* client, const char* channel_name)
866{
867 rdpMcsChannel* channel = nullptr;
868
869 WINPR_ASSERT(channel_name);
870 if (!client || !client->context || !client->context->rdp)
871 return nullptr;
872
873 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
874
875 if (!channel)
876 return nullptr;
877
878 return channel->handle;
879}
880
881void* WTSChannelGetHandleById(freerdp_peer* client, UINT16 channel_id)
882{
883 rdpMcsChannel* channel = nullptr;
884
885 if (!client || !client->context || !client->context->rdp)
886 return nullptr;
887
888 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
889
890 if (!channel)
891 return nullptr;
892
893 return channel->handle;
894}
895
896const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id)
897{
898 rdpMcsChannel* channel = nullptr;
899
900 if (!client || !client->context || !client->context->rdp)
901 return nullptr;
902
903 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
904
905 if (!channel)
906 return nullptr;
907
908 return (const char*)channel->Name;
909}
910
911char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count)
912{
913 rdpMcs* mcs = nullptr;
914 char** names = nullptr;
915
916 if (!client || !client->context || !count)
917 return nullptr;
918
919 WINPR_ASSERT(client->context->rdp);
920 mcs = client->context->rdp->mcs;
921 WINPR_ASSERT(mcs);
922 *count = mcs->channelCount;
923
924 names = (char**)calloc(mcs->channelCount, sizeof(char*));
925 if (!names)
926 return nullptr;
927
928 for (UINT32 index = 0; index < mcs->channelCount; index++)
929 {
930 rdpMcsChannel* mchannel = &mcs->channels[index];
931 names[index] = mchannel->Name;
932 }
933
934 return names;
935}
936
937INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id)
938{
939 rdpMcsChannel* channel = nullptr;
940
941 if (!client || !client->context || !client->context->rdp)
942 return -1;
943
944 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
945
946 if (!channel)
947 return -1;
948
949 return (INT64)channel->options;
950}
951
952BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(WINPR_ATTR_UNUSED LPWSTR pTargetServerName,
953 WINPR_ATTR_UNUSED ULONG TargetLogonId,
954 WINPR_ATTR_UNUSED BYTE HotkeyVk,
955 WINPR_ATTR_UNUSED USHORT HotkeyModifiers)
956{
957 WLog_ERR("TODO", "TODO: implement");
958 return FALSE;
959}
960
961BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionA(WINPR_ATTR_UNUSED LPSTR pTargetServerName,
962 WINPR_ATTR_UNUSED ULONG TargetLogonId,
963 WINPR_ATTR_UNUSED BYTE HotkeyVk,
964 WINPR_ATTR_UNUSED USHORT HotkeyModifiers)
965{
966 WLog_ERR("TODO", "TODO: implement");
967 return FALSE;
968}
969
970BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExW(WINPR_ATTR_UNUSED LPWSTR pTargetServerName,
971 WINPR_ATTR_UNUSED ULONG TargetLogonId,
972 WINPR_ATTR_UNUSED BYTE HotkeyVk,
973 WINPR_ATTR_UNUSED USHORT HotkeyModifiers,
974 WINPR_ATTR_UNUSED DWORD flags)
975{
976 WLog_ERR("TODO", "TODO: implement");
977 return FALSE;
978}
979
980BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExA(WINPR_ATTR_UNUSED LPSTR pTargetServerName,
981 WINPR_ATTR_UNUSED ULONG TargetLogonId,
982 WINPR_ATTR_UNUSED BYTE HotkeyVk,
983 WINPR_ATTR_UNUSED USHORT HotkeyModifiers,
984 WINPR_ATTR_UNUSED DWORD flags)
985{
986 WLog_ERR("TODO", "TODO: implement");
987 return FALSE;
988}
989
990BOOL WINAPI FreeRDP_WTSStopRemoteControlSession(WINPR_ATTR_UNUSED ULONG LogonId)
991{
992 WLog_ERR("TODO", "TODO: implement");
993 return FALSE;
994}
995
996BOOL WINAPI FreeRDP_WTSConnectSessionW(WINPR_ATTR_UNUSED ULONG LogonId,
997 WINPR_ATTR_UNUSED ULONG TargetLogonId,
998 WINPR_ATTR_UNUSED PWSTR pPassword,
999 WINPR_ATTR_UNUSED BOOL bWait)
1000{
1001 WLog_ERR("TODO", "TODO: implement");
1002 return FALSE;
1003}
1004
1005BOOL WINAPI FreeRDP_WTSConnectSessionA(WINPR_ATTR_UNUSED ULONG LogonId,
1006 WINPR_ATTR_UNUSED ULONG TargetLogonId,
1007 WINPR_ATTR_UNUSED PSTR pPassword,
1008 WINPR_ATTR_UNUSED BOOL bWait)
1009{
1010 WLog_ERR("TODO", "TODO: implement");
1011 return FALSE;
1012}
1013
1014BOOL WINAPI FreeRDP_WTSEnumerateServersW(WINPR_ATTR_UNUSED LPWSTR pDomainName,
1015 WINPR_ATTR_UNUSED DWORD Reserved,
1016 WINPR_ATTR_UNUSED DWORD Version,
1017 WINPR_ATTR_UNUSED PWTS_SERVER_INFOW* ppServerInfo,
1018 WINPR_ATTR_UNUSED DWORD* pCount)
1019{
1020 WLog_ERR("TODO", "TODO: implement");
1021 return FALSE;
1022}
1023
1024BOOL WINAPI FreeRDP_WTSEnumerateServersA(WINPR_ATTR_UNUSED LPSTR pDomainName,
1025 WINPR_ATTR_UNUSED DWORD Reserved,
1026 WINPR_ATTR_UNUSED DWORD Version,
1027 WINPR_ATTR_UNUSED PWTS_SERVER_INFOA* ppServerInfo,
1028 WINPR_ATTR_UNUSED DWORD* pCount)
1029{
1030 WLog_ERR("TODO", "TODO: implement");
1031 return FALSE;
1032}
1033
1034HANDLE WINAPI FreeRDP_WTSOpenServerW(WINPR_ATTR_UNUSED LPWSTR pServerName)
1035{
1036 WLog_ERR("TODO", "TODO: implement");
1037 return INVALID_HANDLE_VALUE;
1038}
1039
1040static void wts_virtual_channel_manager_free_message(void* obj)
1041{
1042 wMessage* msg = (wMessage*)obj;
1043
1044 if (msg)
1045 {
1046 BYTE* buffer = (BYTE*)msg->wParam;
1047
1048 if (buffer)
1049 free(buffer);
1050 }
1051}
1052
1053static void channel_free(rdpPeerChannel* channel)
1054{
1055 server_channel_common_free(channel);
1056}
1057
1058static void array_channel_free(void* ptr)
1059{
1060 rdpPeerChannel* channel = ptr;
1061 channel_free(channel);
1062}
1063
1064static BOOL dynChannelMatch(const void* v1, const void* v2)
1065{
1066 const UINT32* p1 = (const UINT32*)v1;
1067 const UINT32* p2 = (const UINT32*)v2;
1068 return *p1 == *p2;
1069}
1070
1071static UINT32 channelId_Hash(const void* key)
1072{
1073 const UINT32* v = (const UINT32*)key;
1074 return *v;
1075}
1076
1077static void clearHandles(void)
1078{
1079 HashTable_Free(g_ServerHandles);
1080 g_ServerHandles = nullptr;
1081}
1082
1083static BOOL CALLBACK initializeHandles(WINPR_ATTR_UNUSED PINIT_ONCE once,
1084 WINPR_ATTR_UNUSED PVOID param,
1085 WINPR_ATTR_UNUSED PVOID* context)
1086{
1087 WINPR_ASSERT(g_ServerHandles == nullptr);
1088 g_ServerHandles = HashTable_New(TRUE);
1089 (void)winpr_atexit(clearHandles);
1090 return g_ServerHandles != nullptr;
1091}
1092
1093static bool setup(void)
1094{
1095 return InitOnceExecuteOnce(&g_HandleInitializer, initializeHandles, nullptr, nullptr);
1096}
1097
1098static void wtsCloseVCM(WTSVirtualChannelManager* vcm, bool closeDrdynvc)
1099{
1100 WINPR_ASSERT(vcm);
1101
1102 HashTable_Lock(g_ServerHandles);
1103
1104/* clang analyzer does not like the check for INVALID_HANDLE_VALUE and considers the path not taken,
1105 * leading to false positives on memory leaks. */
1106#ifdef __clang_analyzer__
1107 const BOOL valid = vcm != nullptr;
1108#else
1109 const BOOL valid = (vcm != nullptr) && (vcm != INVALID_HANDLE_VALUE);
1110#endif
1111 if (valid)
1112 {
1113 HashTable_Remove(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId);
1114
1115 HashTable_Free(vcm->dynamicVirtualChannels);
1116
1117 if (vcm->drdynvc_channel)
1118 {
1119 if (closeDrdynvc)
1120 (void)WTSVirtualChannelClose(vcm->drdynvc_channel);
1121 vcm->drdynvc_channel = nullptr;
1122 }
1123
1124 MessageQueue_Free(vcm->queue);
1125 free(vcm);
1126 }
1127 HashTable_Unlock(g_ServerHandles);
1128}
1129
1130HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName)
1131{
1132 wObject queueCallbacks = WINPR_C_ARRAY_INIT;
1133
1134 rdpContext* context = WINPR_PACKED_ALIGN_CAST(rdpContext*, pServerName);
1135
1136 if (!setup() || !context)
1137 return INVALID_HANDLE_VALUE;
1138
1139 freerdp_peer* client = context->peer;
1140
1141 if (!client)
1142 {
1143 SetLastError(ERROR_INVALID_DATA);
1144 return INVALID_HANDLE_VALUE;
1145 }
1146
1147 WTSVirtualChannelManager* vcm = calloc(1, sizeof(WTSVirtualChannelManager));
1148
1149 if (!vcm)
1150 goto fail;
1151
1152 vcm->client = client;
1153 vcm->rdp = context->rdp;
1154
1155 queueCallbacks.fnObjectFree = wts_virtual_channel_manager_free_message;
1156 vcm->queue = MessageQueue_New(&queueCallbacks);
1157
1158 if (!vcm->queue)
1159 goto fail;
1160
1161 vcm->dvc_channel_id_seq = 0;
1162 vcm->dynamicVirtualChannels = HashTable_New(TRUE);
1163
1164 if (!vcm->dynamicVirtualChannels)
1165 goto fail;
1166
1167 if (!HashTable_SetHashFunction(vcm->dynamicVirtualChannels, channelId_Hash))
1168 goto fail;
1169
1170 {
1171 wObject* obj = HashTable_ValueObject(vcm->dynamicVirtualChannels);
1172 WINPR_ASSERT(obj);
1173 obj->fnObjectFree = array_channel_free;
1174
1175 obj = HashTable_KeyObject(vcm->dynamicVirtualChannels);
1176 obj->fnObjectEquals = dynChannelMatch;
1177 }
1178 client->ReceiveChannelData = WTSReceiveChannelData;
1179 {
1180 HashTable_Lock(g_ServerHandles);
1181 vcm->SessionId = g_SessionId++;
1182 const BOOL rc =
1183 HashTable_Insert(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId, (void*)vcm);
1184 HashTable_Unlock(g_ServerHandles);
1185 if (!rc)
1186 goto fail;
1187 }
1188
1189 HANDLE hServer = (HANDLE)vcm;
1190 return hServer;
1191
1192fail:
1193 wtsCloseVCM(vcm, false);
1194 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1195 return INVALID_HANDLE_VALUE;
1196}
1197
1198HANDLE WINAPI FreeRDP_WTSOpenServerExW(WINPR_ATTR_UNUSED LPWSTR pServerName)
1199{
1200 WLog_ERR("TODO", "TODO: implement");
1201 return INVALID_HANDLE_VALUE;
1202}
1203
1204HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName)
1205{
1206 return FreeRDP_WTSOpenServerA(pServerName);
1207}
1208
1209VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer)
1210{
1212 wtsCloseVCM(vcm, true);
1213}
1214
1215BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(WINPR_ATTR_UNUSED HANDLE hServer,
1216 WINPR_ATTR_UNUSED DWORD Reserved,
1217 WINPR_ATTR_UNUSED DWORD Version,
1218 WINPR_ATTR_UNUSED PWTS_SESSION_INFOW* ppSessionInfo,
1219 WINPR_ATTR_UNUSED DWORD* pCount)
1220{
1221 WLog_ERR("TODO", "TODO: implement");
1222 return FALSE;
1223}
1224
1225BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(WINPR_ATTR_UNUSED HANDLE hServer,
1226 WINPR_ATTR_UNUSED DWORD Reserved,
1227 WINPR_ATTR_UNUSED DWORD Version,
1228 WINPR_ATTR_UNUSED PWTS_SESSION_INFOA* ppSessionInfo,
1229 WINPR_ATTR_UNUSED DWORD* pCount)
1230{
1231 WLog_ERR("TODO", "TODO: implement");
1232 return FALSE;
1233}
1234
1235BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(WINPR_ATTR_UNUSED HANDLE hServer,
1236 WINPR_ATTR_UNUSED DWORD* pLevel,
1237 WINPR_ATTR_UNUSED DWORD Filter,
1238 WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1W* ppSessionInfo,
1239 WINPR_ATTR_UNUSED DWORD* pCount)
1240{
1241 WLog_ERR("TODO", "TODO: implement");
1242 return FALSE;
1243}
1244
1245BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(WINPR_ATTR_UNUSED HANDLE hServer,
1246 WINPR_ATTR_UNUSED DWORD* pLevel,
1247 WINPR_ATTR_UNUSED DWORD Filter,
1248 WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1A* ppSessionInfo,
1249 WINPR_ATTR_UNUSED DWORD* pCount)
1250{
1251 WLog_ERR("TODO", "TODO: implement");
1252 return FALSE;
1253}
1254
1255BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(WINPR_ATTR_UNUSED HANDLE hServer,
1256 WINPR_ATTR_UNUSED DWORD Reserved,
1257 WINPR_ATTR_UNUSED DWORD Version,
1258 WINPR_ATTR_UNUSED PWTS_PROCESS_INFOW* ppProcessInfo,
1259 WINPR_ATTR_UNUSED DWORD* pCount)
1260{
1261 WLog_ERR("TODO", "TODO: implement");
1262 return FALSE;
1263}
1264
1265BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(WINPR_ATTR_UNUSED HANDLE hServer,
1266 WINPR_ATTR_UNUSED DWORD Reserved,
1267 WINPR_ATTR_UNUSED DWORD Version,
1268 WINPR_ATTR_UNUSED PWTS_PROCESS_INFOA* ppProcessInfo,
1269 WINPR_ATTR_UNUSED DWORD* pCount)
1270{
1271 WLog_ERR("TODO", "TODO: implement");
1272 return FALSE;
1273}
1274
1275BOOL WINAPI FreeRDP_WTSTerminateProcess(WINPR_ATTR_UNUSED HANDLE hServer,
1276 WINPR_ATTR_UNUSED DWORD ProcessId,
1277 WINPR_ATTR_UNUSED DWORD ExitCode)
1278{
1279 WLog_ERR("TODO", "TODO: implement");
1280 return FALSE;
1281}
1282
1283BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(WINPR_ATTR_UNUSED HANDLE hServer,
1284 WINPR_ATTR_UNUSED DWORD SessionId,
1285 WINPR_ATTR_UNUSED WTS_INFO_CLASS WTSInfoClass,
1286 WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
1287 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1288{
1289 WLog_ERR("TODO", "TODO: implement");
1290 return FALSE;
1291}
1292
1293BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1294 WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
1295 DWORD* pBytesReturned)
1296{
1297 DWORD BytesReturned = 0;
1298 WTSVirtualChannelManager* vcm = nullptr;
1299 vcm = (WTSVirtualChannelManager*)hServer;
1300
1301 if (!vcm)
1302 return FALSE;
1303
1304 if (WTSInfoClass == WTSSessionId)
1305 {
1306 ULONG* pBuffer = nullptr;
1307 BytesReturned = sizeof(ULONG);
1308 pBuffer = (ULONG*)malloc(sizeof(BytesReturned));
1309
1310 if (!pBuffer)
1311 {
1312 SetLastError(g_err_oom);
1313 return FALSE;
1314 }
1315
1316 *pBuffer = vcm->SessionId;
1317 *ppBuffer = (LPSTR)pBuffer;
1318 *pBytesReturned = BytesReturned;
1319 return TRUE;
1320 }
1321
1322 return FALSE;
1323}
1324
1325BOOL WINAPI FreeRDP_WTSQueryUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
1326 WINPR_ATTR_UNUSED LPWSTR pUserName,
1327 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1328 WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
1329 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1330{
1331 WLog_ERR("TODO", "TODO: implement");
1332 return FALSE;
1333}
1334
1335BOOL WINAPI FreeRDP_WTSQueryUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
1336 WINPR_ATTR_UNUSED LPSTR pUserName,
1337 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1338 WINPR_ATTR_UNUSED LPSTR* ppBuffer,
1339 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1340{
1341 WLog_ERR("TODO", "TODO: implement");
1342 return FALSE;
1343}
1344
1345BOOL WINAPI FreeRDP_WTSSetUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
1346 WINPR_ATTR_UNUSED LPWSTR pUserName,
1347 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1348 WINPR_ATTR_UNUSED LPWSTR pBuffer,
1349 WINPR_ATTR_UNUSED DWORD DataLength)
1350{
1351 WLog_ERR("TODO", "TODO: implement");
1352 return FALSE;
1353}
1354
1355BOOL WINAPI FreeRDP_WTSSetUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
1356 WINPR_ATTR_UNUSED LPSTR pUserName,
1357 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1358 WINPR_ATTR_UNUSED LPSTR pBuffer,
1359 WINPR_ATTR_UNUSED DWORD DataLength)
1360{
1361 WLog_ERR("TODO", "TODO: implement");
1362 return FALSE;
1363}
1364
1365BOOL WINAPI
1366FreeRDP_WTSSendMessageW(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1367 WINPR_ATTR_UNUSED LPWSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
1368 WINPR_ATTR_UNUSED LPWSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
1369 WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
1370 WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
1371{
1372 WLog_ERR("TODO", "TODO: implement");
1373 return FALSE;
1374}
1375
1376BOOL WINAPI
1377FreeRDP_WTSSendMessageA(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1378 WINPR_ATTR_UNUSED LPSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
1379 WINPR_ATTR_UNUSED LPSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
1380 WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
1381 WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
1382{
1383 WLog_ERR("TODO", "TODO: implement");
1384 return FALSE;
1385}
1386
1387BOOL WINAPI FreeRDP_WTSDisconnectSession(WINPR_ATTR_UNUSED HANDLE hServer,
1388 WINPR_ATTR_UNUSED DWORD SessionId,
1389 WINPR_ATTR_UNUSED BOOL bWait)
1390{
1391 WLog_ERR("TODO", "TODO: implement");
1392 return FALSE;
1393}
1394
1395BOOL WINAPI FreeRDP_WTSLogoffSession(WINPR_ATTR_UNUSED HANDLE hServer,
1396 WINPR_ATTR_UNUSED DWORD SessionId,
1397 WINPR_ATTR_UNUSED BOOL bWait)
1398{
1399 WLog_ERR("TODO", "TODO: implement");
1400 return FALSE;
1401}
1402
1403BOOL WINAPI FreeRDP_WTSShutdownSystem(WINPR_ATTR_UNUSED HANDLE hServer,
1404 WINPR_ATTR_UNUSED DWORD ShutdownFlag)
1405{
1406 WLog_ERR("TODO", "TODO: implement");
1407 return FALSE;
1408}
1409
1410BOOL WINAPI FreeRDP_WTSWaitSystemEvent(WINPR_ATTR_UNUSED HANDLE hServer,
1411 WINPR_ATTR_UNUSED DWORD EventMask,
1412 WINPR_ATTR_UNUSED DWORD* pEventFlags)
1413{
1414 WLog_ERR("TODO", "TODO: implement");
1415 return FALSE;
1416}
1417
1418static void peer_channel_queue_free_message(void* obj)
1419{
1420 wMessage* msg = (wMessage*)obj;
1421 if (!msg)
1422 return;
1423
1424 free(msg->context);
1425 msg->context = nullptr;
1426}
1427
1428static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* client,
1429 UINT32 ChannelId, UINT16 index, UINT16 type, size_t chunkSize,
1430 const char* name, UINT32 flags)
1431{
1432 wObject queueCallbacks = WINPR_C_ARRAY_INIT;
1433 queueCallbacks.fnObjectFree = peer_channel_queue_free_message;
1434
1435 rdpPeerChannel* channel =
1436 server_channel_common_new(client, index, ChannelId, chunkSize, &queueCallbacks, name);
1437
1438 WINPR_ASSERT(vcm);
1439 WINPR_ASSERT(client);
1440
1441 if (!channel)
1442 goto fail;
1443
1444 channel->vcm = vcm;
1445 channel->channelType = type;
1446 channel->creationStatus =
1447 (type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS;
1448 channel->channelFlags = flags;
1449
1450 return channel;
1451fail:
1452 channel_free(channel);
1453 return nullptr;
1454}
1455
1456static HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenStatic(HANDLE hServer,
1457 WINPR_ATTR_UNUSED DWORD SessionId,
1458 LPSTR pVirtualName, UINT32 Flags)
1459{
1461 if (!vcm)
1462 {
1463 SetLastError(ERROR_INVALID_DATA);
1464 return nullptr;
1465 }
1466
1467 freerdp_peer* client = vcm->client;
1468 WINPR_ASSERT(client);
1469
1470 rdpContext* context = client->context;
1471 WINPR_ASSERT(context);
1472 WINPR_ASSERT(context->rdp);
1473 WINPR_ASSERT(context->settings);
1474
1475 rdpMcs* mcs = context->rdp->mcs;
1476 WINPR_ASSERT(mcs);
1477
1478 size_t length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1);
1479 if (length > CHANNEL_NAME_LEN)
1480 {
1481 SetLastError(ERROR_NOT_FOUND);
1482 return nullptr;
1483 }
1484
1485 rdpMcsChannel* joined_channel = nullptr;
1486 UINT32 index = 0;
1487 for (; index < mcs->channelCount; index++)
1488 {
1489 rdpMcsChannel* mchannel = &mcs->channels[index];
1490 if (mchannel->joined && (strncmp(mchannel->Name, pVirtualName, length) == 0))
1491 {
1492 joined_channel = mchannel;
1493 break;
1494 }
1495 }
1496
1497 if (!joined_channel)
1498 {
1499 SetLastError(ERROR_NOT_FOUND);
1500 return nullptr;
1501 }
1502
1503 rdpPeerChannel* channel = (rdpPeerChannel*)joined_channel->handle;
1504 if (!channel)
1505 {
1506 const UINT32 VCChunkSize =
1507 freerdp_settings_get_uint32(context->settings, FreeRDP_VCChunkSize);
1508
1509 WINPR_ASSERT(index <= UINT16_MAX);
1510 channel = channel_new(vcm, client, joined_channel->ChannelId, (UINT16)index,
1511 RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName, Flags);
1512
1513 if (!channel)
1514 goto fail;
1515
1516 joined_channel->handle = channel;
1517 }
1518
1519 HANDLE hChannelHandle = (HANDLE)channel;
1520 return hChannelHandle;
1521fail:
1522 channel_free(channel);
1523 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1524 return nullptr;
1525}
1526
1527HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
1528{
1529 return FreeRDP_WTSVirtualChannelOpenStatic(hServer, SessionId, pVirtualName, 0);
1530}
1531
1532HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
1533{
1534 wStream* s = nullptr;
1535 rdpPeerChannel* channel = nullptr;
1536 BOOL joined = FALSE;
1537 ULONG written = 0;
1538
1539 if (!setup())
1540 return nullptr;
1541
1542 if (SessionId == WTS_CURRENT_SESSION)
1543 return nullptr;
1544
1545 HashTable_Lock(g_ServerHandles);
1546 WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)HashTable_GetItemValue(
1547 g_ServerHandles, (void*)(UINT_PTR)SessionId);
1548
1549 if (!vcm)
1550 goto end;
1551
1552 if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC))
1553 {
1554 HashTable_Unlock(g_ServerHandles);
1555 return FreeRDP_WTSVirtualChannelOpenStatic((HANDLE)vcm, SessionId, pVirtualName, flags);
1556 }
1557
1558 freerdp_peer* client = vcm->client;
1559 WINPR_ASSERT(client);
1560 WINPR_ASSERT(client->context);
1561 WINPR_ASSERT(client->context->rdp);
1562
1563 rdpMcs* mcs = client->context->rdp->mcs;
1564 WINPR_ASSERT(mcs);
1565
1566 for (UINT32 index = 0; index < mcs->channelCount; index++)
1567 {
1568 rdpMcsChannel* mchannel = &mcs->channels[index];
1569 if (mchannel->joined &&
1570 (strncmp(mchannel->Name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
1571 {
1572 joined = TRUE;
1573 break;
1574 }
1575 }
1576
1577 if (!joined)
1578 {
1579 SetLastError(ERROR_NOT_FOUND);
1580 goto end;
1581 }
1582
1583 if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY))
1584 {
1585 SetLastError(ERROR_NOT_READY);
1586 goto end;
1587 }
1588
1589 WINPR_ASSERT(client);
1590 WINPR_ASSERT(client->context);
1591 WINPR_ASSERT(client->context->settings);
1592
1593 const UINT32 VCChunkSize =
1594 freerdp_settings_get_uint32(client->context->settings, FreeRDP_VCChunkSize);
1595 channel =
1596 channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName, flags);
1597
1598 if (!channel)
1599 {
1600 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1601 goto end;
1602 }
1603
1604 const LONG hdl = InterlockedIncrement(&vcm->dvc_channel_id_seq);
1605 channel->channelId = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
1606
1607 if (!HashTable_Insert(vcm->dynamicVirtualChannels, &channel->channelId, channel))
1608 {
1609 channel_free(channel);
1610 channel = nullptr;
1611 goto fail;
1612 }
1613 s = Stream_New(nullptr, 64);
1614
1615 if (!s)
1616 goto fail;
1617
1618 if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName))
1619 goto fail;
1620
1621 {
1622 const size_t pos = Stream_GetPosition(s);
1623 WINPR_ASSERT(pos <= UINT32_MAX);
1624 if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char), (UINT32)pos,
1625 &written))
1626 goto fail;
1627 }
1628
1629end:
1630 Stream_Free(s, TRUE);
1631 HashTable_Unlock(g_ServerHandles);
1632 return channel;
1633
1634fail:
1635 Stream_Free(s, TRUE);
1636 if (channel)
1637 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1638 HashTable_Unlock(g_ServerHandles);
1639
1640 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1641 return nullptr;
1642}
1643
1644BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
1645{
1646 wStream* s = nullptr;
1647 rdpMcs* mcs = nullptr;
1648
1649 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1650 BOOL ret = TRUE;
1651
1652 if (channel)
1653 {
1654 WTSVirtualChannelManager* vcm = channel->vcm;
1655
1656 WINPR_ASSERT(vcm);
1657 WINPR_ASSERT(vcm->client);
1658 WINPR_ASSERT(vcm->client->context);
1659 WINPR_ASSERT(vcm->client->context->rdp);
1660 mcs = vcm->client->context->rdp->mcs;
1661
1662 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1663 {
1664 if (channel->index < mcs->channelCount)
1665 {
1666 rdpMcsChannel* cur = &mcs->channels[channel->index];
1667 rdpPeerChannel* peerChannel = (rdpPeerChannel*)cur->handle;
1668 channel_free(peerChannel);
1669 cur->handle = nullptr;
1670 }
1671 }
1672 else
1673 {
1674 if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
1675 {
1676 ULONG written = 0;
1677 s = Stream_New(nullptr, 8);
1678
1679 if (!s)
1680 {
1681 WLog_ERR(TAG, "Stream_New failed!");
1682 ret = FALSE;
1683 }
1684 else
1685 {
1686 wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
1687
1688 const size_t pos = Stream_GetPosition(s);
1689 WINPR_ASSERT(pos <= UINT32_MAX);
1690 ret = WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char),
1691 (UINT32)pos, &written);
1692 Stream_Free(s, TRUE);
1693 }
1694 }
1695 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1696 }
1697 }
1698
1699 return ret;
1700}
1701
1702BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, WINPR_ATTR_UNUSED ULONG TimeOut,
1703 PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead)
1704{
1705 BYTE* buffer = nullptr;
1706 wMessage message = WINPR_C_ARRAY_INIT;
1707 wtsChannelMessage* messageCtx = nullptr;
1708 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1709
1710 WINPR_ASSERT(channel);
1711
1712 if (!MessageQueue_Peek(channel->queue, &message, FALSE))
1713 {
1714 SetLastError(ERROR_NO_DATA);
1715 *pBytesRead = 0;
1716 return FALSE;
1717 }
1718
1719 messageCtx = message.context;
1720
1721 if (messageCtx == nullptr)
1722 return FALSE;
1723
1724 buffer = (BYTE*)(messageCtx + 1);
1725 *pBytesRead = messageCtx->length - messageCtx->offset;
1726
1727 if (Buffer == nullptr || BufferSize == 0)
1728 {
1729 return TRUE;
1730 }
1731
1732 if (*pBytesRead > BufferSize)
1733 *pBytesRead = BufferSize;
1734
1735 CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
1736 messageCtx->offset += *pBytesRead;
1737
1738 if (messageCtx->offset >= messageCtx->length)
1739 {
1740 const int rc = MessageQueue_Peek(channel->queue, &message, TRUE);
1741 peer_channel_queue_free_message(&message);
1742 if (rc < 0)
1743 return FALSE;
1744 }
1745
1746 return TRUE;
1747}
1748
1749BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG uLength,
1750 PULONG pBytesWritten)
1751{
1752 wStream* s = nullptr;
1753 int cbLen = 0;
1754 int cbChId = 0;
1755 int first = 0;
1756 BYTE* buffer = nullptr;
1757 size_t totalWritten = 0;
1758 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1759 BOOL ret = FALSE;
1760
1761 if (!channel)
1762 return FALSE;
1763
1764 EnterCriticalSection(&channel->writeLock);
1765 WINPR_ASSERT(channel->vcm);
1766 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1767 {
1768 buffer = (BYTE*)malloc(uLength);
1769
1770 if (!buffer)
1771 {
1772 SetLastError(g_err_oom);
1773 goto fail;
1774 }
1775
1776 CopyMemory(buffer, Buffer, uLength);
1777 totalWritten = uLength;
1778 if (!wts_queue_send_item(channel, buffer, uLength))
1779 goto fail;
1780 }
1781 else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
1782 {
1783 DEBUG_DVC("drdynvc not ready");
1784 goto fail;
1785 }
1786 else
1787 {
1788 first = TRUE;
1789
1790 size_t Length = uLength;
1791 while (Length > 0)
1792 {
1793 s = Stream_New(nullptr, DVC_MAX_DATA_PDU_SIZE);
1794
1795 if (!s)
1796 {
1797 WLog_ERR(TAG, "Stream_New failed!");
1798 SetLastError(g_err_oom);
1799 goto fail;
1800 }
1801
1802 buffer = Stream_Buffer(s);
1803 Stream_Seek_UINT8(s);
1804 cbChId = wts_write_variable_uint(s, channel->channelId);
1805
1806 if (first && (Length > Stream_GetRemainingLength(s)))
1807 {
1808 cbLen = wts_write_variable_uint(s, WINPR_ASSERTING_INT_CAST(uint32_t, Length));
1809 buffer[0] = ((DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId) & 0xFF;
1810 }
1811 else
1812 {
1813 buffer[0] = ((DATA_PDU << 4) | cbChId) & 0xFF;
1814 }
1815
1816 first = FALSE;
1817 size_t written = Stream_GetRemainingLength(s);
1818
1819 if (written > Length)
1820 written = Length;
1821
1822 Stream_Write(s, Buffer, written);
1823 const size_t length = Stream_GetPosition(s);
1824 Stream_Free(s, FALSE);
1825 if (length > UINT32_MAX)
1826 goto fail;
1827 Length -= written;
1828 Buffer += written;
1829 totalWritten += written;
1830 if (!wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, (UINT32)length))
1831 goto fail;
1832 }
1833 }
1834
1835 if (pBytesWritten)
1836 *pBytesWritten = WINPR_ASSERTING_INT_CAST(uint32_t, totalWritten);
1837
1838 ret = TRUE;
1839fail:
1840 LeaveCriticalSection(&channel->writeLock);
1841 return ret;
1842}
1843
1844BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
1845{
1846 WLog_ERR("TODO", "TODO: implement");
1847 return TRUE;
1848}
1849
1850BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
1851{
1852 WLog_ERR("TODO", "TODO: implement");
1853 return TRUE;
1854}
1855
1856BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
1857 PVOID* ppBuffer, DWORD* pBytesReturned)
1858{
1859 void* pfd = nullptr;
1860 BOOL bval = 0;
1861 void* fds[10] = WINPR_C_ARRAY_INIT;
1862 HANDLE hEvent = nullptr;
1863 int fds_count = 0;
1864 BOOL status = FALSE;
1865 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1866
1867 WINPR_ASSERT(channel);
1868
1869 switch ((UINT32)WtsVirtualClass)
1870 {
1871 case WTSVirtualFileHandle:
1872 hEvent = MessageQueue_Event(channel->queue);
1873 pfd = GetEventWaitObject(hEvent);
1874
1875 if (pfd)
1876 {
1877 fds[fds_count] = pfd;
1878 (fds_count)++;
1879 }
1880
1881 *ppBuffer = malloc(sizeof(void*));
1882
1883 if (!*ppBuffer)
1884 {
1885 SetLastError(g_err_oom);
1886 }
1887 else
1888 {
1889 CopyMemory(*ppBuffer, (void*)&fds[0], sizeof(void*));
1890 *pBytesReturned = sizeof(void*);
1891 status = TRUE;
1892 }
1893
1894 break;
1895
1896 case WTSVirtualEventHandle:
1897 hEvent = MessageQueue_Event(channel->queue);
1898
1899 *ppBuffer = malloc(sizeof(HANDLE));
1900
1901 if (!*ppBuffer)
1902 {
1903 SetLastError(g_err_oom);
1904 }
1905 else
1906 {
1907 CopyMemory(*ppBuffer, (void*)&hEvent, sizeof(HANDLE));
1908 *pBytesReturned = sizeof(void*);
1909 status = TRUE;
1910 }
1911
1912 break;
1913
1914 case WTSVirtualChannelReady:
1915 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1916 {
1917 bval = TRUE;
1918 status = TRUE;
1919 }
1920 else
1921 {
1922 switch (channel->dvc_open_state)
1923 {
1924 case DVC_OPEN_STATE_NONE:
1925 bval = FALSE;
1926 status = TRUE;
1927 break;
1928
1929 case DVC_OPEN_STATE_SUCCEEDED:
1930 bval = TRUE;
1931 status = TRUE;
1932 break;
1933
1934 default:
1935 *ppBuffer = nullptr;
1936 *pBytesReturned = 0;
1937 return FALSE;
1938 }
1939 }
1940
1941 *ppBuffer = malloc(sizeof(BOOL));
1942
1943 if (!*ppBuffer)
1944 {
1945 SetLastError(g_err_oom);
1946 status = FALSE;
1947 }
1948 else
1949 {
1950 CopyMemory(*ppBuffer, &bval, sizeof(BOOL));
1951 *pBytesReturned = sizeof(BOOL);
1952 }
1953
1954 break;
1955 case WTSVirtualChannelOpenStatus:
1956 {
1957 INT32 value = channel->creationStatus;
1958 status = TRUE;
1959
1960 *ppBuffer = malloc(sizeof(value));
1961 if (!*ppBuffer)
1962 {
1963 SetLastError(g_err_oom);
1964 status = FALSE;
1965 }
1966 else
1967 {
1968 CopyMemory(*ppBuffer, &value, sizeof(value));
1969 *pBytesReturned = sizeof(value);
1970 }
1971 break;
1972 }
1973 default:
1974 break;
1975 }
1976
1977 return status;
1978}
1979
1980VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory)
1981{
1982 free(pMemory);
1983}
1984
1985BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
1986 WINPR_ATTR_UNUSED PVOID pMemory,
1987 WINPR_ATTR_UNUSED ULONG NumberOfEntries)
1988{
1989 WLog_ERR("TODO", "TODO: implement");
1990 return FALSE;
1991}
1992
1993BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
1994 WINPR_ATTR_UNUSED PVOID pMemory,
1995 WINPR_ATTR_UNUSED ULONG NumberOfEntries)
1996{
1997 WLog_ERR("TODO", "TODO: implement");
1998 return FALSE;
1999}
2000
2001BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd,
2002 WINPR_ATTR_UNUSED DWORD dwFlags)
2003{
2004 WLog_ERR("TODO", "TODO: implement");
2005 return FALSE;
2006}
2007
2008BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd)
2009{
2010 WLog_ERR("TODO", "TODO: implement");
2011 return FALSE;
2012}
2013
2014BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
2015 WINPR_ATTR_UNUSED HWND hWnd,
2016 WINPR_ATTR_UNUSED DWORD dwFlags)
2017{
2018 WLog_ERR("TODO", "TODO: implement");
2019 return FALSE;
2020}
2021
2022BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
2023 WINPR_ATTR_UNUSED HWND hWnd)
2024{
2025 WLog_ERR("TODO", "TODO: implement");
2026 return FALSE;
2027}
2028
2029BOOL WINAPI FreeRDP_WTSQueryUserToken(WINPR_ATTR_UNUSED ULONG SessionId,
2030 WINPR_ATTR_UNUSED PHANDLE phToken)
2031{
2032 WLog_ERR("TODO", "TODO: implement");
2033 return FALSE;
2034}
2035
2036BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(WINPR_ATTR_UNUSED HANDLE hServer,
2037 WINPR_ATTR_UNUSED DWORD* pLevel,
2038 WINPR_ATTR_UNUSED DWORD SessionId,
2039 WINPR_ATTR_UNUSED LPWSTR* ppProcessInfo,
2040 WINPR_ATTR_UNUSED DWORD* pCount)
2041{
2042 WLog_ERR("TODO", "TODO: implement");
2043 return FALSE;
2044}
2045
2046BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(WINPR_ATTR_UNUSED HANDLE hServer,
2047 WINPR_ATTR_UNUSED DWORD* pLevel,
2048 WINPR_ATTR_UNUSED DWORD SessionId,
2049 WINPR_ATTR_UNUSED LPSTR* ppProcessInfo,
2050 WINPR_ATTR_UNUSED DWORD* pCount)
2051{
2052 WLog_ERR("TODO", "TODO: implement");
2053 return FALSE;
2054}
2055
2056BOOL WINAPI FreeRDP_WTSEnumerateListenersW(WINPR_ATTR_UNUSED HANDLE hServer,
2057 WINPR_ATTR_UNUSED PVOID pReserved,
2058 WINPR_ATTR_UNUSED DWORD Reserved,
2059 WINPR_ATTR_UNUSED PWTSLISTENERNAMEW pListeners,
2060 WINPR_ATTR_UNUSED DWORD* pCount)
2061{
2062 WLog_ERR("TODO", "TODO: implement");
2063 return FALSE;
2064}
2065
2066BOOL WINAPI FreeRDP_WTSEnumerateListenersA(WINPR_ATTR_UNUSED HANDLE hServer,
2067 WINPR_ATTR_UNUSED PVOID pReserved,
2068 WINPR_ATTR_UNUSED DWORD Reserved,
2069 WINPR_ATTR_UNUSED PWTSLISTENERNAMEA pListeners,
2070 WINPR_ATTR_UNUSED DWORD* pCount)
2071{
2072 WLog_ERR("TODO", "TODO: implement");
2073 return FALSE;
2074}
2075
2076BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(WINPR_ATTR_UNUSED HANDLE hServer,
2077 WINPR_ATTR_UNUSED PVOID pReserved,
2078 WINPR_ATTR_UNUSED DWORD Reserved,
2079 WINPR_ATTR_UNUSED LPWSTR pListenerName,
2080 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer)
2081{
2082 WLog_ERR("TODO", "TODO: implement");
2083 return FALSE;
2084}
2085
2086BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(WINPR_ATTR_UNUSED HANDLE hServer,
2087 WINPR_ATTR_UNUSED PVOID pReserved,
2088 WINPR_ATTR_UNUSED DWORD Reserved,
2089 WINPR_ATTR_UNUSED LPSTR pListenerName,
2090 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer)
2091{
2092 WLog_ERR("TODO", "TODO: implement");
2093 return FALSE;
2094}
2095
2096BOOL WINAPI FreeRDP_WTSCreateListenerW(WINPR_ATTR_UNUSED HANDLE hServer,
2097 WINPR_ATTR_UNUSED PVOID pReserved,
2098 WINPR_ATTR_UNUSED DWORD Reserved,
2099 WINPR_ATTR_UNUSED LPWSTR pListenerName,
2100 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer,
2101 WINPR_ATTR_UNUSED DWORD flag)
2102{
2103 WLog_ERR("TODO", "TODO: implement");
2104 return FALSE;
2105}
2106
2107BOOL WINAPI FreeRDP_WTSCreateListenerA(WINPR_ATTR_UNUSED HANDLE hServer,
2108 WINPR_ATTR_UNUSED PVOID pReserved,
2109 WINPR_ATTR_UNUSED DWORD Reserved,
2110 WINPR_ATTR_UNUSED LPSTR pListenerName,
2111 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer,
2112 WINPR_ATTR_UNUSED DWORD flag)
2113{
2114 WLog_ERR("TODO", "TODO: implement");
2115 return FALSE;
2116}
2117
2118BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(
2119 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2120 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
2121 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2122 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
2123{
2124 WLog_ERR("TODO", "TODO: implement");
2125 return FALSE;
2126}
2127
2128BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(
2129 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2130 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
2131 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2132 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
2133{
2134 WLog_ERR("TODO", "TODO: implement");
2135 return FALSE;
2136}
2137
2138BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(
2139 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2140 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
2141 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2142 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
2143 WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
2144{
2145 WLog_ERR("TODO", "TODO: implement");
2146 return FALSE;
2147}
2148
2149BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(
2150 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2151 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
2152 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2153 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
2154 WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
2155{
2156 WLog_ERR("TODO", "TODO: implement");
2157 return FALSE;
2158}
2159
2160BOOL CDECL FreeRDP_WTSEnableChildSessions(WINPR_ATTR_UNUSED BOOL bEnable)
2161{
2162 WLog_ERR("TODO", "TODO: implement");
2163 return FALSE;
2164}
2165
2166BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(WINPR_ATTR_UNUSED PBOOL pbEnabled)
2167{
2168 WLog_ERR("TODO", "TODO: implement");
2169 return FALSE;
2170}
2171
2172BOOL CDECL FreeRDP_WTSGetChildSessionId(WINPR_ATTR_UNUSED PULONG pSessionId)
2173{
2174 WLog_ERR("TODO", "TODO: implement");
2175 return FALSE;
2176}
2177
2178DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(void)
2179{
2180 WLog_ERR("TODO", "TODO: implement");
2181 return 0xFFFFFFFF;
2182}
2183BOOL WINAPI FreeRDP_WTSLogoffUser(WINPR_ATTR_UNUSED HANDLE hServer)
2184{
2185 WLog_ERR("TODO", "TODO: implement");
2186 return FALSE;
2187}
2188
2189BOOL WINAPI FreeRDP_WTSLogonUser(WINPR_ATTR_UNUSED HANDLE hServer,
2190 WINPR_ATTR_UNUSED LPCSTR username,
2191 WINPR_ATTR_UNUSED LPCSTR password, WINPR_ATTR_UNUSED LPCSTR domain)
2192{
2193 WLog_ERR("TODO", "TODO: implement");
2194 return FALSE;
2195}
2196
2197void server_channel_common_free(rdpPeerChannel* channel)
2198{
2199 if (!channel)
2200 return;
2201 MessageQueue_Free(channel->queue);
2202 Stream_Free(channel->receiveData, TRUE);
2203 DeleteCriticalSection(&channel->writeLock);
2204 free(channel);
2205}
2206
2207rdpPeerChannel* server_channel_common_new(freerdp_peer* client, UINT16 index, UINT32 channelId,
2208 size_t chunkSize, const wObject* callback,
2209 const char* name)
2210{
2211 rdpPeerChannel* channel = (rdpPeerChannel*)calloc(1, sizeof(rdpPeerChannel));
2212 if (!channel)
2213 return nullptr;
2214
2215 InitializeCriticalSection(&channel->writeLock);
2216
2217 channel->receiveData = Stream_New(nullptr, chunkSize);
2218 if (!channel->receiveData)
2219 goto fail;
2220
2221 channel->queue = MessageQueue_New(callback);
2222 if (!channel->queue)
2223 goto fail;
2224
2225 channel->index = index;
2226 channel->client = client;
2227 channel->channelId = channelId;
2228 strncpy(channel->channelName, name, ARRAYSIZE(channel->channelName) - 1);
2229 return channel;
2230fail:
2231 WINPR_PRAGMA_DIAG_PUSH
2232 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2233 server_channel_common_free(channel);
2234 WINPR_PRAGMA_DIAG_POP
2235 return nullptr;
2236}
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:59
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals
Definition collections.h:61