Coverage Report

Created: 2026-05-30 06:46

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
0
{
41
0
  RailClientContext* pInterface = nullptr;
42
43
0
  if (!rail)
44
0
    return nullptr;
45
46
0
  pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
47
0
  return pInterface;
48
0
}
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
  free(ruExeOrFile.string);
134
0
  free(ruWorkingDir.string);
135
0
  free(ruArguments.string);
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, RAIL_SYSPARAM_ORDER* sysparam)
161
0
{
162
0
  wStream* s = nullptr;
163
0
  size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
164
0
  railPlugin* rail = nullptr;
165
0
  UINT error = 0;
166
0
  BOOL extendedSpiSupported = 0;
167
168
0
  if (!context || !sysparam)
169
0
    return ERROR_INVALID_PARAMETER;
170
171
0
  rail = (railPlugin*)context->handle;
172
173
0
  switch (sysparam->param)
174
0
  {
175
0
    case SPI_SET_DRAG_FULL_WINDOWS:
176
0
    case SPI_SET_KEYBOARD_CUES:
177
0
    case SPI_SET_KEYBOARD_PREF:
178
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
179
0
      length += 1;
180
0
      break;
181
182
0
    case SPI_SET_WORK_AREA:
183
0
    case SPI_DISPLAY_CHANGE:
184
0
    case SPI_TASKBAR_POS:
185
0
      length += 8;
186
0
      break;
187
188
0
    case SPI_SET_HIGH_CONTRAST:
189
0
      length += sysparam->highContrast.colorSchemeLength + 10;
190
0
      break;
191
192
0
    case SPI_SETFILTERKEYS:
193
0
      length += 20;
194
0
      break;
195
196
0
    case SPI_SETSTICKYKEYS:
197
0
    case SPI_SETCARETWIDTH:
198
0
    case SPI_SETTOGGLEKEYS:
199
0
      length += 4;
200
0
      break;
201
202
0
    default:
203
0
      return ERROR_BAD_ARGUMENTS;
204
0
  }
205
206
0
  s = rail_pdu_init(length);
207
208
0
  if (!s)
209
0
  {
210
0
    WLog_ERR(TAG, "rail_pdu_init failed!");
211
0
    return CHANNEL_RC_NO_MEMORY;
212
0
  }
213
214
0
  extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
215
0
  if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported)))
216
0
  {
217
0
    WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
218
0
    Stream_Free(s, TRUE);
219
0
    return error;
220
0
  }
221
222
0
  return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM);
223
0
}
224
225
/**
226
 * Function description
227
 *
228
 * @return 0 on success, otherwise a Win32 error code
229
 */
230
static UINT rail_client_system_param(RailClientContext* context,
231
                                     const RAIL_SYSPARAM_ORDER* sysInParam)
232
0
{
233
0
  UINT error = CHANNEL_RC_OK;
234
0
  RAIL_SYSPARAM_ORDER sysparam;
235
236
0
  if (!context || !sysInParam)
237
0
    return ERROR_INVALID_PARAMETER;
238
239
0
  sysparam = *sysInParam;
240
241
0
  if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
242
0
  {
243
0
    sysparam.param = SPI_SET_HIGH_CONTRAST;
244
245
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
246
0
    {
247
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
248
0
      return error;
249
0
    }
250
0
  }
251
252
0
  if (sysparam.params & SPI_MASK_TASKBAR_POS)
253
0
  {
254
0
    sysparam.param = SPI_TASKBAR_POS;
255
256
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
257
0
    {
258
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
259
0
      return error;
260
0
    }
261
0
  }
262
263
0
  if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
264
0
  {
265
0
    sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
266
267
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
268
0
    {
269
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
270
0
      return error;
271
0
    }
272
0
  }
273
274
0
  if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
275
0
  {
276
0
    sysparam.param = SPI_SET_KEYBOARD_PREF;
277
278
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
279
0
    {
280
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
281
0
      return error;
282
0
    }
283
0
  }
284
285
0
  if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
286
0
  {
287
0
    sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
288
289
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
290
0
    {
291
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
292
0
      return error;
293
0
    }
294
0
  }
295
296
0
  if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
297
0
  {
298
0
    sysparam.param = SPI_SET_KEYBOARD_CUES;
299
300
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
301
0
    {
302
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
303
0
      return error;
304
0
    }
305
0
  }
306
307
0
  if (sysparam.params & SPI_MASK_SET_WORK_AREA)
308
0
  {
309
0
    sysparam.param = SPI_SET_WORK_AREA;
310
311
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
312
0
    {
313
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
314
0
      return error;
315
0
    }
316
0
  }
317
318
0
  return error;
319
0
}
320
321
/**
322
 * Function description
323
 *
324
 * @return 0 on success, otherwise a Win32 error code
325
 */
