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 UINT32 versionMajor = 0;
159 UINT32 versionMinor = 0;
160
161 WINPR_ASSERT(remdesk);
162 WINPR_ASSERT(s);
163 WINPR_ASSERT(header);
164
165 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
166 return ERROR_INVALID_DATA;
167
168 Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */
169 Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */
170
171 if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0))
172 {
173 WLog_ERR(TAG, "Unsupported protocol version %" PRId32 ".%" PRId32, versionMajor,
174 versionMinor);
175 }
176
177 remdesk->Version = versionMinor;
178 return CHANNEL_RC_OK;
179}
180
186static UINT remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk)
187{
189
190 WINPR_ASSERT(remdesk);
191
192 UINT error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
193 if (error)
194 return error;
195
196 pdu.versionMajor = 1;
197 pdu.versionMinor = 2;
198 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
199
200 if (!s)
201 {
202 WLog_ERR(TAG, "Stream_New failed!");
203 return CHANNEL_RC_NO_MEMORY;
204 }
205
206 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
207 if (error)
208 {
209 Stream_Free(s, TRUE);
210 return error;
211 }
212 Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */
213 Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */
214 Stream_SealLength(s);
215
216 if ((error = remdesk_virtual_channel_write(remdesk, s)))
217 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
218
219 return error;
220}
221
227static UINT remdesk_recv_ctl_result_pdu(WINPR_ATTR_UNUSED remdeskPlugin* remdesk, wStream* s,
228 WINPR_ATTR_UNUSED REMDESK_CHANNEL_HEADER* header,
229 UINT32* pResult)
230{
231 UINT32 result = 0;
232
233 WINPR_ASSERT(remdesk);
234 WINPR_ASSERT(s);
235 WINPR_ASSERT(header);
236 WINPR_ASSERT(pResult);
237
238 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
239 return ERROR_INVALID_DATA;
240
241 Stream_Read_UINT32(s, result); /* result (4 bytes) */
242 *pResult = result;
243 // WLog_DBG(TAG, "RemdeskRecvResult: 0x%08"PRIX32"", result);
244 switch (result)
245 {
246 case REMDESK_ERROR_HELPEESAIDNO:
247 WLog_DBG(TAG, "remote assistance connection request was denied");
248 return ERROR_CONNECTION_REFUSED;
249
250 default:
251 break;
252 }
253
254 return CHANNEL_RC_OK;
255}
256
262static UINT remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk)
263{
264 UINT error = ERROR_INTERNAL_ERROR;
265 size_t cbExpertBlobW = 0;
266 WCHAR* expertBlobW = NULL;
267 size_t cbRaConnectionStringW = 0;
268 REMDESK_CTL_HEADER ctlHeader = { 0 };
269
270 WINPR_ASSERT(remdesk);
271
272 if ((error = remdesk_generate_expert_blob(remdesk)))
273 {
274 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "", error);
275 return error;
276 }
277
278 const char* expertBlob = remdesk->ExpertBlob;
279 WINPR_ASSERT(remdesk->rdpcontext);
280 rdpSettings* settings = remdesk->rdpcontext->settings;
281 WINPR_ASSERT(settings);
282
283 const char* raConnectionString =
284 freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
285 WCHAR* raConnectionStringW =
286 ConvertUtf8ToWCharAlloc(raConnectionString, &cbRaConnectionStringW);
287
288 if (!raConnectionStringW || (cbRaConnectionStringW > UINT32_MAX / sizeof(WCHAR)))
289 goto out;
290
291 cbRaConnectionStringW = cbRaConnectionStringW * sizeof(WCHAR);
292
293 expertBlobW = ConvertUtf8ToWCharAlloc(expertBlob, &cbExpertBlobW);
294
295 if (!expertBlobW)
296 goto out;
297
298 cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
299 error = remdesk_prepare_ctl_header(&(ctlHeader), REMDESK_CTL_AUTHENTICATE,
300 cbRaConnectionStringW + cbExpertBlobW);
301 if (error)
302 goto out;
303
304 {
305 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
306 if (!s)
307 {
308 WLog_ERR(TAG, "Stream_New failed!");
309 error = CHANNEL_RC_NO_MEMORY;
310 goto out;
311 }
312
313 error = remdesk_write_ctl_header(s, &ctlHeader);
314 if (error)
315 {
316 Stream_Free(s, TRUE);
317 goto out;
318 }
319 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
320 Stream_Write(s, expertBlobW, cbExpertBlobW);
321 Stream_SealLength(s);
322
323 error = remdesk_virtual_channel_write(remdesk, s);
324 }
325 if (error)
326 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
327
328out:
329 free(raConnectionStringW);
330 free(expertBlobW);
331
332 return error;
333}
334
340static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk)
341{
342 UINT error = 0;
343 size_t length = 0;
344
345 WINPR_ASSERT(remdesk);
346 WINPR_ASSERT(remdesk->rdpcontext);
347 rdpSettings* settings = remdesk->rdpcontext->settings;
348 WINPR_ASSERT(settings);
349
350 const char* raConnectionString =
351 freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
352 WCHAR* raConnectionStringW = ConvertUtf8ToWCharAlloc(raConnectionString, &length);
353 size_t cbRaConnectionStringW = length * sizeof(WCHAR);
354
355 if (!raConnectionStringW)
356 return ERROR_INTERNAL_ERROR;
357
358 REMDESK_CTL_HEADER ctlHeader = { 0 };
359 error = remdesk_prepare_ctl_header(&ctlHeader, REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
360 cbRaConnectionStringW);
361 if (error != CHANNEL_RC_OK)
362 goto out;
363
364 {
365 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
366
367 if (!s)
368 {
369 WLog_ERR(TAG, "Stream_New failed!");
370 error = CHANNEL_RC_NO_MEMORY;
371 goto out;
372 }
373
374 error = remdesk_write_ctl_header(s, &ctlHeader);
375 if (error)
376 {
377 Stream_Free(s, TRUE);
378 goto out;
379 }
380 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
381 Stream_SealLength(s);
382
383 if ((error = remdesk_virtual_channel_write(remdesk, s)))
384 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
385 }
386
387out:
388 free(raConnectionStringW);
389
390 return error;
391}
392
398static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk)
399{
400 size_t cbExpertBlobW = 0;
402
403 WINPR_ASSERT(remdesk);
404
405 UINT error = remdesk_generate_expert_blob(remdesk);
406 if (error)
407 {
408 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
409 return error;
410 }
411
412 pdu.expertBlob = remdesk->ExpertBlob;
413 WCHAR* expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
414
415 if (!expertBlobW)
416 goto out;
417
418 cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
419 error =
420 remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
421 if (error)
422 goto out;
423
424 {
425 wStream* s =
426 Stream_New(NULL, 1ULL * REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
427
428 if (!s)
429 {
430 WLog_ERR(TAG, "Stream_New failed!");
431 error = CHANNEL_RC_NO_MEMORY;
432 goto out;
433 }
434
435 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
436 if (error)
437 {
438 Stream_Free(s, TRUE);
439 goto out;
440 }
441 Stream_Write(s, expertBlobW, cbExpertBlobW);
442 Stream_SealLength(s);
443
444 error = remdesk_virtual_channel_write(remdesk, s);
445 }
446 if (error)
447 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
448
449out:
450 free(expertBlobW);
451
452 return error;
453}
454
460static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk)
461{
463
464 WINPR_ASSERT(remdesk);
465
466 UINT error = remdesk_generate_expert_blob(remdesk);
467 if (error)
468 {
469 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
470 return error;
471 }
472 if (remdesk->EncryptedPassStubSize > UINT32_MAX)
473 return ERROR_INTERNAL_ERROR;
474
475 pdu.EncryptedPasswordLength = (UINT32)remdesk->EncryptedPassStubSize;
476 pdu.EncryptedPassword = remdesk->EncryptedPassStub;
477 error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
478 pdu.EncryptedPasswordLength);
479 if (error)
480 return error;
481
482 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
483
484 if (!s)
485 {
486 WLog_ERR(TAG, "Stream_New failed!");
487 return CHANNEL_RC_NO_MEMORY;
488 }
489
490 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
491 if (error)
492 {
493 Stream_Free(s, TRUE);
494 return error;
495 }
496 Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
497 Stream_SealLength(s);
498 return remdesk_virtual_channel_write(remdesk, s);
499}
500
506static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
507{
508 UINT error = CHANNEL_RC_OK;
509 UINT32 msgType = 0;
510 UINT32 result = 0;
511
512 WINPR_ASSERT(remdesk);
513 WINPR_ASSERT(s);
514 WINPR_ASSERT(header);
515
516 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
517 return ERROR_INVALID_DATA;
518
519 Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
520
521 // WLog_DBG(TAG, "msgType: %"PRIu32"", msgType);
522
523 switch (msgType)
524 {
525 case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
526 break;
527
528 case REMDESK_CTL_RESULT:
529 if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
530 WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %" PRIu32 "", error);
531
532 break;
533
534 case REMDESK_CTL_AUTHENTICATE:
535 break;
536
537 case REMDESK_CTL_SERVER_ANNOUNCE:
538 if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
539 WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32 "",
540 error);
541
542 break;
543
544 case REMDESK_CTL_DISCONNECT:
545 break;
546
547 case REMDESK_CTL_VERSIONINFO:
548 if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
549 {
550 WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "",
551 error);
552 break;
553 }
554
555 if (remdesk->Version == 1)
556 {
557 if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
558 {
559 WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "",
560 error);
561 break;
562 }
563
564 if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
565 {
566 WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32 "",
567 error);
568 break;
569 }
570
571 if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
572 {
573 WLog_ERR(
574 TAG,
575 "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32 "",
576 error);
577 break;
578 }
579 }
580 else if (remdesk->Version == 2)
581 {
582 if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
583 {
584 WLog_ERR(TAG,
585 "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32 "",
586 error);
587 break;
588 }
589
590 if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
591 {
592 WLog_ERR(TAG,
593 "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32 "",
594 error);
595 break;
596 }
597 }
598
599 break;
600
601 case REMDESK_CTL_ISCONNECTED:
602 break;
603
604 case REMDESK_CTL_VERIFY_PASSWORD:
605 break;
606
607 case REMDESK_CTL_EXPERT_ON_VISTA:
608 break;
609
610 case REMDESK_CTL_RANOVICE_NAME:
611 break;
612
613 case REMDESK_CTL_RAEXPERT_NAME:
614 break;
615
616 case REMDESK_CTL_TOKEN:
617 break;
618
619 default:
620 WLog_ERR(TAG, "unknown msgType: %" PRIu32 "", msgType);
621 error = ERROR_INVALID_DATA;
622 break;
623 }
624
625 return error;
626}
627
633static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
634{
635 UINT status = 0;
637
638 WINPR_ASSERT(remdesk);
639 WINPR_ASSERT(s);
640
641 if ((status = remdesk_read_channel_header(s, &header)))
642 {
643 WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "", status);
644 return status;
645 }
646
647 if (strcmp(header.ChannelName, "RC_CTL") == 0)
648 {
649 status = remdesk_recv_ctl_pdu(remdesk, s, &header);
650 }
651 else if (strcmp(header.ChannelName, "70") == 0)
652 {
653 }
654 else if (strcmp(header.ChannelName, "71") == 0)
655 {
656 }
657 else if (strcmp(header.ChannelName, ".") == 0)
658 {
659 }
660 else if (strcmp(header.ChannelName, "1000.") == 0)
661 {
662 }
663 else if (strcmp(header.ChannelName, "RA_FX") == 0)
664 {
665 }
666 else
667 {
668 }
669
670 return status;
671}
672
673static void remdesk_process_connect(WINPR_ATTR_UNUSED remdeskPlugin* remdesk)
674{
675 WINPR_ASSERT(remdesk);
676 WLog_ERR("TODO", "TODO: implement");
677}
678
684static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, const void* pData,
685 UINT32 dataLength, UINT32 totalLength,
686 UINT32 dataFlags)
687{
688 wStream* data_in = NULL;
689
690 WINPR_ASSERT(remdesk);
691
692 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
693 {
694 return CHANNEL_RC_OK;
695 }
696
697 if (dataFlags & CHANNEL_FLAG_FIRST)
698 {
699 if (remdesk->data_in)
700 Stream_Free(remdesk->data_in, TRUE);
701
702 remdesk->data_in = Stream_New(NULL, totalLength);
703
704 if (!remdesk->data_in)
705 {
706 WLog_ERR(TAG, "Stream_New failed!");
707 return CHANNEL_RC_NO_MEMORY;
708 }
709 }
710
711 data_in = remdesk->data_in;
712
713 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
714 {
715 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
716 return CHANNEL_RC_NO_MEMORY;
717 }
718
719 Stream_Write(data_in, pData, dataLength);
720
721 if (dataFlags & CHANNEL_FLAG_LAST)
722 {
723 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
724 {
725 WLog_ERR(TAG, "read error");
726 return ERROR_INTERNAL_ERROR;
727 }
728
729 remdesk->data_in = NULL;
730 Stream_SealLength(data_in);
731 Stream_SetPosition(data_in, 0);
732
733 if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*)data_in, NULL))
734 {
735 WLog_ERR(TAG, "MessageQueue_Post failed!");
736 return ERROR_INTERNAL_ERROR;
737 }
738 }
739
740 return CHANNEL_RC_OK;
741}
742
743static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
744 UINT event, LPVOID pData,
745 UINT32 dataLength, UINT32 totalLength,
746 UINT32 dataFlags)
747{
748 UINT error = CHANNEL_RC_OK;
749 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
750
751 switch (event)
752 {
753 case CHANNEL_EVENT_INITIALIZED:
754 break;
755
756 case CHANNEL_EVENT_DATA_RECEIVED:
757 if (!remdesk || (remdesk->OpenHandle != openHandle))
758 {
759 WLog_ERR(TAG, "error no match");
760 return;
761 }
762 if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
763 totalLength, dataFlags)))
764 WLog_ERR(TAG,
765 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
766 "!",
767 error);
768
769 break;
770
771 case CHANNEL_EVENT_WRITE_CANCELLED:
772 case CHANNEL_EVENT_WRITE_COMPLETE:
773 {
774 wStream* s = (wStream*)pData;
775 Stream_Free(s, TRUE);
776 }
777 break;
778
779 case CHANNEL_EVENT_USER:
780 break;
781
782 default:
783 WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event);
784 error = ERROR_INTERNAL_ERROR;
785 break;
786 }
787
788 if (error && remdesk && remdesk->rdpcontext)
789 setChannelError(remdesk->rdpcontext, error,
790 "remdesk_virtual_channel_open_event_ex reported an error");
791}
792
793static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
794{
795 wStream* data = NULL;
796 wMessage message = { 0 };
797 remdeskPlugin* remdesk = (remdeskPlugin*)arg;
798 UINT error = CHANNEL_RC_OK;
799
800 WINPR_ASSERT(remdesk);
801
802 remdesk_process_connect(remdesk);
803
804 while (1)
805 {
806 if (!MessageQueue_Wait(remdesk->queue))
807 {
808 WLog_ERR(TAG, "MessageQueue_Wait failed!");
809 error = ERROR_INTERNAL_ERROR;
810 break;
811 }
812
813 if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
814 {
815 WLog_ERR(TAG, "MessageQueue_Peek failed!");
816 error = ERROR_INTERNAL_ERROR;
817 break;
818 }
819
820 if (message.id == WMQ_QUIT)
821 break;
822
823 if (message.id == 0)
824 {
825 data = (wStream*)message.wParam;
826
827 if ((error = remdesk_process_receive(remdesk, data)))
828 {
829 WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
830 Stream_Free(data, TRUE);
831 break;
832 }
833
834 Stream_Free(data, TRUE);
835 }
836 }
837
838 if (error && remdesk->rdpcontext)
839 setChannelError(remdesk->rdpcontext, error,
840 "remdesk_virtual_channel_client_thread reported an error");
841
842 ExitThread(error);
843 return error;
844}
845
851static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk,
852 WINPR_ATTR_UNUSED LPVOID pData,
853 WINPR_ATTR_UNUSED UINT32 dataLength)
854{
855 UINT error = 0;
856
857 WINPR_ASSERT(remdesk);
858
859 remdesk->queue = MessageQueue_New(NULL);
860
861 if (!remdesk->queue)
862 {
863 WLog_ERR(TAG, "MessageQueue_New failed!");
864 error = CHANNEL_RC_NO_MEMORY;
865 goto error_out;
866 }
867
868 remdesk->thread =
869 CreateThread(NULL, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, NULL);
870
871 if (!remdesk->thread)
872 {
873 WLog_ERR(TAG, "CreateThread failed");
874 error = ERROR_INTERNAL_ERROR;
875 goto error_out;
876 }
877
878 return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
879 remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
880 remdesk_virtual_channel_open_event_ex);
881error_out:
882 MessageQueue_Free(remdesk->queue);
883 remdesk->queue = NULL;
884 return error;
885}
886
892static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
893{
894 UINT rc = CHANNEL_RC_OK;
895
896 WINPR_ASSERT(remdesk);
897
898 if (remdesk->queue && remdesk->thread)
899 {
900 if (MessageQueue_PostQuit(remdesk->queue, 0) &&
901 (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
902 {
903 rc = GetLastError();
904 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
905 return rc;
906 }
907 }
908
909 if (remdesk->OpenHandle != 0)
910 {
911 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
912 rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
913 remdesk->OpenHandle);
914
915 if (CHANNEL_RC_OK != rc)
916 {
917 WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
918 WTSErrorToString(rc), rc);
919 }
920
921 remdesk->OpenHandle = 0;
922 }
923 MessageQueue_Free(remdesk->queue);
924 (void)CloseHandle(remdesk->thread);
925 Stream_Free(remdesk->data_in, TRUE);
926 remdesk->data_in = NULL;
927 remdesk->queue = NULL;
928 remdesk->thread = NULL;
929 return rc;
930}
931
932static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
933{
934 WINPR_ASSERT(remdesk);
935
936 remdesk->InitHandle = 0;
937 free(remdesk->context);
938 free(remdesk);
939}
940
941static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
942 UINT event, LPVOID pData,
943 UINT dataLength)
944{
945 UINT error = CHANNEL_RC_OK;
946 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
947
948 if (!remdesk || (remdesk->InitHandle != pInitHandle))
949 {
950 WLog_ERR(TAG, "error no match");
951 return;
952 }
953
954 switch (event)
955 {
956 case CHANNEL_EVENT_CONNECTED:
957 if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
958 WLog_ERR(TAG,
959 "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "",
960 error);
961
962 break;
963
964 case CHANNEL_EVENT_DISCONNECTED:
965 if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
966 WLog_ERR(TAG,
967 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "",
968 error);
969
970 break;
971
972 case CHANNEL_EVENT_TERMINATED:
973 remdesk_virtual_channel_event_terminated(remdesk);
974 break;
975
976 case CHANNEL_EVENT_ATTACHED:
977 case CHANNEL_EVENT_DETACHED:
978 default:
979 break;
980 }
981
982 if (error && remdesk->rdpcontext)
983 setChannelError(remdesk->rdpcontext, error,
984 "remdesk_virtual_channel_init_event reported an error");
985}
986
987/* remdesk is always built-in */
988#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
989
990FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
991 PVOID pInitHandle))
992{
993 UINT rc = 0;
994 remdeskPlugin* remdesk = NULL;
995 RemdeskClientContext* context = NULL;
996 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
997
998 if (!pEntryPoints)
999 {
1000 return FALSE;
1001 }
1002
1003 remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin));
1004
1005 if (!remdesk)
1006 {
1007 WLog_ERR(TAG, "calloc failed!");
1008 return FALSE;
1009 }
1010
1011 remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1012 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1013 (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1014 REMDESK_SVC_CHANNEL_NAME);
1015 remdesk->Version = 2;
1016 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1017
1018 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1019 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1020 {
1021 context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext));
1022
1023 if (!context)
1024 {
1025 WLog_ERR(TAG, "calloc failed!");
1026 goto error_out;
1027 }
1028
1029 context->handle = (void*)remdesk;
1030 remdesk->context = context;
1031 remdesk->rdpcontext = pEntryPointsEx->context;
1032 }
1033
1034 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1036 remdesk->InitHandle = pInitHandle;
1037 rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1038 remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1039 remdesk_virtual_channel_init_event_ex);
1040
1041 if (CHANNEL_RC_OK != rc)
1042 {
1043 WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1044 rc);
1045 goto error_out;
1046 }
1047
1048 remdesk->channelEntryPoints.pInterface = context;
1049 return TRUE;
1050error_out:
1051 free(remdesk);
1052 free(context);
1053 return FALSE;
1054}
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