FreeRDP
Loading...
Searching...
No Matches
client/encomsp_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/channels/log.h>
30#include <freerdp/client/encomsp.h>
31
32#include "encomsp_main.h"
33
34struct encomsp_plugin
35{
36 CHANNEL_DEF channelDef;
37 CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints;
38
39 EncomspClientContext* context;
40
41 HANDLE thread;
42 wStream* data_in;
43 void* InitHandle;
44 DWORD OpenHandle;
45 wMessageQueue* queue;
46 rdpContext* rdpcontext;
47};
48
54static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
55{
56 WINPR_ASSERT(header);
57 if (!Stream_CheckAndLogRequiredLength(TAG, s, ENCOMSP_ORDER_HEADER_SIZE))
58 return ERROR_INVALID_DATA;
59
60 Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
61 Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
62 return CHANNEL_RC_OK;
63}
64
70static UINT encomsp_write_header(wStream* s, const ENCOMSP_ORDER_HEADER* header)
71{
72 WINPR_ASSERT(header);
73 Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */
74 Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */
75 return CHANNEL_RC_OK;
76}
77
83static UINT encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str)
84{
85 WINPR_ASSERT(str);
86 const ENCOMSP_UNICODE_STRING empty = WINPR_C_ARRAY_INIT;
87 *str = empty;
88
89 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
90 return ERROR_INVALID_DATA;
91
92 Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */
93
94 if (str->cchString > 1024)
95 {
96 WLog_ERR(TAG, "cchString was %" PRIu16 " but has to be < 1025!", str->cchString);
97 return ERROR_INVALID_DATA;
98 }
99
100 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, str->cchString, sizeof(WCHAR)))
101 return ERROR_INVALID_DATA;
102
103 Stream_Read(s, &(str->wString), (sizeof(WCHAR) * str->cchString)); /* String (variable) */
104 return CHANNEL_RC_OK;
105}
106
107static EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp)
108{
109 WINPR_ASSERT(encomsp);
110 return (EncomspClientContext*)encomsp->channelEntryPoints.pInterface;
111}
112
118static UINT encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s)
119{
120 if (!encomsp)
121 {
122 Stream_Free(s, TRUE);
123 return ERROR_INVALID_HANDLE;
124 }
125
126 const UINT status = encomsp->channelEntryPoints.pVirtualChannelWriteEx(
127 encomsp->InitHandle, encomsp->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s);
128
129 if (status != CHANNEL_RC_OK)
130 {
131 Stream_Free(s, TRUE);
132 WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
133 WTSErrorToString(status), status);
134 }
135 return status;
136}
137
143static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s,
144 const ENCOMSP_ORDER_HEADER* header)
145{
146 ENCOMSP_FILTER_UPDATED_PDU pdu = WINPR_C_ARRAY_INIT;
147 UINT error = CHANNEL_RC_OK;
148 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
149
150 if (!context)
151 return ERROR_INVALID_HANDLE;
152
153 WINPR_ASSERT(header);
154 const size_t pos = Stream_GetPosition(s);
155 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
156 return ERROR_INVALID_DATA;
157 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
158 pdu.Length = header->Length;
159 pdu.Type = header->Type;
160
161 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
162 return ERROR_INVALID_DATA;
163
164 Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */
165 const size_t end = Stream_GetPosition(s);
166 const size_t body = beg + header->Length;
167
168 if (body < end)
169 {
170 WLog_ERR(TAG, "Not enough data!");
171 return ERROR_INVALID_DATA;
172 }
173
174 if (body > end)
175 {
176 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
177 return ERROR_INVALID_DATA;
178
179 if (!Stream_SetPosition(s, body))
180 return ERROR_INVALID_DATA;
181 }
182
183 IFCALLRET(context->FilterUpdated, error, context, &pdu);
184
185 if (error)
186 WLog_ERR(TAG, "context->FilterUpdated failed with error %" PRIu32 "", error);
187
188 return error;
189}
190
196static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s,
197 const ENCOMSP_ORDER_HEADER* header)
198{
199 ENCOMSP_APPLICATION_CREATED_PDU pdu = WINPR_C_ARRAY_INIT;
200 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
201
202 if (!context)
203 return ERROR_INVALID_HANDLE;
204
205 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
206 return ERROR_INVALID_DATA;
207
208 const size_t pos = Stream_GetPosition(s);
209 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
210 return ERROR_INVALID_DATA;
211 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
212
213 WINPR_ASSERT(header);
214 pdu.Length = header->Length;
215 pdu.Type = header->Type;
216
217 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
218 Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
219
220 UINT error = encomsp_read_unicode_string(s, &(pdu.Name));
221 if (error != CHANNEL_RC_OK)
222 {
223 WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
224 return error;
225 }
226
227 const size_t end = Stream_GetPosition(s);
228 const size_t body = beg + header->Length;
229
230 if (body < end)
231 {
232 WLog_ERR(TAG, "Not enough data!");
233 return ERROR_INVALID_DATA;
234 }
235
236 if (body > end)
237 {
238 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
239 return ERROR_INVALID_DATA;
240
241 if (!Stream_SetPosition(s, body))
242 return ERROR_INVALID_DATA;
243 }
244
245 IFCALLRET(context->ApplicationCreated, error, context, &pdu);
246
247 if (error)
248 WLog_ERR(TAG, "context->ApplicationCreated failed with error %" PRIu32 "", error);
249
250 return error;
251}
252
258static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s,
259 const ENCOMSP_ORDER_HEADER* header)
260{
261 ENCOMSP_APPLICATION_REMOVED_PDU pdu = WINPR_C_ARRAY_INIT;
262 UINT error = CHANNEL_RC_OK;
263 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
264
265 if (!context)
266 return ERROR_INVALID_HANDLE;
267
268 const size_t pos = Stream_GetPosition(s);
269 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
270 return ERROR_INVALID_DATA;
271 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
272
273 WINPR_ASSERT(header);
274 pdu.Length = header->Length;
275 pdu.Type = header->Type;
276
277 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
278 return ERROR_INVALID_DATA;
279
280 Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
281 const size_t end = Stream_GetPosition(s);
282 const size_t body = beg + header->Length;
283
284 if (body < end)
285 {
286 WLog_ERR(TAG, "Not enough data!");
287 return ERROR_INVALID_DATA;
288 }
289
290 if (body > end)
291 {
292 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
293 return ERROR_INVALID_DATA;
294
295 if (!Stream_SetPosition(s, body))
296 return ERROR_INVALID_DATA;
297 }
298
299 IFCALLRET(context->ApplicationRemoved, error, context, &pdu);
300
301 if (error)
302 WLog_ERR(TAG, "context->ApplicationRemoved failed with error %" PRIu32 "", error);
303
304 return error;
305}
306
312static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s,
313 const ENCOMSP_ORDER_HEADER* header)
314{
315 ENCOMSP_WINDOW_CREATED_PDU pdu = WINPR_C_ARRAY_INIT;
316 UINT error = CHANNEL_RC_OK;
317 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
318
319 if (!context)
320 return ERROR_INVALID_HANDLE;
321
322 const size_t pos = Stream_GetPosition(s);
323 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
324 return ERROR_INVALID_DATA;
325 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
326
327 WINPR_ASSERT(header);
328 pdu.Length = header->Length;
329 pdu.Type = header->Type;
330
331 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
332 return ERROR_INVALID_DATA;
333
334 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
335 Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
336 Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
337
338 if ((error = encomsp_read_unicode_string(s, &(pdu.Name))))
339 {
340 WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
341 return error;
342 }
343
344 const size_t end = Stream_GetPosition(s);
345 const size_t body = beg + header->Length;
346
347 if (body < end)
348 {
349 WLog_ERR(TAG, "Not enough data!");
350 return ERROR_INVALID_DATA;
351 }
352
353 if (body > end)
354 {
355 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
356 return ERROR_INVALID_DATA;
357
358 if (!Stream_SetPosition(s, body))
359 return ERROR_INVALID_DATA;
360 }
361
362 IFCALLRET(context->WindowCreated, error, context, &pdu);
363
364 if (error)
365 WLog_ERR(TAG, "context->WindowCreated failed with error %" PRIu32 "", error);
366
367 return error;
368}
369
375static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s,
376 const ENCOMSP_ORDER_HEADER* header)
377{
378 ENCOMSP_WINDOW_REMOVED_PDU pdu = WINPR_C_ARRAY_INIT;
379 UINT error = CHANNEL_RC_OK;
380 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
381
382 if (!context)
383 return ERROR_INVALID_HANDLE;
384
385 const size_t pos = Stream_GetPosition(s);
386 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
387 return ERROR_INVALID_DATA;
388 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
389
390 WINPR_ASSERT(header);
391 pdu.Length = header->Length;
392 pdu.Type = header->Type;
393
394 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
395 return ERROR_INVALID_DATA;
396
397 Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
398 const size_t end = Stream_GetPosition(s);
399 const size_t body = beg + header->Length;
400
401 if (body < end)
402 {
403 WLog_ERR(TAG, "Not enough data!");
404 return ERROR_INVALID_DATA;
405 }
406
407 if (body > end)
408 {
409 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
410 return ERROR_INVALID_DATA;
411
412 if (!Stream_SetPosition(s, body))
413 return ERROR_INVALID_DATA;
414 }
415
416 IFCALLRET(context->WindowRemoved, error, context, &pdu);
417
418 if (error)
419 WLog_ERR(TAG, "context->WindowRemoved failed with error %" PRIu32 "", error);
420
421 return error;
422}
423
429static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s,
430 const ENCOMSP_ORDER_HEADER* header)
431{
432 ENCOMSP_SHOW_WINDOW_PDU pdu = WINPR_C_ARRAY_INIT;
433 UINT error = CHANNEL_RC_OK;
434 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
435
436 if (!context)
437 return ERROR_INVALID_HANDLE;
438
439 const size_t pos = Stream_GetPosition(s);
440 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
441 return ERROR_INVALID_DATA;
442 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
443
444 WINPR_ASSERT(header);
445 pdu.Length = header->Length;
446 pdu.Type = header->Type;
447
448 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
449 return ERROR_INVALID_DATA;
450
451 Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
452 const size_t end = Stream_GetPosition(s);
453 const size_t body = beg + header->Length;
454
455 if (body < end)
456 {
457 WLog_ERR(TAG, "Not enough data!");
458 return ERROR_INVALID_DATA;
459 }
460
461 if (body > end)
462 {
463 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
464 return ERROR_INVALID_DATA;
465
466 if (!Stream_SetPosition(s, body))
467 return ERROR_INVALID_DATA;
468 }
469
470 IFCALLRET(context->ShowWindow, error, context, &pdu);
471
472 if (error)
473 WLog_ERR(TAG, "context->ShowWindow failed with error %" PRIu32 "", error);
474
475 return error;
476}
477
483static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s,
484 const ENCOMSP_ORDER_HEADER* header)
485{
486 ENCOMSP_PARTICIPANT_CREATED_PDU pdu = WINPR_C_ARRAY_INIT;
487 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
488
489 if (!context)
490 return ERROR_INVALID_HANDLE;
491
492 const size_t pos = Stream_GetPosition(s);
493 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
494 return ERROR_INVALID_DATA;
495 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
496
497 WINPR_ASSERT(header);
498 pdu.Length = header->Length;
499 pdu.Type = header->Type;
500
501 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
502 return ERROR_INVALID_DATA;
503
504 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
505 Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */
506 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
507
508 UINT error = encomsp_read_unicode_string(s, &(pdu.FriendlyName));
509 if (error != CHANNEL_RC_OK)
510 {
511 WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
512 return error;
513 }
514
515 const size_t end = Stream_GetPosition(s);
516 const size_t body = beg + header->Length;
517
518 if (body < end)
519 {
520 WLog_ERR(TAG, "Not enough data!");
521 return ERROR_INVALID_DATA;
522 }
523
524 if (body > end)
525 {
526 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
527 return ERROR_INVALID_DATA;
528
529 if (!Stream_SetPosition(s, body))
530 return ERROR_INVALID_DATA;
531 }
532
533 IFCALLRET(context->ParticipantCreated, error, context, &pdu);
534
535 if (error)
536 WLog_ERR(TAG, "context->ParticipantCreated failed with error %" PRIu32 "", error);
537
538 return error;
539}
540
546static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s,
547 const ENCOMSP_ORDER_HEADER* header)
548{
549 ENCOMSP_PARTICIPANT_REMOVED_PDU pdu = WINPR_C_ARRAY_INIT;
550 UINT error = CHANNEL_RC_OK;
551 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
552
553 if (!context)
554 return ERROR_INVALID_HANDLE;
555
556 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
557 return ERROR_INVALID_DATA;
558
559 const size_t beg = (Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
560
561 WINPR_ASSERT(header);
562 pdu.Length = header->Length;
563 pdu.Type = header->Type;
564
565 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
566 Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */
567 Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */
568 const size_t end = Stream_GetPosition(s);
569 const size_t body = beg + header->Length;
570
571 if (body < end)
572 {
573 WLog_ERR(TAG, "Not enough data!");
574 return ERROR_INVALID_DATA;
575 }
576
577 if (body > end)
578 {
579 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
580 return ERROR_INVALID_DATA;
581
582 if (!Stream_SetPosition(s, body))
583 return ERROR_INVALID_DATA;
584 }
585
586 IFCALLRET(context->ParticipantRemoved, error, context, &pdu);
587
588 if (error)
589 WLog_ERR(TAG, "context->ParticipantRemoved failed with error %" PRIu32 "", error);
590
591 return error;
592}
593
599static UINT encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s,
600 const ENCOMSP_ORDER_HEADER* header)
601{
602 ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu = WINPR_C_ARRAY_INIT;
603 UINT error = CHANNEL_RC_OK;
604 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
605
606 if (!context)
607 return ERROR_INVALID_HANDLE;
608
609 const size_t pos = Stream_GetPosition(s);
610 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
611 return ERROR_INVALID_DATA;
612 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
613
614 WINPR_ASSERT(header);
615 pdu.Length = header->Length;
616 pdu.Type = header->Type;
617
618 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
619 return ERROR_INVALID_DATA;
620
621 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
622 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
623 const size_t end = Stream_GetPosition(s);
624 const size_t body = beg + header->Length;
625
626 if (body < end)
627 {
628 WLog_ERR(TAG, "Not enough data!");
629 return ERROR_INVALID_DATA;
630 }
631
632 if (body > end)
633 {
634 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
635 return ERROR_INVALID_DATA;
636
637 if (!Stream_SetPosition(s, body))
638 return ERROR_INVALID_DATA;
639 }
640
641 IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
642
643 if (error)
644 WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
645 error);
646
647 return error;
648}
649
655static UINT encomsp_send_change_participant_control_level_pdu(
656 EncomspClientContext* context, const ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu)
657{
658 ENCOMSP_ORDER_HEADER header = WINPR_C_ARRAY_INIT;
659
660 WINPR_ASSERT(context);
661 encomspPlugin* encomsp = (encomspPlugin*)context->handle;
662
663 header.Type = ODTYPE_PARTICIPANT_CTRL_CHANGED;
664 header.Length = ENCOMSP_ORDER_HEADER_SIZE + 6;
665
666 wStream* s = Stream_New(nullptr, header.Length);
667
668 if (!s)
669 {
670 WLog_ERR(TAG, "Stream_New failed!");
671 return CHANNEL_RC_NO_MEMORY;
672 }
673
674 const UINT error = encomsp_write_header(s, &header);
675 if (error != CHANNEL_RC_OK)
676 {
677 WLog_ERR(TAG, "encomsp_write_header failed with error %" PRIu32 "!", error);
678 return error;
679 }
680
681 Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */
682 Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */
683 Stream_SealLength(s);
684 return encomsp_virtual_channel_write(encomsp, s);
685}
686
692static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s,
693 const ENCOMSP_ORDER_HEADER* header)
694{
695 ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU pdu = WINPR_C_ARRAY_INIT;
696 UINT error = CHANNEL_RC_OK;
697 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
698
699 if (!context)
700 return ERROR_INVALID_HANDLE;
701
702 const size_t pos = Stream_GetPosition(s);
703 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
704 return ERROR_INVALID_DATA;
705 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
706
707 WINPR_ASSERT(header);
708 pdu.Length = header->Length;
709 pdu.Type = header->Type;
710
711 const size_t end = Stream_GetPosition(s);
712 const size_t body = beg + header->Length;
713
714 if (body < end)
715 {
716 WLog_ERR(TAG, "Not enough data!");
717 return ERROR_INVALID_DATA;
718 }
719
720 if (body > end)
721 {
722 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
723 return ERROR_INVALID_DATA;
724
725 if (!Stream_SetPosition(s, body))
726 return ERROR_INVALID_DATA;
727 }
728
729 IFCALLRET(context->GraphicsStreamPaused, error, context, &pdu);
730
731 if (error)
732 WLog_ERR(TAG, "context->GraphicsStreamPaused failed with error %" PRIu32 "", error);
733
734 return error;
735}
736
742static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s,
743 const ENCOMSP_ORDER_HEADER* header)
744{
745 ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU pdu = WINPR_C_ARRAY_INIT;
746 UINT error = CHANNEL_RC_OK;
747 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
748
749 if (!context)
750 return ERROR_INVALID_HANDLE;
751
752 const size_t pos = Stream_GetPosition(s);
753 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
754 return ERROR_INVALID_DATA;
755 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
756
757 WINPR_ASSERT(header);
758 pdu.Length = header->Length;
759 pdu.Type = header->Type;
760
761 const size_t end = Stream_GetPosition(s);
762 const size_t body = beg + header->Length;
763
764 if (body < end)
765 {
766 WLog_ERR(TAG, "Not enough data!");
767 return ERROR_INVALID_DATA;
768 }
769
770 if (body > end)
771 {
772 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
773 return ERROR_INVALID_DATA;
774
775 if (!Stream_SetPosition(s, body))
776 return ERROR_INVALID_DATA;
777 }
778
779 IFCALLRET(context->GraphicsStreamResumed, error, context, &pdu);
780
781 if (error)
782 WLog_ERR(TAG, "context->GraphicsStreamResumed failed with error %" PRIu32 "", error);
783
784 return error;
785}
786
792static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s)
793{
794 UINT error = CHANNEL_RC_OK;
795 ENCOMSP_ORDER_HEADER header = WINPR_C_ARRAY_INIT;
796
797 WINPR_ASSERT(encomsp);
798 while (Stream_GetRemainingLength(s) > 0)
799 {
800 if ((error = encomsp_read_header(s, &header)))
801 {
802 WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
803 return error;
804 }
805
806 // WLog_DBG(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type,
807 // header.Length);
808
809 switch (header.Type)
810 {
811 case ODTYPE_FILTER_STATE_UPDATED:
812 if ((error = encomsp_recv_filter_updated_pdu(encomsp, s, &header)))
813 {
814 WLog_ERR(TAG, "encomsp_recv_filter_updated_pdu failed with error %" PRIu32 "!",
815 error);
816 return error;
817 }
818
819 break;
820
821 case ODTYPE_APP_REMOVED:
822 if ((error = encomsp_recv_application_removed_pdu(encomsp, s, &header)))
823 {
824 WLog_ERR(TAG,
825 "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!",
826 error);
827 return error;
828 }
829
830 break;
831
832 case ODTYPE_APP_CREATED:
833 if ((error = encomsp_recv_application_created_pdu(encomsp, s, &header)))
834 {
835 WLog_ERR(TAG,
836 "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!",
837 error);
838 return error;
839 }
840
841 break;
842
843 case ODTYPE_WND_REMOVED:
844 if ((error = encomsp_recv_window_removed_pdu(encomsp, s, &header)))
845 {
846 WLog_ERR(TAG, "encomsp_recv_window_removed_pdu failed with error %" PRIu32 "!",
847 error);
848 return error;
849 }
850
851 break;
852
853 case ODTYPE_WND_CREATED:
854 if ((error = encomsp_recv_window_created_pdu(encomsp, s, &header)))
855 {
856 WLog_ERR(TAG, "encomsp_recv_window_created_pdu failed with error %" PRIu32 "!",
857 error);
858 return error;
859 }
860
861 break;
862
863 case ODTYPE_WND_SHOW:
864 if ((error = encomsp_recv_show_window_pdu(encomsp, s, &header)))
865 {
866 WLog_ERR(TAG, "encomsp_recv_show_window_pdu failed with error %" PRIu32 "!",
867 error);
868 return error;
869 }
870
871 break;
872
873 case ODTYPE_PARTICIPANT_REMOVED:
874 if ((error = encomsp_recv_participant_removed_pdu(encomsp, s, &header)))
875 {
876 WLog_ERR(TAG,
877 "encomsp_recv_participant_removed_pdu failed with error %" PRIu32 "!",
878 error);
879 return error;
880 }
881
882 break;
883
884 case ODTYPE_PARTICIPANT_CREATED:
885 if ((error = encomsp_recv_participant_created_pdu(encomsp, s, &header)))
886 {
887 WLog_ERR(TAG,
888 "encomsp_recv_participant_created_pdu failed with error %" PRIu32 "!",
889 error);
890 return error;
891 }
892
893 break;
894
895 case ODTYPE_PARTICIPANT_CTRL_CHANGED:
896 if ((error =
897 encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header)))
898 {
899 WLog_ERR(TAG,
900 "encomsp_recv_change_participant_control_level_pdu failed with error "
901 "%" PRIu32 "!",
902 error);
903 return error;
904 }
905
906 break;
907
908 case ODTYPE_GRAPHICS_STREAM_PAUSED:
909 if ((error = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header)))
910 {
911 WLog_ERR(TAG,
912 "encomsp_recv_graphics_stream_paused_pdu failed with error %" PRIu32
913 "!",
914 error);
915 return error;
916 }
917
918 break;
919
920 case ODTYPE_GRAPHICS_STREAM_RESUMED:
921 if ((error = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header)))
922 {
923 WLog_ERR(TAG,
924 "encomsp_recv_graphics_stream_resumed_pdu failed with error %" PRIu32
925 "!",
926 error);
927 return error;
928 }
929
930 break;
931
932 default:
933 WLog_ERR(TAG, "header.Type %" PRIu16 " not found", header.Type);
934 return ERROR_INVALID_DATA;
935 }
936 }
937
938 return error;
939}
940
946static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, const void* pData,
947 UINT32 dataLength, UINT32 totalLength,
948 UINT32 dataFlags)
949{
950 WINPR_ASSERT(encomsp);
951
952 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
953 return CHANNEL_RC_OK;
954
955 if (dataFlags & CHANNEL_FLAG_FIRST)
956 {
957 if (encomsp->data_in)
958 Stream_Free(encomsp->data_in, TRUE);
959
960 encomsp->data_in = Stream_New(nullptr, totalLength);
961
962 if (!encomsp->data_in)
963 {
964 WLog_ERR(TAG, "Stream_New failed!");
965 return CHANNEL_RC_NO_MEMORY;
966 }
967 }
968
969 wStream* data_in = encomsp->data_in;
970
971 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
972 {
973 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
974 return ERROR_INTERNAL_ERROR;
975 }
976
977 Stream_Write(data_in, pData, dataLength);
978
979 if (dataFlags & CHANNEL_FLAG_LAST)
980 {
981 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
982 {
983 WLog_ERR(TAG, "encomsp_plugin_process_received: read error");
984 return ERROR_INVALID_DATA;
985 }
986
987 encomsp->data_in = nullptr;
988 Stream_SealLength(data_in);
989 Stream_ResetPosition(data_in);
990
991 if (!MessageQueue_Post(encomsp->queue, nullptr, 0, (void*)data_in, nullptr))
992 {
993 WLog_ERR(TAG, "MessageQueue_Post failed!");
994 return ERROR_INTERNAL_ERROR;
995 }
996 }
997
998 return CHANNEL_RC_OK;
999}
1000
1001static VOID VCAPITYPE encomsp_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
1002 UINT event, LPVOID pData,
1003 UINT32 dataLength, UINT32 totalLength,
1004 UINT32 dataFlags)
1005{
1006 UINT error = CHANNEL_RC_OK;
1007 encomspPlugin* encomsp = (encomspPlugin*)lpUserParam;
1008
1009 switch (event)
1010 {
1011 case CHANNEL_EVENT_DATA_RECEIVED:
1012 if (!encomsp || (encomsp->OpenHandle != openHandle))
1013 {
1014 WLog_ERR(TAG, "error no match");
1015 return;
1016 }
1017 if ((error = encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength,
1018 totalLength, dataFlags)))
1019 WLog_ERR(TAG,
1020 "encomsp_virtual_channel_event_data_received failed with error %" PRIu32
1021 "",
1022 error);
1023
1024 break;
1025
1026 case CHANNEL_EVENT_WRITE_CANCELLED:
1027 case CHANNEL_EVENT_WRITE_COMPLETE:
1028 {
1029 wStream* s = (wStream*)pData;
1030 Stream_Free(s, TRUE);
1031 }
1032 break;
1033
1034 case CHANNEL_EVENT_USER:
1035 break;
1036 default:
1037 break;
1038 }
1039
1040 if (error && encomsp && encomsp->rdpcontext)
1041 setChannelError(encomsp->rdpcontext, error,
1042 "encomsp_virtual_channel_open_event reported an error");
1043}
1044
1045static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg)
1046{
1047 wStream* data = nullptr;
1048 wMessage message = WINPR_C_ARRAY_INIT;
1049 encomspPlugin* encomsp = (encomspPlugin*)arg;
1050 UINT error = CHANNEL_RC_OK;
1051
1052 WINPR_ASSERT(encomsp);
1053 while (1)
1054 {
1055 if (!MessageQueue_Wait(encomsp->queue))
1056 {
1057 WLog_ERR(TAG, "MessageQueue_Wait failed!");
1058 error = ERROR_INTERNAL_ERROR;
1059 break;
1060 }
1061
1062 if (!MessageQueue_Peek(encomsp->queue, &message, TRUE))
1063 {
1064 WLog_ERR(TAG, "MessageQueue_Peek failed!");
1065 error = ERROR_INTERNAL_ERROR;
1066 break;
1067 }
1068
1069 if (message.id == WMQ_QUIT)
1070 break;
1071
1072 if (message.id == 0)
1073 {
1074 data = (wStream*)message.wParam;
1075
1076 if ((error = encomsp_process_receive(encomsp, data)))
1077 {
1078 WLog_ERR(TAG, "encomsp_process_receive failed with error %" PRIu32 "!", error);
1079 Stream_Free(data, TRUE);
1080 break;
1081 }
1082
1083 Stream_Free(data, TRUE);
1084 }
1085 }
1086
1087 if (error && encomsp->rdpcontext)
1088 setChannelError(encomsp->rdpcontext, error,
1089 "encomsp_virtual_channel_client_thread reported an error");
1090
1091 ExitThread(error);
1092 return error;
1093}
1094
1100static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp,
1101 WINPR_ATTR_UNUSED LPVOID pData,
1102 WINPR_ATTR_UNUSED UINT32 dataLength)
1103{
1104 WINPR_ASSERT(encomsp);
1105
1106 encomsp->queue = MessageQueue_New(nullptr);
1107
1108 if (!encomsp->queue)
1109 {
1110 WLog_ERR(TAG, "MessageQueue_New failed!");
1111 return CHANNEL_RC_NO_MEMORY;
1112 }
1113
1114 if (!(encomsp->thread = CreateThread(nullptr, 0, encomsp_virtual_channel_client_thread,
1115 (void*)encomsp, 0, nullptr)))
1116 {
1117 WLog_ERR(TAG, "CreateThread failed!");
1118 MessageQueue_Free(encomsp->queue);
1119 return ERROR_INTERNAL_ERROR;
1120 }
1121
1122 return encomsp->channelEntryPoints.pVirtualChannelOpenEx(
1123 encomsp->InitHandle, &encomsp->OpenHandle, encomsp->channelDef.name,
1124 encomsp_virtual_channel_open_event_ex);
1125}
1126
1132static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp)
1133{
1134 WINPR_ASSERT(encomsp);
1135 if (encomsp->OpenHandle == 0)
1136 return CHANNEL_RC_OK;
1137
1138 if (encomsp->queue && encomsp->thread)
1139 {
1140 if (MessageQueue_PostQuit(encomsp->queue, 0) &&
1141 (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED))
1142 {
1143 const UINT rc = GetLastError();
1144 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
1145 return rc;
1146 }
1147 }
1148
1149 MessageQueue_Free(encomsp->queue);
1150 (void)CloseHandle(encomsp->thread);
1151 encomsp->queue = nullptr;
1152 encomsp->thread = nullptr;
1153
1154 WINPR_ASSERT(encomsp->channelEntryPoints.pVirtualChannelCloseEx);
1155 const UINT rc = encomsp->channelEntryPoints.pVirtualChannelCloseEx(encomsp->InitHandle,
1156 encomsp->OpenHandle);
1157
1158 if (CHANNEL_RC_OK != rc)
1159 {
1160 WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1161 rc);
1162 return rc;
1163 }
1164
1165 encomsp->OpenHandle = 0;
1166
1167 if (encomsp->data_in)
1168 {
1169 Stream_Free(encomsp->data_in, TRUE);
1170 encomsp->data_in = nullptr;
1171 }
1172
1173 return CHANNEL_RC_OK;
1174}
1175
1181static UINT encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp)
1182{
1183 WINPR_ASSERT(encomsp);
1184
1185 encomsp->InitHandle = nullptr;
1186 free(encomsp->context);
1187 free(encomsp);
1188 return CHANNEL_RC_OK;
1189}
1190
1191static VOID VCAPITYPE encomsp_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1192 UINT event, LPVOID pData,
1193 UINT dataLength)
1194{
1195 UINT error = CHANNEL_RC_OK;
1196 encomspPlugin* encomsp = (encomspPlugin*)lpUserParam;
1197
1198 if (!encomsp || (encomsp->InitHandle != pInitHandle))
1199 {
1200 WLog_ERR(TAG, "error no match");
1201 return;
1202 }
1203
1204 switch (event)
1205 {
1206 case CHANNEL_EVENT_INITIALIZED:
1207 break;
1208
1209 case CHANNEL_EVENT_CONNECTED:
1210 if ((error = encomsp_virtual_channel_event_connected(encomsp, pData, dataLength)))
1211 WLog_ERR(TAG,
1212 "encomsp_virtual_channel_event_connected failed with error %" PRIu32 "",
1213 error);
1214
1215 break;
1216
1217 case CHANNEL_EVENT_DISCONNECTED:
1218 if ((error = encomsp_virtual_channel_event_disconnected(encomsp)))
1219 WLog_ERR(TAG,
1220 "encomsp_virtual_channel_event_disconnected failed with error %" PRIu32 "",
1221 error);
1222
1223 break;
1224
1225 case CHANNEL_EVENT_TERMINATED:
1226 encomsp_virtual_channel_event_terminated(encomsp);
1227 break;
1228
1229 default:
1230 break;
1231 }
1232
1233 if (error && encomsp->rdpcontext)
1234 setChannelError(encomsp->rdpcontext, error,
1235 "encomsp_virtual_channel_init_event reported an error");
1236}
1237
1238/* encomsp is always built-in */
1239#define VirtualChannelEntryEx encomsp_VirtualChannelEntryEx
1240
1241FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
1242 PVOID pInitHandle))
1243{
1244 BOOL isFreerdp = FALSE;
1245 encomspPlugin* encomsp = (encomspPlugin*)calloc(1, sizeof(encomspPlugin));
1246
1247 if (!encomsp)
1248 {
1249 WLog_ERR(TAG, "calloc failed!");
1250 return FALSE;
1251 }
1252
1253 encomsp->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1254 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1255 (void)sprintf_s(encomsp->channelDef.name, ARRAYSIZE(encomsp->channelDef.name),
1256 ENCOMSP_SVC_CHANNEL_NAME);
1257 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx =
1258 (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1259 WINPR_ASSERT(pEntryPointsEx);
1260
1261 EncomspClientContext* context = nullptr;
1262 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1263 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1264 {
1265 context = (EncomspClientContext*)calloc(1, sizeof(EncomspClientContext));
1266
1267 if (!context)
1268 {
1269 WLog_ERR(TAG, "calloc failed!");
1270 goto error_out;
1271 }
1272
1273 context->handle = (void*)encomsp;
1274 context->FilterUpdated = nullptr;
1275 context->ApplicationCreated = nullptr;
1276 context->ApplicationRemoved = nullptr;
1277 context->WindowCreated = nullptr;
1278 context->WindowRemoved = nullptr;
1279 context->ShowWindow = nullptr;
1280 context->ParticipantCreated = nullptr;
1281 context->ParticipantRemoved = nullptr;
1282 context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu;
1283 context->GraphicsStreamPaused = nullptr;
1284 context->GraphicsStreamResumed = nullptr;
1285 encomsp->context = context;
1286 encomsp->rdpcontext = pEntryPointsEx->context;
1287 isFreerdp = TRUE;
1288 }
1289
1290 CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints,
1292 encomsp->InitHandle = pInitHandle;
1293
1294 {
1295 const UINT rc = encomsp->channelEntryPoints.pVirtualChannelInitEx(
1296 encomsp, context, pInitHandle, &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1297 encomsp_virtual_channel_init_event_ex);
1298
1299 if (CHANNEL_RC_OK != rc)
1300 {
1301 WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
1302 goto error_out;
1303 }
1304 }
1305
1306 encomsp->channelEntryPoints.pInterface = context;
1307 return TRUE;
1308error_out:
1309
1310 if (isFreerdp)
1311 free(encomsp->context);
1312
1313 free(encomsp);
1314 return FALSE;
1315}
Definition svc.h:60