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