326
static UINT rail_client_system_command(RailClientContext* context,
327
                                       const RAIL_SYSCOMMAND_ORDER* syscommand)
328
0
{
329
0
  railPlugin* rail = nullptr;
330
331
0
  if (!context || !syscommand)
332
0
    return ERROR_INVALID_PARAMETER;
333
334
0
  rail = (railPlugin*)context->handle;
335
0
  return rail_send_client_syscommand_order(rail, syscommand);
336
0
}
337
338
/**
339
 * Function description
340
 *
341
 * @return 0 on success, otherwise a Win32 error code
342
 */
343
static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
344
0
{
345
0
  if (!context || !handshake)
346
0
    return ERROR_INVALID_PARAMETER;
347
348
0
  railPlugin* rail = (railPlugin*)context->handle;
349
0
  WINPR_ASSERT(rail);
350
0
  WLog_Print(rail->log, WLOG_DEBUG, "build=0x%08" PRIx32, handshake->buildNumber);
351
0
  return rail_send_handshake_order(rail, handshake);
352
0
}
353
354
static UINT rail_server_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
355
0
{
356
0
  WINPR_ASSERT(context);
357
0
  WINPR_ASSERT(handshake);
358
359
0
  railPlugin* rail = (railPlugin*)context->handle;
360
0
  WINPR_ASSERT(rail);
361
362
0
  WLog_Print(rail->log, WLOG_DEBUG, "build=0x%08" PRIx32, handshake->buildNumber);
363
364
0
  const UINT32 buildnumber =
365
0
      freerdp_settings_get_uint32(rail->rdpcontext->settings, FreeRDP_ClientBuild);
366
0
  const RAIL_HANDSHAKE_ORDER clientHandshake = { buildnumber };
367
0
  return context->ClientHandshake(context, &clientHandshake);
368
0
}
369
370
static UINT rail_server_handshake_ex(RailClientContext* context,
371
                                     const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
372
0
{
373
0
  WINPR_ASSERT(context);
374
0
  WINPR_ASSERT(handshakeEx);
375
376
0
  railPlugin* rail = (railPlugin*)context->handle;
377
0
  WINPR_ASSERT(rail);
378
379
0
  const RAIL_HANDSHAKE_ORDER handshake = { handshakeEx->buildNumber };
380
381
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
382
0
  WLog_Print(
383
0
      rail->log, WLOG_DEBUG, "build=0x%08" PRIx32 ", flags=%s", handshakeEx->buildNumber,
384
0
      rail_handshake_ex_flags_to_string(handshakeEx->railHandshakeFlags, buffer, sizeof(buffer)));
385
0
  return rail_server_handshake(context, &handshake);
386
0
}
387
388
/**
389
 * Function description
390
 *
391
 * @return 0 on success, otherwise a Win32 error code
392
 */
393
static UINT rail_client_notify_event(RailClientContext* context,
394
                                     const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
395
0
{
396
0
  railPlugin* rail = nullptr;
397
398
0
  if (!context || !notifyEvent)
399
0
    return ERROR_INVALID_PARAMETER;
400
401
0
  rail = (railPlugin*)context->handle;
402
0
  return rail_send_client_notify_event_order(rail, notifyEvent);
403
0
}
404
405
/**
406
 * Function description
407
 *
408
 * @return 0 on success, otherwise a Win32 error code
409
 */
410
static UINT rail_client_window_move(RailClientContext* context,
411
                                    const RAIL_WINDOW_MOVE_ORDER* windowMove)
412
0
{
413
0
  railPlugin* rail = nullptr;
414
415
0
  if (!context || !windowMove)
416
0
    return ERROR_INVALID_PARAMETER;
417
418
0
  rail = (railPlugin*)context->handle;
419
0
  return rail_send_client_window_move_order(rail, windowMove);
420
0
}
421
422
/**
423
 * Function description
424
 *
425
 * @return 0 on success, otherwise a Win32 error code
426
 */
427
static UINT rail_client_information(RailClientContext* context,
428
                                    const RAIL_CLIENT_STATUS_ORDER* clientStatus)
429
0
{
430
0
  railPlugin* rail = nullptr;
431
432
0
  if (!context || !clientStatus)
433
0
    return ERROR_INVALID_PARAMETER;
434
435
0
  rail = (railPlugin*)context->handle;
436
0
  return rail_send_client_status_order(rail, clientStatus);
437
0
}
438
439
/**
440
 * Function description
441
 *
442
 * @return 0 on success, otherwise a Win32 error code
443
 */
444
static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
445
0
{
446
0
  railPlugin* rail = nullptr;
447
448
0
  if (!context || !sysmenu)
449
0
    return ERROR_INVALID_PARAMETER;
450
451
0
  rail = (railPlugin*)context->handle;
452
0
  return rail_send_client_sysmenu_order(rail, sysmenu);
453
0
}
454
455
/**
456
 * Function description
457
 *
458
 * @return 0 on success, otherwise a Win32 error code
459
 */
460
static UINT rail_client_language_bar_info(RailClientContext* context,
461
                                          const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
462
0
{
463
0
  railPlugin* rail = nullptr;
464
465
0
  if (!context || !langBarInfo)
466
0
    return ERROR_INVALID_PARAMETER;
467
468
0
  rail = (railPlugin*)context->handle;
469
0
  return rail_send_client_langbar_info_order(rail, langBarInfo);
470
0
}
471
472
static UINT rail_client_language_ime_info(RailClientContext* context,
473
                                          const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
474
0
{
475
0
  railPlugin* rail = nullptr;
476
477
0
  if (!context || !langImeInfo)
478
0
    return ERROR_INVALID_PARAMETER;
479
480
0
  rail = (railPlugin*)context->handle;
481
0
  return rail_send_client_languageime_info_order(rail, langImeInfo);
482
0
}
483
484
/**
485
 * Function description
486
 *
487
 * @return 0 on success, otherwise a Win32 error code
488
 */
489
static UINT rail_client_get_appid_request(RailClientContext* context,
490
                                          const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
491
0
{
492
0
  railPlugin* rail = nullptr;
493
494
0
  if (!context || !getAppIdReq || !context->handle)
495
0
    return ERROR_INVALID_PARAMETER;
496
497
0
  rail = (railPlugin*)context->handle;
498
0
  return rail_send_client_get_appid_req_order(rail, getAppIdReq);
499
0
}
500
501
static UINT rail_client_compartment_info(RailClientContext* context,
502
                                         const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
503
0
{
504
0
  railPlugin* rail = nullptr;
505
506
0
  if (!context || !compartmentInfo || !context->handle)
507
0
    return ERROR_INVALID_PARAMETER;
508
509
0
  rail = (railPlugin*)context->handle;
510
0
  return rail_send_client_compartment_info_order(rail, compartmentInfo);
511
0
}
512
513
static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
514
0
{
515
0
  railPlugin* rail = nullptr;
516
517
0
  if (!context || !cloak || !context->handle)
518
0
    return ERROR_INVALID_PARAMETER;
519
520
0
  rail = (railPlugin*)context->handle;
521
0
  return rail_send_client_cloak_order(rail, cloak);
522
0
}
523
524
static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
525
0
{
526
0
  railPlugin* rail = nullptr;
527
528
0
  if (!context || !snap || !context->handle)
529
0
    return ERROR_INVALID_PARAMETER;
530
531
0
  rail = (railPlugin*)context->handle;
532
0
  return rail_send_client_snap_arrange_order(rail, snap);
533
0
}
534
535
static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
536
0
{
537
0
  if (!context || !context->handle)
538
0
    return ERROR_INVALID_PARAMETER;
539
540
0
  railPlugin* rail = (railPlugin*)context->handle;
541
0
  return rail_send_client_text_scale_order(rail, textScale);
542
0
}
543
544
static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
545
0
{
546
0
  if (!context || !context->handle)
547
0
    return ERROR_INVALID_PARAMETER;
548
549
0
  railPlugin* rail = (railPlugin*)context->handle;
550
0
  return rail_send_client_caret_blink_rate_order(rail, rate);
551
0
}
552
553
static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
554
                                                         UINT event, LPVOID pData,
555
                                                         UINT32 dataLength, UINT32 totalLength,
556
                                                         UINT32 dataFlags)
557
0
{
558
0
  UINT error = CHANNEL_RC_OK;
559
0
  railPlugin* rail = (railPlugin*)lpUserParam;
560
561
0
  switch (event)
562
0
  {
563
0
    case CHANNEL_EVENT_DATA_RECEIVED:
564
0
      if (!rail || (rail->OpenHandle != openHandle))
565
0
      {
566
0
        WLog_ERR(TAG, "error no match");
567
0
        return;
568
0
      }
569
570
0
      if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
571
0
                                               totalLength, dataFlags)))
572
0
      {
573
0
        WLog_ERR(TAG,
574
0
                 "rail_virtual_channel_event_data_received"
575
0
                 " failed with error %" PRIu32 "!",
576
0
                 error);
577
0
      }
578
579
0
      break;
580
581
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
582
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
583
0
    {
584
0
      wStream* s = (wStream*)pData;
585
0
      Stream_Free(s, TRUE);
586
0
    }
587
0
    break;
588
589
0
    case CHANNEL_EVENT_USER:
590
0
      break;
591
0
    default:
592
0
      break;
593
0
  }
594
595
0
  if (error && rail && rail->rdpcontext)
596
0
    setChannelError(rail->rdpcontext, error,
597
0
                    "rail_virtual_channel_open_event reported an error");
598
0
}
599
600
/**
601
 * Function description
602
 *
603
 * @return 0 on success, otherwise a Win32 error code
604
 */
605
static UINT rail_virtual_channel_event_connected(railPlugin* rail, WINPR_ATTR_UNUSED LPVOID pData,
606
                                                 WINPR_ATTR_UNUSED UINT32 dataLength)
607
0
{
608
0
  WINPR_ASSERT(rail);
609
610
0
  rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
611
0
                                                   RAIL_SVC_CHANNEL_NAME);
612
0
  if (!rail->MsgsHandle)
613
0
    return ERROR_INTERNAL_ERROR;
614
615
0
  return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
616
0
                                                        rail->channelDef.name,
617
0
                                                        rail_virtual_channel_open_event_ex);
618
0
}
619
620
/**
621
 * Function description
622
 *
623
 * @return 0 on success, otherwise a Win32 error code
624
 */
