Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/channels/rail/client/rail_main.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RAIL Virtual Channel Plugin
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
7
 * Copyright 2011 Vic Lee
8
 * Copyright 2015 Thincast Technologies GmbH
9
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
10
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
11
 * Copyright 2017 Thincast Technologies GmbH
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 *     http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25
26
#include <freerdp/config.h>
27
28
#include <winpr/crt.h>
29
30
#include <freerdp/types.h>
31
#include <freerdp/constants.h>
32
#include <freerdp/freerdp.h>
33
34
#include "rail_orders.h"
35
#include "rail_main.h"
36
37
#include "../../../channels/client/addin.h"
38
39
RailClientContext* rail_get_client_interface(railPlugin* rail)
40
1.15k
{
41
1.15k
  RailClientContext* pInterface = nullptr;
42
43
1.15k
  if (!rail)
44
0
    return nullptr;
45
46
1.15k
  pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
47
1.15k
  return pInterface;
48
1.15k
}
49
50
/**
51
 * Function description
52
 *
53
 * @return 0 on success, otherwise a Win32 error code
54
 */
55
static UINT rail_send(railPlugin* rail, wStream* s)
56
0
{
57
0
  UINT status = 0;
58
59
0
  if (!rail)
60
0
  {
61
0
    Stream_Free(s, TRUE);
62
0
    return CHANNEL_RC_BAD_INIT_HANDLE;
63
0
  }
64
65
0
  status = rail->channelEntryPoints.pVirtualChannelWriteEx(
66
0
      rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
67
68
0
  if (status != CHANNEL_RC_OK)
69
0
  {
70
0
    Stream_Free(s, TRUE);
71
0
    WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
72
0
             WTSErrorToString(status), status);
73
0
  }
74
75
0
  return status;
76
0
}
77
78
/**
79
 * Function description
80
 *
81
 * @return 0 on success, otherwise a Win32 error code
82
 */
83
UINT rail_send_channel_data(railPlugin* rail, wStream* src)
84
0
{
85
0
  if (!rail || !src)
86
0
  {
87
0
    Stream_Free(src, TRUE);
88
0
    return ERROR_INVALID_PARAMETER;
89
0
  }
90
91
0
  return rail_send(rail, src);
92
0
}
93
94
/**
95
 * Callback Interface
96
 */
97
98
/**
99
 * Function description
100
 *
101
 * @return 0 on success, otherwise a Win32 error code
102
 */
103
static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec)
104
0
{
105
0
  const char* exeOrFile = nullptr;
106
0
  UINT error = 0;
107
0
  railPlugin* rail = nullptr;
108
0
  UINT16 flags = 0;
109
0
  RAIL_UNICODE_STRING ruExeOrFile = WINPR_C_ARRAY_INIT;
110
0
  RAIL_UNICODE_STRING ruWorkingDir = WINPR_C_ARRAY_INIT;
111
0
  RAIL_UNICODE_STRING ruArguments = WINPR_C_ARRAY_INIT;
112
113
0
  if (!context || !exec)
114
0
    return ERROR_INVALID_PARAMETER;
115
116
0
  rail = (railPlugin*)context->handle;
117
0
  exeOrFile = exec->RemoteApplicationProgram;
118
0
  flags = exec->flags;
119
120
0
  if (!exeOrFile)
121
0
    return ERROR_INVALID_PARAMETER;
122
123
0
  if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
124
0
                                  &ruExeOrFile) || /* RemoteApplicationProgram */
125
0
      !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
126
0
                                  &ruWorkingDir) || /* ShellWorkingDirectory */
127
0
      !utf8_string_to_rail_string(exec->RemoteApplicationArguments,
128
0
                                  &ruArguments)) /* RemoteApplicationCmdLine */
129
0
    error = ERROR_INTERNAL_ERROR;
130
0
  else
131
0
    error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
132
133
0
  rail_unicode_string_free(&ruExeOrFile);
134
0
  rail_unicode_string_free(&ruWorkingDir);
135
0
  rail_unicode_string_free(&ruArguments);
136
0
  return error;
137
0
}
138
139
/**
140
 * Function description
141
 *
142
 * @return 0 on success, otherwise a Win32 error code
143
 */
