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