Coverage Report

Created: 2026-10-15 06:27

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