144
static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate)
145
0
{
146
0
  railPlugin* rail = nullptr;
147
148
0
  if (!context || !activate)
149
0
    return ERROR_INVALID_PARAMETER;
150
151
0
  rail = (railPlugin*)context->handle;
152
0
  return rail_send_client_activate_order(rail, activate);
153
0
}
154
155
/**
156
 * Function description
157
 *
158
 * @return 0 on success, otherwise a Win32 error code
159
 */
160
static UINT rail_send_client_sysparam(RailClientContext* context,
161
                                      const RAIL_SYSPARAM_ORDER* sysparam)
162
0
{
163
0
  size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
164
165
0
  if (!context || !sysparam)
166
0
    return ERROR_INVALID_PARAMETER;
167
168
0
  railPlugin* rail = (railPlugin*)context->handle;
169
170
0
  switch (sysparam->param)
171
0
  {
172
0
    case SPI_SET_DRAG_FULL_WINDOWS:
173
0
    case SPI_SET_KEYBOARD_CUES:
174
0
    case SPI_SET_KEYBOARD_PREF:
175
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
176
0
      length += 1;
177
0
      break;
178
179
0
    case SPI_SET_WORK_AREA:
180
0
    case SPI_DISPLAY_CHANGE:
181
0
    case SPI_TASKBAR_POS:
182
0
      length += 8;
183
0
      break;
184
185
0
    case SPI_SET_HIGH_CONTRAST:
186
0
      length += sysparam->highContrast.colorSchemeLength + 10;
187
0
      break;
188
189
0
    case SPI_SETFILTERKEYS:
190
0
      length += 20;
191
0
      break;
192
193
0
    case SPI_SETSTICKYKEYS:
194
0
    case SPI_SETCARETWIDTH:
195
0
    case SPI_SETTOGGLEKEYS:
196
0
      length += 4;
197
0
      break;
198
199
0
    default:
200
0
      return ERROR_BAD_ARGUMENTS;
201
0
  }
202
203
0
  wStream* s = rail_pdu_init(length);
204
205
0
  if (!s)
206
0
  {
207
0
    WLog_ERR(TAG, "rail_pdu_init failed!");
208
0
    return CHANNEL_RC_NO_MEMORY;
209
0
  }
210
211
0
  const BOOL extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
212
0
  const UINT error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported);
213
0
  if (error)
214
0
  {
215
0
    WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
216
0
    Stream_Free(s, TRUE);
217
0
    return error;
218
0
  }
219
220
0
  return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM);
221
0
}
222
223
/**
224
 * Function description
225
 *
226
 * @return 0 on success, otherwise a Win32 error code
227
 */
228
static UINT rail_client_system_param(RailClientContext* context,
229
                                     const RAIL_SYSPARAM_ORDER* sysInParam)
230
0
{
231
0
  UINT error = CHANNEL_RC_OK;
232
233
0
  if (!context || !sysInParam)
234
0
    return ERROR_INVALID_PARAMETER;
235
236
0
  RAIL_SYSPARAM_ORDER sysparam = *sysInParam;
237
238
0
  if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
239
0
  {
240
0
    sysparam.param = SPI_SET_HIGH_CONTRAST;
241
242
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
243
0
    {
244
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
245
0
      return error;
246
0
    }
247
0
  }
248
249
0
  if (sysparam.params & SPI_MASK_TASKBAR_POS)
250
0
  {
251
0
    sysparam.param = SPI_TASKBAR_POS;
252
253
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
254
0
    {
255
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
256
0
      return error;
257
0
    }
258
0
  }
259
260
0
  if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
261
0
  {
262
0
    sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
263
264
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
265
0
    {
266
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
267
0
      return error;
268
0
    }
269
0
  }
270
271
0
  if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
272
0
  {
273
0
    sysparam.param = SPI_SET_KEYBOARD_PREF;
274
275
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
276
0
    {
277
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
278
0
      return error;
279
0
    }
280
0
  }
281
282
0
  if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
283
0
  {
284
0
    sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
285
286
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
287
0
    {
288
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
289
0
      return error;
290
0
    }
291
0
  }
292
293
0
  if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
294
0
  {
295
0
    sysparam.param = SPI_SET_KEYBOARD_CUES;
296
297
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
298
0
    {
299
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
300
0
      return error;
301
0
    }
302
0
  }
303
304
0
  if (sysparam.params & SPI_MASK_SET_WORK_AREA)
305
0
  {
306
0
    sysparam.param = SPI_SET_WORK_AREA;
307
308
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
309
0
    {
310
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
311
0
      return error;
312
0
    }
313
0
  }
314
315
0
  return error;
316
0
}
317
318
/**
319
 * Function description
320
 *
321
 * @return 0 on success, otherwise a Win32 error code
322
 */
