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