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 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
305
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 if (error)
325 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
326
327out:
328 free(raConnectionStringW);
329 free(expertBlobW);
330
331 return error;
332}
333
339static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk)
340{
341 UINT error = 0;
342 size_t length = 0;
343
344 WINPR_ASSERT(remdesk);
345 WINPR_ASSERT(remdesk->rdpcontext);
346 rdpSettings* settings = remdesk->rdpcontext->settings;
347 WINPR_ASSERT(settings);
348
349 const char* raConnectionString =
350 freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
351 WCHAR* raConnectionStringW = ConvertUtf8ToWCharAlloc(raConnectionString, &length);
352 size_t cbRaConnectionStringW = length * sizeof(WCHAR);
353
354 if (!raConnectionStringW)
355 return ERROR_INTERNAL_ERROR;
356
357 REMDESK_CTL_HEADER ctlHeader = { 0 };
358 error = remdesk_prepare_ctl_header(&ctlHeader, REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
359 cbRaConnectionStringW);
360 if (error != CHANNEL_RC_OK)
361 goto out;
362
363 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
364
365 if (!s)
366 {
367 WLog_ERR(TAG, "Stream_New failed!");
368 error = CHANNEL_RC_NO_MEMORY;
369 goto out;
370 }
371
372 error = remdesk_write_ctl_header(s, &ctlHeader);
373 if (error)
374 {
375 Stream_Free(s, TRUE);
376 goto out;
377 }
378 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
379 Stream_SealLength(s);
380
381 if ((error = remdesk_virtual_channel_write(remdesk, s)))
382 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
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 wStream* s = Stream_New(NULL, 1ULL * REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
422
423 if (!s)
424 {
425 WLog_ERR(TAG, "Stream_New failed!");
426 error = CHANNEL_RC_NO_MEMORY;
427 goto out;
428 }
429
430 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
431 if (error)
432 {
433 Stream_Free(s, TRUE);
434 goto out;
435 }
436 Stream_Write(s, expertBlobW, cbExpertBlobW);
437 Stream_SealLength(s);
438
439 error = remdesk_virtual_channel_write(remdesk, s);
440 if (error)
441 WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
442
443out:
444 free(expertBlobW);
445
446 return error;
447}
448
454static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk)
455{
457
458 WINPR_ASSERT(remdesk);
459
460 UINT error = remdesk_generate_expert_blob(remdesk);
461 if (error)
462 {
463 WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
464 return error;
465 }
466 if (remdesk->EncryptedPassStubSize > UINT32_MAX)
467 return ERROR_INTERNAL_ERROR;
468
469 pdu.EncryptedPasswordLength = (UINT32)remdesk->EncryptedPassStubSize;
470 pdu.EncryptedPassword = remdesk->EncryptedPassStub;
471 error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
472 pdu.EncryptedPasswordLength);
473 if (error)
474 return error;
475
476 wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
477
478 if (!s)
479 {
480 WLog_ERR(TAG, "Stream_New failed!");
481 return CHANNEL_RC_NO_MEMORY;
482 }
483
484 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
485 if (error)
486 {
487 Stream_Free(s, TRUE);
488 return error;
489 }
490 Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
491 Stream_SealLength(s);
492 return remdesk_virtual_channel_write(remdesk, s);
493}
494
500static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
501{
502 UINT error = CHANNEL_RC_OK;
503 UINT32 msgType = 0;
504 UINT32 result = 0;
505
506 WINPR_ASSERT(remdesk);
507 WINPR_ASSERT(s);
508 WINPR_ASSERT(header);
509
510 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
511 return ERROR_INVALID_DATA;
512
513 Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
514
515 // WLog_DBG(TAG, "msgType: %"PRIu32"", msgType);
516
517 switch (msgType)
518 {
519 case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
520 break;
521
522 case REMDESK_CTL_RESULT:
523 if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
524 WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %" PRIu32 "", error);
525
526 break;
527
528 case REMDESK_CTL_AUTHENTICATE:
529 break;
530
531 case REMDESK_CTL_SERVER_ANNOUNCE:
532 if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
533 WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32 "",
534 error);
535
536 break;
537
538 case REMDESK_CTL_DISCONNECT:
539 break;
540
541 case REMDESK_CTL_VERSIONINFO:
542 if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
543 {
544 WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "",
545 error);
546 break;
547 }
548
549 if (remdesk->Version == 1)
550 {
551 if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
552 {
553 WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "",
554 error);
555 break;
556 }
557
558 if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
559 {
560 WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32 "",
561 error);
562 break;
563 }
564
565 if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
566 {
567 WLog_ERR(
568 TAG,
569 "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32 "",
570 error);
571 break;
572 }
573 }
574 else if (remdesk->Version == 2)
575 {
576 if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
577 {
578 WLog_ERR(TAG,
579 "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32 "",
580 error);
581 break;
582 }
583
584 if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
585 {
586 WLog_ERR(TAG,
587 "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32 "",
588 error);
589 break;
590 }
591 }
592
593 break;
594
595 case REMDESK_CTL_ISCONNECTED:
596 break;
597
598 case REMDESK_CTL_VERIFY_PASSWORD:
599 break;
600
601 case REMDESK_CTL_EXPERT_ON_VISTA:
602 break;
603
604 case REMDESK_CTL_RANOVICE_NAME:
605 break;
606
607 case REMDESK_CTL_RAEXPERT_NAME:
608 break;
609
610 case REMDESK_CTL_TOKEN:
611 break;
612
613 default:
614 WLog_ERR(TAG, "unknown msgType: %" PRIu32 "", msgType);
615 error = ERROR_INVALID_DATA;
616 break;
617 }
618
619 return error;
620}
621
627static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
628{
629 UINT status = 0;
631
632 WINPR_ASSERT(remdesk);
633 WINPR_ASSERT(s);
634
635 if ((status = remdesk_read_channel_header(s, &header)))
636 {
637 WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "", status);
638 return status;
639 }
640
641 if (strcmp(header.ChannelName, "RC_CTL") == 0)
642 {
643 status = remdesk_recv_ctl_pdu(remdesk, s, &header);
644 }
645 else if (strcmp(header.ChannelName, "70") == 0)
646 {
647 }
648 else if (strcmp(header.ChannelName, "71") == 0)
649 {
650 }
651 else if (strcmp(header.ChannelName, ".") == 0)
652 {
653 }
654 else if (strcmp(header.ChannelName, "1000.") == 0)
655 {
656 }
657 else if (strcmp(header.ChannelName, "RA_FX") == 0)
658 {
659 }
660 else
661 {
662 }
663
664 return status;
665}
666
667static void remdesk_process_connect(WINPR_ATTR_UNUSED remdeskPlugin* remdesk)
668{
669 WINPR_ASSERT(remdesk);
670 WLog_ERR("TODO", "TODO: implement");
671}
672
678static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, const void* pData,
679 UINT32 dataLength, UINT32 totalLength,
680 UINT32 dataFlags)
681{
682 wStream* data_in = NULL;
683
684 WINPR_ASSERT(remdesk);
685
686 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
687 {
688 return CHANNEL_RC_OK;
689 }
690
691 if (dataFlags & CHANNEL_FLAG_FIRST)
692 {
693 if (remdesk->data_in)
694 Stream_Free(remdesk->data_in, TRUE);
695
696 remdesk->data_in = Stream_New(NULL, totalLength);
697
698 if (!remdesk->data_in)
699 {
700 WLog_ERR(TAG, "Stream_New failed!");
701 return CHANNEL_RC_NO_MEMORY;
702 }
703 }
704
705 data_in = remdesk->data_in;
706
707 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
708 {
709 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
710 return CHANNEL_RC_NO_MEMORY;
711 }
712
713 Stream_Write(data_in, pData, dataLength);
714
715 if (dataFlags & CHANNEL_FLAG_LAST)
716 {
717 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
718 {
719 WLog_ERR(TAG, "read error");
720 return ERROR_INTERNAL_ERROR;
721 }
722
723 remdesk->data_in = NULL;
724 Stream_SealLength(data_in);
725 Stream_SetPosition(data_in, 0);
726
727 if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*)data_in, NULL))
728 {
729 WLog_ERR(TAG, "MessageQueue_Post failed!");
730 return ERROR_INTERNAL_ERROR;
731 }
732 }
733
734 return CHANNEL_RC_OK;
735}
736
737static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
738 UINT event, LPVOID pData,
739 UINT32 dataLength, UINT32 totalLength,
740 UINT32 dataFlags)
741{
742 UINT error = CHANNEL_RC_OK;
743 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
744
745 switch (event)
746 {
747 case CHANNEL_EVENT_INITIALIZED:
748 break;
749
750 case CHANNEL_EVENT_DATA_RECEIVED:
751 if (!remdesk || (remdesk->OpenHandle != openHandle))
752 {
753 WLog_ERR(TAG, "error no match");
754 return;
755 }
756 if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
757 totalLength, dataFlags)))
758 WLog_ERR(TAG,
759 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
760 "!",
761 error);
762
763 break;
764
765 case CHANNEL_EVENT_WRITE_CANCELLED:
766 case CHANNEL_EVENT_WRITE_COMPLETE:
767 {
768 wStream* s = (wStream*)pData;
769 Stream_Free(s, TRUE);
770 }
771 break;
772
773 case CHANNEL_EVENT_USER:
774 break;
775
776 default:
777 WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event);
778 error = ERROR_INTERNAL_ERROR;
779 break;
780 }
781
782 if (error && remdesk && remdesk->rdpcontext)
783 setChannelError(remdesk->rdpcontext, error,
784 "remdesk_virtual_channel_open_event_ex reported an error");
785}
786
787static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
788{
789 wStream* data = NULL;
790 wMessage message = { 0 };
791 remdeskPlugin* remdesk = (remdeskPlugin*)arg;
792 UINT error = CHANNEL_RC_OK;
793
794 WINPR_ASSERT(remdesk);
795
796 remdesk_process_connect(remdesk);
797
798 while (1)
799 {
800 if (!MessageQueue_Wait(remdesk->queue))
801 {
802 WLog_ERR(TAG, "MessageQueue_Wait failed!");
803 error = ERROR_INTERNAL_ERROR;
804 break;
805 }
806
807 if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
808 {
809 WLog_ERR(TAG, "MessageQueue_Peek failed!");
810 error = ERROR_INTERNAL_ERROR;
811 break;
812 }
813
814 if (message.id == WMQ_QUIT)
815 break;
816
817 if (message.id == 0)
818 {
819 data = (wStream*)message.wParam;
820
821 if ((error = remdesk_process_receive(remdesk, data)))
822 {
823 WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
824 Stream_Free(data, TRUE);
825 break;
826 }
827
828 Stream_Free(data, TRUE);
829 }
830 }
831
832 if (error && remdesk->rdpcontext)
833 setChannelError(remdesk->rdpcontext, error,
834 "remdesk_virtual_channel_client_thread reported an error");
835
836 ExitThread(error);
837 return error;
838}
839
845static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk,
846 WINPR_ATTR_UNUSED LPVOID pData,
847 WINPR_ATTR_UNUSED UINT32 dataLength)
848{
849 UINT error = 0;
850
851 WINPR_ASSERT(remdesk);
852
853 remdesk->queue = MessageQueue_New(NULL);
854
855 if (!remdesk->queue)
856 {
857 WLog_ERR(TAG, "MessageQueue_New failed!");
858 error = CHANNEL_RC_NO_MEMORY;
859 goto error_out;
860 }
861
862 remdesk->thread =
863 CreateThread(NULL, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, NULL);
864
865 if (!remdesk->thread)
866 {
867 WLog_ERR(TAG, "CreateThread failed");
868 error = ERROR_INTERNAL_ERROR;
869 goto error_out;
870 }
871
872 return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
873 remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
874 remdesk_virtual_channel_open_event_ex);
875error_out:
876 MessageQueue_Free(remdesk->queue);
877 remdesk->queue = NULL;
878 return error;
879}
880
886static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
887{
888 UINT rc = CHANNEL_RC_OK;
889
890 WINPR_ASSERT(remdesk);
891
892 if (remdesk->queue && remdesk->thread)
893 {
894 if (MessageQueue_PostQuit(remdesk->queue, 0) &&
895 (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
896 {
897 rc = GetLastError();
898 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
899 return rc;
900 }
901 }
902
903 if (remdesk->OpenHandle != 0)
904 {
905 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
906 rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
907 remdesk->OpenHandle);
908
909 if (CHANNEL_RC_OK != rc)
910 {
911 WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
912 WTSErrorToString(rc), rc);
913 }
914
915 remdesk->OpenHandle = 0;
916 }
917 MessageQueue_Free(remdesk->queue);
918 (void)CloseHandle(remdesk->thread);
919 Stream_Free(remdesk->data_in, TRUE);
920 remdesk->data_in = NULL;
921 remdesk->queue = NULL;
922 remdesk->thread = NULL;
923 return rc;
924}
925
926static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
927{
928 WINPR_ASSERT(remdesk);
929
930 remdesk->InitHandle = 0;
931 free(remdesk->context);
932 free(remdesk);
933}
934
935static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
936 UINT event, LPVOID pData,
937 UINT dataLength)
938{
939 UINT error = CHANNEL_RC_OK;
940 remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
941
942 if (!remdesk || (remdesk->InitHandle != pInitHandle))
943 {
944 WLog_ERR(TAG, "error no match");
945 return;
946 }
947
948 switch (event)
949 {
950 case CHANNEL_EVENT_CONNECTED:
951 if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
952 WLog_ERR(TAG,
953 "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "",
954 error);
955
956 break;
957
958 case CHANNEL_EVENT_DISCONNECTED:
959 if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
960 WLog_ERR(TAG,
961 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "",
962 error);
963
964 break;
965
966 case CHANNEL_EVENT_TERMINATED:
967 remdesk_virtual_channel_event_terminated(remdesk);
968 break;
969
970 case CHANNEL_EVENT_ATTACHED:
971 case CHANNEL_EVENT_DETACHED:
972 default:
973 break;
974 }
975
976 if (error && remdesk->rdpcontext)
977 setChannelError(remdesk->rdpcontext, error,
978 "remdesk_virtual_channel_init_event reported an error");
979}
980
981/* remdesk is always built-in */
982#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
983
984FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
985 PVOID pInitHandle))
986{
987 UINT rc = 0;
988 remdeskPlugin* remdesk = NULL;
989 RemdeskClientContext* context = NULL;
990 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
991
992 if (!pEntryPoints)
993 {
994 return FALSE;
995 }
996
997 remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin));
998
999 if (!remdesk)
1000 {
1001 WLog_ERR(TAG, "calloc failed!");
1002 return FALSE;
1003 }
1004
1005 remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1006 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1007 (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1008 REMDESK_SVC_CHANNEL_NAME);
1009 remdesk->Version = 2;
1010 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1011
1012 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1013 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1014 {
1015 context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext));
1016
1017 if (!context)
1018 {
1019 WLog_ERR(TAG, "calloc failed!");
1020 goto error_out;
1021 }
1022
1023 context->handle = (void*)remdesk;
1024 remdesk->context = context;
1025 remdesk->rdpcontext = pEntryPointsEx->context;
1026 }
1027
1028 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1030 remdesk->InitHandle = pInitHandle;
1031 rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1032 remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1033 remdesk_virtual_channel_init_event_ex);
1034
1035 if (CHANNEL_RC_OK != rc)
1036 {
1037 WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1038 rc);
1039 goto error_out;
1040 }
1041
1042 remdesk->channelEntryPoints.pInterface = context;
1043 return TRUE;
1044error_out:
1045 free(remdesk);
1046 free(context);
1047 return FALSE;
1048}
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