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 = { 0 };
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 = { 0 };
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 Stream_SetPosition(s, body);
180 }
181
182 IFCALLRET(context->FilterUpdated, error, context, &pdu);
183
184 if (error)
185 WLog_ERR(TAG, "context->FilterUpdated failed with error %" PRIu32 "", error);
186
187 return error;
188}
189
195static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s,
196 const ENCOMSP_ORDER_HEADER* header)
197{
199 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
200
201 if (!context)
202 return ERROR_INVALID_HANDLE;
203
204 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
205 return ERROR_INVALID_DATA;
206
207 const size_t pos = Stream_GetPosition(s);
208 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
209 return ERROR_INVALID_DATA;
210 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
211
212 WINPR_ASSERT(header);
213 pdu.Length = header->Length;
214 pdu.Type = header->Type;
215
216 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
217 Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
218
219 UINT error = encomsp_read_unicode_string(s, &(pdu.Name));
220 if (error != CHANNEL_RC_OK)
221 {
222 WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
223 return error;
224 }
225
226 const size_t end = Stream_GetPosition(s);
227 const size_t body = beg + header->Length;
228
229 if (body < end)
230 {
231 WLog_ERR(TAG, "Not enough data!");
232 return ERROR_INVALID_DATA;
233 }
234
235 if (body > end)
236 {
237 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
238 return ERROR_INVALID_DATA;
239
240 Stream_SetPosition(s, body);
241 }
242
243 IFCALLRET(context->ApplicationCreated, error, context, &pdu);
244
245 if (error)
246 WLog_ERR(TAG, "context->ApplicationCreated failed with error %" PRIu32 "", error);
247
248 return error;
249}
250
256static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s,
257 const ENCOMSP_ORDER_HEADER* header)
258{
260 UINT error = CHANNEL_RC_OK;
261 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
262
263 if (!context)
264 return ERROR_INVALID_HANDLE;
265
266 const size_t pos = Stream_GetPosition(s);
267 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
268 return ERROR_INVALID_DATA;
269 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
270
271 WINPR_ASSERT(header);
272 pdu.Length = header->Length;
273 pdu.Type = header->Type;
274
275 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
276 return ERROR_INVALID_DATA;
277
278 Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
279 const size_t end = Stream_GetPosition(s);
280 const size_t body = beg + header->Length;
281
282 if (body < end)
283 {
284 WLog_ERR(TAG, "Not enough data!");
285 return ERROR_INVALID_DATA;
286 }
287
288 if (body > end)
289 {
290 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
291 return ERROR_INVALID_DATA;
292
293 Stream_SetPosition(s, body);
294 }
295
296 IFCALLRET(context->ApplicationRemoved, error, context, &pdu);
297
298 if (error)
299 WLog_ERR(TAG, "context->ApplicationRemoved failed with error %" PRIu32 "", error);
300
301 return error;
302}
303
309static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s,
310 const ENCOMSP_ORDER_HEADER* header)
311{
312 ENCOMSP_WINDOW_CREATED_PDU pdu = { 0 };
313 UINT error = CHANNEL_RC_OK;
314 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
315
316 if (!context)
317 return ERROR_INVALID_HANDLE;
318
319 const size_t pos = Stream_GetPosition(s);
320 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
321 return ERROR_INVALID_DATA;
322 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
323
324 WINPR_ASSERT(header);
325 pdu.Length = header->Length;
326 pdu.Type = header->Type;
327
328 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
329 return ERROR_INVALID_DATA;
330
331 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
332 Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
333 Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
334
335 if ((error = encomsp_read_unicode_string(s, &(pdu.Name))))
336 {
337 WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
338 return error;
339 }
340
341 const size_t end = Stream_GetPosition(s);
342 const size_t body = beg + header->Length;
343
344 if (body < end)
345 {
346 WLog_ERR(TAG, "Not enough data!");
347 return ERROR_INVALID_DATA;
348 }
349
350 if (body > end)
351 {
352 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
353 return ERROR_INVALID_DATA;
354
355 Stream_SetPosition(s, body);
356 }
357
358 IFCALLRET(context->WindowCreated, error, context, &pdu);
359
360 if (error)
361 WLog_ERR(TAG, "context->WindowCreated failed with error %" PRIu32 "", error);
362
363 return error;
364}
365
371static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s,
372 const ENCOMSP_ORDER_HEADER* header)
373{
374 ENCOMSP_WINDOW_REMOVED_PDU pdu = { 0 };
375 UINT error = CHANNEL_RC_OK;
376 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
377
378 if (!context)
379 return ERROR_INVALID_HANDLE;
380
381 const size_t pos = Stream_GetPosition(s);
382 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
383 return ERROR_INVALID_DATA;
384 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
385
386 WINPR_ASSERT(header);
387 pdu.Length = header->Length;
388 pdu.Type = header->Type;
389
390 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
391 return ERROR_INVALID_DATA;
392
393 Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
394 const size_t end = Stream_GetPosition(s);
395 const size_t body = beg + header->Length;
396
397 if (body < end)
398 {
399 WLog_ERR(TAG, "Not enough data!");
400 return ERROR_INVALID_DATA;
401 }
402
403 if (body > end)
404 {
405 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
406 return ERROR_INVALID_DATA;
407
408 Stream_SetPosition(s, body);
409 }
410
411 IFCALLRET(context->WindowRemoved, error, context, &pdu);
412
413 if (error)
414 WLog_ERR(TAG, "context->WindowRemoved failed with error %" PRIu32 "", error);
415
416 return error;
417}
418
424static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s,
425 const ENCOMSP_ORDER_HEADER* header)
426{
427 ENCOMSP_SHOW_WINDOW_PDU pdu = { 0 };
428 UINT error = CHANNEL_RC_OK;
429 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
430
431 if (!context)
432 return ERROR_INVALID_HANDLE;
433
434 const size_t pos = Stream_GetPosition(s);
435 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
436 return ERROR_INVALID_DATA;
437 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
438
439 WINPR_ASSERT(header);
440 pdu.Length = header->Length;
441 pdu.Type = header->Type;
442
443 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
444 return ERROR_INVALID_DATA;
445
446 Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
447 const size_t end = Stream_GetPosition(s);
448 const size_t body = beg + header->Length;
449
450 if (body < end)
451 {
452 WLog_ERR(TAG, "Not enough data!");
453 return ERROR_INVALID_DATA;
454 }
455
456 if (body > end)
457 {
458 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
459 return ERROR_INVALID_DATA;
460
461 Stream_SetPosition(s, body);
462 }
463
464 IFCALLRET(context->ShowWindow, error, context, &pdu);
465
466 if (error)
467 WLog_ERR(TAG, "context->ShowWindow failed with error %" PRIu32 "", error);
468
469 return error;
470}
471
477static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s,
478 const ENCOMSP_ORDER_HEADER* header)
479{
481 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
482
483 if (!context)
484 return ERROR_INVALID_HANDLE;
485
486 const size_t pos = Stream_GetPosition(s);
487 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
488 return ERROR_INVALID_DATA;
489 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
490
491 WINPR_ASSERT(header);
492 pdu.Length = header->Length;
493 pdu.Type = header->Type;
494
495 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
496 return ERROR_INVALID_DATA;
497
498 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
499 Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */
500 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
501
502 UINT error = encomsp_read_unicode_string(s, &(pdu.FriendlyName));
503 if (error != CHANNEL_RC_OK)
504 {
505 WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
506 return error;
507 }
508
509 const size_t end = Stream_GetPosition(s);
510 const size_t body = beg + header->Length;
511
512 if (body < end)
513 {
514 WLog_ERR(TAG, "Not enough data!");
515 return ERROR_INVALID_DATA;
516 }
517
518 if (body > end)
519 {
520 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
521 return ERROR_INVALID_DATA;
522
523 Stream_SetPosition(s, body);
524 }
525
526 IFCALLRET(context->ParticipantCreated, error, context, &pdu);
527
528 if (error)
529 WLog_ERR(TAG, "context->ParticipantCreated failed with error %" PRIu32 "", error);
530
531 return error;
532}
533
539static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s,
540 const ENCOMSP_ORDER_HEADER* header)
541{
543 UINT error = CHANNEL_RC_OK;
544 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
545
546 if (!context)
547 return ERROR_INVALID_HANDLE;
548
549 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
550 return ERROR_INVALID_DATA;
551
552 const size_t beg = (Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
553
554 WINPR_ASSERT(header);
555 pdu.Length = header->Length;
556 pdu.Type = header->Type;
557
558 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
559 Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */
560 Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */
561 const size_t end = Stream_GetPosition(s);
562 const size_t body = beg + header->Length;
563
564 if (body < end)
565 {
566 WLog_ERR(TAG, "Not enough data!");
567 return ERROR_INVALID_DATA;
568 }
569
570 if (body > end)
571 {
572 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
573 return ERROR_INVALID_DATA;
574
575 Stream_SetPosition(s, body);
576 }
577
578 IFCALLRET(context->ParticipantRemoved, error, context, &pdu);
579
580 if (error)
581 WLog_ERR(TAG, "context->ParticipantRemoved failed with error %" PRIu32 "", error);
582
583 return error;
584}
585
591static UINT encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s,
592 const ENCOMSP_ORDER_HEADER* header)
593{
595 UINT error = CHANNEL_RC_OK;
596 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
597
598 if (!context)
599 return ERROR_INVALID_HANDLE;
600
601 const size_t pos = Stream_GetPosition(s);
602 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
603 return ERROR_INVALID_DATA;
604 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
605
606 WINPR_ASSERT(header);
607 pdu.Length = header->Length;
608 pdu.Type = header->Type;
609
610 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
611 return ERROR_INVALID_DATA;
612
613 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
614 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
615 const size_t end = Stream_GetPosition(s);
616 const size_t body = beg + header->Length;
617
618 if (body < end)
619 {
620 WLog_ERR(TAG, "Not enough data!");
621 return ERROR_INVALID_DATA;
622 }
623
624 if (body > end)
625 {
626 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
627 return ERROR_INVALID_DATA;
628
629 Stream_SetPosition(s, body);
630 }
631
632 IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
633
634 if (error)
635 WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
636 error);
637
638 return error;
639}
640
646static UINT encomsp_send_change_participant_control_level_pdu(
647 EncomspClientContext* context, const ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu)
648{
649 ENCOMSP_ORDER_HEADER header = { 0 };
650
651 WINPR_ASSERT(context);
652 encomspPlugin* encomsp = (encomspPlugin*)context->handle;
653
654 header.Type = ODTYPE_PARTICIPANT_CTRL_CHANGED;
655 header.Length = ENCOMSP_ORDER_HEADER_SIZE + 6;
656
657 wStream* s = Stream_New(NULL, header.Length);
658
659 if (!s)
660 {
661 WLog_ERR(TAG, "Stream_New failed!");
662 return CHANNEL_RC_NO_MEMORY;
663 }
664
665 const UINT error = encomsp_write_header(s, &header);
666 if (error != CHANNEL_RC_OK)
667 {
668 WLog_ERR(TAG, "encomsp_write_header failed with error %" PRIu32 "!", error);
669 return error;
670 }
671
672 Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */
673 Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */
674 Stream_SealLength(s);
675 return encomsp_virtual_channel_write(encomsp, s);
676}
677
683static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s,
684 const ENCOMSP_ORDER_HEADER* header)
685{
687 UINT error = CHANNEL_RC_OK;
688 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
689
690 if (!context)
691 return ERROR_INVALID_HANDLE;
692
693 const size_t pos = Stream_GetPosition(s);
694 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
695 return ERROR_INVALID_DATA;
696 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
697
698 WINPR_ASSERT(header);
699 pdu.Length = header->Length;
700 pdu.Type = header->Type;
701
702 const size_t end = Stream_GetPosition(s);
703 const size_t body = beg + header->Length;
704
705 if (body < end)
706 {
707 WLog_ERR(TAG, "Not enough data!");
708 return ERROR_INVALID_DATA;
709 }
710
711 if (body > end)
712 {
713 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
714 return ERROR_INVALID_DATA;
715
716 Stream_SetPosition(s, body);
717 }
718
719 IFCALLRET(context->GraphicsStreamPaused, error, context, &pdu);
720
721 if (error)
722 WLog_ERR(TAG, "context->GraphicsStreamPaused failed with error %" PRIu32 "", error);
723
724 return error;
725}
726
732static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s,
733 const ENCOMSP_ORDER_HEADER* header)
734{
736 UINT error = CHANNEL_RC_OK;
737 EncomspClientContext* context = encomsp_get_client_interface(encomsp);
738
739 if (!context)
740 return ERROR_INVALID_HANDLE;
741
742 const size_t pos = Stream_GetPosition(s);
743 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
744 return ERROR_INVALID_DATA;
745 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
746
747 WINPR_ASSERT(header);
748 pdu.Length = header->Length;
749 pdu.Type = header->Type;
750
751 const size_t end = Stream_GetPosition(s);
752 const size_t body = beg + header->Length;
753
754 if (body < end)
755 {
756 WLog_ERR(TAG, "Not enough data!");
757 return ERROR_INVALID_DATA;
758 }
759
760 if (body > end)
761 {
762 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
763 return ERROR_INVALID_DATA;
764
765 Stream_SetPosition(s, body);
766 }
767
768 IFCALLRET(context->GraphicsStreamResumed, error, context, &pdu);
769
770 if (error)
771 WLog_ERR(TAG, "context->GraphicsStreamResumed failed with error %" PRIu32 "", error);
772
773 return error;
774}
775
781static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s)
782{
783 UINT error = CHANNEL_RC_OK;
784 ENCOMSP_ORDER_HEADER header = { 0 };
785
786 WINPR_ASSERT(encomsp);
787 while (Stream_GetRemainingLength(s) > 0)
788 {
789 if ((error = encomsp_read_header(s, &header)))
790 {
791 WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
792 return error;
793 }
794
795 // WLog_DBG(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type,
796 // header.Length);
797
798 switch (header.Type)
799 {
800 case ODTYPE_FILTER_STATE_UPDATED:
801 if ((error = encomsp_recv_filter_updated_pdu(encomsp, s, &header)))
802 {
803 WLog_ERR(TAG, "encomsp_recv_filter_updated_pdu failed with error %" PRIu32 "!",
804 error);
805 return error;
806 }
807
808 break;
809
810 case ODTYPE_APP_REMOVED:
811 if ((error = encomsp_recv_application_removed_pdu(encomsp, s, &header)))
812 {
813 WLog_ERR(TAG,
814 "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!",
815 error);
816 return error;
817 }
818
819 break;
820
821 case ODTYPE_APP_CREATED:
822 if ((error = encomsp_recv_application_created_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_WND_REMOVED:
833 if ((error = encomsp_recv_window_removed_pdu(encomsp, s, &header)))
834 {
835 WLog_ERR(TAG, "encomsp_recv_window_removed_pdu failed with error %" PRIu32 "!",
836 error);
837 return error;
838 }
839
840 break;
841
842 case ODTYPE_WND_CREATED:
843 if ((error = encomsp_recv_window_created_pdu(encomsp, s, &header)))
844 {
845 WLog_ERR(TAG, "encomsp_recv_window_created_pdu failed with error %" PRIu32 "!",
846 error);
847 return error;
848 }
849
850 break;
851
852 case ODTYPE_WND_SHOW:
853 if ((error = encomsp_recv_show_window_pdu(encomsp, s, &header)))
854 {
855 WLog_ERR(TAG, "encomsp_recv_show_window_pdu failed with error %" PRIu32 "!",
856 error);
857 return error;
858 }
859
860 break;
861
862 case ODTYPE_PARTICIPANT_REMOVED:
863 if ((error = encomsp_recv_participant_removed_pdu(encomsp, s, &header)))
864 {
865 WLog_ERR(TAG,
866 "encomsp_recv_participant_removed_pdu failed with error %" PRIu32 "!",
867 error);
868 return error;
869 }
870
871 break;
872
873 case ODTYPE_PARTICIPANT_CREATED:
874 if ((error = encomsp_recv_participant_created_pdu(encomsp, s, &header)))
875 {
876 WLog_ERR(TAG,
877 "encomsp_recv_participant_created_pdu failed with error %" PRIu32 "!",
878 error);
879 return error;
880 }
881
882 break;
883
884 case ODTYPE_PARTICIPANT_CTRL_CHANGED:
885 if ((error =
886 encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header)))
887 {
888 WLog_ERR(TAG,
889 "encomsp_recv_change_participant_control_level_pdu failed with error "
890 "%" PRIu32 "!",
891 error);
892 return error;
893 }
894
895 break;
896
897 case ODTYPE_GRAPHICS_STREAM_PAUSED:
898 if ((error = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header)))
899 {
900 WLog_ERR(TAG,
901 "encomsp_recv_graphics_stream_paused_pdu failed with error %" PRIu32
902 "!",
903 error);
904 return error;
905 }
906
907 break;
908
909 case ODTYPE_GRAPHICS_STREAM_RESUMED:
910 if ((error = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header)))
911 {
912 WLog_ERR(TAG,
913 "encomsp_recv_graphics_stream_resumed_pdu failed with error %" PRIu32
914 "!",
915 error);
916 return error;
917 }
918
919 break;
920
921 default:
922 WLog_ERR(TAG, "header.Type %" PRIu16 " not found", header.Type);
923 return ERROR_INVALID_DATA;
924 }
925 }
926
927 return error;
928}
929
935static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, const void* pData,
936 UINT32 dataLength, UINT32 totalLength,
937 UINT32 dataFlags)
938{
939 WINPR_ASSERT(encomsp);
940
941 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
942 return CHANNEL_RC_OK;
943
944 if (dataFlags & CHANNEL_FLAG_FIRST)
945 {
946 if (encomsp->data_in)
947 Stream_Free(encomsp->data_in, TRUE);
948
949 encomsp->data_in = Stream_New(NULL, totalLength);
950
951 if (!encomsp->data_in)
952 {
953 WLog_ERR(TAG, "Stream_New failed!");
954 return CHANNEL_RC_NO_MEMORY;
955 }
956 }
957
958 wStream* data_in = encomsp->data_in;
959
960 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
961 {
962 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
963 return ERROR_INTERNAL_ERROR;
964 }
965
966 Stream_Write(data_in, pData, dataLength);
967
968 if (dataFlags & CHANNEL_FLAG_LAST)
969 {
970 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
971 {
972 WLog_ERR(TAG, "encomsp_plugin_process_received: read error");
973 return ERROR_INVALID_DATA;
974 }
975
976 encomsp->data_in = NULL;
977 Stream_SealLength(data_in);
978 Stream_SetPosition(data_in, 0);
979
980 if (!MessageQueue_Post(encomsp->queue, NULL, 0, (void*)data_in, NULL))
981 {
982 WLog_ERR(TAG, "MessageQueue_Post failed!");
983 return ERROR_INTERNAL_ERROR;
984 }
985 }
986
987 return CHANNEL_RC_OK;
988}
989
990static VOID VCAPITYPE encomsp_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
991 UINT event, LPVOID pData,
992 UINT32 dataLength, UINT32 totalLength,
993 UINT32 dataFlags)
994{
995 UINT error = CHANNEL_RC_OK;
996 encomspPlugin* encomsp = (encomspPlugin*)lpUserParam;
997
998 switch (event)
999 {
1000 case CHANNEL_EVENT_DATA_RECEIVED:
1001 if (!encomsp || (encomsp->OpenHandle != openHandle))
1002 {
1003 WLog_ERR(TAG, "error no match");
1004 return;
1005 }
1006 if ((error = encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength,
1007 totalLength, dataFlags)))
1008 WLog_ERR(TAG,
1009 "encomsp_virtual_channel_event_data_received failed with error %" PRIu32
1010 "",
1011 error);
1012
1013 break;
1014
1015 case CHANNEL_EVENT_WRITE_CANCELLED:
1016 case CHANNEL_EVENT_WRITE_COMPLETE:
1017 {
1018 wStream* s = (wStream*)pData;
1019 Stream_Free(s, TRUE);
1020 }
1021 break;
1022
1023 case CHANNEL_EVENT_USER:
1024 break;
1025 default:
1026 break;
1027 }
1028
1029 if (error && encomsp && encomsp->rdpcontext)
1030 setChannelError(encomsp->rdpcontext, error,
1031 "encomsp_virtual_channel_open_event reported an error");
1032}
1033
1034static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg)
1035{
1036 wStream* data = NULL;
1037 wMessage message = { 0 };
1038 encomspPlugin* encomsp = (encomspPlugin*)arg;
1039 UINT error = CHANNEL_RC_OK;
1040
1041 WINPR_ASSERT(encomsp);
1042 while (1)
1043 {
1044 if (!MessageQueue_Wait(encomsp->queue))
1045 {
1046 WLog_ERR(TAG, "MessageQueue_Wait failed!");
1047 error = ERROR_INTERNAL_ERROR;
1048 break;
1049 }
1050
1051 if (!MessageQueue_Peek(encomsp->queue, &message, TRUE))
1052 {
1053 WLog_ERR(TAG, "MessageQueue_Peek failed!");
1054 error = ERROR_INTERNAL_ERROR;
1055 break;
1056 }
1057
1058 if (message.id == WMQ_QUIT)
1059 break;
1060
1061 if (message.id == 0)
1062 {
1063 data = (wStream*)message.wParam;
1064
1065 if ((error = encomsp_process_receive(encomsp, data)))
1066 {
1067 WLog_ERR(TAG, "encomsp_process_receive failed with error %" PRIu32 "!", error);
1068 Stream_Free(data, TRUE);
1069 break;
1070 }
1071
1072 Stream_Free(data, TRUE);
1073 }
1074 }
1075
1076 if (error && encomsp->rdpcontext)
1077 setChannelError(encomsp->rdpcontext, error,
1078 "encomsp_virtual_channel_client_thread reported an error");
1079
1080 ExitThread(error);
1081 return error;
1082}
1083
1089static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp,
1090 WINPR_ATTR_UNUSED LPVOID pData,
1091 WINPR_ATTR_UNUSED UINT32 dataLength)
1092{
1093 WINPR_ASSERT(encomsp);
1094
1095 encomsp->queue = MessageQueue_New(NULL);
1096
1097 if (!encomsp->queue)
1098 {
1099 WLog_ERR(TAG, "MessageQueue_New failed!");
1100 return CHANNEL_RC_NO_MEMORY;
1101 }
1102
1103 if (!(encomsp->thread = CreateThread(NULL, 0, encomsp_virtual_channel_client_thread,
1104 (void*)encomsp, 0, NULL)))
1105 {
1106 WLog_ERR(TAG, "CreateThread failed!");
1107 MessageQueue_Free(encomsp->queue);
1108 return ERROR_INTERNAL_ERROR;
1109 }
1110
1111 return encomsp->channelEntryPoints.pVirtualChannelOpenEx(
1112 encomsp->InitHandle, &encomsp->OpenHandle, encomsp->channelDef.name,
1113 encomsp_virtual_channel_open_event_ex);
1114}
1115
1121static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp)
1122{
1123 WINPR_ASSERT(encomsp);
1124 if (encomsp->OpenHandle == 0)
1125 return CHANNEL_RC_OK;
1126
1127 if (encomsp->queue && encomsp->thread)
1128 {
1129 if (MessageQueue_PostQuit(encomsp->queue, 0) &&
1130 (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED))
1131 {
1132 const UINT rc = GetLastError();
1133 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
1134 return rc;
1135 }
1136 }
1137
1138 MessageQueue_Free(encomsp->queue);
1139 (void)CloseHandle(encomsp->thread);
1140 encomsp->queue = NULL;
1141 encomsp->thread = NULL;
1142
1143 WINPR_ASSERT(encomsp->channelEntryPoints.pVirtualChannelCloseEx);
1144 const UINT rc = encomsp->channelEntryPoints.pVirtualChannelCloseEx(encomsp->InitHandle,
1145 encomsp->OpenHandle);
1146
1147 if (CHANNEL_RC_OK != rc)
1148 {
1149 WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1150 rc);
1151 return rc;
1152 }
1153
1154 encomsp->OpenHandle = 0;
1155
1156 if (encomsp->data_in)
1157 {
1158 Stream_Free(encomsp->data_in, TRUE);
1159 encomsp->data_in = NULL;
1160 }
1161
1162 return CHANNEL_RC_OK;
1163}
1164
1170static UINT encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp)
1171{
1172 WINPR_ASSERT(encomsp);
1173
1174 encomsp->InitHandle = 0;
1175 free(encomsp->context);
1176 free(encomsp);
1177 return CHANNEL_RC_OK;
1178}
1179
1180static VOID VCAPITYPE encomsp_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1181 UINT event, LPVOID pData,
1182 UINT dataLength)
1183{
1184 UINT error = CHANNEL_RC_OK;
1185 encomspPlugin* encomsp = (encomspPlugin*)lpUserParam;
1186
1187 if (!encomsp || (encomsp->InitHandle != pInitHandle))
1188 {
1189 WLog_ERR(TAG, "error no match");
1190 return;
1191 }
1192
1193 switch (event)
1194 {
1195 case CHANNEL_EVENT_INITIALIZED:
1196 break;
1197
1198 case CHANNEL_EVENT_CONNECTED:
1199 if ((error = encomsp_virtual_channel_event_connected(encomsp, pData, dataLength)))
1200 WLog_ERR(TAG,
1201 "encomsp_virtual_channel_event_connected failed with error %" PRIu32 "",
1202 error);
1203
1204 break;
1205
1206 case CHANNEL_EVENT_DISCONNECTED:
1207 if ((error = encomsp_virtual_channel_event_disconnected(encomsp)))
1208 WLog_ERR(TAG,
1209 "encomsp_virtual_channel_event_disconnected failed with error %" PRIu32 "",
1210 error);
1211
1212 break;
1213
1214 case CHANNEL_EVENT_TERMINATED:
1215 encomsp_virtual_channel_event_terminated(encomsp);
1216 break;
1217
1218 default:
1219 break;
1220 }
1221
1222 if (error && encomsp->rdpcontext)
1223 setChannelError(encomsp->rdpcontext, error,
1224 "encomsp_virtual_channel_init_event reported an error");
1225}
1226
1227/* encomsp is always built-in */
1228#define VirtualChannelEntryEx encomsp_VirtualChannelEntryEx
1229
1230FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
1231 PVOID pInitHandle))
1232{
1233 BOOL isFreerdp = FALSE;
1234 encomspPlugin* encomsp = (encomspPlugin*)calloc(1, sizeof(encomspPlugin));
1235
1236 if (!encomsp)
1237 {
1238 WLog_ERR(TAG, "calloc failed!");
1239 return FALSE;
1240 }
1241
1242 encomsp->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1243 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1244 (void)sprintf_s(encomsp->channelDef.name, ARRAYSIZE(encomsp->channelDef.name),
1245 ENCOMSP_SVC_CHANNEL_NAME);
1246 CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx =
1247 (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1248 WINPR_ASSERT(pEntryPointsEx);
1249
1250 EncomspClientContext* context = NULL;
1251 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1252 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1253 {
1254 context = (EncomspClientContext*)calloc(1, sizeof(EncomspClientContext));
1255
1256 if (!context)
1257 {
1258 WLog_ERR(TAG, "calloc failed!");
1259 goto error_out;
1260 }
1261
1262 context->handle = (void*)encomsp;
1263 context->FilterUpdated = NULL;
1264 context->ApplicationCreated = NULL;
1265 context->ApplicationRemoved = NULL;
1266 context->WindowCreated = NULL;
1267 context->WindowRemoved = NULL;
1268 context->ShowWindow = NULL;
1269 context->ParticipantCreated = NULL;
1270 context->ParticipantRemoved = NULL;
1271 context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu;
1272 context->GraphicsStreamPaused = NULL;
1273 context->GraphicsStreamResumed = NULL;
1274 encomsp->context = context;
1275 encomsp->rdpcontext = pEntryPointsEx->context;
1276 isFreerdp = TRUE;
1277 }
1278
1279 CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints,
1281 encomsp->InitHandle = pInitHandle;
1282 const UINT rc = encomsp->channelEntryPoints.pVirtualChannelInitEx(
1283 encomsp, context, pInitHandle, &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1284 encomsp_virtual_channel_init_event_ex);
1285
1286 if (CHANNEL_RC_OK != rc)
1287 {
1288 WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
1289 goto error_out;
1290 }
1291
1292 encomsp->channelEntryPoints.pInterface = context;
1293 return TRUE;
1294error_out:
1295
1296 if (isFreerdp)
1297 free(encomsp->context);
1298
1299 free(encomsp);
1300 return FALSE;
1301}
Definition svc.h:60