Coverage Report

Created: 2026-07-16 07:09

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.25k
{
41
1.25k
  RailClientContext* pInterface = nullptr;
42
43
1.25k
  if (!rail)
44
0
    return nullptr;
45
46
1.25k
  pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
47
1.25k
  return pInterface;
48
1.25k
}
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
  return context->ClientHandshake(context, &clientHandshake);
365
0
}
366
367
static UINT rail_server_handshake_ex(RailClientContext* context,
368
                                     const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
369
0
{
370
0
  WINPR_ASSERT(context);
371
0
  WINPR_ASSERT(handshakeEx);
372
373
0
  railPlugin* rail = (railPlugin*)context->handle;
374
0
  WINPR_ASSERT(rail);
375
376
0
  const RAIL_HANDSHAKE_ORDER handshake = { handshakeEx->buildNumber };
377
378
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
379
0
  WLog_Print(
380
0
      rail->log, WLOG_DEBUG, "build=0x%08" PRIx32 ", flags=%s", handshakeEx->buildNumber,
381
0
      rail_handshake_ex_flags_to_string(handshakeEx->railHandshakeFlags, buffer, sizeof(buffer)));
382
0
  return rail_server_handshake(context, &handshake);
383
0
}
384
385
/**
386
 * Function description
387
 *
388
 * @return 0 on success, otherwise a Win32 error code
389
 */
390
static UINT rail_client_notify_event(RailClientContext* context,
391
                                     const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
392
0
{
393
0
  railPlugin* rail = nullptr;
394
395
0
  if (!context || !notifyEvent)
396
0
    return ERROR_INVALID_PARAMETER;
397
398
0
  rail = (railPlugin*)context->handle;
399
0
  return rail_send_client_notify_event_order(rail, notifyEvent);
400
0
}
401
402
/**
403
 * Function description
404
 *
405
 * @return 0 on success, otherwise a Win32 error code
406
 */
407
static UINT rail_client_window_move(RailClientContext* context,
408
                                    const RAIL_WINDOW_MOVE_ORDER* windowMove)
409
0
{
410
0
  railPlugin* rail = nullptr;
411
412
0
  if (!context || !windowMove)
413
0
    return ERROR_INVALID_PARAMETER;
414
415
0
  rail = (railPlugin*)context->handle;
416
0
  return rail_send_client_window_move_order(rail, windowMove);
417
0
}
418
419
/**
420
 * Function description
421
 *
422
 * @return 0 on success, otherwise a Win32 error code
423
 */
424
static UINT rail_client_information(RailClientContext* context,
425
                                    const RAIL_CLIENT_STATUS_ORDER* clientStatus)
426
0
{
427
0
  railPlugin* rail = nullptr;
428
429
0
  if (!context || !clientStatus)
430
0
    return ERROR_INVALID_PARAMETER;
431
432
0
  rail = (railPlugin*)context->handle;
433
0
  return rail_send_client_status_order(rail, clientStatus);
434
0
}
435
436
/**
437
 * Function description
438
 *
439
 * @return 0 on success, otherwise a Win32 error code
440
 */
441
static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
442
0
{
443
0
  railPlugin* rail = nullptr;
444
445
0
  if (!context || !sysmenu)
446
0
    return ERROR_INVALID_PARAMETER;
447
448
0
  rail = (railPlugin*)context->handle;
449
0
  return rail_send_client_sysmenu_order(rail, sysmenu);
450
0
}
451
452
/**
453
 * Function description
454
 *
455
 * @return 0 on success, otherwise a Win32 error code
456
 */
457
static UINT rail_client_language_bar_info(RailClientContext* context,
458
                                          const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
459
0
{
460
0
  railPlugin* rail = nullptr;
461
462
0
  if (!context || !langBarInfo)
463
0
    return ERROR_INVALID_PARAMETER;
464
465
0
  rail = (railPlugin*)context->handle;
466
0
  return rail_send_client_langbar_info_order(rail, langBarInfo);
467
0
}
468
469
static UINT rail_client_language_ime_info(RailClientContext* context,
470
                                          const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
471
0
{
472
0
  railPlugin* rail = nullptr;
473
474
0
  if (!context || !langImeInfo)
475
0
    return ERROR_INVALID_PARAMETER;
476
477
0
  rail = (railPlugin*)context->handle;
478
0
  return rail_send_client_languageime_info_order(rail, langImeInfo);
479
0
}
480
481
/**
482
 * Function description
483
 *
484
 * @return 0 on success, otherwise a Win32 error code
485
 */
486
static UINT rail_client_get_appid_request(RailClientContext* context,
487
                                          const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
488
0
{
489
0
  railPlugin* rail = nullptr;
490
491
0
  if (!context || !getAppIdReq || !context->handle)
492
0
    return ERROR_INVALID_PARAMETER;
493
494
0
  rail = (railPlugin*)context->handle;
495
0
  return rail_send_client_get_appid_req_order(rail, getAppIdReq);
496
0
}
497
498
static UINT rail_client_compartment_info(RailClientContext* context,
499
                                         const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
500
0
{
501
0
  railPlugin* rail = nullptr;
502
503
0
  if (!context || !compartmentInfo || !context->handle)
504
0
    return ERROR_INVALID_PARAMETER;
505
506
0
  rail = (railPlugin*)context->handle;
507
0
  return rail_send_client_compartment_info_order(rail, compartmentInfo);
508
0
}
509
510
static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
511
0
{
512
0
  railPlugin* rail = nullptr;
513
514
0
  if (!context || !cloak || !context->handle)
515
0
    return ERROR_INVALID_PARAMETER;
516
517
0
  rail = (railPlugin*)context->handle;
518
0
  return rail_send_client_cloak_order(rail, cloak);
519
0
}
520
521
static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
522
0
{
523
0
  railPlugin* rail = nullptr;
524
525
0
  if (!context || !snap || !context->handle)
526
0
    return ERROR_INVALID_PARAMETER;
527
528
0
  rail = (railPlugin*)context->handle;
529
0
  return rail_send_client_snap_arrange_order(rail, snap);
530
0
}
531
532
static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
533
0
{
534
0
  if (!context || !context->handle)
535
0
    return ERROR_INVALID_PARAMETER;
536
537
0
  railPlugin* rail = (railPlugin*)context->handle;
538
0
  return rail_send_client_text_scale_order(rail, textScale);
539
0
}
540
541
static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
542
0
{
543
0
  if (!context || !context->handle)
544
0
    return ERROR_INVALID_PARAMETER;
545
546
0
  railPlugin* rail = (railPlugin*)context->handle;
547
0
  return rail_send_client_caret_blink_rate_order(rail, rate);
548
0
}
549
550
static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
551
                                                         UINT event, LPVOID pData,
552
                                                         UINT32 dataLength, UINT32 totalLength,
553
                                                         UINT32 dataFlags)
554
0
{
555
0
  UINT error = CHANNEL_RC_OK;
556
0
  railPlugin* rail = (railPlugin*)lpUserParam;
557
558
0
  switch (event)
559
0
  {
560
0
    case CHANNEL_EVENT_DATA_RECEIVED:
561
0
      if (!rail || (rail->OpenHandle != openHandle))
562
0
      {
563
0
        WLog_ERR(TAG, "error no match");
564
0
        return;
565
0
      }
566
567
0
      if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
568
0
                                               totalLength, dataFlags)))
569
0
      {
570
0
        WLog_ERR(TAG,
571
0
                 "rail_virtual_channel_event_data_received"
572
0
                 " failed with error %" PRIu32 "!",
573
0
                 error);
574
0
      }
575
576
0
      break;
577
578
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
579
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
580
0
    {
581
0
      wStream* s = (wStream*)pData;
582
0
      Stream_Free(s, TRUE);
583
0
    }
584
0
    break;
585
586
0
    case CHANNEL_EVENT_USER:
587
0
      break;
588
0
    default:
589
0
      break;
590
0
  }
591
592
0
  if (error && rail && rail->rdpcontext)
593
0
    setChannelError(rail->rdpcontext, error,
594
0
                    "rail_virtual_channel_open_event reported an error");
595
0
}
596
597
/**
598
 * Function description
599
 *
600
 * @return 0 on success, otherwise a Win32 error code
601
 */
602
static UINT rail_virtual_channel_event_connected(railPlugin* rail, WINPR_ATTR_UNUSED LPVOID pData,
603
                                                 WINPR_ATTR_UNUSED UINT32 dataLength)
604
0
{
605
0
  WINPR_ASSERT(rail);
606
607
0
  rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
608
0
                                                   RAIL_SVC_CHANNEL_NAME);
609
0
  if (!rail->MsgsHandle)
610
0
    return ERROR_INTERNAL_ERROR;
611
612
0
  return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
613
0
                                                        rail->channelDef.name,
614
0
                                                        rail_virtual_channel_open_event_ex);
615
0
}
616
617
/**
618
 * Function description
619
 *
620
 * @return 0 on success, otherwise a Win32 error code
621
 */
