FreeRDP
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 
34 struct 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 
54 static 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 
70 static 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 
83 static 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 
107 static EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp)
108 {
109  WINPR_ASSERT(encomsp);
110  return (EncomspClientContext*)encomsp->channelEntryPoints.pInterface;
111 }
112 
118 static 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 #if 0
127  WLog_INFO(TAG, "EncomspWrite (%"PRIuz")", Stream_Length(s));
128  winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
129 #endif
130  const UINT status = encomsp->channelEntryPoints.pVirtualChannelWriteEx(
131  encomsp->InitHandle, encomsp->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s);
132 
133  if (status != CHANNEL_RC_OK)
134  {
135  Stream_Free(s, TRUE);
136  WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
137  WTSErrorToString(status), status);
138  }
139  return status;
140 }
141 
147 static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s,
148  const ENCOMSP_ORDER_HEADER* header)
149 {
150  ENCOMSP_FILTER_UPDATED_PDU pdu = { 0 };
151  UINT error = CHANNEL_RC_OK;
152  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
153 
154  if (!context)
155  return ERROR_INVALID_HANDLE;
156 
157  WINPR_ASSERT(header);
158  const size_t pos = Stream_GetPosition(s);
159  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
160  return ERROR_INVALID_DATA;
161  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
162  pdu.Length = header->Length;
163  pdu.Type = header->Type;
164 
165  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
166  return ERROR_INVALID_DATA;
167 
168  Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */
169  const size_t end = Stream_GetPosition(s);
170  const size_t body = beg + header->Length;
171 
172  if (body < end)
173  {
174  WLog_ERR(TAG, "Not enough data!");
175  return ERROR_INVALID_DATA;
176  }
177 
178  if (body > end)
179  {
180  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
181  return ERROR_INVALID_DATA;
182 
183  Stream_SetPosition(s, body);
184  }
185 
186  IFCALLRET(context->FilterUpdated, error, context, &pdu);
187 
188  if (error)
189  WLog_ERR(TAG, "context->FilterUpdated failed with error %" PRIu32 "", error);
190 
191  return error;
192 }
193 
199 static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s,
200  const ENCOMSP_ORDER_HEADER* header)
201 {
203  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
204 
205  if (!context)
206  return ERROR_INVALID_HANDLE;
207 
208  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
209  return ERROR_INVALID_DATA;
210 
211  const size_t pos = Stream_GetPosition(s);
212  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
213  return ERROR_INVALID_DATA;
214  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
215 
216  WINPR_ASSERT(header);
217  pdu.Length = header->Length;
218  pdu.Type = header->Type;
219 
220  Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
221  Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
222 
223  UINT error = encomsp_read_unicode_string(s, &(pdu.Name));
224  if (error != CHANNEL_RC_OK)
225  {
226  WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
227  return error;
228  }
229 
230  const size_t end = Stream_GetPosition(s);
231  const size_t body = beg + header->Length;
232 
233  if (body < end)
234  {
235  WLog_ERR(TAG, "Not enough data!");
236  return ERROR_INVALID_DATA;
237  }
238 
239  if (body > end)
240  {
241  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
242  return ERROR_INVALID_DATA;
243 
244  Stream_SetPosition(s, body);
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 
260 static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s,
261  const ENCOMSP_ORDER_HEADER* header)
262 {
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  Stream_SetPosition(s, body);
298  }
299 
300  IFCALLRET(context->ApplicationRemoved, error, context, &pdu);
301 
302  if (error)
303  WLog_ERR(TAG, "context->ApplicationRemoved failed with error %" PRIu32 "", error);
304 
305  return error;
306 }
307 
313 static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s,
314  const ENCOMSP_ORDER_HEADER* header)
315 {
316  ENCOMSP_WINDOW_CREATED_PDU pdu = { 0 };
317  UINT error = CHANNEL_RC_OK;
318  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
319 
320  if (!context)
321  return ERROR_INVALID_HANDLE;
322 
323  const size_t pos = Stream_GetPosition(s);
324  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
325  return ERROR_INVALID_DATA;
326  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
327 
328  WINPR_ASSERT(header);
329  pdu.Length = header->Length;
330  pdu.Type = header->Type;
331 
332  if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
333  return ERROR_INVALID_DATA;
334 
335  Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
336  Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
337  Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
338 
339  if ((error = encomsp_read_unicode_string(s, &(pdu.Name))))
340  {
341  WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
342  return error;
343  }
344 
345  const size_t end = Stream_GetPosition(s);
346  const size_t body = beg + header->Length;
347 
348  if (body < end)
349  {
350  WLog_ERR(TAG, "Not enough data!");
351  return ERROR_INVALID_DATA;
352  }
353 
354  if (body > end)
355  {
356  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
357  return ERROR_INVALID_DATA;
358 
359  Stream_SetPosition(s, body);
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 
375 static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s,
376  const ENCOMSP_ORDER_HEADER* header)
377 {
378  ENCOMSP_WINDOW_REMOVED_PDU pdu = { 0 };
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  Stream_SetPosition(s, body);
413  }
414 
415  IFCALLRET(context->WindowRemoved, error, context, &pdu);
416 
417  if (error)
418  WLog_ERR(TAG, "context->WindowRemoved failed with error %" PRIu32 "", error);
419 
420  return error;
421 }
422 
428 static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s,
429  const ENCOMSP_ORDER_HEADER* header)
430 {
431  ENCOMSP_SHOW_WINDOW_PDU pdu = { 0 };
432  UINT error = CHANNEL_RC_OK;
433  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
434 
435  if (!context)
436  return ERROR_INVALID_HANDLE;
437 
438  const size_t pos = Stream_GetPosition(s);
439  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
440  return ERROR_INVALID_DATA;
441  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
442 
443  WINPR_ASSERT(header);
444  pdu.Length = header->Length;
445  pdu.Type = header->Type;
446 
447  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
448  return ERROR_INVALID_DATA;
449 
450  Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
451  const size_t end = Stream_GetPosition(s);
452  const size_t body = beg + header->Length;
453 
454  if (body < end)
455  {
456  WLog_ERR(TAG, "Not enough data!");
457  return ERROR_INVALID_DATA;
458  }
459 
460  if (body > end)
461  {
462  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
463  return ERROR_INVALID_DATA;
464 
465  Stream_SetPosition(s, body);
466  }
467 
468  IFCALLRET(context->ShowWindow, error, context, &pdu);
469 
470  if (error)
471  WLog_ERR(TAG, "context->ShowWindow failed with error %" PRIu32 "", error);
472 
473  return error;
474 }
475 
481 static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s,
482  const ENCOMSP_ORDER_HEADER* header)
483 {
485  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
486 
487  if (!context)
488  return ERROR_INVALID_HANDLE;
489 
490  const size_t pos = Stream_GetPosition(s);
491  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
492  return ERROR_INVALID_DATA;
493  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
494 
495  WINPR_ASSERT(header);
496  pdu.Length = header->Length;
497  pdu.Type = header->Type;
498 
499  if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
500  return ERROR_INVALID_DATA;
501 
502  Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
503  Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */
504  Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
505 
506  UINT error = encomsp_read_unicode_string(s, &(pdu.FriendlyName));
507  if (error != CHANNEL_RC_OK)
508  {
509  WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error);
510  return error;
511  }
512 
513  const size_t end = Stream_GetPosition(s);
514  const size_t body = beg + header->Length;
515 
516  if (body < end)
517  {
518  WLog_ERR(TAG, "Not enough data!");
519  return ERROR_INVALID_DATA;
520  }
521 
522  if (body > end)
523  {
524  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
525  return ERROR_INVALID_DATA;
526 
527  Stream_SetPosition(s, body);
528  }
529 
530  IFCALLRET(context->ParticipantCreated, error, context, &pdu);
531 
532  if (error)
533  WLog_ERR(TAG, "context->ParticipantCreated failed with error %" PRIu32 "", error);
534 
535  return error;
536 }
537 
543 static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s,
544  const ENCOMSP_ORDER_HEADER* header)
545 {
547  UINT error = CHANNEL_RC_OK;
548  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
549 
550  if (!context)
551  return ERROR_INVALID_HANDLE;
552 
553  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
554  return ERROR_INVALID_DATA;
555 
556  const size_t beg = (Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
557 
558  WINPR_ASSERT(header);
559  pdu.Length = header->Length;
560  pdu.Type = header->Type;
561 
562  Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
563  Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */
564  Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */
565  const size_t end = Stream_GetPosition(s);
566  const size_t body = beg + header->Length;
567 
568  if (body < end)
569  {
570  WLog_ERR(TAG, "Not enough data!");
571  return ERROR_INVALID_DATA;
572  }
573 
574  if (body > end)
575  {
576  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
577  return ERROR_INVALID_DATA;
578 
579  Stream_SetPosition(s, body);
580  }
581 
582  IFCALLRET(context->ParticipantRemoved, error, context, &pdu);
583 
584  if (error)
585  WLog_ERR(TAG, "context->ParticipantRemoved failed with error %" PRIu32 "", error);
586 
587  return error;
588 }
589 
595 static UINT encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s,
596  const ENCOMSP_ORDER_HEADER* header)
597 {
599  UINT error = CHANNEL_RC_OK;
600  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
601 
602  if (!context)
603  return ERROR_INVALID_HANDLE;
604 
605  const size_t pos = Stream_GetPosition(s);
606  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
607  return ERROR_INVALID_DATA;
608  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
609 
610  WINPR_ASSERT(header);
611  pdu.Length = header->Length;
612  pdu.Type = header->Type;
613 
614  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
615  return ERROR_INVALID_DATA;
616 
617  Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
618  Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
619  const size_t end = Stream_GetPosition(s);
620  const size_t body = beg + header->Length;
621 
622  if (body < end)
623  {
624  WLog_ERR(TAG, "Not enough data!");
625  return ERROR_INVALID_DATA;
626  }
627 
628  if (body > end)
629  {
630  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
631  return ERROR_INVALID_DATA;
632 
633  Stream_SetPosition(s, body);
634  }
635 
636  IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
637 
638  if (error)
639  WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
640  error);
641 
642  return error;
643 }
644 
650 static UINT encomsp_send_change_participant_control_level_pdu(
651  EncomspClientContext* context, const ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu)
652 {
653  ENCOMSP_ORDER_HEADER header = { 0 };
654 
655  WINPR_ASSERT(context);
656  encomspPlugin* encomsp = (encomspPlugin*)context->handle;
657 
658  header.Type = ODTYPE_PARTICIPANT_CTRL_CHANGED;
659  header.Length = ENCOMSP_ORDER_HEADER_SIZE + 6;
660 
661  wStream* s = Stream_New(NULL, header.Length);
662 
663  if (!s)
664  {
665  WLog_ERR(TAG, "Stream_New failed!");
666  return CHANNEL_RC_NO_MEMORY;
667  }
668 
669  const UINT error = encomsp_write_header(s, &header);
670  if (error != CHANNEL_RC_OK)
671  {
672  WLog_ERR(TAG, "encomsp_write_header failed with error %" PRIu32 "!", error);
673  return error;
674  }
675 
676  Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */
677  Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */
678  Stream_SealLength(s);
679  return encomsp_virtual_channel_write(encomsp, s);
680 }
681 
687 static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s,
688  const ENCOMSP_ORDER_HEADER* header)
689 {
691  UINT error = CHANNEL_RC_OK;
692  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
693 
694  if (!context)
695  return ERROR_INVALID_HANDLE;
696 
697  const size_t pos = Stream_GetPosition(s);
698  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
699  return ERROR_INVALID_DATA;
700  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
701 
702  WINPR_ASSERT(header);
703  pdu.Length = header->Length;
704  pdu.Type = header->Type;
705 
706  const size_t end = Stream_GetPosition(s);
707  const size_t body = beg + header->Length;
708 
709  if (body < end)
710  {
711  WLog_ERR(TAG, "Not enough data!");
712  return ERROR_INVALID_DATA;
713  }
714 
715  if (body > end)
716  {
717  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
718  return ERROR_INVALID_DATA;
719 
720  Stream_SetPosition(s, body);
721  }
722 
723  IFCALLRET(context->GraphicsStreamPaused, error, context, &pdu);
724 
725  if (error)
726  WLog_ERR(TAG, "context->GraphicsStreamPaused failed with error %" PRIu32 "", error);
727 
728  return error;
729 }
730 
736 static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s,
737  const ENCOMSP_ORDER_HEADER* header)
738 {
740  UINT error = CHANNEL_RC_OK;
741  EncomspClientContext* context = encomsp_get_client_interface(encomsp);
742 
743  if (!context)
744  return ERROR_INVALID_HANDLE;
745 
746  const size_t pos = Stream_GetPosition(s);
747  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
748  return ERROR_INVALID_DATA;
749  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
750 
751  WINPR_ASSERT(header);
752  pdu.Length = header->Length;
753  pdu.Type = header->Type;
754 
755  const size_t end = Stream_GetPosition(s);
756  const size_t body = beg + header->Length;
757 
758  if (body < end)
759  {
760  WLog_ERR(TAG, "Not enough data!");
761  return ERROR_INVALID_DATA;
762  }
763 
764  if (body > end)
765  {
766  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(body - end)))
767  return ERROR_INVALID_DATA;
768 
769  Stream_SetPosition(s, body);
770  }
771 
772  IFCALLRET(context->GraphicsStreamResumed, error, context, &pdu);
773 
774  if (error)
775  WLog_ERR(TAG, "context->GraphicsStreamResumed failed with error %" PRIu32 "", error);
776 
777  return error;
778 }
779 
785 static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s)
786 {
787  UINT error = CHANNEL_RC_OK;
788  ENCOMSP_ORDER_HEADER header = { 0 };
789 
790  WINPR_ASSERT(encomsp);
791  while (Stream_GetRemainingLength(s) > 0)
792  {
793  if ((error = encomsp_read_header(s, &header)))
794  {
795  WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
796  return error;
797  }
798 
799  // WLog_DBG(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type,
800  // header.Length);
801 
802  switch (header.Type)
803  {
804  case ODTYPE_FILTER_STATE_UPDATED:
805  if ((error = encomsp_recv_filter_updated_pdu(encomsp, s, &header)))
806  {
807  WLog_ERR(TAG, "encomsp_recv_filter_updated_pdu failed with error %" PRIu32 "!",
808  error);
809  return error;
810  }
811 
812  break;
813 
814  case ODTYPE_APP_REMOVED:
815  if ((error = encomsp_recv_application_removed_pdu(encomsp, s, &header)))
816  {
817  WLog_ERR(TAG,
818  "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!",
819  error);
820  return error;
821  }
822 
823  break;
824 
825  case ODTYPE_APP_CREATED:
826  if ((error = encomsp_recv_application_created_pdu(encomsp, s, &header)))
827  {
828  WLog_ERR(TAG,
829  "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!",
830  error);
831  return error;
832  }
833 
834  break;
835 
836  case ODTYPE_WND_REMOVED:
837  if ((error = encomsp_recv_window_removed_pdu(encomsp, s, &header)))
838  {
839  WLog_ERR(TAG, "encomsp_recv_window_removed_pdu failed with error %" PRIu32 "!",
840  error);
841  return error;
842  }
843 
844  break;
845 
846  case ODTYPE_WND_CREATED:
847  if ((error = encomsp_recv_window_created_pdu(encomsp, s, &header)))
848  {
849  WLog_ERR(TAG, "encomsp_recv_window_created_pdu failed with error %" PRIu32 "!",
850  error);
851  return error;
852  }
853 
854  break;
855 
856  case ODTYPE_WND_SHOW:
857  if ((error = encomsp_recv_show_window_pdu(encomsp, s, &header)))
858  {
859  WLog_ERR(TAG, "encomsp_recv_show_window_pdu failed with error %" PRIu32 "!",
860  error);
861  return error;
862  }
863 
864  break;
865 
866  case ODTYPE_PARTICIPANT_REMOVED:
867  if ((error = encomsp_recv_participant_removed_pdu(encomsp, s, &header)))
868  {
869  WLog_ERR(TAG,
870  "encomsp_recv_participant_removed_pdu failed with error %" PRIu32 "!",
871  error);
872  return error;
873  }
874 
875  break;
876 
877  case ODTYPE_PARTICIPANT_CREATED:
878  if ((error = encomsp_recv_participant_created_pdu(encomsp, s, &header)))
879  {
880  WLog_ERR(TAG,
881  "encomsp_recv_participant_created_pdu failed with error %" PRIu32 "!",
882  error);
883  return error;
884  }
885 
886  break;
887 
888  case ODTYPE_PARTICIPANT_CTRL_CHANGED:
889  if ((error =
890  encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header)))
891  {
892  WLog_ERR(TAG,
893  "encomsp_recv_change_participant_control_level_pdu failed with error "
894  "%" PRIu32 "!",
895  error);
896  return error;
897  }
898 
899  break;
900 
901  case ODTYPE_GRAPHICS_STREAM_PAUSED:
902  if ((error = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header)))
903  {
904  WLog_ERR(TAG,
905  "encomsp_recv_graphics_stream_paused_pdu failed with error %" PRIu32
906  "!",
907  error);
908  return error;
909  }
910 
911  break;
912 
913  case ODTYPE_GRAPHICS_STREAM_RESUMED:
914  if ((error = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header)))
915  {
916  WLog_ERR(TAG,
917  "encomsp_recv_graphics_stream_resumed_pdu failed with error %" PRIu32
918  "!",
919  error);
920  return error;
921  }
922 
923  break;
924 
925  default:
926  WLog_ERR(TAG, "header.Type %" PRIu16 " not found", header.Type);
927  return ERROR_INVALID_DATA;
928  }
929  }
930 
931  return error;
932 }
933 
939 static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, const void* pData,
940  UINT32 dataLength, UINT32 totalLength,
941  UINT32 dataFlags)
942 {
943  WINPR_ASSERT(encomsp);
944 
945  if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
946  return CHANNEL_RC_OK;
947 
948  if (dataFlags & CHANNEL_FLAG_FIRST)
949  {
950  if (encomsp->data_in)
951  Stream_Free(encomsp->data_in, TRUE);
952 
953  encomsp->data_in = Stream_New(NULL, totalLength);
954 
955  if (!encomsp->data_in)
956  {
957  WLog_ERR(TAG, "Stream_New failed!");
958  return CHANNEL_RC_NO_MEMORY;
959  }
960  }
961 
962  wStream* data_in = encomsp->data_in;
963 
964  if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
965  {
966  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
967  return ERROR_INTERNAL_ERROR;
968  }
969 
970  Stream_Write(data_in, pData, dataLength);
971 
972  if (dataFlags & CHANNEL_FLAG_LAST)
973  {
974  if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
975  {
976  WLog_ERR(TAG, "encomsp_plugin_process_received: read error");
977  return ERROR_INVALID_DATA;
978  }
979 
980  encomsp->data_in = NULL;
981  Stream_SealLength(data_in);
982  Stream_SetPosition(data_in, 0);
983 
984  if (!MessageQueue_Post(encomsp->queue, NULL, 0, (void*)data_in, NULL))
985  {
986  WLog_ERR(TAG, "MessageQueue_Post failed!");
987  return ERROR_INTERNAL_ERROR;
988  }
989  }
990 
991  return CHANNEL_RC_OK;
992 }
993 
994 static VOID VCAPITYPE encomsp_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
995  UINT event, LPVOID pData,
996  UINT32 dataLength, UINT32 totalLength,
997  UINT32 dataFlags)
998 {
999  UINT error = CHANNEL_RC_OK;
1000  encomspPlugin* encomsp = (encomspPlugin*)lpUserParam;
1001 
1002  switch (event)
1003  {
1004  case CHANNEL_EVENT_DATA_RECEIVED:
1005  if (!encomsp || (encomsp->OpenHandle != openHandle))
1006  {
1007  WLog_ERR(TAG, "error no match");
1008  return;
1009  }
1010  if ((error = encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength,
1011  totalLength, dataFlags)))
1012  WLog_ERR(TAG,
1013  "encomsp_virtual_channel_event_data_received failed with error %" PRIu32
1014  "",
1015  error);
1016 
1017  break;
1018 
1019  case CHANNEL_EVENT_WRITE_CANCELLED:
1020  case CHANNEL_EVENT_WRITE_COMPLETE:
1021  {
1022  wStream* s = (wStream*)pData;
1023  Stream_Free(s, TRUE);
1024  }
1025  break;
1026 
1027  case CHANNEL_EVENT_USER:
1028  break;
1029  default:
1030  break;
1031  }
1032 
1033  if (error && encomsp && encomsp->rdpcontext)
1034  setChannelError(encomsp->rdpcontext, error,
1035  "encomsp_virtual_channel_open_event reported an error");
1036 }
1037 
1038 static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg)
1039 {
1040  wStream* data = NULL;
1041  wMessage message = { 0 };
1042  encomspPlugin* encomsp = (encomspPlugin*)arg;
1043  UINT error = CHANNEL_RC_OK;
1044 
1045  WINPR_ASSERT(encomsp);
1046  while (1)
1047  {
1048  if (!MessageQueue_Wait(encomsp->queue))
1049  {
1050  WLog_ERR(TAG, "MessageQueue_Wait failed!");
1051  error = ERROR_INTERNAL_ERROR;
1052  break;
1053  }
1054 
1055  if (!MessageQueue_Peek(encomsp->queue, &message, TRUE))
1056  {
1057  WLog_ERR(TAG, "MessageQueue_Peek failed!");
1058  error = ERROR_INTERNAL_ERROR;
1059  break;
1060  }
1061 
1062  if (message.id == WMQ_QUIT)
1063  break;
1064 
1065  if (message.id == 0)
1066  {
1067  data = (wStream*)message.wParam;
1068 
1069  if ((error = encomsp_process_receive(encomsp, data)))
1070  {
1071  WLog_ERR(TAG, "encomsp_process_receive failed with error %" PRIu32 "!", error);
1072  Stream_Free(data, TRUE);
1073  break;
1074  }
1075 
1076  Stream_Free(data, TRUE);
1077  }
1078  }
1079 
1080  if (error && encomsp->rdpcontext)
1081  setChannelError(encomsp->rdpcontext, error,
1082  "encomsp_virtual_channel_client_thread reported an error");
1083 
1084  ExitThread(error);
1085  return error;
1086 }
1087 
1093 static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, LPVOID pData,
1094  UINT32 dataLength)
1095 {
1096  WINPR_ASSERT(encomsp);
1097 
1098  encomsp->queue = MessageQueue_New(NULL);
1099 
1100  if (!encomsp->queue)
1101  {
1102  WLog_ERR(TAG, "MessageQueue_New failed!");
1103  return CHANNEL_RC_NO_MEMORY;
1104  }
1105 
1106  if (!(encomsp->thread = CreateThread(NULL, 0, encomsp_virtual_channel_client_thread,
1107  (void*)encomsp, 0, NULL)))
1108  {
1109  WLog_ERR(TAG, "CreateThread failed!");
1110  MessageQueue_Free(encomsp->queue);
1111  return ERROR_INTERNAL_ERROR;
1112  }
1113 
1114  return encomsp->channelEntryPoints.pVirtualChannelOpenEx(
1115  encomsp->InitHandle, &encomsp->OpenHandle, encomsp->channelDef.name,
1116  encomsp_virtual_channel_open_event_ex);
1117 }
1118 
1124 static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp)
1125 {
1126  WINPR_ASSERT(encomsp);
1127  if (encomsp->OpenHandle == 0)
1128  return CHANNEL_RC_OK;
1129 
1130  if (encomsp->queue && encomsp->thread)
1131  {
1132  if (MessageQueue_PostQuit(encomsp->queue, 0) &&
1133  (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED))
1134  {
1135  const UINT rc = GetLastError();
1136  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
1137  return rc;
1138  }
1139  }
1140 
1141  MessageQueue_Free(encomsp->queue);
1142  (void)CloseHandle(encomsp->thread);
1143  encomsp->queue = NULL;
1144  encomsp->thread = NULL;
1145 
1146  WINPR_ASSERT(encomsp->channelEntryPoints.pVirtualChannelCloseEx);
1147  const UINT rc = encomsp->channelEntryPoints.pVirtualChannelCloseEx(encomsp->InitHandle,
1148  encomsp->OpenHandle);
1149 
1150  if (CHANNEL_RC_OK != rc)
1151  {
1152  WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1153  rc);
1154  return rc;
1155  }
1156 
1157  encomsp->OpenHandle = 0;
1158 
1159  if (encomsp->data_in)
1160  {
1161  Stream_Free(encomsp->data_in, TRUE);
1162  encomsp->data_in = NULL;
1163  }
1164 
1165  return CHANNEL_RC_OK;
1166 }
1167 
1173 static UINT encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp)
1174 {
1175  WINPR_ASSERT(encomsp);
1176 
1177  encomsp->InitHandle = 0;
1178  free(encomsp->context);
1179  free(encomsp);
1180  return CHANNEL_RC_OK;
1181 }
1182 
1183 static VOID VCAPITYPE encomsp_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1184  UINT event, LPVOID pData,
1185  UINT dataLength)
1186 {
1187  UINT error = CHANNEL_RC_OK;
1188  encomspPlugin* encomsp = (encomspPlugin*)lpUserParam;
1189 
1190  if (!encomsp || (encomsp->InitHandle != pInitHandle))
1191  {
1192  WLog_ERR(TAG, "error no match");
1193  return;
1194  }
1195 
1196  switch (event)
1197  {
1198  case CHANNEL_EVENT_INITIALIZED:
1199  break;
1200 
1201  case CHANNEL_EVENT_CONNECTED:
1202  if ((error = encomsp_virtual_channel_event_connected(encomsp, pData, dataLength)))
1203  WLog_ERR(TAG,
1204  "encomsp_virtual_channel_event_connected failed with error %" PRIu32 "",
1205  error);
1206 
1207  break;
1208 
1209  case CHANNEL_EVENT_DISCONNECTED:
1210  if ((error = encomsp_virtual_channel_event_disconnected(encomsp)))
1211  WLog_ERR(TAG,
1212  "encomsp_virtual_channel_event_disconnected failed with error %" PRIu32 "",
1213  error);
1214 
1215  break;
1216 
1217  case CHANNEL_EVENT_TERMINATED:
1218  encomsp_virtual_channel_event_terminated(encomsp);
1219  break;
1220 
1221  default:
1222  break;
1223  }
1224 
1225  if (error && encomsp->rdpcontext)
1226  setChannelError(encomsp->rdpcontext, error,
1227  "encomsp_virtual_channel_init_event reported an error");
1228 }
1229 
1230 /* encomsp is always built-in */
1231 #define VirtualChannelEntryEx encomsp_VirtualChannelEntryEx
1232 
1233 FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
1234  PVOID pInitHandle))
1235 {
1236  BOOL isFreerdp = FALSE;
1237  encomspPlugin* encomsp = (encomspPlugin*)calloc(1, sizeof(encomspPlugin));
1238 
1239  if (!encomsp)
1240  {
1241  WLog_ERR(TAG, "calloc failed!");
1242  return FALSE;
1243  }
1244 
1245  encomsp->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1246  CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1247  (void)sprintf_s(encomsp->channelDef.name, ARRAYSIZE(encomsp->channelDef.name),
1248  ENCOMSP_SVC_CHANNEL_NAME);
1249  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx =
1250  (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1251  WINPR_ASSERT(pEntryPointsEx);
1252 
1253  EncomspClientContext* context = NULL;
1254  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1255  (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1256  {
1257  context = (EncomspClientContext*)calloc(1, sizeof(EncomspClientContext));
1258 
1259  if (!context)
1260  {
1261  WLog_ERR(TAG, "calloc failed!");
1262  goto error_out;
1263  }
1264 
1265  context->handle = (void*)encomsp;
1266  context->FilterUpdated = NULL;
1267  context->ApplicationCreated = NULL;
1268  context->ApplicationRemoved = NULL;
1269  context->WindowCreated = NULL;
1270  context->WindowRemoved = NULL;
1271  context->ShowWindow = NULL;
1272  context->ParticipantCreated = NULL;
1273  context->ParticipantRemoved = NULL;
1274  context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu;
1275  context->GraphicsStreamPaused = NULL;
1276  context->GraphicsStreamResumed = NULL;
1277  encomsp->context = context;
1278  encomsp->rdpcontext = pEntryPointsEx->context;
1279  isFreerdp = TRUE;
1280  }
1281 
1282  CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints,
1284  encomsp->InitHandle = pInitHandle;
1285  const UINT rc = encomsp->channelEntryPoints.pVirtualChannelInitEx(
1286  encomsp, context, pInitHandle, &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1287  encomsp_virtual_channel_init_event_ex);
1288 
1289  if (CHANNEL_RC_OK != rc)
1290  {
1291  WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
1292  goto error_out;
1293  }
1294 
1295  encomsp->channelEntryPoints.pInterface = context;
1296  return TRUE;
1297 error_out:
1298 
1299  if (isFreerdp)
1300  free(encomsp->context);
1301 
1302  free(encomsp);
1303  return FALSE;
1304 }
Definition: svc.h:61