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) || (channel->dvc_total_length == 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#endif
615
616BOOL WTSVirtualChannelManagerOpen(HANDLE hServer)
617{
619
620 if (!vcm)
621 return FALSE;
622
623 if (vcm->drdynvc_state == DRDYNVC_STATE_NONE)
624 {
625 rdpPeerChannel* channel = nullptr;
626
627 /* Initialize drdynvc channel once and only once. */
628 vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
629 channel = (rdpPeerChannel*)WTSVirtualChannelOpen((HANDLE)vcm, WTS_CURRENT_SESSION,
630 DRDYNVC_SVC_CHANNEL_NAME);
631
632 if (channel)
633 {
634 BYTE capaBuffer[12] = WINPR_C_ARRAY_INIT;
635 wStream staticS = WINPR_C_ARRAY_INIT;
636 wStream* s = Stream_StaticInit(&staticS, capaBuffer, sizeof(capaBuffer));
637
638 vcm->drdynvc_channel = channel;
639 vcm->dvc_spoken_version = 1;
640 Stream_Write_UINT8(s, 0x50); /* Cmd=5 sp=0 cbId=0 */
641 Stream_Write_UINT8(s, 0x00); /* Pad */
642 Stream_Write_UINT16(s, 0x0001); /* Version */
643
644 /* TODO: shall implement version 2 and 3 */
645
646 const size_t pos = Stream_GetPosition(s);
647 WINPR_ASSERT(pos <= UINT32_MAX);
648 ULONG written = 0;
649 if (!WTSVirtualChannelWrite(channel, (PCHAR)capaBuffer, (UINT32)pos, &written))
650 return FALSE;
651 }
652 }
653
654 return TRUE;
655}
656
657BOOL WTSVirtualChannelManagerCheckFileDescriptorEx(HANDLE hServer, BOOL autoOpen)
658{
659 wMessage message = WINPR_C_ARRAY_INIT;
660 BOOL status = TRUE;
661 WTSVirtualChannelManager* vcm = nullptr;
662
663 if (!hServer || hServer == INVALID_HANDLE_VALUE)
664 return FALSE;
665
666 vcm = (WTSVirtualChannelManager*)hServer;
667
668 if (autoOpen)
669 {
670 if (!WTSVirtualChannelManagerOpen(hServer))
671 return FALSE;
672 }
673
674 while (MessageQueue_Peek(vcm->queue, &message, TRUE))
675 {
676 BYTE* buffer = nullptr;
677 UINT32 length = 0;
678 UINT16 channelId = 0;
679 channelId = (UINT16)(UINT_PTR)message.context;
680 buffer = (BYTE*)message.wParam;
681 length = (UINT32)(UINT_PTR)message.lParam;
682
683 WINPR_ASSERT(vcm->client);
684 WINPR_ASSERT(vcm->client->SendChannelData);
685 if (!vcm->client->SendChannelData(vcm->client, channelId, buffer, length))
686 {
687 status = FALSE;
688 }
689
690 free(buffer);
691
692 if (!status)
693 break;
694 }
695
696 return status;
697}
698
699BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer)
700{
701 return WTSVirtualChannelManagerCheckFileDescriptorEx(hServer, TRUE);
702}
703
704HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer)
705{
707 WINPR_ASSERT(vcm);
708 return MessageQueue_Event(vcm->queue);
709}
710
711static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs, const char* channel_name)
712{
713 if (!mcs || !channel_name || !strnlen(channel_name, CHANNEL_NAME_LEN + 1))
714 return nullptr;
715
716 for (UINT32 index = 0; index < mcs->channelCount; index++)
717 {
718 rdpMcsChannel* mchannel = &mcs->channels[index];
719 if (mchannel->joined)
720 {
721 if (_strnicmp(mchannel->Name, channel_name, CHANNEL_NAME_LEN + 1) == 0)
722 return mchannel;
723 }
724 }
725
726 return nullptr;
727}
728
729static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs, const UINT16 channel_id)
730{
731 if (!mcs || !channel_id)
732 return nullptr;
733
734 WINPR_ASSERT(mcs->channels);
735 for (UINT32 index = 0; index < mcs->channelCount; index++)
736 {
737 rdpMcsChannel* mchannel = &mcs->channels[index];
738 if (mchannel->joined)
739 {
740 if (mchannel->ChannelId == channel_id)
741 return &mcs->channels[index];
742 }
743 }
744
745 return nullptr;
746}
747
748BOOL WTSIsChannelJoinedByName(freerdp_peer* client, const char* channel_name)
749{
750 if (!client || !client->context || !client->context->rdp)
751 return FALSE;
752
753 return (wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) != nullptr);
754}
755
756BOOL WTSIsChannelJoinedById(freerdp_peer* client, UINT16 channel_id)
757{
758 if (!client || !client->context || !client->context->rdp)
759 return FALSE;
760
761 return (wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id) != nullptr);
762}
763
764BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name)
765{
767
768 if (!vcm || !vcm->rdp)
769 return FALSE;
770
771 return (wts_get_joined_channel_by_name(vcm->rdp->mcs, name) != nullptr);
772}
773
774BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer)
775{
777 WINPR_ASSERT(vcm);
778 return vcm->drdynvc_state;
779}
780
781void WTSVirtualChannelManagerSetDVCCreationCallback(HANDLE hServer, psDVCCreationStatusCallback cb,
782 void* userdata)
783{
784 WTSVirtualChannelManager* vcm = hServer;
785
786 WINPR_ASSERT(vcm);
787
788 vcm->dvc_creation_status = cb;
789 vcm->dvc_creation_status_userdata = userdata;
790}
791
792UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name)
793{
794 rdpMcsChannel* channel = nullptr;
795
796 WINPR_ASSERT(channel_name);
797 if (!client || !client->context || !client->context->rdp)
798 return 0;
799
800 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
801
802 if (!channel)
803 return 0;
804
805 return channel->ChannelId;
806}
807
808UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle)
809{
810 rdpPeerChannel* channel = hChannelHandle;
811
812 WINPR_ASSERT(channel);
813
814 return channel->channelId;
815}
816
817BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle)
818{
819 rdpMcsChannel* channel = nullptr;
820
821 WINPR_ASSERT(channel_name);
822 if (!client || !client->context || !client->context->rdp)
823 return FALSE;
824
825 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
826
827 if (!channel)
828 return FALSE;
829
830 channel->handle = handle;
831 return TRUE;
832}
833
834BOOL WTSChannelSetHandleById(freerdp_peer* client, UINT16 channel_id, void* handle)
835{
836 rdpMcsChannel* channel = nullptr;
837
838 if (!client || !client->context || !client->context->rdp)
839 return FALSE;
840
841 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
842
843 if (!channel)
844 return FALSE;
845
846 channel->handle = handle;
847 return TRUE;
848}
849
850void* WTSChannelGetHandleByName(freerdp_peer* client, const char* channel_name)
851{
852 rdpMcsChannel* channel = nullptr;
853
854 WINPR_ASSERT(channel_name);
855 if (!client || !client->context || !client->context->rdp)
856 return nullptr;
857
858 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
859
860 if (!channel)
861 return nullptr;
862
863 return channel->handle;
864}
865
866void* WTSChannelGetHandleById(freerdp_peer* client, UINT16 channel_id)
867{
868 rdpMcsChannel* channel = nullptr;
869
870 if (!client || !client->context || !client->context->rdp)
871 return nullptr;
872
873 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
874
875 if (!channel)
876 return nullptr;
877
878 return channel->handle;
879}
880
881const char* WTSChannelGetName(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 (const char*)channel->Name;
894}
895
896char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count)
897{
898 rdpMcs* mcs = nullptr;
899 char** names = nullptr;
900
901 if (!client || !client->context || !count)
902 return nullptr;
903
904 WINPR_ASSERT(client->context->rdp);
905 mcs = client->context->rdp->mcs;
906 WINPR_ASSERT(mcs);
907 *count = mcs->channelCount;
908
909 names = (char**)calloc(mcs->channelCount, sizeof(char*));
910 if (!names)
911 return nullptr;
912
913 for (UINT32 index = 0; index < mcs->channelCount; index++)
914 {
915 rdpMcsChannel* mchannel = &mcs->channels[index];
916 names[index] = mchannel->Name;
917 }
918
919 return names;
920}
921
922INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id)
923{
924 rdpMcsChannel* channel = nullptr;
925
926 if (!client || !client->context || !client->context->rdp)
927 return -1;
928
929 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
930
931 if (!channel)
932 return -1;
933
934 return (INT64)channel->options;
935}
936
937BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(WINPR_ATTR_UNUSED LPWSTR pTargetServerName,
938 WINPR_ATTR_UNUSED ULONG TargetLogonId,
939 WINPR_ATTR_UNUSED BYTE HotkeyVk,
940 WINPR_ATTR_UNUSED USHORT HotkeyModifiers)
941{
942 WLog_ERR("TODO", "TODO: implement");
943 return FALSE;
944}
945
946BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionA(WINPR_ATTR_UNUSED LPSTR pTargetServerName,
947 WINPR_ATTR_UNUSED ULONG TargetLogonId,
948 WINPR_ATTR_UNUSED BYTE HotkeyVk,
949 WINPR_ATTR_UNUSED USHORT HotkeyModifiers)
950{
951 WLog_ERR("TODO", "TODO: implement");
952 return FALSE;
953}
954
955BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExW(WINPR_ATTR_UNUSED LPWSTR pTargetServerName,
956 WINPR_ATTR_UNUSED ULONG TargetLogonId,
957 WINPR_ATTR_UNUSED BYTE HotkeyVk,
958 WINPR_ATTR_UNUSED USHORT HotkeyModifiers,
959 WINPR_ATTR_UNUSED DWORD flags)
960{
961 WLog_ERR("TODO", "TODO: implement");
962 return FALSE;
963}
964
965BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExA(WINPR_ATTR_UNUSED LPSTR pTargetServerName,
966 WINPR_ATTR_UNUSED ULONG TargetLogonId,
967 WINPR_ATTR_UNUSED BYTE HotkeyVk,
968 WINPR_ATTR_UNUSED USHORT HotkeyModifiers,
969 WINPR_ATTR_UNUSED DWORD flags)
970{
971 WLog_ERR("TODO", "TODO: implement");
972 return FALSE;
973}
974
975BOOL WINAPI FreeRDP_WTSStopRemoteControlSession(WINPR_ATTR_UNUSED ULONG LogonId)
976{
977 WLog_ERR("TODO", "TODO: implement");
978 return FALSE;
979}
980
981BOOL WINAPI FreeRDP_WTSConnectSessionW(WINPR_ATTR_UNUSED ULONG LogonId,
982 WINPR_ATTR_UNUSED ULONG TargetLogonId,
983 WINPR_ATTR_UNUSED PWSTR pPassword,
984 WINPR_ATTR_UNUSED BOOL bWait)
985{
986 WLog_ERR("TODO", "TODO: implement");
987 return FALSE;
988}
989
990BOOL WINAPI FreeRDP_WTSConnectSessionA(WINPR_ATTR_UNUSED ULONG LogonId,
991 WINPR_ATTR_UNUSED ULONG TargetLogonId,
992 WINPR_ATTR_UNUSED PSTR pPassword,
993 WINPR_ATTR_UNUSED BOOL bWait)
994{
995 WLog_ERR("TODO", "TODO: implement");
996 return FALSE;
997}
998
999BOOL WINAPI FreeRDP_WTSEnumerateServersW(WINPR_ATTR_UNUSED LPWSTR pDomainName,
1000 WINPR_ATTR_UNUSED DWORD Reserved,
1001 WINPR_ATTR_UNUSED DWORD Version,
1002 WINPR_ATTR_UNUSED PWTS_SERVER_INFOW* ppServerInfo,
1003 WINPR_ATTR_UNUSED DWORD* pCount)
1004{
1005 WLog_ERR("TODO", "TODO: implement");
1006 return FALSE;
1007}
1008
1009BOOL WINAPI FreeRDP_WTSEnumerateServersA(WINPR_ATTR_UNUSED LPSTR pDomainName,
1010 WINPR_ATTR_UNUSED DWORD Reserved,
1011 WINPR_ATTR_UNUSED DWORD Version,
1012 WINPR_ATTR_UNUSED PWTS_SERVER_INFOA* ppServerInfo,
1013 WINPR_ATTR_UNUSED DWORD* pCount)
1014{
1015 WLog_ERR("TODO", "TODO: implement");
1016 return FALSE;
1017}
1018
1019HANDLE WINAPI FreeRDP_WTSOpenServerW(WINPR_ATTR_UNUSED LPWSTR pServerName)
1020{
1021 WLog_ERR("TODO", "TODO: implement");
1022 return INVALID_HANDLE_VALUE;
1023}
1024
1025static void wts_virtual_channel_manager_free_message(void* obj)
1026{
1027 wMessage* msg = (wMessage*)obj;
1028
1029 if (msg)
1030 {
1031 BYTE* buffer = (BYTE*)msg->wParam;
1032
1033 if (buffer)
1034 free(buffer);
1035 }
1036}
1037
1038static void channel_free(rdpPeerChannel* channel)
1039{
1040 server_channel_common_free(channel);
1041}
1042
1043static void array_channel_free(void* ptr)
1044{
1045 rdpPeerChannel* channel = ptr;
1046 channel_free(channel);
1047}
1048
1049static BOOL dynChannelMatch(const void* v1, const void* v2)
1050{
1051 const UINT32* p1 = (const UINT32*)v1;
1052 const UINT32* p2 = (const UINT32*)v2;
1053 return *p1 == *p2;
1054}
1055
1056static UINT32 channelId_Hash(const void* key)
1057{
1058 const UINT32* v = (const UINT32*)key;
1059 return *v;
1060}
1061
1062static void clearHandles(void)
1063{
1064 HashTable_Free(g_ServerHandles);
1065 g_ServerHandles = nullptr;
1066}
1067
1068static BOOL CALLBACK initializeHandles(WINPR_ATTR_UNUSED PINIT_ONCE once,
1069 WINPR_ATTR_UNUSED PVOID param,
1070 WINPR_ATTR_UNUSED PVOID* context)
1071{
1072 WINPR_ASSERT(g_ServerHandles == nullptr);
1073 g_ServerHandles = HashTable_New(TRUE);
1074 (void)winpr_atexit(clearHandles);
1075 return g_ServerHandles != nullptr;
1076}
1077
1078static bool setup(void)
1079{
1080 return InitOnceExecuteOnce(&g_HandleInitializer, initializeHandles, nullptr, nullptr);
1081}
1082
1083static void wtsCloseVCM(WTSVirtualChannelManager* vcm, bool closeDrdynvc)
1084{
1085 WINPR_ASSERT(vcm);
1086
1087 HashTable_Lock(g_ServerHandles);
1088
1089/* clang analyzer does not like the check for INVALID_HANDLE_VALUE and considers the path not taken,
1090 * leading to false positives on memory leaks. */
1091#ifdef __clang_analyzer__
1092 const BOOL valid = vcm != nullptr;
1093#else
1094 const BOOL valid = (vcm != nullptr) && (vcm != INVALID_HANDLE_VALUE);
1095#endif
1096 if (valid)
1097 {
1098 HashTable_Remove(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId);
1099
1100 HashTable_Free(vcm->dynamicVirtualChannels);
1101
1102 if (vcm->drdynvc_channel)
1103 {
1104 if (closeDrdynvc)
1105 (void)WTSVirtualChannelClose(vcm->drdynvc_channel);
1106 vcm->drdynvc_channel = nullptr;
1107 }
1108
1109 MessageQueue_Free(vcm->queue);
1110 free(vcm);
1111 }
1112 HashTable_Unlock(g_ServerHandles);
1113}
1114
1115HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName)
1116{
1117 wObject queueCallbacks = WINPR_C_ARRAY_INIT;
1118
1119 rdpContext* context = WINPR_PACKED_ALIGN_CAST(rdpContext*, pServerName);
1120
1121 if (!setup() || !context)
1122 return INVALID_HANDLE_VALUE;
1123
1124 freerdp_peer* client = context->peer;
1125
1126 if (!client)
1127 {
1128 SetLastError(ERROR_INVALID_DATA);
1129 return INVALID_HANDLE_VALUE;
1130 }
1131
1132 WTSVirtualChannelManager* vcm = calloc(1, sizeof(WTSVirtualChannelManager));
1133
1134 if (!vcm)
1135 goto fail;
1136
1137 vcm->client = client;
1138 vcm->rdp = context->rdp;
1139
1140 queueCallbacks.fnObjectFree = wts_virtual_channel_manager_free_message;
1141 vcm->queue = MessageQueue_New(&queueCallbacks);
1142
1143 if (!vcm->queue)
1144 goto fail;
1145
1146 vcm->dvc_channel_id_seq = 0;
1147 vcm->dynamicVirtualChannels = HashTable_New(TRUE);
1148
1149 if (!vcm->dynamicVirtualChannels)
1150 goto fail;
1151
1152 if (!HashTable_SetHashFunction(vcm->dynamicVirtualChannels, channelId_Hash))
1153 goto fail;
1154
1155 {
1156 wObject* obj = HashTable_ValueObject(vcm->dynamicVirtualChannels);
1157 WINPR_ASSERT(obj);
1158 obj->fnObjectFree = array_channel_free;
1159
1160 obj = HashTable_KeyObject(vcm->dynamicVirtualChannels);
1161 obj->fnObjectEquals = dynChannelMatch;
1162 }
1163 client->ReceiveChannelData = WTSReceiveChannelData;
1164 {
1165 HashTable_Lock(g_ServerHandles);
1166 vcm->SessionId = g_SessionId++;
1167 const BOOL rc =
1168 HashTable_Insert(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId, (void*)vcm);
1169 HashTable_Unlock(g_ServerHandles);
1170 if (!rc)
1171 goto fail;
1172 }
1173
1174 HANDLE hServer = (HANDLE)vcm;
1175 return hServer;
1176
1177fail:
1178 wtsCloseVCM(vcm, false);
1179 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1180 return INVALID_HANDLE_VALUE;
1181}
1182
1183HANDLE WINAPI FreeRDP_WTSOpenServerExW(WINPR_ATTR_UNUSED LPWSTR pServerName)
1184{
1185 WLog_ERR("TODO", "TODO: implement");
1186 return INVALID_HANDLE_VALUE;
1187}
1188
1189HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName)
1190{
1191 return FreeRDP_WTSOpenServerA(pServerName);
1192}
1193
1194VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer)
1195{
1197 wtsCloseVCM(vcm, true);
1198}
1199
1200BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(WINPR_ATTR_UNUSED HANDLE hServer,
1201 WINPR_ATTR_UNUSED DWORD Reserved,
1202 WINPR_ATTR_UNUSED DWORD Version,
1203 WINPR_ATTR_UNUSED PWTS_SESSION_INFOW* ppSessionInfo,
1204 WINPR_ATTR_UNUSED DWORD* pCount)
1205{
1206 WLog_ERR("TODO", "TODO: implement");
1207 return FALSE;
1208}
1209
1210BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(WINPR_ATTR_UNUSED HANDLE hServer,
1211 WINPR_ATTR_UNUSED DWORD Reserved,
1212 WINPR_ATTR_UNUSED DWORD Version,
1213 WINPR_ATTR_UNUSED PWTS_SESSION_INFOA* ppSessionInfo,
1214 WINPR_ATTR_UNUSED DWORD* pCount)
1215{
1216 WLog_ERR("TODO", "TODO: implement");
1217 return FALSE;
1218}
1219
1220BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(WINPR_ATTR_UNUSED HANDLE hServer,
1221 WINPR_ATTR_UNUSED DWORD* pLevel,
1222 WINPR_ATTR_UNUSED DWORD Filter,
1223 WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1W* ppSessionInfo,
1224 WINPR_ATTR_UNUSED DWORD* pCount)
1225{
1226 WLog_ERR("TODO", "TODO: implement");
1227 return FALSE;
1228}
1229
1230BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(WINPR_ATTR_UNUSED HANDLE hServer,
1231 WINPR_ATTR_UNUSED DWORD* pLevel,
1232 WINPR_ATTR_UNUSED DWORD Filter,
1233 WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1A* ppSessionInfo,
1234 WINPR_ATTR_UNUSED DWORD* pCount)
1235{
1236 WLog_ERR("TODO", "TODO: implement");
1237 return FALSE;
1238}
1239
1240BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(WINPR_ATTR_UNUSED HANDLE hServer,
1241 WINPR_ATTR_UNUSED DWORD Reserved,
1242 WINPR_ATTR_UNUSED DWORD Version,
1243 WINPR_ATTR_UNUSED PWTS_PROCESS_INFOW* ppProcessInfo,
1244 WINPR_ATTR_UNUSED DWORD* pCount)
1245{
1246 WLog_ERR("TODO", "TODO: implement");
1247 return FALSE;
1248}
1249
1250BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(WINPR_ATTR_UNUSED HANDLE hServer,
1251 WINPR_ATTR_UNUSED DWORD Reserved,
1252 WINPR_ATTR_UNUSED DWORD Version,
1253 WINPR_ATTR_UNUSED PWTS_PROCESS_INFOA* ppProcessInfo,
1254 WINPR_ATTR_UNUSED DWORD* pCount)
1255{
1256 WLog_ERR("TODO", "TODO: implement");
1257 return FALSE;
1258}
1259
1260BOOL WINAPI FreeRDP_WTSTerminateProcess(WINPR_ATTR_UNUSED HANDLE hServer,
1261 WINPR_ATTR_UNUSED DWORD ProcessId,
1262 WINPR_ATTR_UNUSED DWORD ExitCode)
1263{
1264 WLog_ERR("TODO", "TODO: implement");
1265 return FALSE;
1266}
1267
1268BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(WINPR_ATTR_UNUSED HANDLE hServer,
1269 WINPR_ATTR_UNUSED DWORD SessionId,
1270 WINPR_ATTR_UNUSED WTS_INFO_CLASS WTSInfoClass,
1271 WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
1272 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1273{
1274 WLog_ERR("TODO", "TODO: implement");
1275 return FALSE;
1276}
1277
1278BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1279 WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
1280 DWORD* pBytesReturned)
1281{
1282 DWORD BytesReturned = 0;
1283 WTSVirtualChannelManager* vcm = nullptr;
1284 vcm = (WTSVirtualChannelManager*)hServer;
1285
1286 if (!vcm)
1287 return FALSE;
1288
1289 if (WTSInfoClass == WTSSessionId)
1290 {
1291 ULONG* pBuffer = nullptr;
1292 BytesReturned = sizeof(ULONG);
1293 pBuffer = (ULONG*)malloc(sizeof(BytesReturned));
1294
1295 if (!pBuffer)
1296 {
1297 SetLastError(g_err_oom);
1298 return FALSE;
1299 }
1300
1301 *pBuffer = vcm->SessionId;
1302 *ppBuffer = (LPSTR)pBuffer;
1303 *pBytesReturned = BytesReturned;
1304 return TRUE;
1305 }
1306
1307 return FALSE;
1308}
1309
1310BOOL WINAPI FreeRDP_WTSQueryUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
1311 WINPR_ATTR_UNUSED LPWSTR pUserName,
1312 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1313 WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
1314 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1315{
1316 WLog_ERR("TODO", "TODO: implement");
1317 return FALSE;
1318}
1319
1320BOOL WINAPI FreeRDP_WTSQueryUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
1321 WINPR_ATTR_UNUSED LPSTR pUserName,
1322 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1323 WINPR_ATTR_UNUSED LPSTR* ppBuffer,
1324 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1325{
1326 WLog_ERR("TODO", "TODO: implement");
1327 return FALSE;
1328}
1329
1330BOOL WINAPI FreeRDP_WTSSetUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
1331 WINPR_ATTR_UNUSED LPWSTR pUserName,
1332 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1333 WINPR_ATTR_UNUSED LPWSTR pBuffer,
1334 WINPR_ATTR_UNUSED DWORD DataLength)
1335{
1336 WLog_ERR("TODO", "TODO: implement");
1337 return FALSE;
1338}
1339
1340BOOL WINAPI FreeRDP_WTSSetUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
1341 WINPR_ATTR_UNUSED LPSTR pUserName,
1342 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1343 WINPR_ATTR_UNUSED LPSTR pBuffer,
1344 WINPR_ATTR_UNUSED DWORD DataLength)
1345{
1346 WLog_ERR("TODO", "TODO: implement");
1347 return FALSE;
1348}
1349
1350BOOL WINAPI
1351FreeRDP_WTSSendMessageW(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1352 WINPR_ATTR_UNUSED LPWSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
1353 WINPR_ATTR_UNUSED LPWSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
1354 WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
1355 WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
1356{
1357 WLog_ERR("TODO", "TODO: implement");
1358 return FALSE;
1359}
1360
1361BOOL WINAPI
1362FreeRDP_WTSSendMessageA(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1363 WINPR_ATTR_UNUSED LPSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
1364 WINPR_ATTR_UNUSED LPSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
1365 WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
1366 WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
1367{
1368 WLog_ERR("TODO", "TODO: implement");
1369 return FALSE;
1370}
1371
1372BOOL WINAPI FreeRDP_WTSDisconnectSession(WINPR_ATTR_UNUSED HANDLE hServer,
1373 WINPR_ATTR_UNUSED DWORD SessionId,
1374 WINPR_ATTR_UNUSED BOOL bWait)
1375{
1376 WLog_ERR("TODO", "TODO: implement");
1377 return FALSE;
1378}
1379
1380BOOL WINAPI FreeRDP_WTSLogoffSession(WINPR_ATTR_UNUSED HANDLE hServer,
1381 WINPR_ATTR_UNUSED DWORD SessionId,
1382 WINPR_ATTR_UNUSED BOOL bWait)
1383{
1384 WLog_ERR("TODO", "TODO: implement");
1385 return FALSE;
1386}
1387
1388BOOL WINAPI FreeRDP_WTSShutdownSystem(WINPR_ATTR_UNUSED HANDLE hServer,
1389 WINPR_ATTR_UNUSED DWORD ShutdownFlag)
1390{
1391 WLog_ERR("TODO", "TODO: implement");
1392 return FALSE;
1393}
1394
1395BOOL WINAPI FreeRDP_WTSWaitSystemEvent(WINPR_ATTR_UNUSED HANDLE hServer,
1396 WINPR_ATTR_UNUSED DWORD EventMask,
1397 WINPR_ATTR_UNUSED DWORD* pEventFlags)
1398{
1399 WLog_ERR("TODO", "TODO: implement");
1400 return FALSE;
1401}
1402
1403static void peer_channel_queue_free_message(void* obj)
1404{
1405 wMessage* msg = (wMessage*)obj;
1406 if (!msg)
1407 return;
1408
1409 free(msg->context);
1410 msg->context = nullptr;
1411}
1412
1413static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* client,
1414 UINT32 ChannelId, UINT16 index, UINT16 type, size_t chunkSize,
1415 const char* name, UINT32 flags)
1416{
1417 wObject queueCallbacks = WINPR_C_ARRAY_INIT;
1418 queueCallbacks.fnObjectFree = peer_channel_queue_free_message;
1419
1420 rdpPeerChannel* channel =
1421 server_channel_common_new(client, index, ChannelId, chunkSize, &queueCallbacks, name);
1422
1423 WINPR_ASSERT(vcm);
1424 WINPR_ASSERT(client);
1425
1426 if (!channel)
1427 goto fail;
1428
1429 channel->vcm = vcm;
1430 channel->channelType = type;
1431 channel->creationStatus =
1432 (type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS;
1433 channel->channelFlags = flags;
1434
1435 return channel;
1436fail:
1437 channel_free(channel);
1438 return nullptr;
1439}
1440
1441static HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenStatic(HANDLE hServer,
1442 WINPR_ATTR_UNUSED DWORD SessionId,
1443 LPSTR pVirtualName, UINT32 Flags)
1444{
1446 if (!vcm)
1447 {
1448 SetLastError(ERROR_INVALID_DATA);
1449 return nullptr;
1450 }
1451
1452 freerdp_peer* client = vcm->client;
1453 WINPR_ASSERT(client);
1454
1455 rdpContext* context = client->context;
1456 WINPR_ASSERT(context);
1457 WINPR_ASSERT(context->rdp);
1458 WINPR_ASSERT(context->settings);
1459
1460 rdpMcs* mcs = context->rdp->mcs;
1461 WINPR_ASSERT(mcs);
1462
1463 size_t length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1);
1464 if (length > CHANNEL_NAME_LEN)
1465 {
1466 SetLastError(ERROR_NOT_FOUND);
1467 return nullptr;
1468 }
1469
1470 rdpMcsChannel* joined_channel = nullptr;
1471 UINT32 index = 0;
1472 for (; index < mcs->channelCount; index++)
1473 {
1474 rdpMcsChannel* mchannel = &mcs->channels[index];
1475 if (mchannel->joined && (strncmp(mchannel->Name, pVirtualName, length) == 0))
1476 {
1477 joined_channel = mchannel;
1478 break;
1479 }
1480 }
1481
1482 if (!joined_channel)
1483 {
1484 SetLastError(ERROR_NOT_FOUND);
1485 return nullptr;
1486 }
1487
1488 rdpPeerChannel* channel = (rdpPeerChannel*)joined_channel->handle;
1489 if (!channel)
1490 {
1491 const UINT32 VCChunkSize =
1492 freerdp_settings_get_uint32(context->settings, FreeRDP_VCChunkSize);
1493
1494 WINPR_ASSERT(index <= UINT16_MAX);
1495 channel = channel_new(vcm, client, joined_channel->ChannelId, (UINT16)index,
1496 RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName, Flags);
1497
1498 if (!channel)
1499 goto fail;
1500
1501 joined_channel->handle = channel;
1502 }
1503
1504 HANDLE hChannelHandle = (HANDLE)channel;
1505 return hChannelHandle;
1506fail:
1507 channel_free(channel);
1508 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1509 return nullptr;
1510}
1511
1512HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
1513{
1514 return FreeRDP_WTSVirtualChannelOpenStatic(hServer, SessionId, pVirtualName, 0);
1515}
1516
1517HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
1518{
1519 wStream* s = nullptr;
1520 rdpPeerChannel* channel = nullptr;
1521 BOOL joined = FALSE;
1522 ULONG written = 0;
1523
1524 if (!setup())
1525 return nullptr;
1526
1527 if (SessionId == WTS_CURRENT_SESSION)
1528 return nullptr;
1529
1530 HashTable_Lock(g_ServerHandles);
1531 WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)HashTable_GetItemValue(
1532 g_ServerHandles, (void*)(UINT_PTR)SessionId);
1533
1534 if (!vcm)
1535 goto end;
1536
1537 if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC))
1538 {
1539 HashTable_Unlock(g_ServerHandles);
1540 return FreeRDP_WTSVirtualChannelOpenStatic((HANDLE)vcm, SessionId, pVirtualName, flags);
1541 }
1542
1543 freerdp_peer* client = vcm->client;
1544 WINPR_ASSERT(client);
1545 WINPR_ASSERT(client->context);
1546 WINPR_ASSERT(client->context->rdp);
1547
1548 rdpMcs* mcs = client->context->rdp->mcs;
1549 WINPR_ASSERT(mcs);
1550
1551 for (UINT32 index = 0; index < mcs->channelCount; index++)
1552 {
1553 rdpMcsChannel* mchannel = &mcs->channels[index];
1554 if (mchannel->joined &&
1555 (strncmp(mchannel->Name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
1556 {
1557 joined = TRUE;
1558 break;
1559 }
1560 }
1561
1562 if (!joined)
1563 {
1564 SetLastError(ERROR_NOT_FOUND);
1565 goto end;
1566 }
1567
1568 if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY))
1569 {
1570 SetLastError(ERROR_NOT_READY);
1571 goto end;
1572 }
1573
1574 WINPR_ASSERT(client);
1575 WINPR_ASSERT(client->context);
1576 WINPR_ASSERT(client->context->settings);
1577
1578 const UINT32 VCChunkSize =
1579 freerdp_settings_get_uint32(client->context->settings, FreeRDP_VCChunkSize);
1580 channel =
1581 channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName, flags);
1582
1583 if (!channel)
1584 {
1585 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1586 goto end;
1587 }
1588
1589 const LONG hdl = InterlockedIncrement(&vcm->dvc_channel_id_seq);
1590 channel->channelId = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
1591
1592 if (!HashTable_Insert(vcm->dynamicVirtualChannels, &channel->channelId, channel))
1593 {
1594 channel_free(channel);
1595 channel = nullptr;
1596 goto fail;
1597 }
1598 s = Stream_New(nullptr, 64);
1599
1600 if (!s)
1601 goto fail;
1602
1603 if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName))
1604 goto fail;
1605
1606 {
1607 const size_t pos = Stream_GetPosition(s);
1608 WINPR_ASSERT(pos <= UINT32_MAX);
1609 if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char), (UINT32)pos,
1610 &written))
1611 goto fail;
1612 }
1613
1614end:
1615 Stream_Free(s, TRUE);
1616 HashTable_Unlock(g_ServerHandles);
1617 return channel;
1618
1619fail:
1620 Stream_Free(s, TRUE);
1621 if (channel)
1622 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1623 HashTable_Unlock(g_ServerHandles);
1624
1625 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1626 return nullptr;
1627}
1628
1629BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
1630{
1631 wStream* s = nullptr;
1632 rdpMcs* mcs = nullptr;
1633
1634 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1635 BOOL ret = TRUE;
1636
1637 if (channel)
1638 {
1639 WTSVirtualChannelManager* vcm = channel->vcm;
1640
1641 WINPR_ASSERT(vcm);
1642 WINPR_ASSERT(vcm->client);
1643 WINPR_ASSERT(vcm->client->context);
1644 WINPR_ASSERT(vcm->client->context->rdp);
1645 mcs = vcm->client->context->rdp->mcs;
1646
1647 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1648 {
1649 if (channel->index < mcs->channelCount)
1650 {
1651 rdpMcsChannel* cur = &mcs->channels[channel->index];
1652 rdpPeerChannel* peerChannel = (rdpPeerChannel*)cur->handle;
1653 channel_free(peerChannel);
1654 cur->handle = nullptr;
1655 }
1656 }
1657 else
1658 {
1659 if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
1660 {
1661 ULONG written = 0;
1662 s = Stream_New(nullptr, 8);
1663
1664 if (!s)
1665 {
1666 WLog_ERR(TAG, "Stream_New failed!");
1667 ret = FALSE;
1668 }
1669 else
1670 {
1671 wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
1672
1673 const size_t pos = Stream_GetPosition(s);
1674 WINPR_ASSERT(pos <= UINT32_MAX);
1675 ret = WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char),
1676 (UINT32)pos, &written);
1677 Stream_Free(s, TRUE);
1678 }
1679 }
1680 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1681 }
1682 }
1683
1684 return ret;
1685}
1686
1687BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, WINPR_ATTR_UNUSED ULONG TimeOut,
1688 PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead)
1689{
1690 BYTE* buffer = nullptr;
1691 wMessage message = WINPR_C_ARRAY_INIT;
1692 wtsChannelMessage* messageCtx = nullptr;
1693 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1694
1695 WINPR_ASSERT(channel);
1696
1697 if (!MessageQueue_Peek(channel->queue, &message, FALSE))
1698 {
1699 SetLastError(ERROR_NO_DATA);
1700 *pBytesRead = 0;
1701 return FALSE;
1702 }
1703
1704 messageCtx = message.context;
1705
1706 if (messageCtx == nullptr)
1707 return FALSE;
1708
1709 buffer = (BYTE*)(messageCtx + 1);
1710 *pBytesRead = messageCtx->length - messageCtx->offset;
1711
1712 if (Buffer == nullptr || BufferSize == 0)
1713 {
1714 return TRUE;
1715 }
1716
1717 if (*pBytesRead > BufferSize)
1718 *pBytesRead = BufferSize;
1719
1720 CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
1721 messageCtx->offset += *pBytesRead;
1722
1723 if (messageCtx->offset >= messageCtx->length)
1724 {
1725 const int rc = MessageQueue_Peek(channel->queue, &message, TRUE);
1726 peer_channel_queue_free_message(&message);
1727 if (rc < 0)
1728 return FALSE;
1729 }
1730
1731 return TRUE;
1732}
1733
1734BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG uLength,
1735 PULONG pBytesWritten)
1736{
1737 wStream* s = nullptr;
1738 int cbLen = 0;
1739 int cbChId = 0;
1740 int first = 0;
1741 BYTE* buffer = nullptr;
1742 size_t totalWritten = 0;
1743 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1744 BOOL ret = FALSE;
1745
1746 if (!channel)
1747 return FALSE;
1748
1749 EnterCriticalSection(&channel->writeLock);
1750 WINPR_ASSERT(channel->vcm);
1751 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1752 {
1753 buffer = (BYTE*)malloc(uLength);
1754
1755 if (!buffer)
1756 {
1757 SetLastError(g_err_oom);
1758 goto fail;
1759 }
1760
1761 CopyMemory(buffer, Buffer, uLength);
1762 totalWritten = uLength;
1763 if (!wts_queue_send_item(channel, buffer, uLength))
1764 goto fail;
1765 }
1766 else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
1767 {
1768 DEBUG_DVC("drdynvc not ready");
1769 goto fail;
1770 }
1771 else
1772 {
1773 first = TRUE;
1774
1775 size_t Length = uLength;
1776 while (Length > 0)
1777 {
1778 s = Stream_New(nullptr, DVC_MAX_DATA_PDU_SIZE);
1779
1780 if (!s)
1781 {
1782 WLog_ERR(TAG, "Stream_New failed!");
1783 SetLastError(g_err_oom);
1784 goto fail;
1785 }
1786
1787 buffer = Stream_Buffer(s);
1788 Stream_Seek_UINT8(s);
1789 cbChId = wts_write_variable_uint(s, channel->channelId);
1790
1791 if (first && (Length > Stream_GetRemainingLength(s)))
1792 {
1793 cbLen = wts_write_variable_uint(s, WINPR_ASSERTING_INT_CAST(uint32_t, Length));
1794 buffer[0] = ((DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId) & 0xFF;
1795 }
1796 else
1797 {
1798 buffer[0] = ((DATA_PDU << 4) | cbChId) & 0xFF;
1799 }
1800
1801 first = FALSE;
1802 size_t written = Stream_GetRemainingLength(s);
1803
1804 if (written > Length)
1805 written = Length;
1806
1807 Stream_Write(s, Buffer, written);
1808 const size_t length = Stream_GetPosition(s);
1809 Stream_Free(s, FALSE);
1810 if (length > UINT32_MAX)
1811 goto fail;
1812 Length -= written;
1813 Buffer += written;
1814 totalWritten += written;
1815 if (!wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, (UINT32)length))
1816 goto fail;
1817 }
1818 }
1819
1820 if (pBytesWritten)
1821 *pBytesWritten = WINPR_ASSERTING_INT_CAST(uint32_t, totalWritten);
1822
1823 ret = TRUE;
1824fail:
1825 LeaveCriticalSection(&channel->writeLock);
1826 return ret;
1827}
1828
1829BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
1830{
1831 WLog_ERR("TODO", "TODO: implement");
1832 return TRUE;
1833}
1834
1835BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
1836{
1837 WLog_ERR("TODO", "TODO: implement");
1838 return TRUE;
1839}
1840
1841BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
1842 PVOID* ppBuffer, DWORD* pBytesReturned)
1843{
1844 void* pfd = nullptr;
1845 BOOL bval = 0;
1846 void* fds[10] = WINPR_C_ARRAY_INIT;
1847 HANDLE hEvent = nullptr;
1848 int fds_count = 0;
1849 BOOL status = FALSE;
1850 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1851
1852 WINPR_ASSERT(channel);
1853
1854 switch ((UINT32)WtsVirtualClass)
1855 {
1856 case WTSVirtualFileHandle:
1857 hEvent = MessageQueue_Event(channel->queue);
1858 pfd = GetEventWaitObject(hEvent);
1859
1860 if (pfd)
1861 {
1862 fds[fds_count] = pfd;
1863 (fds_count)++;
1864 }
1865
1866 *ppBuffer = malloc(sizeof(void*));
1867
1868 if (!*ppBuffer)
1869 {
1870 SetLastError(g_err_oom);
1871 }
1872 else
1873 {
1874 CopyMemory(*ppBuffer, (void*)&fds[0], sizeof(void*));
1875 *pBytesReturned = sizeof(void*);
1876 status = TRUE;
1877 }
1878
1879 break;
1880
1881 case WTSVirtualEventHandle:
1882 hEvent = MessageQueue_Event(channel->queue);
1883
1884 *ppBuffer = malloc(sizeof(HANDLE));
1885
1886 if (!*ppBuffer)
1887 {
1888 SetLastError(g_err_oom);
1889 }
1890 else
1891 {
1892 CopyMemory(*ppBuffer, (void*)&hEvent, sizeof(HANDLE));
1893 *pBytesReturned = sizeof(void*);
1894 status = TRUE;
1895 }
1896
1897 break;
1898
1899 case WTSVirtualChannelReady:
1900 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1901 {
1902 bval = TRUE;
1903 status = TRUE;
1904 }
1905 else
1906 {
1907 switch (channel->dvc_open_state)
1908 {
1909 case DVC_OPEN_STATE_NONE:
1910 bval = FALSE;
1911 status = TRUE;
1912 break;
1913
1914 case DVC_OPEN_STATE_SUCCEEDED:
1915 bval = TRUE;
1916 status = TRUE;
1917 break;
1918
1919 default:
1920 *ppBuffer = nullptr;
1921 *pBytesReturned = 0;
1922 return FALSE;
1923 }
1924 }
1925
1926 *ppBuffer = malloc(sizeof(BOOL));
1927
1928 if (!*ppBuffer)
1929 {
1930 SetLastError(g_err_oom);
1931 status = FALSE;
1932 }
1933 else
1934 {
1935 CopyMemory(*ppBuffer, &bval, sizeof(BOOL));
1936 *pBytesReturned = sizeof(BOOL);
1937 }
1938
1939 break;
1940 case WTSVirtualChannelOpenStatus:
1941 {
1942 INT32 value = channel->creationStatus;
1943 status = TRUE;
1944
1945 *ppBuffer = malloc(sizeof(value));
1946 if (!*ppBuffer)
1947 {
1948 SetLastError(g_err_oom);
1949 status = FALSE;
1950 }
1951 else
1952 {
1953 CopyMemory(*ppBuffer, &value, sizeof(value));
1954 *pBytesReturned = sizeof(value);
1955 }
1956 break;
1957 }
1958 default:
1959 break;
1960 }
1961
1962 return status;
1963}
1964
1965VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory)
1966{
1967 free(pMemory);
1968}
1969
1970BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
1971 WINPR_ATTR_UNUSED PVOID pMemory,
1972 WINPR_ATTR_UNUSED ULONG NumberOfEntries)
1973{
1974 WLog_ERR("TODO", "TODO: implement");
1975 return FALSE;
1976}
1977
1978BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
1979 WINPR_ATTR_UNUSED PVOID pMemory,
1980 WINPR_ATTR_UNUSED ULONG NumberOfEntries)
1981{
1982 WLog_ERR("TODO", "TODO: implement");
1983 return FALSE;
1984}
1985
1986BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd,
1987 WINPR_ATTR_UNUSED DWORD dwFlags)
1988{
1989 WLog_ERR("TODO", "TODO: implement");
1990 return FALSE;
1991}
1992
1993BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd)
1994{
1995 WLog_ERR("TODO", "TODO: implement");
1996 return FALSE;
1997}
1998
1999BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
2000 WINPR_ATTR_UNUSED HWND hWnd,
2001 WINPR_ATTR_UNUSED DWORD dwFlags)
2002{
2003 WLog_ERR("TODO", "TODO: implement");
2004 return FALSE;
2005}
2006
2007BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
2008 WINPR_ATTR_UNUSED HWND hWnd)
2009{
2010 WLog_ERR("TODO", "TODO: implement");
2011 return FALSE;
2012}
2013
2014BOOL WINAPI FreeRDP_WTSQueryUserToken(WINPR_ATTR_UNUSED ULONG SessionId,
2015 WINPR_ATTR_UNUSED PHANDLE phToken)
2016{
2017 WLog_ERR("TODO", "TODO: implement");
2018 return FALSE;
2019}
2020
2021BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(WINPR_ATTR_UNUSED HANDLE hServer,
2022 WINPR_ATTR_UNUSED DWORD* pLevel,
2023 WINPR_ATTR_UNUSED DWORD SessionId,
2024 WINPR_ATTR_UNUSED LPWSTR* ppProcessInfo,
2025 WINPR_ATTR_UNUSED DWORD* pCount)
2026{
2027 WLog_ERR("TODO", "TODO: implement");
2028 return FALSE;
2029}
2030
2031BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(WINPR_ATTR_UNUSED HANDLE hServer,
2032 WINPR_ATTR_UNUSED DWORD* pLevel,
2033 WINPR_ATTR_UNUSED DWORD SessionId,
2034 WINPR_ATTR_UNUSED LPSTR* ppProcessInfo,
2035 WINPR_ATTR_UNUSED DWORD* pCount)
2036{
2037 WLog_ERR("TODO", "TODO: implement");
2038 return FALSE;
2039}
2040
2041BOOL WINAPI FreeRDP_WTSEnumerateListenersW(WINPR_ATTR_UNUSED HANDLE hServer,
2042 WINPR_ATTR_UNUSED PVOID pReserved,
2043 WINPR_ATTR_UNUSED DWORD Reserved,
2044 WINPR_ATTR_UNUSED PWTSLISTENERNAMEW pListeners,
2045 WINPR_ATTR_UNUSED DWORD* pCount)
2046{
2047 WLog_ERR("TODO", "TODO: implement");
2048 return FALSE;
2049}
2050
2051BOOL WINAPI FreeRDP_WTSEnumerateListenersA(WINPR_ATTR_UNUSED HANDLE hServer,
2052 WINPR_ATTR_UNUSED PVOID pReserved,
2053 WINPR_ATTR_UNUSED DWORD Reserved,
2054 WINPR_ATTR_UNUSED PWTSLISTENERNAMEA pListeners,
2055 WINPR_ATTR_UNUSED DWORD* pCount)
2056{
2057 WLog_ERR("TODO", "TODO: implement");
2058 return FALSE;
2059}
2060
2061BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(WINPR_ATTR_UNUSED HANDLE hServer,
2062 WINPR_ATTR_UNUSED PVOID pReserved,
2063 WINPR_ATTR_UNUSED DWORD Reserved,
2064 WINPR_ATTR_UNUSED LPWSTR pListenerName,
2065 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer)
2066{
2067 WLog_ERR("TODO", "TODO: implement");
2068 return FALSE;
2069}
2070
2071BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(WINPR_ATTR_UNUSED HANDLE hServer,
2072 WINPR_ATTR_UNUSED PVOID pReserved,
2073 WINPR_ATTR_UNUSED DWORD Reserved,
2074 WINPR_ATTR_UNUSED LPSTR pListenerName,
2075 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer)
2076{
2077 WLog_ERR("TODO", "TODO: implement");
2078 return FALSE;
2079}
2080
2081BOOL WINAPI FreeRDP_WTSCreateListenerW(WINPR_ATTR_UNUSED HANDLE hServer,
2082 WINPR_ATTR_UNUSED PVOID pReserved,
2083 WINPR_ATTR_UNUSED DWORD Reserved,
2084 WINPR_ATTR_UNUSED LPWSTR pListenerName,
2085 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer,
2086 WINPR_ATTR_UNUSED DWORD flag)
2087{
2088 WLog_ERR("TODO", "TODO: implement");
2089 return FALSE;
2090}
2091
2092BOOL WINAPI FreeRDP_WTSCreateListenerA(WINPR_ATTR_UNUSED HANDLE hServer,
2093 WINPR_ATTR_UNUSED PVOID pReserved,
2094 WINPR_ATTR_UNUSED DWORD Reserved,
2095 WINPR_ATTR_UNUSED LPSTR pListenerName,
2096 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer,
2097 WINPR_ATTR_UNUSED DWORD flag)
2098{
2099 WLog_ERR("TODO", "TODO: implement");
2100 return FALSE;
2101}
2102
2103BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(
2104 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2105 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
2106 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2107 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
2108{
2109 WLog_ERR("TODO", "TODO: implement");
2110 return FALSE;
2111}
2112
2113BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(
2114 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2115 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
2116 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2117 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
2118{
2119 WLog_ERR("TODO", "TODO: implement");
2120 return FALSE;
2121}
2122
2123BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(
2124 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2125 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
2126 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2127 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
2128 WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
2129{
2130 WLog_ERR("TODO", "TODO: implement");
2131 return FALSE;
2132}
2133
2134BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(
2135 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2136 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
2137 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2138 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
2139 WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
2140{
2141 WLog_ERR("TODO", "TODO: implement");
2142 return FALSE;
2143}
2144
2145BOOL CDECL FreeRDP_WTSEnableChildSessions(WINPR_ATTR_UNUSED BOOL bEnable)
2146{
2147 WLog_ERR("TODO", "TODO: implement");
2148 return FALSE;
2149}
2150
2151BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(WINPR_ATTR_UNUSED PBOOL pbEnabled)
2152{
2153 WLog_ERR("TODO", "TODO: implement");
2154 return FALSE;
2155}
2156
2157BOOL CDECL FreeRDP_WTSGetChildSessionId(WINPR_ATTR_UNUSED PULONG pSessionId)
2158{
2159 WLog_ERR("TODO", "TODO: implement");
2160 return FALSE;
2161}
2162
2163DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(void)
2164{
2165 WLog_ERR("TODO", "TODO: implement");
2166 return 0xFFFFFFFF;
2167}
2168BOOL WINAPI FreeRDP_WTSLogoffUser(WINPR_ATTR_UNUSED HANDLE hServer)
2169{
2170 WLog_ERR("TODO", "TODO: implement");
2171 return FALSE;
2172}
2173
2174BOOL WINAPI FreeRDP_WTSLogonUser(WINPR_ATTR_UNUSED HANDLE hServer,
2175 WINPR_ATTR_UNUSED LPCSTR username,
2176 WINPR_ATTR_UNUSED LPCSTR password, WINPR_ATTR_UNUSED LPCSTR domain)
2177{
2178 WLog_ERR("TODO", "TODO: implement");
2179 return FALSE;
2180}
2181
2182void server_channel_common_free(rdpPeerChannel* channel)
2183{
2184 if (!channel)
2185 return;
2186 MessageQueue_Free(channel->queue);
2187 Stream_Free(channel->receiveData, TRUE);
2188 DeleteCriticalSection(&channel->writeLock);
2189 free(channel);
2190}
2191
2192rdpPeerChannel* server_channel_common_new(freerdp_peer* client, UINT16 index, UINT32 channelId,
2193 size_t chunkSize, const wObject* callback,
2194 const char* name)
2195{
2196 rdpPeerChannel* channel = (rdpPeerChannel*)calloc(1, sizeof(rdpPeerChannel));
2197 if (!channel)
2198 return nullptr;
2199
2200 InitializeCriticalSection(&channel->writeLock);
2201
2202 channel->receiveData = Stream_New(nullptr, chunkSize);
2203 if (!channel->receiveData)
2204 goto fail;
2205
2206 channel->queue = MessageQueue_New(callback);
2207 if (!channel->queue)
2208 goto fail;
2209
2210 channel->index = index;
2211 channel->client = client;
2212 channel->channelId = channelId;
2213 strncpy(channel->channelName, name, ARRAYSIZE(channel->channelName) - 1);
2214 return channel;
2215fail:
2216 WINPR_PRAGMA_DIAG_PUSH
2217 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2218 server_channel_common_free(channel);
2219 WINPR_PRAGMA_DIAG_POP
2220 return nullptr;
2221}
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