323
static UINT rail_client_system_command(RailClientContext* context,
324
                                       const RAIL_SYSCOMMAND_ORDER* syscommand)
325
0
{
326
0
  railPlugin* rail = nullptr;
327
328
0
  if (!context || !syscommand)
329
0
    return ERROR_INVALID_PARAMETER;
330
331
0
  rail = (railPlugin*)context->handle;
332
0
  return rail_send_client_syscommand_order(rail, syscommand);
333
0
}
334
335
/**
336
 * Function description
337
 *
338
 * @return 0 on success, otherwise a Win32 error code
339
 */
340
static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
341
0
{
342
0
  if (!context || !handshake)
343
0
    return ERROR_INVALID_PARAMETER;
344
345
0
  railPlugin* rail = (railPlugin*)context->handle;
346
0
  WINPR_ASSERT(rail);
347
0
  WLog_Print(rail->log, WLOG_DEBUG, "build=0x%08" PRIx32, handshake->buildNumber);
348
0
  return rail_send_handshake_order(rail, handshake);
349
0
}
350
351
static UINT rail_server_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
352
0
{
353
0
  WINPR_ASSERT(context);
354
0
  WINPR_ASSERT(handshake);
355
356
0
  railPlugin* rail = (railPlugin*)context->handle;
357
0
  WINPR_ASSERT(rail);
358
359
0
  WLog_Print(rail->log, WLOG_DEBUG, "build=0x%08" PRIx32, handshake->buildNumber);
360
361
0
  const UINT32 buildnumber =
362
0
      freerdp_settings_get_uint32(rail->rdpcontext->settings, FreeRDP_ClientBuild);
363
0
  const RAIL_HANDSHAKE_ORDER clientHandshake = { buildnumber };
364
0
  const UINT status = context->ClientHandshake(context, &clientHandshake);
365
0
  if (status != CHANNEL_RC_OK)
366
0
    return status;
367
  /* Advertise client status before waiting for monitored-desktop orders. */
368
0
  return rail_send_client_status(context);
369
0
}
370
371
static UINT rail_server_handshake_ex(RailClientContext* context,
372
                                     const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
373
0
{
374
0
  WINPR_ASSERT(context);
375
0
  WINPR_ASSERT(handshakeEx);
376
377
0
  railPlugin* rail = (railPlugin*)context->handle;
378
0
  WINPR_ASSERT(rail);
379
380
0
  const RAIL_HANDSHAKE_ORDER handshake = { handshakeEx->buildNumber };
381
382
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
383
0
  WLog_Print(
384
0
      rail->log, WLOG_DEBUG, "build=0x%08" PRIx32 ", flags=%s", handshakeEx->buildNumber,
385
0
      rail_handshake_ex_flags_to_string(handshakeEx->railHandshakeFlags, buffer, sizeof(buffer)));
386
0
  return rail_server_handshake(context, &handshake);
387
0
}
388
389
/**
390
 * Function description
391
 *
392
 * @return 0 on success, otherwise a Win32 error code
393
 */
394
static UINT rail_client_notify_event(RailClientContext* context,
395
                                     const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
396
0
{
397
0
  railPlugin* rail = nullptr;
398
399
0
  if (!context || !notifyEvent)
400
0
    return ERROR_INVALID_PARAMETER;
401
402
0
  rail = (railPlugin*)context->handle;
403
0
  return rail_send_client_notify_event_order(rail, notifyEvent);
404
0
}
405
406
/**
407
 * Function description
408
 *
409
 * @return 0 on success, otherwise a Win32 error code
410
 */
411
static UINT rail_client_window_move(RailClientContext* context,
412
                                    const RAIL_WINDOW_MOVE_ORDER* windowMove)
413
0
{
414
0
  railPlugin* rail = nullptr;
415
416
0
  if (!context || !windowMove)
417
0
    return ERROR_INVALID_PARAMETER;
418
419
0
  rail = (railPlugin*)context->handle;
420
0
  return rail_send_client_window_move_order(rail, windowMove);
421
0
}
422
423
/**
424
 * Function description
425
 *
426
 * @return 0 on success, otherwise a Win32 error code
427
 */
428
static UINT rail_client_information(RailClientContext* context,
429
                                    const RAIL_CLIENT_STATUS_ORDER* clientStatus)
430
0
{
431
0
  railPlugin* rail = nullptr;
432
433
0
  if (!context || !clientStatus)
434
0
    return ERROR_INVALID_PARAMETER;
435
436
0
  rail = (railPlugin*)context->handle;
437
0
  return rail_send_client_status_order(rail, clientStatus);
438
0
}
439
440
/**
441
 * Function description
442
 *
443
 * @return 0 on success, otherwise a Win32 error code
444
 */
445
static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
446
0
{
447
0
  railPlugin* rail = nullptr;
448
449
0
  if (!context || !sysmenu)
450
0
    return ERROR_INVALID_PARAMETER;
451
452
0
  rail = (railPlugin*)context->handle;
453
0
  return rail_send_client_sysmenu_order(rail, sysmenu);
454
0
}
455
456
/**
457
 * Function description
458
 *
459
 * @return 0 on success, otherwise a Win32 error code
460
 */
461
static UINT rail_client_language_bar_info(RailClientContext* context,
462
                                          const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
463
0
{
464
0
  railPlugin* rail = nullptr;
465
466
0
  if (!context || !langBarInfo)
467
0
    return ERROR_INVALID_PARAMETER;
468
469
0
  rail = (railPlugin*)context->handle;
470
0
  return rail_send_client_langbar_info_order(rail, langBarInfo);
471
0
}
472
473
static UINT rail_client_language_ime_info(RailClientContext* context,
474
                                          const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
475
0
{
476
0
  railPlugin* rail = nullptr;
477
478
0
  if (!context || !langImeInfo)
479
0
    return ERROR_INVALID_PARAMETER;
480
481
0
  rail = (railPlugin*)context->handle;
482
0
  return rail_send_client_languageime_info_order(rail, langImeInfo);
483
0
}
484
485
/**
486
 * Function description
487
 *
488
 * @return 0 on success, otherwise a Win32 error code
489
 */
490
static UINT rail_client_get_appid_request(RailClientContext* context,
491
                                          const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
492
0
{
493
0
  railPlugin* rail = nullptr;
494
495
0
  if (!context || !getAppIdReq || !context->handle)
496
0
    return ERROR_INVALID_PARAMETER;
497
498
0
  rail = (railPlugin*)context->handle;
499
0
  return rail_send_client_get_appid_req_order(rail, getAppIdReq);
500
0
}
501
502
static UINT rail_client_compartment_info(RailClientContext* context,
503
                                         const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
504
0
{
505
0
  railPlugin* rail = nullptr;
506
507
0
  if (!context || !compartmentInfo || !context->handle)
508
0
    return ERROR_INVALID_PARAMETER;
509
510
0
  rail = (railPlugin*)context->handle;
511
0
  return rail_send_client_compartment_info_order(rail, compartmentInfo);
512
0
}
513
514
static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
515
0
{
516
0
  railPlugin* rail = nullptr;
517
518
0
  if (!context || !cloak || !context->handle)
519
0
    return ERROR_INVALID_PARAMETER;
520
521
0
  rail = (railPlugin*)context->handle;
522
0
  return rail_send_client_cloak_order(rail, cloak);
523
0
}
524
525
static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
526
0
{
527
0
  railPlugin* rail = nullptr;
528
529
0
  if (!context || !snap || !context->handle)
530
0
    return ERROR_INVALID_PARAMETER;
531
532
0
  rail = (railPlugin*)context->handle;
533
0
  return rail_send_client_snap_arrange_order(rail, snap);
534
0
}
535
536
static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
537
0
{
538
0
  if (!context || !context->handle)
539
0
    return ERROR_INVALID_PARAMETER;
540
541
0
  railPlugin* rail = (railPlugin*)context->handle;
542
0
  return rail_send_client_text_scale_order(rail, textScale);
543
0
}
544
545
static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
546
0
{
547
0
  if (!context || !context->handle)
548
0
    return ERROR_INVALID_PARAMETER;
549
550
0
  railPlugin* rail = (railPlugin*)context->handle;
551
0
  return rail_send_client_caret_blink_rate_order(rail, rate);
552
0
}
553
554
static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
555
                                                         UINT event, LPVOID pData,
556
                                                         UINT32 dataLength, UINT32 totalLength,
557
                                                         UINT32 dataFlags)
558
0
{
559
0
  UINT error = CHANNEL_RC_OK;
560
0
  railPlugin* rail = (railPlugin*)lpUserParam;
561
562
0
  switch (event)
563
0
  {
564
0
    case CHANNEL_EVENT_DATA_RECEIVED:
565
0
      if (!rail || (rail->OpenHandle != openHandle))
566
0
      {
567
0
        WLog_ERR(TAG, "error no match");
568
0
        return;
569
0
      }
570
571
0
      if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
572
0
                                               totalLength, dataFlags)))
573
0
      {
574
0
        WLog_ERR(TAG,
575
0
                 "rail_virtual_channel_event_data_received"
576
0
                 " failed with error %" PRIu32 "!",
577
0
                 error);
578
0
      }
579
580
0
      break;
581
582
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
583
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
584
0
    {
585
0
      wStream* s = (wStream*)pData;
586
0
      Stream_Free(s, TRUE);
587
0
    }
588
0
    break;
589
590
0
    case CHANNEL_EVENT_USER:
591
0
      break;
592
0
    default:
593
0
      break;
594
0
  }
595
596
0
  if (error && rail && rail->rdpcontext)
597
0
    setChannelError(rail->rdpcontext, error,
598
0
                    "rail_virtual_channel_open_event reported an error");
599
0
}
600
601
/**
602
 * Function description
603
 *
604
 * @return 0 on success, otherwise a Win32 error code
605
 */
606
static UINT rail_virtual_channel_event_connected(railPlugin* rail, WINPR_ATTR_UNUSED LPVOID pData,
607
                                                 WINPR_ATTR_UNUSED UINT32 dataLength)
608
0
{
609
0
  WINPR_ASSERT(rail);
610
611
0
  rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
612
0
                                                   RAIL_SVC_CHANNEL_NAME);
613
0
  if (!rail->MsgsHandle)
614
0
    return ERROR_INTERNAL_ERROR;
615
616
0
  return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
617
0
                                                        rail->channelDef.name,
618
0
                                                        rail_virtual_channel_open_event_ex);
619
0
}
620
621
/**
622
 * Function description
623
 *
624
 * @return 0 on success, otherwise a Win32 error code
625
 */
