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