Coverage Report

Created: 2025-07-01 06:46

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