622
static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
623
0
{
624
0
  UINT rc = 0;
625
626
0
  channel_client_quit_handler(rail->MsgsHandle);
627
0
  if (rail->OpenHandle == 0)
628
0
    return CHANNEL_RC_OK;
629
630
0
  WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
631
0
  rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
632
633
0
  if (CHANNEL_RC_OK != rc)
634
0
  {
635
0
    WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
636
0
             rc);
637
0
    return rc;
638
0
  }
639
640
0
  rail->OpenHandle = 0;
641
642
0
  return CHANNEL_RC_OK;
643
0
}
644
645
static void rail_virtual_channel_event_terminated(railPlugin* rail)
646
0
{
647
0
  rail->InitHandle = nullptr;
648
0
  free(rail->context);
649
0
  free(rail);
650
0
}
651
652
static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
653
                                                         UINT event, LPVOID pData, UINT dataLength)
654
0
{
655
0
  UINT error = CHANNEL_RC_OK;
656
0
  railPlugin* rail = (railPlugin*)lpUserParam;
657
658
0
  if (!rail || (rail->InitHandle != pInitHandle))
659
0
  {
660
0
    WLog_ERR(TAG, "error no match");
661
0
    return;
662
0
  }
663
664
0
  switch (event)
665
0
  {
666
0
    case CHANNEL_EVENT_CONNECTED:
667
0
      if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
668
0
        WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
669
0
                 error);
670
671
0
      break;
672
673
0
    case CHANNEL_EVENT_DISCONNECTED:
674
0
      if ((error = rail_virtual_channel_event_disconnected(rail)))
675
0
        WLog_ERR(TAG,
676
0
                 "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
677
0
                 error);
678
679
0
      break;
680
681
0
    case CHANNEL_EVENT_TERMINATED:
682
0
      rail_virtual_channel_event_terminated(rail);
683
0
      break;
684
685
0
    case CHANNEL_EVENT_ATTACHED:
686
0
    case CHANNEL_EVENT_DETACHED:
687
0
    default:
688
0
      break;
689
0
  }