626
static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
627
0
{
628
0
  UINT rc = 0;
629
630
0
  channel_client_quit_handler(rail->MsgsHandle);
631
0
  if (rail->OpenHandle == 0)
632
0
    return CHANNEL_RC_OK;
633
634
0
  WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
635
0
  rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
636
637
0
  if (CHANNEL_RC_OK != rc)
638
0
  {
639
0
    WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
640
0
             rc);
641
0
    return rc;
642
0
  }
643
644
0
  rail->OpenHandle = 0;
645
646
0
  return CHANNEL_RC_OK;
647
0
}
648
649
static void rail_virtual_channel_event_terminated(railPlugin* rail)
650
0
{
651
0
  rail->InitHandle = nullptr;
652
0
  free(rail->context);
653
0
  free(rail);
654
0
}
655
656
static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
657
                                                         UINT event, LPVOID pData, UINT dataLength)
658
0
{
659
0
  UINT error = CHANNEL_RC_OK;
660
0
  railPlugin* rail = (railPlugin*)lpUserParam;
661
662
0
  if (!rail || (rail->InitHandle != pInitHandle))
663
0
  {
664
0
    WLog_ERR(TAG, "error no match");
665
0
    return;
666
0
  }
667
668
0
  switch (event)
669
0
  {
670
0
    case CHANNEL_EVENT_CONNECTED:
671
0
      if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
672
0
        WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
673
0
                 error);
674
675
0
      break;
676
677
0
    case CHANNEL_EVENT_DISCONNECTED:
678
0
      if ((error = rail_virtual_channel_event_disconnected(rail)))
679
0
        WLog_ERR(TAG,
680
0
                 "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
681
0
                 error);
682
683
0
      break;
684
685
0
    case CHANNEL_EVENT_TERMINATED:
686
0
      rail_virtual_channel_event_terminated(rail);
687
0
      break;
688
689
0
    case CHANNEL_EVENT_ATTACHED:
690
0
    case CHANNEL_EVENT_DETACHED:
691
0
    default:
692
0
      break;
693
0
  }
