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 bool setup(void)
1020{
1021 return InitOnceExecuteOnce(&g_HandleInitializer, initializeHandles, nullptr, nullptr);
1022}
1023
1024static void wtsCloseVCM(WTSVirtualChannelManager* vcm, bool closeDrdynvc)
1025{
1026 WINPR_ASSERT(vcm);
1027
1028 HashTable_Lock(g_ServerHandles);
1029
1030/* clang analyzer does not like the check for INVALID_HANDLE_VALUE and considers the path not taken,
1031 * leading to false positives on memory leaks. */
1032#ifdef __clang_analyzer__
1033 const BOOL valid = vcm != nullptr;
1034#else
1035 const BOOL valid = (vcm != nullptr) && (vcm != INVALID_HANDLE_VALUE);
1036#endif
1037 if (valid)
1038 {
1039 HashTable_Remove(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId);
1040
1041 HashTable_Free(vcm->dynamicVirtualChannels);
1042
1043 if (vcm->drdynvc_channel)
1044 {
1045 if (closeDrdynvc)
1046 (void)WTSVirtualChannelClose(vcm->drdynvc_channel);
1047 vcm->drdynvc_channel = nullptr;
1048 }
1049
1050 MessageQueue_Free(vcm->queue);
1051 free(vcm);
1052 }
1053 HashTable_Unlock(g_ServerHandles);
1054}
1055
1056HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName)
1057{
1058 wObject queueCallbacks = WINPR_C_ARRAY_INIT;
1059
1060 rdpContext* context = (rdpContext*)pServerName;
1061
1062 if (!setup() || !context)
1063 return INVALID_HANDLE_VALUE;
1064
1065 freerdp_peer* client = context->peer;
1066
1067 if (!client)
1068 {
1069 SetLastError(ERROR_INVALID_DATA);
1070 return INVALID_HANDLE_VALUE;
1071 }
1072
1073 WTSVirtualChannelManager* vcm = calloc(1, sizeof(WTSVirtualChannelManager));
1074
1075 if (!vcm)
1076 goto fail;
1077
1078 vcm->client = client;
1079 vcm->rdp = context->rdp;
1080
1081 queueCallbacks.fnObjectFree = wts_virtual_channel_manager_free_message;
1082 vcm->queue = MessageQueue_New(&queueCallbacks);
1083
1084 if (!vcm->queue)
1085 goto fail;
1086
1087 vcm->dvc_channel_id_seq = 0;
1088 vcm->dynamicVirtualChannels = HashTable_New(TRUE);
1089
1090 if (!vcm->dynamicVirtualChannels)
1091 goto fail;
1092
1093 if (!HashTable_SetHashFunction(vcm->dynamicVirtualChannels, channelId_Hash))
1094 goto fail;
1095
1096 {
1097 wObject* obj = HashTable_ValueObject(vcm->dynamicVirtualChannels);
1098 WINPR_ASSERT(obj);
1099 obj->fnObjectFree = array_channel_free;
1100
1101 obj = HashTable_KeyObject(vcm->dynamicVirtualChannels);
1102 obj->fnObjectEquals = dynChannelMatch;
1103 }
1104 client->ReceiveChannelData = WTSReceiveChannelData;
1105 {
1106 HashTable_Lock(g_ServerHandles);
1107 vcm->SessionId = g_SessionId++;
1108 const BOOL rc =
1109 HashTable_Insert(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId, (void*)vcm);
1110 HashTable_Unlock(g_ServerHandles);
1111 if (!rc)
1112 goto fail;
1113 }
1114
1115 HANDLE hServer = (HANDLE)vcm;
1116 return hServer;
1117
1118fail:
1119 wtsCloseVCM(vcm, false);
1120 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1121 return INVALID_HANDLE_VALUE;
1122}
1123
1124HANDLE WINAPI FreeRDP_WTSOpenServerExW(WINPR_ATTR_UNUSED LPWSTR pServerName)
1125{
1126 WLog_ERR("TODO", "TODO: implement");
1127 return INVALID_HANDLE_VALUE;
1128}
1129
1130HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName)
1131{
1132 return FreeRDP_WTSOpenServerA(pServerName);
1133}
1134
1135VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer)
1136{
1138 wtsCloseVCM(vcm, true);
1139}
1140
1141BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(WINPR_ATTR_UNUSED HANDLE hServer,
1142 WINPR_ATTR_UNUSED DWORD Reserved,
1143 WINPR_ATTR_UNUSED DWORD Version,
1144 WINPR_ATTR_UNUSED PWTS_SESSION_INFOW* ppSessionInfo,
1145 WINPR_ATTR_UNUSED DWORD* pCount)
1146{
1147 WLog_ERR("TODO", "TODO: implement");
1148 return FALSE;
1149}
1150
1151BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(WINPR_ATTR_UNUSED HANDLE hServer,
1152 WINPR_ATTR_UNUSED DWORD Reserved,
1153 WINPR_ATTR_UNUSED DWORD Version,
1154 WINPR_ATTR_UNUSED PWTS_SESSION_INFOA* ppSessionInfo,
1155 WINPR_ATTR_UNUSED DWORD* pCount)
1156{
1157 WLog_ERR("TODO", "TODO: implement");
1158 return FALSE;
1159}
1160
1161BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(WINPR_ATTR_UNUSED HANDLE hServer,
1162 WINPR_ATTR_UNUSED DWORD* pLevel,
1163 WINPR_ATTR_UNUSED DWORD Filter,
1164 WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1W* ppSessionInfo,
1165 WINPR_ATTR_UNUSED DWORD* pCount)
1166{
1167 WLog_ERR("TODO", "TODO: implement");
1168 return FALSE;
1169}
1170
1171BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(WINPR_ATTR_UNUSED HANDLE hServer,
1172 WINPR_ATTR_UNUSED DWORD* pLevel,
1173 WINPR_ATTR_UNUSED DWORD Filter,
1174 WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1A* ppSessionInfo,
1175 WINPR_ATTR_UNUSED DWORD* pCount)
1176{
1177 WLog_ERR("TODO", "TODO: implement");
1178 return FALSE;
1179}
1180
1181BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(WINPR_ATTR_UNUSED HANDLE hServer,
1182 WINPR_ATTR_UNUSED DWORD Reserved,
1183 WINPR_ATTR_UNUSED DWORD Version,
1184 WINPR_ATTR_UNUSED PWTS_PROCESS_INFOW* ppProcessInfo,
1185 WINPR_ATTR_UNUSED DWORD* pCount)
1186{
1187 WLog_ERR("TODO", "TODO: implement");
1188 return FALSE;
1189}
1190
1191BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(WINPR_ATTR_UNUSED HANDLE hServer,
1192 WINPR_ATTR_UNUSED DWORD Reserved,
1193 WINPR_ATTR_UNUSED DWORD Version,
1194 WINPR_ATTR_UNUSED PWTS_PROCESS_INFOA* ppProcessInfo,
1195 WINPR_ATTR_UNUSED DWORD* pCount)
1196{
1197 WLog_ERR("TODO", "TODO: implement");
1198 return FALSE;
1199}
1200
1201BOOL WINAPI FreeRDP_WTSTerminateProcess(WINPR_ATTR_UNUSED HANDLE hServer,
1202 WINPR_ATTR_UNUSED DWORD ProcessId,
1203 WINPR_ATTR_UNUSED DWORD ExitCode)
1204{
1205 WLog_ERR("TODO", "TODO: implement");
1206 return FALSE;
1207}
1208
1209BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(WINPR_ATTR_UNUSED HANDLE hServer,
1210 WINPR_ATTR_UNUSED DWORD SessionId,
1211 WINPR_ATTR_UNUSED WTS_INFO_CLASS WTSInfoClass,
1212 WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
1213 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1214{
1215 WLog_ERR("TODO", "TODO: implement");
1216 return FALSE;
1217}
1218
1219BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1220 WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
1221 DWORD* pBytesReturned)
1222{
1223 DWORD BytesReturned = 0;
1224 WTSVirtualChannelManager* vcm = nullptr;
1225 vcm = (WTSVirtualChannelManager*)hServer;
1226
1227 if (!vcm)
1228 return FALSE;
1229
1230 if (WTSInfoClass == WTSSessionId)
1231 {
1232 ULONG* pBuffer = nullptr;
1233 BytesReturned = sizeof(ULONG);
1234 pBuffer = (ULONG*)malloc(sizeof(BytesReturned));
1235
1236 if (!pBuffer)
1237 {
1238 SetLastError(g_err_oom);
1239 return FALSE;
1240 }
1241
1242 *pBuffer = vcm->SessionId;
1243 *ppBuffer = (LPSTR)pBuffer;
1244 *pBytesReturned = BytesReturned;
1245 return TRUE;
1246 }
1247
1248 return FALSE;
1249}
1250
1251BOOL WINAPI FreeRDP_WTSQueryUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
1252 WINPR_ATTR_UNUSED LPWSTR pUserName,
1253 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1254 WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
1255 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1256{
1257 WLog_ERR("TODO", "TODO: implement");
1258 return FALSE;
1259}
1260
1261BOOL WINAPI FreeRDP_WTSQueryUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
1262 WINPR_ATTR_UNUSED LPSTR pUserName,
1263 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1264 WINPR_ATTR_UNUSED LPSTR* ppBuffer,
1265 WINPR_ATTR_UNUSED DWORD* pBytesReturned)
1266{
1267 WLog_ERR("TODO", "TODO: implement");
1268 return FALSE;
1269}
1270
1271BOOL WINAPI FreeRDP_WTSSetUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
1272 WINPR_ATTR_UNUSED LPWSTR pUserName,
1273 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1274 WINPR_ATTR_UNUSED LPWSTR pBuffer,
1275 WINPR_ATTR_UNUSED DWORD DataLength)
1276{
1277 WLog_ERR("TODO", "TODO: implement");
1278 return FALSE;
1279}
1280
1281BOOL WINAPI FreeRDP_WTSSetUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
1282 WINPR_ATTR_UNUSED LPSTR pUserName,
1283 WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
1284 WINPR_ATTR_UNUSED LPSTR pBuffer,
1285 WINPR_ATTR_UNUSED DWORD DataLength)
1286{
1287 WLog_ERR("TODO", "TODO: implement");
1288 return FALSE;
1289}
1290
1291BOOL WINAPI
1292FreeRDP_WTSSendMessageW(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1293 WINPR_ATTR_UNUSED LPWSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
1294 WINPR_ATTR_UNUSED LPWSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
1295 WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
1296 WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
1297{
1298 WLog_ERR("TODO", "TODO: implement");
1299 return FALSE;
1300}
1301
1302BOOL WINAPI
1303FreeRDP_WTSSendMessageA(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1304 WINPR_ATTR_UNUSED LPSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
1305 WINPR_ATTR_UNUSED LPSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
1306 WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
1307 WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
1308{
1309 WLog_ERR("TODO", "TODO: implement");
1310 return FALSE;
1311}
1312
1313BOOL WINAPI FreeRDP_WTSDisconnectSession(WINPR_ATTR_UNUSED HANDLE hServer,
1314 WINPR_ATTR_UNUSED DWORD SessionId,
1315 WINPR_ATTR_UNUSED BOOL bWait)
1316{
1317 WLog_ERR("TODO", "TODO: implement");
1318 return FALSE;
1319}
1320
1321BOOL WINAPI FreeRDP_WTSLogoffSession(WINPR_ATTR_UNUSED HANDLE hServer,
1322 WINPR_ATTR_UNUSED DWORD SessionId,
1323 WINPR_ATTR_UNUSED BOOL bWait)
1324{
1325 WLog_ERR("TODO", "TODO: implement");
1326 return FALSE;
1327}
1328
1329BOOL WINAPI FreeRDP_WTSShutdownSystem(WINPR_ATTR_UNUSED HANDLE hServer,
1330 WINPR_ATTR_UNUSED DWORD ShutdownFlag)
1331{
1332 WLog_ERR("TODO", "TODO: implement");
1333 return FALSE;
1334}
1335
1336BOOL WINAPI FreeRDP_WTSWaitSystemEvent(WINPR_ATTR_UNUSED HANDLE hServer,
1337 WINPR_ATTR_UNUSED DWORD EventMask,
1338 WINPR_ATTR_UNUSED DWORD* pEventFlags)
1339{
1340 WLog_ERR("TODO", "TODO: implement");
1341 return FALSE;
1342}
1343
1344static void peer_channel_queue_free_message(void* obj)
1345{
1346 wMessage* msg = (wMessage*)obj;
1347 if (!msg)
1348 return;
1349
1350 free(msg->context);
1351 msg->context = nullptr;
1352}
1353
1354static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* client,
1355 UINT32 ChannelId, UINT16 index, UINT16 type, size_t chunkSize,
1356 const char* name)
1357{
1358 wObject queueCallbacks = WINPR_C_ARRAY_INIT;
1359 queueCallbacks.fnObjectFree = peer_channel_queue_free_message;
1360
1361 rdpPeerChannel* channel =
1362 server_channel_common_new(client, index, ChannelId, chunkSize, &queueCallbacks, name);
1363
1364 WINPR_ASSERT(vcm);
1365 WINPR_ASSERT(client);
1366
1367 if (!channel)
1368 goto fail;
1369
1370 channel->vcm = vcm;
1371 channel->channelType = type;
1372 channel->creationStatus =
1373 (type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS;
1374
1375 return channel;
1376fail:
1377 channel_free(channel);
1378 return nullptr;
1379}
1380
1381HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
1382 LPSTR pVirtualName)
1383{
1384 size_t length = 0;
1385 rdpMcs* mcs = nullptr;
1386 rdpMcsChannel* joined_channel = nullptr;
1387 freerdp_peer* client = nullptr;
1388 rdpPeerChannel* channel = nullptr;
1389 WTSVirtualChannelManager* vcm = nullptr;
1390 HANDLE hChannelHandle = nullptr;
1391 rdpContext* context = nullptr;
1392 vcm = (WTSVirtualChannelManager*)hServer;
1393
1394 if (!vcm)
1395 {
1396 SetLastError(ERROR_INVALID_DATA);
1397 return nullptr;
1398 }
1399
1400 client = vcm->client;
1401 WINPR_ASSERT(client);
1402
1403 context = client->context;
1404 WINPR_ASSERT(context);
1405 WINPR_ASSERT(context->rdp);
1406 WINPR_ASSERT(context->settings);
1407
1408 mcs = context->rdp->mcs;
1409 WINPR_ASSERT(mcs);
1410
1411 length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1);
1412
1413 if (length > CHANNEL_NAME_LEN)
1414 {
1415 SetLastError(ERROR_NOT_FOUND);
1416 return nullptr;
1417 }
1418
1419 UINT32 index = 0;
1420 for (; index < mcs->channelCount; index++)
1421 {
1422 rdpMcsChannel* mchannel = &mcs->channels[index];
1423 if (mchannel->joined && (strncmp(mchannel->Name, pVirtualName, length) == 0))
1424 {
1425 joined_channel = mchannel;
1426 break;
1427 }
1428 }
1429
1430 if (!joined_channel)
1431 {
1432 SetLastError(ERROR_NOT_FOUND);
1433 return nullptr;
1434 }
1435
1436 channel = (rdpPeerChannel*)joined_channel->handle;
1437
1438 if (!channel)
1439 {
1440 const UINT32 VCChunkSize =
1441 freerdp_settings_get_uint32(context->settings, FreeRDP_VCChunkSize);
1442
1443 WINPR_ASSERT(index <= UINT16_MAX);
1444 channel = channel_new(vcm, client, joined_channel->ChannelId, (UINT16)index,
1445 RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName);
1446
1447 if (!channel)
1448 goto fail;
1449
1450 joined_channel->handle = channel;
1451 }
1452
1453 hChannelHandle = (HANDLE)channel;
1454 return hChannelHandle;
1455fail:
1456 channel_free(channel);
1457 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1458 return nullptr;
1459}
1460
1461HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
1462{
1463 wStream* s = nullptr;
1464 rdpPeerChannel* channel = nullptr;
1465 BOOL joined = FALSE;
1466 ULONG written = 0;
1467
1468 if (!setup())
1469 return nullptr;
1470
1471 if (SessionId == WTS_CURRENT_SESSION)
1472 return nullptr;
1473
1474 HashTable_Lock(g_ServerHandles);
1475 WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)HashTable_GetItemValue(
1476 g_ServerHandles, (void*)(UINT_PTR)SessionId);
1477
1478 if (!vcm)
1479 goto end;
1480
1481 if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC))
1482 {
1483 HashTable_Unlock(g_ServerHandles);
1484 return FreeRDP_WTSVirtualChannelOpen((HANDLE)vcm, SessionId, pVirtualName);
1485 }
1486
1487 freerdp_peer* client = vcm->client;
1488 WINPR_ASSERT(client);
1489 WINPR_ASSERT(client->context);
1490 WINPR_ASSERT(client->context->rdp);
1491
1492 rdpMcs* mcs = client->context->rdp->mcs;
1493 WINPR_ASSERT(mcs);
1494
1495 for (UINT32 index = 0; index < mcs->channelCount; index++)
1496 {
1497 rdpMcsChannel* mchannel = &mcs->channels[index];
1498 if (mchannel->joined &&
1499 (strncmp(mchannel->Name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
1500 {
1501 joined = TRUE;
1502 break;
1503 }
1504 }
1505
1506 if (!joined)
1507 {
1508 SetLastError(ERROR_NOT_FOUND);
1509 goto end;
1510 }
1511
1512 if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY))
1513 {
1514 SetLastError(ERROR_NOT_READY);
1515 goto end;
1516 }
1517
1518 WINPR_ASSERT(client);
1519 WINPR_ASSERT(client->context);
1520 WINPR_ASSERT(client->context->settings);
1521
1522 const UINT32 VCChunkSize =
1523 freerdp_settings_get_uint32(client->context->settings, FreeRDP_VCChunkSize);
1524 channel = channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName);
1525
1526 if (!channel)
1527 {
1528 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1529 goto end;
1530 }
1531
1532 const LONG hdl = InterlockedIncrement(&vcm->dvc_channel_id_seq);
1533 channel->channelId = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
1534
1535 if (!HashTable_Insert(vcm->dynamicVirtualChannels, &channel->channelId, channel))
1536 {
1537 channel_free(channel);
1538 channel = nullptr;
1539 goto fail;
1540 }
1541 s = Stream_New(nullptr, 64);
1542
1543 if (!s)
1544 goto fail;
1545
1546 if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName))
1547 goto fail;
1548
1549 {
1550 const size_t pos = Stream_GetPosition(s);
1551 WINPR_ASSERT(pos <= UINT32_MAX);
1552 if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char), (UINT32)pos,
1553 &written))
1554 goto fail;
1555 }
1556
1557end:
1558 Stream_Free(s, TRUE);
1559 HashTable_Unlock(g_ServerHandles);
1560 return channel;
1561
1562fail:
1563 Stream_Free(s, TRUE);
1564 if (channel)
1565 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1566 HashTable_Unlock(g_ServerHandles);
1567
1568 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1569 return nullptr;
1570}
1571
1572BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
1573{
1574 wStream* s = nullptr;
1575 rdpMcs* mcs = nullptr;
1576
1577 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1578 BOOL ret = TRUE;
1579
1580 if (channel)
1581 {
1582 WTSVirtualChannelManager* vcm = channel->vcm;
1583
1584 WINPR_ASSERT(vcm);
1585 WINPR_ASSERT(vcm->client);
1586 WINPR_ASSERT(vcm->client->context);
1587 WINPR_ASSERT(vcm->client->context->rdp);
1588 mcs = vcm->client->context->rdp->mcs;
1589
1590 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1591 {
1592 if (channel->index < mcs->channelCount)
1593 {
1594 rdpMcsChannel* cur = &mcs->channels[channel->index];
1595 rdpPeerChannel* peerChannel = (rdpPeerChannel*)cur->handle;
1596 channel_free(peerChannel);
1597 cur->handle = nullptr;
1598 }
1599 }
1600 else
1601 {
1602 if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
1603 {
1604 ULONG written = 0;
1605 s = Stream_New(nullptr, 8);
1606
1607 if (!s)
1608 {
1609 WLog_ERR(TAG, "Stream_New failed!");
1610 ret = FALSE;
1611 }
1612 else
1613 {
1614 wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
1615
1616 const size_t pos = Stream_GetPosition(s);
1617 WINPR_ASSERT(pos <= UINT32_MAX);
1618 ret = WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char),
1619 (UINT32)pos, &written);
1620 Stream_Free(s, TRUE);
1621 }
1622 }
1623 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1624 }
1625 }
1626
1627 return ret;
1628}
1629
1630BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, WINPR_ATTR_UNUSED ULONG TimeOut,
1631 PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead)
1632{
1633 BYTE* buffer = nullptr;
1634 wMessage message = WINPR_C_ARRAY_INIT;
1635 wtsChannelMessage* messageCtx = nullptr;
1636 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1637
1638 WINPR_ASSERT(channel);
1639
1640 if (!MessageQueue_Peek(channel->queue, &message, FALSE))
1641 {
1642 SetLastError(ERROR_NO_DATA);
1643 *pBytesRead = 0;
1644 return FALSE;
1645 }
1646
1647 messageCtx = message.context;
1648
1649 if (messageCtx == nullptr)
1650 return FALSE;
1651
1652 buffer = (BYTE*)(messageCtx + 1);
1653 *pBytesRead = messageCtx->length - messageCtx->offset;
1654
1655 if (Buffer == nullptr || BufferSize == 0)
1656 {
1657 return TRUE;
1658 }
1659
1660 if (*pBytesRead > BufferSize)
1661 *pBytesRead = BufferSize;
1662
1663 CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
1664 messageCtx->offset += *pBytesRead;
1665
1666 if (messageCtx->offset >= messageCtx->length)
1667 {
1668 const int rc = MessageQueue_Peek(channel->queue, &message, TRUE);
1669 peer_channel_queue_free_message(&message);
1670 if (rc < 0)
1671 return FALSE;
1672 }
1673
1674 return TRUE;
1675}
1676
1677BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG uLength,
1678 PULONG pBytesWritten)
1679{
1680 wStream* s = nullptr;
1681 int cbLen = 0;
1682 int cbChId = 0;
1683 int first = 0;
1684 BYTE* buffer = nullptr;
1685 size_t totalWritten = 0;
1686 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1687 BOOL ret = FALSE;
1688
1689 if (!channel)
1690 return FALSE;
1691
1692 EnterCriticalSection(&channel->writeLock);
1693 WINPR_ASSERT(channel->vcm);
1694 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1695 {
1696 buffer = (BYTE*)malloc(uLength);
1697
1698 if (!buffer)
1699 {
1700 SetLastError(g_err_oom);
1701 goto fail;
1702 }
1703
1704 CopyMemory(buffer, Buffer, uLength);
1705 totalWritten = uLength;
1706 if (!wts_queue_send_item(channel, buffer, uLength))
1707 goto fail;
1708 }
1709 else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
1710 {
1711 DEBUG_DVC("drdynvc not ready");
1712 goto fail;
1713 }
1714 else
1715 {
1716 first = TRUE;
1717
1718 size_t Length = uLength;
1719 while (Length > 0)
1720 {
1721 s = Stream_New(nullptr, DVC_MAX_DATA_PDU_SIZE);
1722
1723 if (!s)
1724 {
1725 WLog_ERR(TAG, "Stream_New failed!");
1726 SetLastError(g_err_oom);
1727 goto fail;
1728 }
1729
1730 buffer = Stream_Buffer(s);
1731 Stream_Seek_UINT8(s);
1732 cbChId = wts_write_variable_uint(s, channel->channelId);
1733
1734 if (first && (Length > Stream_GetRemainingLength(s)))
1735 {
1736 cbLen = wts_write_variable_uint(s, WINPR_ASSERTING_INT_CAST(uint32_t, Length));
1737 buffer[0] = ((DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId) & 0xFF;
1738 }
1739 else
1740 {
1741 buffer[0] = ((DATA_PDU << 4) | cbChId) & 0xFF;
1742 }
1743
1744 first = FALSE;
1745 size_t written = Stream_GetRemainingLength(s);
1746
1747 if (written > Length)
1748 written = Length;
1749
1750 Stream_Write(s, Buffer, written);
1751 const size_t length = Stream_GetPosition(s);
1752 Stream_Free(s, FALSE);
1753 if (length > UINT32_MAX)
1754 goto fail;
1755 Length -= written;
1756 Buffer += written;
1757 totalWritten += written;
1758 if (!wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, (UINT32)length))
1759 goto fail;
1760 }
1761 }
1762
1763 if (pBytesWritten)
1764 *pBytesWritten = WINPR_ASSERTING_INT_CAST(uint32_t, totalWritten);
1765
1766 ret = TRUE;
1767fail:
1768 LeaveCriticalSection(&channel->writeLock);
1769 return ret;
1770}
1771
1772BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
1773{
1774 WLog_ERR("TODO", "TODO: implement");
1775 return TRUE;
1776}
1777
1778BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
1779{
1780 WLog_ERR("TODO", "TODO: implement");
1781 return TRUE;
1782}
1783
1784BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
1785 PVOID* ppBuffer, DWORD* pBytesReturned)
1786{
1787 void* pfd = nullptr;
1788 BOOL bval = 0;
1789 void* fds[10] = WINPR_C_ARRAY_INIT;
1790 HANDLE hEvent = nullptr;
1791 int fds_count = 0;
1792 BOOL status = FALSE;
1793 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1794
1795 WINPR_ASSERT(channel);
1796
1797 switch ((UINT32)WtsVirtualClass)
1798 {
1799 case WTSVirtualFileHandle:
1800 hEvent = MessageQueue_Event(channel->queue);
1801 pfd = GetEventWaitObject(hEvent);
1802
1803 if (pfd)
1804 {
1805 fds[fds_count] = pfd;
1806 (fds_count)++;
1807 }
1808
1809 *ppBuffer = malloc(sizeof(void*));
1810
1811 if (!*ppBuffer)
1812 {
1813 SetLastError(g_err_oom);
1814 }
1815 else
1816 {
1817 CopyMemory(*ppBuffer, (void*)&fds[0], sizeof(void*));
1818 *pBytesReturned = sizeof(void*);
1819 status = TRUE;
1820 }
1821
1822 break;
1823
1824 case WTSVirtualEventHandle:
1825 hEvent = MessageQueue_Event(channel->queue);
1826
1827 *ppBuffer = malloc(sizeof(HANDLE));
1828
1829 if (!*ppBuffer)
1830 {
1831 SetLastError(g_err_oom);
1832 }
1833 else
1834 {
1835 CopyMemory(*ppBuffer, (void*)&hEvent, sizeof(HANDLE));
1836 *pBytesReturned = sizeof(void*);
1837 status = TRUE;
1838 }
1839
1840 break;
1841
1842 case WTSVirtualChannelReady:
1843 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1844 {
1845 bval = TRUE;
1846 status = TRUE;
1847 }
1848 else
1849 {
1850 switch (channel->dvc_open_state)
1851 {
1852 case DVC_OPEN_STATE_NONE:
1853 bval = FALSE;
1854 status = TRUE;
1855 break;
1856
1857 case DVC_OPEN_STATE_SUCCEEDED:
1858 bval = TRUE;
1859 status = TRUE;
1860 break;
1861
1862 default:
1863 *ppBuffer = nullptr;
1864 *pBytesReturned = 0;
1865 return FALSE;
1866 }
1867 }
1868
1869 *ppBuffer = malloc(sizeof(BOOL));
1870
1871 if (!*ppBuffer)
1872 {
1873 SetLastError(g_err_oom);
1874 status = FALSE;
1875 }
1876 else
1877 {
1878 CopyMemory(*ppBuffer, &bval, sizeof(BOOL));
1879 *pBytesReturned = sizeof(BOOL);
1880 }
1881
1882 break;
1883 case WTSVirtualChannelOpenStatus:
1884 {
1885 INT32 value = channel->creationStatus;
1886 status = TRUE;
1887
1888 *ppBuffer = malloc(sizeof(value));
1889 if (!*ppBuffer)
1890 {
1891 SetLastError(g_err_oom);
1892 status = FALSE;
1893 }
1894 else
1895 {
1896 CopyMemory(*ppBuffer, &value, sizeof(value));
1897 *pBytesReturned = sizeof(value);
1898 }
1899 break;
1900 }
1901 default:
1902 break;
1903 }
1904
1905 return status;
1906}
1907
1908VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory)
1909{
1910 free(pMemory);
1911}
1912
1913BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
1914 WINPR_ATTR_UNUSED PVOID pMemory,
1915 WINPR_ATTR_UNUSED ULONG NumberOfEntries)
1916{
1917 WLog_ERR("TODO", "TODO: implement");
1918 return FALSE;
1919}
1920
1921BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
1922 WINPR_ATTR_UNUSED PVOID pMemory,
1923 WINPR_ATTR_UNUSED ULONG NumberOfEntries)
1924{
1925 WLog_ERR("TODO", "TODO: implement");
1926 return FALSE;
1927}
1928
1929BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd,
1930 WINPR_ATTR_UNUSED DWORD dwFlags)
1931{
1932 WLog_ERR("TODO", "TODO: implement");
1933 return FALSE;
1934}
1935
1936BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd)
1937{
1938 WLog_ERR("TODO", "TODO: implement");
1939 return FALSE;
1940}
1941
1942BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
1943 WINPR_ATTR_UNUSED HWND hWnd,
1944 WINPR_ATTR_UNUSED DWORD dwFlags)
1945{
1946 WLog_ERR("TODO", "TODO: implement");
1947 return FALSE;
1948}
1949
1950BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
1951 WINPR_ATTR_UNUSED HWND hWnd)
1952{
1953 WLog_ERR("TODO", "TODO: implement");
1954 return FALSE;
1955}
1956
1957BOOL WINAPI FreeRDP_WTSQueryUserToken(WINPR_ATTR_UNUSED ULONG SessionId,
1958 WINPR_ATTR_UNUSED PHANDLE phToken)
1959{
1960 WLog_ERR("TODO", "TODO: implement");
1961 return FALSE;
1962}
1963
1964BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(WINPR_ATTR_UNUSED HANDLE hServer,
1965 WINPR_ATTR_UNUSED DWORD* pLevel,
1966 WINPR_ATTR_UNUSED DWORD SessionId,
1967 WINPR_ATTR_UNUSED LPWSTR* ppProcessInfo,
1968 WINPR_ATTR_UNUSED DWORD* pCount)
1969{
1970 WLog_ERR("TODO", "TODO: implement");
1971 return FALSE;
1972}
1973
1974BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(WINPR_ATTR_UNUSED HANDLE hServer,
1975 WINPR_ATTR_UNUSED DWORD* pLevel,
1976 WINPR_ATTR_UNUSED DWORD SessionId,
1977 WINPR_ATTR_UNUSED LPSTR* ppProcessInfo,
1978 WINPR_ATTR_UNUSED DWORD* pCount)
1979{
1980 WLog_ERR("TODO", "TODO: implement");
1981 return FALSE;
1982}
1983
1984BOOL WINAPI FreeRDP_WTSEnumerateListenersW(WINPR_ATTR_UNUSED HANDLE hServer,
1985 WINPR_ATTR_UNUSED PVOID pReserved,
1986 WINPR_ATTR_UNUSED DWORD Reserved,
1987 WINPR_ATTR_UNUSED PWTSLISTENERNAMEW pListeners,
1988 WINPR_ATTR_UNUSED DWORD* pCount)
1989{
1990 WLog_ERR("TODO", "TODO: implement");
1991 return FALSE;
1992}
1993
1994BOOL WINAPI FreeRDP_WTSEnumerateListenersA(WINPR_ATTR_UNUSED HANDLE hServer,
1995 WINPR_ATTR_UNUSED PVOID pReserved,
1996 WINPR_ATTR_UNUSED DWORD Reserved,
1997 WINPR_ATTR_UNUSED PWTSLISTENERNAMEA pListeners,
1998 WINPR_ATTR_UNUSED DWORD* pCount)
1999{
2000 WLog_ERR("TODO", "TODO: implement");
2001 return FALSE;
2002}
2003
2004BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(WINPR_ATTR_UNUSED HANDLE hServer,
2005 WINPR_ATTR_UNUSED PVOID pReserved,
2006 WINPR_ATTR_UNUSED DWORD Reserved,
2007 WINPR_ATTR_UNUSED LPWSTR pListenerName,
2008 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer)
2009{
2010 WLog_ERR("TODO", "TODO: implement");
2011 return FALSE;
2012}
2013
2014BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(WINPR_ATTR_UNUSED HANDLE hServer,
2015 WINPR_ATTR_UNUSED PVOID pReserved,
2016 WINPR_ATTR_UNUSED DWORD Reserved,
2017 WINPR_ATTR_UNUSED LPSTR pListenerName,
2018 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer)
2019{
2020 WLog_ERR("TODO", "TODO: implement");
2021 return FALSE;
2022}
2023
2024BOOL WINAPI FreeRDP_WTSCreateListenerW(WINPR_ATTR_UNUSED HANDLE hServer,
2025 WINPR_ATTR_UNUSED PVOID pReserved,
2026 WINPR_ATTR_UNUSED DWORD Reserved,
2027 WINPR_ATTR_UNUSED LPWSTR pListenerName,
2028 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer,
2029 WINPR_ATTR_UNUSED DWORD flag)
2030{
2031 WLog_ERR("TODO", "TODO: implement");
2032 return FALSE;
2033}
2034
2035BOOL WINAPI FreeRDP_WTSCreateListenerA(WINPR_ATTR_UNUSED HANDLE hServer,
2036 WINPR_ATTR_UNUSED PVOID pReserved,
2037 WINPR_ATTR_UNUSED DWORD Reserved,
2038 WINPR_ATTR_UNUSED LPSTR pListenerName,
2039 WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer,
2040 WINPR_ATTR_UNUSED DWORD flag)
2041{
2042 WLog_ERR("TODO", "TODO: implement");
2043 return FALSE;
2044}
2045
2046BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(
2047 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2048 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
2049 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2050 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
2051{
2052 WLog_ERR("TODO", "TODO: implement");
2053 return FALSE;
2054}
2055
2056BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(
2057 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2058 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
2059 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2060 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
2061{
2062 WLog_ERR("TODO", "TODO: implement");
2063 return FALSE;
2064}
2065
2066BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(
2067 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2068 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
2069 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2070 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
2071 WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
2072{
2073 WLog_ERR("TODO", "TODO: implement");
2074 return FALSE;
2075}
2076
2077BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(
2078 WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
2079 WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
2080 WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
2081 WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
2082 WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
2083{
2084 WLog_ERR("TODO", "TODO: implement");
2085 return FALSE;
2086}
2087
2088BOOL CDECL FreeRDP_WTSEnableChildSessions(WINPR_ATTR_UNUSED BOOL bEnable)
2089{
2090 WLog_ERR("TODO", "TODO: implement");
2091 return FALSE;
2092}
2093
2094BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(WINPR_ATTR_UNUSED PBOOL pbEnabled)
2095{
2096 WLog_ERR("TODO", "TODO: implement");
2097 return FALSE;
2098}
2099
2100BOOL CDECL FreeRDP_WTSGetChildSessionId(WINPR_ATTR_UNUSED PULONG pSessionId)
2101{
2102 WLog_ERR("TODO", "TODO: implement");
2103 return FALSE;
2104}
2105
2106DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(void)
2107{
2108 WLog_ERR("TODO", "TODO: implement");
2109 return 0xFFFFFFFF;
2110}
2111BOOL WINAPI FreeRDP_WTSLogoffUser(WINPR_ATTR_UNUSED HANDLE hServer)
2112{
2113 WLog_ERR("TODO", "TODO: implement");
2114 return FALSE;
2115}
2116
2117BOOL WINAPI FreeRDP_WTSLogonUser(WINPR_ATTR_UNUSED HANDLE hServer,
2118 WINPR_ATTR_UNUSED LPCSTR username,
2119 WINPR_ATTR_UNUSED LPCSTR password, WINPR_ATTR_UNUSED LPCSTR domain)
2120{
2121 WLog_ERR("TODO", "TODO: implement");
2122 return FALSE;
2123}
2124
2125void server_channel_common_free(rdpPeerChannel* channel)
2126{
2127 if (!channel)
2128 return;
2129 MessageQueue_Free(channel->queue);
2130 Stream_Free(channel->receiveData, TRUE);
2131 DeleteCriticalSection(&channel->writeLock);
2132 free(channel);
2133}
2134
2135rdpPeerChannel* server_channel_common_new(freerdp_peer* client, UINT16 index, UINT32 channelId,
2136 size_t chunkSize, const wObject* callback,
2137 const char* name)
2138{
2139 rdpPeerChannel* channel = (rdpPeerChannel*)calloc(1, sizeof(rdpPeerChannel));
2140 if (!channel)
2141 return nullptr;
2142
2143 InitializeCriticalSection(&channel->writeLock);
2144
2145 channel->receiveData = Stream_New(nullptr, chunkSize);
2146 if (!channel->receiveData)
2147 goto fail;
2148
2149 channel->queue = MessageQueue_New(callback);
2150 if (!channel->queue)
2151 goto fail;
2152
2153 channel->index = index;
2154 channel->client = client;
2155 channel->channelId = channelId;
2156 strncpy(channel->channelName, name, ARRAYSIZE(channel->channelName) - 1);
2157 return channel;
2158fail:
2159 WINPR_PRAGMA_DIAG_PUSH
2160 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2161 server_channel_common_free(channel);
2162 WINPR_PRAGMA_DIAG_POP
2163 return nullptr;
2164}
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