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 = NULL;
74 char* pass = NULL;
75 const char* password = NULL;
76 rdpSettings* settings = NULL;
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{
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(NULL, 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 = NULL;
264 size_t cbRaConnectionStringW = 0;
265 REMDESK_CTL_HEADER ctlHeader = { 0 };
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(NULL, 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 = { 0 };
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(NULL, 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;
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(NULL, 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{
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(NULL, 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 wStream* data_in = NULL;
686
687 WINPR_ASSERT(remdesk);
688
689 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
690 {
691 return CHANNEL_RC_OK;
692 }
693
694 if (dataFlags & CHANNEL_FLAG_FIRST)
695 {
696 if (remdesk->data_in)
697 Stream_Free(remdesk->data_in, TRUE);
698
699 remdesk->data_in = Stream_New(NULL, totalLength);
700
701 if (!remdesk->data_in)
702 {
703 WLog_ERR(TAG, "Stream_New failed!");
704 return CHANNEL_RC_NO_MEMORY;
705 }
706 }
707
708 data_in = remdesk->data_in;
709
710 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
711 {
712 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
713 return CHANNEL_RC_NO_MEMORY;
714 }
715
716 Stream_Write(data_in, pData, dataLength);
717
718 if (dataFlags & CHANNEL_FLAG_LAST)
719 {
720 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
721 {
722 WLog_ERR(TAG, "read error");
723 return ERROR_INTERNAL_ERROR;
724 }
725
726 remdesk->data_in = NULL;
727 Stream_SealLength(data_in);
728 Stream_SetPosition(data_in, 0);
729
730 if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*)data_in, NULL))
731 {
732 WLog_ERR(TAG, "MessageQueue_Post failed!");
733 return ERROR_INTERNAL_ERROR;
734 }
735 }
736
737 return CHANNEL_RC_OK;
738}
739
740static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
741 UINT event, LPVOID pData,
742 UINT32 dataLength, UINT32 totalLength,
743 UINT32 dataFlags)
744{
745 UINT error = CHANNEL_RC_OK;
746 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
747
748 switch (event)
749 {
750 case CHANNEL_EVENT_INITIALIZED:
751 break;
752
753 case CHANNEL_EVENT_DATA_RECEIVED:
754 if (!remdesk || (remdesk->OpenHandle != openHandle))
755 {
756 WLog_ERR(TAG, "error no match");
757 return;
758 }
759 if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
760 totalLength, dataFlags)))
761 WLog_ERR(TAG,
762 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
763 "!",
764 error);
765
766 break;
767
768 case CHANNEL_EVENT_WRITE_CANCELLED:
769 case CHANNEL_EVENT_WRITE_COMPLETE:
770 {
771 wStream* s = (wStream*)pData;
772 Stream_Free(s, TRUE);
773 }
774 break;
775
776 case CHANNEL_EVENT_USER:
777 break;
778
779 default:
780 WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event);
781 error = ERROR_INTERNAL_ERROR;
782 break;
783 }
784
785 if (error && remdesk && remdesk->rdpcontext)
786 setChannelError(remdesk->rdpcontext, error,
787 "remdesk_virtual_channel_open_event_ex reported an error");
788}
789
790static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
791{
792 wStream* data = NULL;
793 wMessage message = { 0 };
794 remdeskPlugin* remdesk = (remdeskPlugin*)arg;
795 UINT error = CHANNEL_RC_OK;
796
797 WINPR_ASSERT(remdesk);
798
799 remdesk_process_connect(remdesk);
800
801 while (1)
802 {
803 if (!MessageQueue_Wait(remdesk->queue))
804 {
805 WLog_ERR(TAG, "MessageQueue_Wait failed!");
806 error = ERROR_INTERNAL_ERROR;
807 break;
808 }
809
810 if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
811 {
812 WLog_ERR(TAG, "MessageQueue_Peek failed!");
813 error = ERROR_INTERNAL_ERROR;
814 break;
815 }
816
817 if (message.id == WMQ_QUIT)
818 break;
819
820 if (message.id == 0)
821 {
822 data = (wStream*)message.wParam;
823
824 if ((error = remdesk_process_receive(remdesk, data)))
825 {
826 WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
827 Stream_Free(data, TRUE);
828 break;
829 }
830
831 Stream_Free(data, TRUE);
832 }
833 }
834
835 if (error && remdesk->rdpcontext)
836 setChannelError(remdesk->rdpcontext, error,
837 "remdesk_virtual_channel_client_thread reported an error");
838
839 ExitThread(error);
840 return error;
841}
842
848static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk,
849 WINPR_ATTR_UNUSED LPVOID pData,
850 WINPR_ATTR_UNUSED UINT32 dataLength)
851{
852 UINT error = 0;
853
854 WINPR_ASSERT(remdesk);
855
856 remdesk->queue = MessageQueue_New(NULL);
857
858 if (!remdesk->queue)
859 {
860 WLog_ERR(TAG, "MessageQueue_New failed!");
861 error = CHANNEL_RC_NO_MEMORY;
862 goto error_out;
863 }
864
865 remdesk->thread =
866 CreateThread(NULL, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, NULL);
867
868 if (!remdesk->thread)
869 {
870 WLog_ERR(TAG, "CreateThread failed");
871 error = ERROR_INTERNAL_ERROR;
872 goto error_out;
873 }
874
875 return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
876 remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
877 remdesk_virtual_channel_open_event_ex);
878error_out:
879 MessageQueue_Free(remdesk->queue);
880 remdesk->queue = NULL;
881 return error;
882}
883
889static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
890{
891 UINT rc = CHANNEL_RC_OK;
892
893 WINPR_ASSERT(remdesk);
894
895 if (remdesk->queue && remdesk->thread)
896 {
897 if (MessageQueue_PostQuit(remdesk->queue, 0) &&
898 (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
899 {
900 rc = GetLastError();
901 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
902 return rc;
903 }
904 }
905
906 if (remdesk->OpenHandle != 0)
907 {
908 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
909 rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
910 remdesk->OpenHandle);
911
912 if (CHANNEL_RC_OK != rc)
913 {
914 WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
915 WTSErrorToString(rc), rc);
916 }
917
918 remdesk->OpenHandle = 0;
919 }
920 MessageQueue_Free(remdesk->queue);
921 (void)CloseHandle(remdesk->thread);
922 Stream_Free(remdesk->data_in, TRUE);
923 remdesk->data_in = NULL;
924 remdesk->queue = NULL;
925 remdesk->thread = NULL;
926 return rc;
927}
928
929static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
930{
931 WINPR_ASSERT(remdesk);
932
933 remdesk->InitHandle = 0;
934 free(remdesk->context);
935 free(remdesk);
936}
937
938static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
939 UINT event, LPVOID pData,
940 UINT dataLength)
941{
942 UINT error = CHANNEL_RC_OK;
943 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
944
945 if (!remdesk || (remdesk->InitHandle != pInitHandle))
946 {
947 WLog_ERR(TAG, "error no match");
948 return;
949 }
950
951 switch (event)
952 {
953 case CHANNEL_EVENT_CONNECTED:
954 if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
955 WLog_ERR(TAG,
956 "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "",
957 error);
958
959 break;
960
961 case CHANNEL_EVENT_DISCONNECTED:
962 if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
963 WLog_ERR(TAG,
964 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "",
965 error);
966
967 break;
968
969 case CHANNEL_EVENT_TERMINATED:
970 remdesk_virtual_channel_event_terminated(remdesk);
971 break;
972
973 case CHANNEL_EVENT_ATTACHED:
974 case CHANNEL_EVENT_DETACHED:
975 default:
976 break;
977 }
978
979 if (error && remdesk->rdpcontext)
980 setChannelError(remdesk->rdpcontext, error,
981 "remdesk_virtual_channel_init_event reported an error");
982}
983
984/* remdesk is always built-in */
985#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
986
987FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
988 PVOID pInitHandle))
989{
990 UINT rc = 0;
991 remdeskPlugin* remdesk = NULL;
992 RemdeskClientContext* context = NULL;
993 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
994
995 if (!pEntryPoints)
996 {
997 return FALSE;
998 }
999
1000 remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin));
1001
1002 if (!remdesk)
1003 {
1004 WLog_ERR(TAG, "calloc failed!");
1005 return FALSE;
1006 }
1007
1008 remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1009 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1010 (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1011 REMDESK_SVC_CHANNEL_NAME);
1012 remdesk->Version = 2;
1013 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1014
1015 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1016 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1017 {
1018 context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext));
1019
1020 if (!context)
1021 {
1022 WLog_ERR(TAG, "calloc failed!");
1023 goto error_out;
1024 }
1025
1026 context->handle = (void*)remdesk;
1027 remdesk->context = context;
1028 remdesk->rdpcontext = pEntryPointsEx->context;
1029 }
1030
1031 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1033 remdesk->InitHandle = pInitHandle;
1034 rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1035 remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1036 remdesk_virtual_channel_init_event_ex);
1037
1038 if (CHANNEL_RC_OK != rc)
1039 {
1040 WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1041 rc);
1042 goto error_out;
1043 }
1044
1045 remdesk->channelEntryPoints.pInterface = context;
1046 return TRUE;
1047error_out:
1048 free(remdesk);
1049 free(context);
1050 return FALSE;
1051}
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