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