694
695
0
  if (error && rail->rdpcontext)
696
0
    setChannelError(rail->rdpcontext, error,
697
0
                    "rail_virtual_channel_init_event_ex reported an error");
698
0
}
699
700
/* rail is always built-in */
701
#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
702
703
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
704
                                                         PVOID pInitHandle))
705
0
{
706
0
  UINT rc = 0;
707
0
  railPlugin* rail = nullptr;
708
0
  RailClientContext* context = nullptr;
709
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = nullptr;
710
0
  BOOL isFreerdp = FALSE;
711
0
  rail = (railPlugin*)calloc(1, sizeof(railPlugin));
712
713
0
  if (!rail)
714
0
  {
715
0
    WLog_ERR(TAG, "calloc failed!");
716
0
    return FALSE;
717
0
  }
718
719
0
  rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
720
0
                             CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
721
0
  (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
722
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
723
724
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
725
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
726
0
  {
727
0
    context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
728
729
0
    if (!context)
730
0
    {
731
0
      WLog_ERR(TAG, "calloc failed!");
732
0
      free(rail);
733
0
      return FALSE;
734
0
    }
735
736
0
    context->handle = (void*)rail;
737
0
    context->custom = nullptr;
738
0
    context->ClientExecute = rail_client_execute;
739
0
    context->ClientActivate = rail_client_activate;
740
0
    context->ClientSystemParam = rail_client_system_param;
741
0
    context->ClientSystemCommand = rail_client_system_command;
742
0
    context->ClientHandshake = rail_client_handshake;
743
0
    context->ServerHandshake = rail_server_handshake;
744
0
    context->ServerHandshakeEx = rail_server_handshake_ex;
745
0
    context->ClientNotifyEvent = rail_client_notify_event;
746
0
    context->ClientWindowMove = rail_client_window_move;
747
0
    context->ClientInformation = rail_client_information;
748
0
    context->ClientSystemMenu = rail_client_system_menu;
749
0
    context->ClientLanguageBarInfo = rail_client_language_bar_info;
750
0
    context->ClientLanguageIMEInfo = rail_client_language_ime_info;
751
0
    context->ClientGetAppIdRequest = rail_client_get_appid_request;
752
0
    context->ClientSnapArrange = rail_client_snap_arrange;
753
0
    context->ClientCloak = rail_client_cloak;
754
0
    context->ClientCompartmentInfo = rail_client_compartment_info;
755
0
    context->ClientTextScale = rail_client_text_scale;
756
0
    context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
757
0
    rail->rdpcontext = pEntryPointsEx->context;
758
0
    rail->context = context;
759
0
    isFreerdp = TRUE;
760
0
  }
761
762
0
  rail->log = WLog_Get("com.freerdp.channels.rail.client");
763
0
  WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
764
0
  CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
765
0
  rail->InitHandle = pInitHandle;
766
0
  rc = rail->channelEntryPoints.pVirtualChannelInitEx(
767
0
      rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
768
0
      rail_virtual_channel_init_event_ex);
769
770
0
  if (CHANNEL_RC_OK != rc)
771
0
  {
772
0
    WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
773
0
    goto error_out;
774
0
  }
775
776
0
  rail->channelEntryPoints.pInterface = context;
777
0
  return TRUE;
778
0
error_out:
779
780
0
  if (isFreerdp)
781
0
    free(rail->context);
782
783
0
  free(rail);
784
0
  return FALSE;
785
0
}