625
static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
626
0
{
627
0
  UINT rc = 0;
628
629
0
  channel_client_quit_handler(rail->MsgsHandle);
630
0
  if (rail->OpenHandle == 0)
631
0
    return CHANNEL_RC_OK;
632
633
0
  WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
634
0
  rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
635
636
0
  if (CHANNEL_RC_OK != rc)
637
0
  {
638
0
    WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
639
0
             rc);
640
0
    return rc;
641
0
  }
642
643
0
  rail->OpenHandle = 0;
644
645
0
  return CHANNEL_RC_OK;
646
0
}
647
648
static void rail_virtual_channel_event_terminated(railPlugin* rail)
649
0
{
650
0
  rail->InitHandle = nullptr;
651
0
  free(rail->context);
652
0
  free(rail);
653
0
}
654
655
static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
656
                                                         UINT event, LPVOID pData, UINT dataLength)
657
0
{
658
0
  UINT error = CHANNEL_RC_OK;
659
0
  railPlugin* rail = (railPlugin*)lpUserParam;
660
661
0
  if (!rail || (rail->InitHandle != pInitHandle))
662
0
  {
663
0
    WLog_ERR(TAG, "error no match");
664
0
    return;
665
0
  }
666
667
0
  switch (event)
668
0
  {
669
0
    case CHANNEL_EVENT_CONNECTED:
670
0
      if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
671
0
        WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
672
0
                 error);
673
674
0
      break;
675
676
0
    case CHANNEL_EVENT_DISCONNECTED:
677
0
      if ((error = rail_virtual_channel_event_disconnected(rail)))
678
0
        WLog_ERR(TAG,
679
0
                 "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
680
0
                 error);
681
682
0
      break;
683
684
0
    case CHANNEL_EVENT_TERMINATED:
685
0
      rail_virtual_channel_event_terminated(rail);
686
0
      break;
687
688
0
    case CHANNEL_EVENT_ATTACHED:
689
0
    case CHANNEL_EVENT_DETACHED:
690
0
    default:
691
0
      break;
692
0
  }