690
691
0
  if (error && rail->rdpcontext)
692
0
    setChannelError(rail->rdpcontext, error,
693
0
                    "rail_virtual_channel_init_event_ex reported an error");
694
0
}
695
696
/* rail is always built-in */
697
#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
698
699
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
700
                                                         PVOID pInitHandle))
701
0
{
702
0
  UINT rc = 0;
703
0
  railPlugin* rail = nullptr;
704
0
  RailClientContext* context = nullptr;
705
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = nullptr;
706
0
  BOOL isFreerdp = FALSE;
707
0
  rail = (railPlugin*)calloc(1, sizeof(railPlugin));
708
709
0
  if (!rail)
710
0
  {
711
0
    WLog_ERR(TAG, "calloc failed!");
712
0
    return FALSE;
713
0
  }
714
715
0
  rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
716
0
                             CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
717
0
  (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
718
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
719
720
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
721
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
722
0
  {
723
0
    context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
724
725
0
    if (!context)
726
0
    {
727
0
      WLog_ERR(TAG, "calloc failed!");
728
0
      free(rail);
729
0
      return FALSE;
730
0
    }
731
732
0
    context->handle = (void*)rail;
733
0
    context->custom = nullptr;
734
0
    context->ClientExecute = rail_client_execute;
735
0
    context->ClientActivate = rail_client_activate;
736
0
    context->ClientSystemParam = rail_client_system_param;
737
0
    context->ClientSystemCommand = rail_client_system_command;
738
0
    context->ClientHandshake = rail_client_handshake;
739
0
    context->ServerHandshake = rail_server_handshake;
740
0
    context->ServerHandshakeEx = rail_server_handshake_ex;
741
0
    context->ClientNotifyEvent = rail_client_notify_event;
742
0
    context->ClientWindowMove = rail_client_window_move;
743
0
    context->ClientInformation = rail_client_information;
744
0
    context->ClientSystemMenu = rail_client_system_menu;
745
0
    context->ClientLanguageBarInfo = rail_client_language_bar_info;
746
0
    context->ClientLanguageIMEInfo = rail_client_language_ime_info;
747
0
    context->ClientGetAppIdRequest = rail_client_get_appid_request;
748
0
    context->ClientSnapArrange = rail_client_snap_arrange;
749
0
    context->ClientCloak = rail_client_cloak;
750
0
    context->ClientCompartmentInfo = rail_client_compartment_info;
751
0
    context->ClientTextScale = rail_client_text_scale;
752
0
    context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
753
0
    rail->rdpcontext = pEntryPointsEx->context;
754
0
    rail->context = context;
755
0
    isFreerdp = TRUE;
756
0
  }
757
758
0
  rail->log = WLog_Get("com.freerdp.channels.rail.client");
759
0
  WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
760
0
  CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
761
0
  rail->InitHandle = pInitHandle;
762
0
  rc = rail->channelEntryPoints.pVirtualChannelInitEx(
763
0
      rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
764
0
      rail_virtual_channel_init_event_ex);
765
766
0
  if (CHANNEL_RC_OK != rc)
767
0
  {
768
0
    WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
769
0
    goto error_out;
770
0
  }
771
772
0
  rail->channelEntryPoints.pInterface = context;
773
0
  return TRUE;
774
0
error_out:
775
776
0
  if (isFreerdp)
777
0
    free(rail->context);
778
779
0
  free(rail);
780
0
  return FALSE;
781
0
}