Coverage Report

Created: 2024-05-20 06:11

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