FreeRDP
Loading...
Searching...
No Matches
client/remdesk_main.c
1
22#include <freerdp/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/assert.h>
26#include <winpr/print.h>
27
28#include <freerdp/freerdp.h>
29#include <freerdp/assistance.h>
30
31#include <freerdp/channels/log.h>
32#include <freerdp/client/remdesk.h>
33
34#include "remdesk_main.h"
35#include "remdesk_common.h"
36
42static UINT remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s)
43{
44 UINT32 status = 0;
45
46 if (!remdesk)
47 {
48 WLog_ERR(TAG, "remdesk was null!");
49 Stream_Free(s, TRUE);
50 return CHANNEL_RC_INVALID_INSTANCE;
51 }
52
53 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelWriteEx);
54 status = remdesk->channelEntryPoints.pVirtualChannelWriteEx(
55 remdesk->InitHandle, remdesk->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s);
56
57 if (status != CHANNEL_RC_OK)
58 {
59 Stream_Free(s, TRUE);
60 WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
61 WTSErrorToString(status), status);
62 }
63 return status;
64}
65
71static UINT remdesk_generate_expert_blob(remdeskPlugin* remdesk)
72{
73 const char* name = nullptr;
74 char* pass = nullptr;
75 const char* password = nullptr;
76 rdpSettings* settings = nullptr;
77
78 WINPR_ASSERT(remdesk);
79
80 WINPR_ASSERT(remdesk->rdpcontext);
81 settings = remdesk->rdpcontext->settings;
82 WINPR_ASSERT(settings);
83
84 if (remdesk->ExpertBlob)
85 return CHANNEL_RC_OK;
86
87 password = freerdp_settings_get_string(settings, FreeRDP_RemoteAssistancePassword);
88 if (!password)
89 password = freerdp_settings_get_string(settings, FreeRDP_Password);
90
91 if (!password)
92 {
93 WLog_ERR(TAG, "password was not set!");
94 return ERROR_INTERNAL_ERROR;
95 }
96
97 name = freerdp_settings_get_string(settings, FreeRDP_Username);
98
99 if (!name)
100 name = "Expert";
101
102 const char* stub = freerdp_settings_get_string(settings, FreeRDP_RemoteAssistancePassStub);
103 remdesk->EncryptedPassStub =
104 freerdp_assistance_encrypt_pass_stub(password, stub, &(remdesk->EncryptedPassStubSize));
105
106 if (!remdesk->EncryptedPassStub)
107 {
108 WLog_ERR(TAG, "freerdp_assistance_encrypt_pass_stub failed!");
109 return ERROR_INTERNAL_ERROR;
110 }
111
112 pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub,
113 remdesk->EncryptedPassStubSize);
114
115 if (!pass)
116 {
117 WLog_ERR(TAG, "freerdp_assistance_bin_to_hex_string failed!");
118 return ERROR_INTERNAL_ERROR;
119 }
120
121 remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass);
122 free(pass);
123
124 if (!remdesk->ExpertBlob)
125 {
126 WLog_ERR(TAG, "freerdp_assistance_construct_expert_blob failed!");
127 return ERROR_INTERNAL_ERROR;
128 }
129
130 return CHANNEL_RC_OK;
131}
132
138static UINT remdesk_recv_ctl_server_announce_pdu(WINPR_ATTR_UNUSED remdeskPlugin* remdesk,
139 WINPR_ATTR_UNUSED wStream* s,
140 WINPR_ATTR_UNUSED REMDESK_CHANNEL_HEADER* header)
141{
142 WINPR_ASSERT(remdesk);
143 WINPR_ASSERT(s);
144 WINPR_ASSERT(header);
145
146 WLog_ERR("TODO", "TODO: implement");
147 return CHANNEL_RC_OK;
148}
149
155static UINT remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s,
156 WINPR_ATTR_UNUSED REMDESK_CHANNEL_HEADER* header)
157{
158 WINPR_ASSERT(remdesk);
159 WINPR_ASSERT(s);
160 WINPR_ASSERT(header);
161
162 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
163 return ERROR_INVALID_DATA;
164
165 const UINT32 versionMajor = Stream_Get_UINT32(s); /* versionMajor (4 bytes) */
166 const UINT32 versionMinor = Stream_Get_UINT32(s); /* versionMinor (4 bytes) */
167
168 if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0))
169 {
170 WLog_ERR(TAG, "Unsupported protocol version %" PRIu32 ".%" PRIu32, versionMajor,
171 versionMinor);
172 }
173
174 remdesk->Version = versionMinor;
175 return CHANNEL_RC_OK;
176}
177
183static UINT remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk)
184{
185 REMDESK_CTL_VERSION_INFO_PDU pdu = WINPR_C_ARRAY_INIT;
186
187 WINPR_ASSERT(remdesk);
188
189 UINT error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
190 if (error)
191 return error;
192
193 pdu.versionMajor = 1;
194 pdu.versionMinor = 2;
195 wStream* s = Stream_New(nullptr, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
196
197 if (!s)
198 {
199 WLog_ERR(TAG, "Stream_New failed!");
200 return CHANNEL_RC_NO_MEMORY;
201 }
202
203 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
204 if (error)
205 {
206 Stream_Free(s, TRUE);
207 return error;
208 }
209 Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */
210 Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */
211 Stream_SealLength(s);
212
213 if ((error = remdesk_virtual_channel_write(remdesk, s)))
214 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
215
216 return error;
217}
218
224static UINT remdesk_recv_ctl_result_pdu(WINPR_ATTR_UNUSED remdeskPlugin* remdesk, wStream* s,
225 WINPR_ATTR_UNUSED REMDESK_CHANNEL_HEADER* header,
226 UINT32* pResult)
227{
228 UINT32 result = 0;
229
230 WINPR_ASSERT(remdesk);
231 WINPR_ASSERT(s);
232 WINPR_ASSERT(header);
233 WINPR_ASSERT(pResult);
234
235 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
236 return ERROR_INVALID_DATA;
237
238 Stream_Read_UINT32(s, result); /* result (4 bytes) */
239 *pResult = result;
240 // WLog_DBG(TAG, "RemdeskRecvResult: 0x%08"PRIX32"", result);
241 switch (result)
242 {
243 case REMDESK_ERROR_HELPEESAIDNO:
244 WLog_DBG(TAG, "remote assistance connection request was denied");
245 return ERROR_CONNECTION_REFUSED;
246
247 default:
248 break;
249 }
250
251 return CHANNEL_RC_OK;
252}
253
259static UINT remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk)
260{
261 UINT error = ERROR_INTERNAL_ERROR;
262 size_t cbExpertBlobW = 0;
263 WCHAR* expertBlobW = nullptr;
264 size_t cbRaConnectionStringW = 0;
265 REMDESK_CTL_HEADER ctlHeader = WINPR_C_ARRAY_INIT;
266
267 WINPR_ASSERT(remdesk);
268
269 if ((error = remdesk_generate_expert_blob(remdesk)))
270 {
271 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "", error);
272 return error;
273 }
274
275 const char* expertBlob = remdesk->ExpertBlob;
276 WINPR_ASSERT(remdesk->rdpcontext);
277 rdpSettings* settings = remdesk->rdpcontext->settings;
278 WINPR_ASSERT(settings);
279
280 const char* raConnectionString =
281 freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
282 WCHAR* raConnectionStringW =
283 ConvertUtf8ToWCharAlloc(raConnectionString, &cbRaConnectionStringW);
284
285 if (!raConnectionStringW || (cbRaConnectionStringW > UINT32_MAX / sizeof(WCHAR)))
286 goto out;
287
288 cbRaConnectionStringW = cbRaConnectionStringW * sizeof(WCHAR);
289
290 expertBlobW = ConvertUtf8ToWCharAlloc(expertBlob, &cbExpertBlobW);
291
292 if (!expertBlobW)
293 goto out;
294
295 cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
296 error = remdesk_prepare_ctl_header(&(ctlHeader), REMDESK_CTL_AUTHENTICATE,
297 cbRaConnectionStringW + cbExpertBlobW);
298 if (error)
299 goto out;
300
301 {
302 wStream* s = Stream_New(nullptr, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
303 if (!s)
304 {
305 WLog_ERR(TAG, "Stream_New failed!");
306 error = CHANNEL_RC_NO_MEMORY;
307 goto out;
308 }
309
310 error = remdesk_write_ctl_header(s, &ctlHeader);
311 if (error)
312 {
313 Stream_Free(s, TRUE);
314 goto out;
315 }
316 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
317 Stream_Write(s, expertBlobW, cbExpertBlobW);
318 Stream_SealLength(s);
319
320 error = remdesk_virtual_channel_write(remdesk, s);
321 }
322 if (error)
323 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
324
325out:
326 free(raConnectionStringW);
327 free(expertBlobW);
328
329 return error;
330}
331
337static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk)
338{
339 UINT error = 0;
340 size_t length = 0;
341
342 WINPR_ASSERT(remdesk);
343 WINPR_ASSERT(remdesk->rdpcontext);
344 rdpSettings* settings = remdesk->rdpcontext->settings;
345 WINPR_ASSERT(settings);
346
347 const char* raConnectionString =
348 freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
349 WCHAR* raConnectionStringW = ConvertUtf8ToWCharAlloc(raConnectionString, &length);
350 size_t cbRaConnectionStringW = length * sizeof(WCHAR);
351
352 if (!raConnectionStringW)
353 return ERROR_INTERNAL_ERROR;
354
355 REMDESK_CTL_HEADER ctlHeader = WINPR_C_ARRAY_INIT;
356 error = remdesk_prepare_ctl_header(&ctlHeader, REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
357 cbRaConnectionStringW);
358 if (error != CHANNEL_RC_OK)
359 goto out;
360
361 {
362 wStream* s = Stream_New(nullptr, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
363
364 if (!s)
365 {
366 WLog_ERR(TAG, "Stream_New failed!");
367 error = CHANNEL_RC_NO_MEMORY;
368 goto out;
369 }
370
371 error = remdesk_write_ctl_header(s, &ctlHeader);
372 if (error)
373 {
374 Stream_Free(s, TRUE);
375 goto out;
376 }
377 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
378 Stream_SealLength(s);
379
380 if ((error = remdesk_virtual_channel_write(remdesk, s)))
381 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
382 }
383
384out:
385 free(raConnectionStringW);
386
387 return error;
388}
389
395static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk)
396{
397 size_t cbExpertBlobW = 0;
398 REMDESK_CTL_VERIFY_PASSWORD_PDU pdu = WINPR_C_ARRAY_INIT;
399
400 WINPR_ASSERT(remdesk);
401
402 UINT error = remdesk_generate_expert_blob(remdesk);
403 if (error)
404 {
405 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
406 return error;
407 }
408
409 pdu.expertBlob = remdesk->ExpertBlob;
410 WCHAR* expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
411
412 if (!expertBlobW)
413 goto out;
414
415 cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
416 error =
417 remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
418 if (error)
419 goto out;
420
421 {
422 wStream* s =
423 Stream_New(nullptr, 1ULL * REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
424
425 if (!s)
426 {
427 WLog_ERR(TAG, "Stream_New failed!");
428 error = CHANNEL_RC_NO_MEMORY;
429 goto out;
430 }
431
432 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
433 if (error)
434 {
435 Stream_Free(s, TRUE);
436 goto out;
437 }
438 Stream_Write(s, expertBlobW, cbExpertBlobW);
439 Stream_SealLength(s);
440
441 error = remdesk_virtual_channel_write(remdesk, s);
442 }
443 if (error)
444 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
445
446out:
447 free(expertBlobW);
448
449 return error;
450}
451
457static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk)
458{
459 REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu = WINPR_C_ARRAY_INIT;
460
461 WINPR_ASSERT(remdesk);
462
463 UINT error = remdesk_generate_expert_blob(remdesk);
464 if (error)
465 {
466 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
467 return error;
468 }
469 if (remdesk->EncryptedPassStubSize > UINT32_MAX)
470 return ERROR_INTERNAL_ERROR;
471
472 pdu.EncryptedPasswordLength = (UINT32)remdesk->EncryptedPassStubSize;
473 pdu.EncryptedPassword = remdesk->EncryptedPassStub;
474 error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
475 pdu.EncryptedPasswordLength);
476 if (error)
477 return error;
478
479 wStream* s = Stream_New(nullptr, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
480
481 if (!s)
482 {
483 WLog_ERR(TAG, "Stream_New failed!");
484 return CHANNEL_RC_NO_MEMORY;
485 }
486
487 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
488 if (error)
489 {
490 Stream_Free(s, TRUE);
491 return error;
492 }
493 Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
494 Stream_SealLength(s);
495 return remdesk_virtual_channel_write(remdesk, s);
496}
497
503static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
504{
505 UINT error = CHANNEL_RC_OK;
506 UINT32 msgType = 0;
507 UINT32 result = 0;
508
509 WINPR_ASSERT(remdesk);
510 WINPR_ASSERT(s);
511 WINPR_ASSERT(header);
512
513 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
514 return ERROR_INVALID_DATA;
515
516 Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
517
518 // WLog_DBG(TAG, "msgType: %"PRIu32"", msgType);
519
520 switch (msgType)
521 {
522 case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
523 break;
524
525 case REMDESK_CTL_RESULT:
526 if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
527 WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %" PRIu32 "", error);
528
529 break;
530
531 case REMDESK_CTL_AUTHENTICATE:
532 break;
533
534 case REMDESK_CTL_SERVER_ANNOUNCE:
535 if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
536 WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32 "",
537 error);
538
539 break;
540
541 case REMDESK_CTL_DISCONNECT:
542 break;
543
544 case REMDESK_CTL_VERSIONINFO:
545 if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
546 {
547 WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "",
548 error);
549 break;
550 }
551
552 if (remdesk->Version == 1)
553 {
554 if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
555 {
556 WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "",
557 error);
558 break;
559 }
560
561 if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
562 {
563 WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32 "",
564 error);
565 break;
566 }
567
568 if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
569 {
570 WLog_ERR(
571 TAG,
572 "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32 "",
573 error);
574 break;
575 }
576 }
577 else if (remdesk->Version == 2)
578 {
579 if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
580 {
581 WLog_ERR(TAG,
582 "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32 "",
583 error);
584 break;
585 }
586
587 if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
588 {
589 WLog_ERR(TAG,
590 "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32 "",
591 error);
592 break;
593 }
594 }
595
596 break;
597
598 case REMDESK_CTL_ISCONNECTED:
599 break;
600
601 case REMDESK_CTL_VERIFY_PASSWORD:
602 break;
603
604 case REMDESK_CTL_EXPERT_ON_VISTA:
605 break;
606
607 case REMDESK_CTL_RANOVICE_NAME:
608 break;
609
610 case REMDESK_CTL_RAEXPERT_NAME:
611 break;
612
613 case REMDESK_CTL_TOKEN:
614 break;
615
616 default:
617 WLog_ERR(TAG, "unknown msgType: %" PRIu32 "", msgType);
618 error = ERROR_INVALID_DATA;
619 break;
620 }
621
622 return error;
623}
624
630static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
631{
632 UINT status = 0;
634
635 WINPR_ASSERT(remdesk);
636 WINPR_ASSERT(s);
637
638 if ((status = remdesk_read_channel_header(s, &header)))
639 {
640 WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "", status);
641 return status;
642 }
643
644 if (strcmp(header.ChannelName, "RC_CTL") == 0)
645 {
646 status = remdesk_recv_ctl_pdu(remdesk, s, &header);
647 }
648 else if (strcmp(header.ChannelName, "70") == 0)
649 {
650 }
651 else if (strcmp(header.ChannelName, "71") == 0)
652 {
653 }
654 else if (strcmp(header.ChannelName, ".") == 0)
655 {
656 }
657 else if (strcmp(header.ChannelName, "1000.") == 0)
658 {
659 }
660 else if (strcmp(header.ChannelName, "RA_FX") == 0)
661 {
662 }
663 else
664 {
665 }
666
667 return status;
668}
669
670static void remdesk_process_connect(WINPR_ATTR_UNUSED remdeskPlugin* remdesk)
671{
672 WINPR_ASSERT(remdesk);
673 WLog_ERR("TODO", "TODO: implement");
674}
675
681static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, const void* pData,
682 UINT32 dataLength, UINT32 totalLength,
683 UINT32 dataFlags)
684{
685 WINPR_ASSERT(remdesk);
686
687 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
688 {
689 return CHANNEL_RC_OK;
690 }
691
692 if (dataFlags & CHANNEL_FLAG_FIRST)
693 {
694 if (remdesk->firstFlagReceived)
695 return ERROR_INVALID_DATA;
696
697 if (remdesk->data_in)
698 Stream_Free(remdesk->data_in, TRUE);
699
700 remdesk->data_in = Stream_New(nullptr, dataLength);
701
702 if (!remdesk->data_in)
703 {
704 WLog_ERR(TAG, "Stream_New failed!");
705 return CHANNEL_RC_NO_MEMORY;
706 }
707 remdesk->firstFlagReceived = TRUE;
708 remdesk->totalLength = totalLength;
709 }
710
711 wStream* data_in = remdesk->data_in;
712 if (!data_in)
713 return ERROR_INVALID_DATA;
714
715 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
716 {
717 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
718 return CHANNEL_RC_NO_MEMORY;
719 }
720
721 Stream_Write(data_in, pData, dataLength);
722 if ((Stream_GetPosition(data_in) > totalLength) || (remdesk->totalLength != totalLength))
723 return ERROR_INVALID_DATA;
724
725 if (dataFlags & CHANNEL_FLAG_LAST)
726 {
727 if (!remdesk->firstFlagReceived)
728 return ERROR_INVALID_DATA;
729 remdesk->firstFlagReceived = FALSE;
730
731 if (remdesk->totalLength != Stream_GetPosition(data_in))
732 {
733 WLog_ERR(TAG, "read error");
734 return ERROR_INTERNAL_ERROR;
735 }
736
737 remdesk->totalLength = 0;
738 remdesk->data_in = nullptr;
739 Stream_SealLength(data_in);
740 Stream_ResetPosition(data_in);
741
742 if (!MessageQueue_Post(remdesk->queue, nullptr, 0, (void*)data_in, nullptr))
743 {
744 WLog_ERR(TAG, "MessageQueue_Post failed!");
745 return ERROR_INTERNAL_ERROR;
746 }
747 }
748
749 return CHANNEL_RC_OK;
750}
751
752static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
753 UINT event, LPVOID pData,
754 UINT32 dataLength, UINT32 totalLength,
755 UINT32 dataFlags)
756{
757 UINT error = CHANNEL_RC_OK;
758 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
759
760 switch (event)
761 {
762 case CHANNEL_EVENT_INITIALIZED:
763 break;
764
765 case CHANNEL_EVENT_DATA_RECEIVED:
766 if (!remdesk || (remdesk->OpenHandle != openHandle))
767 {
768 WLog_ERR(TAG, "error no match");
769 return;
770 }
771 if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
772 totalLength, dataFlags)))
773 WLog_ERR(TAG,
774 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
775 "!",
776 error);
777
778 break;
779
780 case CHANNEL_EVENT_WRITE_CANCELLED:
781 case CHANNEL_EVENT_WRITE_COMPLETE:
782 {
783 wStream* s = (wStream*)pData;
784 Stream_Free(s, TRUE);
785 }
786 break;
787
788 case CHANNEL_EVENT_USER:
789 break;
790
791 default:
792 WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event);
793 error = ERROR_INTERNAL_ERROR;
794 break;
795 }
796
797 if (error && remdesk && remdesk->rdpcontext)
798 setChannelError(remdesk->rdpcontext, error,
799 "remdesk_virtual_channel_open_event_ex reported an error");
800}
801
802static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
803{
804 wStream* data = nullptr;
805 wMessage message = WINPR_C_ARRAY_INIT;
806 remdeskPlugin* remdesk = (remdeskPlugin*)arg;
807 UINT error = CHANNEL_RC_OK;
808
809 WINPR_ASSERT(remdesk);
810
811 remdesk_process_connect(remdesk);
812
813 while (1)
814 {
815 if (!MessageQueue_Wait(remdesk->queue))
816 {
817 WLog_ERR(TAG, "MessageQueue_Wait failed!");
818 error = ERROR_INTERNAL_ERROR;
819 break;
820 }
821
822 if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
823 {
824 WLog_ERR(TAG, "MessageQueue_Peek failed!");
825 error = ERROR_INTERNAL_ERROR;
826 break;
827 }
828
829 if (message.id == WMQ_QUIT)
830 break;
831
832 if (message.id == 0)
833 {
834 data = (wStream*)message.wParam;
835
836 if ((error = remdesk_process_receive(remdesk, data)))
837 {
838 WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
839 Stream_Free(data, TRUE);
840 break;
841 }
842
843 Stream_Free(data, TRUE);
844 }
845 }
846
847 if (error && remdesk->rdpcontext)
848 setChannelError(remdesk->rdpcontext, error,
849 "remdesk_virtual_channel_client_thread reported an error");
850
851 ExitThread(error);
852 return error;
853}
854
860static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk,
861 WINPR_ATTR_UNUSED LPVOID pData,
862 WINPR_ATTR_UNUSED UINT32 dataLength)
863{
864 UINT error = 0;
865
866 WINPR_ASSERT(remdesk);
867
868 remdesk->queue = MessageQueue_New(nullptr);
869
870 if (!remdesk->queue)
871 {
872 WLog_ERR(TAG, "MessageQueue_New failed!");
873 error = CHANNEL_RC_NO_MEMORY;
874 goto error_out;
875 }
876
877 remdesk->thread =
878 CreateThread(nullptr, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, nullptr);
879
880 if (!remdesk->thread)
881 {
882 WLog_ERR(TAG, "CreateThread failed");
883 error = ERROR_INTERNAL_ERROR;
884 goto error_out;
885 }
886
887 return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
888 remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
889 remdesk_virtual_channel_open_event_ex);
890error_out:
891 MessageQueue_Free(remdesk->queue);
892 remdesk->queue = nullptr;
893 return error;
894}
895
901static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
902{
903 UINT rc = CHANNEL_RC_OK;
904
905 WINPR_ASSERT(remdesk);
906
907 if (remdesk->queue && remdesk->thread)
908 {
909 if (MessageQueue_PostQuit(remdesk->queue, 0) &&
910 (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
911 {
912 rc = GetLastError();
913 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
914 return rc;
915 }
916 }
917
918 if (remdesk->OpenHandle != 0)
919 {
920 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
921 rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
922 remdesk->OpenHandle);
923
924 if (CHANNEL_RC_OK != rc)
925 {
926 WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
927 WTSErrorToString(rc), rc);
928 }
929
930 remdesk->OpenHandle = 0;
931 }
932 MessageQueue_Free(remdesk->queue);
933 (void)CloseHandle(remdesk->thread);
934 Stream_Free(remdesk->data_in, TRUE);
935 remdesk->data_in = nullptr;
936 remdesk->queue = nullptr;
937 remdesk->thread = nullptr;
938 return rc;
939}
940
941static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
942{
943 WINPR_ASSERT(remdesk);
944
945 remdesk->InitHandle = nullptr;
946 free(remdesk->context);
947 free(remdesk);
948}
949
950static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
951 UINT event, LPVOID pData,
952 UINT dataLength)
953{
954 UINT error = CHANNEL_RC_OK;
955 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
956
957 if (!remdesk || (remdesk->InitHandle != pInitHandle))
958 {
959 WLog_ERR(TAG, "error no match");
960 return;
961 }
962
963 switch (event)
964 {
965 case CHANNEL_EVENT_CONNECTED:
966 if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
967 WLog_ERR(TAG,
968 "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "",
969 error);
970
971 break;
972
973 case CHANNEL_EVENT_DISCONNECTED:
974 if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
975 WLog_ERR(TAG,
976 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "",
977 error);
978
979 break;
980
981 case CHANNEL_EVENT_TERMINATED:
982 remdesk_virtual_channel_event_terminated(remdesk);
983 break;
984
985 case CHANNEL_EVENT_ATTACHED:
986 case CHANNEL_EVENT_DETACHED:
987 default:
988 break;
989 }
990
991 if (error && remdesk->rdpcontext)
992 setChannelError(remdesk->rdpcontext, error,
993 "remdesk_virtual_channel_init_event reported an error");
994}
995
996/* remdesk is always built-in */
997#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
998
999FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
1000 PVOID pInitHandle))
1001{
1002 UINT rc = 0;
1003 remdeskPlugin* remdesk = nullptr;
1004 RemdeskClientContext* context = nullptr;
1005 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = nullptr;
1006
1007 if (!pEntryPoints)
1008 {
1009 return FALSE;
1010 }
1011
1012 remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin));
1013
1014 if (!remdesk)
1015 {
1016 WLog_ERR(TAG, "calloc failed!");
1017 return FALSE;
1018 }
1019
1020 remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1021 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1022 (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1023 REMDESK_SVC_CHANNEL_NAME);
1024 remdesk->Version = 2;
1025 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1026
1027 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1028 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1029 {
1030 context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext));
1031
1032 if (!context)
1033 {
1034 WLog_ERR(TAG, "calloc failed!");
1035 goto error_out;
1036 }
1037
1038 context->handle = (void*)remdesk;
1039 remdesk->context = context;
1040 remdesk->rdpcontext = pEntryPointsEx->context;
1041 }
1042
1043 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1045 remdesk->InitHandle = pInitHandle;
1046 rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1047 remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1048 remdesk_virtual_channel_init_event_ex);
1049
1050 if (CHANNEL_RC_OK != rc)
1051 {
1052 WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1053 rc);
1054 goto error_out;
1055 }
1056
1057 remdesk->channelEntryPoints.pInterface = context;
1058 return TRUE;
1059error_out:
1060 free(remdesk);
1061 free(context);
1062 return FALSE;
1063}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
Definition svc.h:60