693
694
0
  if (error && rail->rdpcontext)
695
0
    setChannelError(rail->rdpcontext, error,
696
0
                    "rail_virtual_channel_init_event_ex reported an error");
697
0
}
698
699
/* rail is always built-in */
700
#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
701
702
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
703
                                                         PVOID pInitHandle))
704
0
{
705
0
  UINT rc = 0;
706
0
  railPlugin* rail = nullptr;
707
0
  RailClientContext* context = nullptr;
708
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = nullptr;
709
0
  BOOL isFreerdp = FALSE;
710
0
  rail = (railPlugin*)calloc(1, sizeof(railPlugin));
711
712
0
  if (!rail)
713
0
  {
714
0
    WLog_ERR(TAG, "calloc failed!");
715
0
    return FALSE;
716
0
  }
717
718
0
  rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
719
0
                             CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
720
0
  (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
721
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
722
723
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
724
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
725
0
  {
726
0
    context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
727
728
0
    if (!context)
729
0
    {
730
0
      WLog_ERR(TAG, "calloc failed!");
731
0
      free(rail);
732
0
      return FALSE;
733
0
    }
734
735
0
    context->handle = (void*)rail;
736
0
    context->custom = nullptr;
737
0
    context->ClientExecute = rail_client_execute;
738
0
    context->ClientActivate = rail_client_activate;
739
0
    context->ClientSystemParam = rail_client_system_param;
740
0
    context->ClientSystemCommand = rail_client_system_command;
741
0
    context->ClientHandshake = rail_client_handshake;
742
0
    context->ServerHandshake = rail_server_handshake;
743
0
    context->ServerHandshakeEx = rail_server_handshake_ex;
744
0
    context->ClientNotifyEvent = rail_client_notify_event;
745
0
    context->ClientWindowMove = rail_client_window_move;
746
0
    context->ClientInformation = rail_client_information;
747
0
    context->ClientSystemMenu = rail_client_system_menu;
748
0
    context->ClientLanguageBarInfo = rail_client_language_bar_info;
749
0
    context->ClientLanguageIMEInfo = rail_client_language_ime_info;
750
0
    context->ClientGetAppIdRequest = rail_client_get_appid_request;
751
0
    context->ClientSnapArrange = rail_client_snap_arrange;
752
0
    context->ClientCloak = rail_client_cloak;
753
0
    context->ClientCompartmentInfo = rail_client_compartment_info;
754
0
    context->ClientTextScale = rail_client_text_scale;
755
0
    context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
756
0
    rail->rdpcontext = pEntryPointsEx->context;
757
0
    rail->context = context;
758
0
    isFreerdp = TRUE;
759
0
  }
760
761
0
  rail->log = WLog_Get("com.freerdp.channels.rail.client");
762
0
  WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
763
0
  CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
764
0
  rail->InitHandle = pInitHandle;
765
0
  rc = rail->channelEntryPoints.pVirtualChannelInitEx(
766
0
      rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
767
0
      rail_virtual_channel_init_event_ex);
768
769
0
  if (CHANNEL_RC_OK != rc)
770
0
  {
771
0
    WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
772
0
    goto error_out;
773
0
  }
774
775
0
  rail->channelEntryPoints.pInterface = context;
776
0
  return TRUE;
777
0
error_out:
778
779
0
  if (isFreerdp)
780
0
    free(rail->context);
781
782
0
  free(rail);
783
0
  return FALSE;
784
0
}