FreeRDP
client/rail_main.c
1 
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 {
41  RailClientContext* pInterface = NULL;
42 
43  if (!rail)
44  return NULL;
45 
46  pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
47  return pInterface;
48 }
49 
55 static UINT rail_send(railPlugin* rail, wStream* s)
56 {
57  UINT status = 0;
58 
59  if (!rail)
60  {
61  Stream_Free(s, TRUE);
62  return CHANNEL_RC_BAD_INIT_HANDLE;
63  }
64 
65  status = rail->channelEntryPoints.pVirtualChannelWriteEx(
66  rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
67 
68  if (status != CHANNEL_RC_OK)
69  {
70  Stream_Free(s, TRUE);
71  WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
72  WTSErrorToString(status), status);
73  }
74 
75  return status;
76 }
77 
83 UINT rail_send_channel_data(railPlugin* rail, wStream* src)
84 {
85  if (!rail || !src)
86  {
87  Stream_Free(src, TRUE);
88  return ERROR_INVALID_PARAMETER;
89  }
90 
91  return rail_send(rail, src);
92 }
93 
103 static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec)
104 {
105  const char* exeOrFile = NULL;
106  UINT error = 0;
107  railPlugin* rail = NULL;
108  UINT16 flags = 0;
109  RAIL_UNICODE_STRING ruExeOrFile = { 0 };
110  RAIL_UNICODE_STRING ruWorkingDir = { 0 };
111  RAIL_UNICODE_STRING ruArguments = { 0 };
112 
113  if (!context || !exec)
114  return ERROR_INVALID_PARAMETER;
115 
116  rail = (railPlugin*)context->handle;
117  exeOrFile = exec->RemoteApplicationProgram;
118  flags = exec->flags;
119 
120  if (!exeOrFile)
121  return ERROR_INVALID_PARAMETER;
122 
123  if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
124  &ruExeOrFile) || /* RemoteApplicationProgram */
125  !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
126  &ruWorkingDir) || /* ShellWorkingDirectory */
127  !utf8_string_to_rail_string(exec->RemoteApplicationArguments,
128  &ruArguments)) /* RemoteApplicationCmdLine */
129  error = ERROR_INTERNAL_ERROR;
130  else
131  error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
132 
133  free(ruExeOrFile.string);
134  free(ruWorkingDir.string);
135  free(ruArguments.string);
136  return error;
137 }
138 
144 static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate)
145 {
146  railPlugin* rail = NULL;
147 
148  if (!context || !activate)
149  return ERROR_INVALID_PARAMETER;
150 
151  rail = (railPlugin*)context->handle;
152  return rail_send_client_activate_order(rail, activate);
153 }
154 
160 static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ORDER* sysparam)
161 {
162  wStream* s = NULL;
163  size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
164  railPlugin* rail = NULL;
165  UINT error = 0;
166  BOOL extendedSpiSupported = 0;
167 
168  if (!context || !sysparam)
169  return ERROR_INVALID_PARAMETER;
170 
171  rail = (railPlugin*)context->handle;
172 
173  switch (sysparam->param)
174  {
175  case SPI_SET_DRAG_FULL_WINDOWS:
176  case SPI_SET_KEYBOARD_CUES:
177  case SPI_SET_KEYBOARD_PREF:
178  case SPI_SET_MOUSE_BUTTON_SWAP:
179  length += 1;
180  break;
181 
182  case SPI_SET_WORK_AREA:
183  case SPI_DISPLAY_CHANGE:
184  case SPI_TASKBAR_POS:
185  length += 8;
186  break;
187 
188  case SPI_SET_HIGH_CONTRAST:
189  length += sysparam->highContrast.colorSchemeLength + 10;
190  break;
191 
192  case SPI_SETFILTERKEYS:
193  length += 20;
194  break;
195 
196  case SPI_SETSTICKYKEYS:
197  case SPI_SETCARETWIDTH:
198  case SPI_SETTOGGLEKEYS:
199  length += 4;
200  break;
201 
202  default:
203  return ERROR_BAD_ARGUMENTS;
204  }
205 
206  s = rail_pdu_init(length);
207 
208  if (!s)
209  {
210  WLog_ERR(TAG, "rail_pdu_init failed!");
211  return CHANNEL_RC_NO_MEMORY;
212  }
213 
214  extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
215  if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported)))
216  {
217  WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
218  Stream_Free(s, TRUE);
219  return error;
220  }
221 
222  return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM);
223 }
224 
230 static UINT rail_client_system_param(RailClientContext* context,
231  const RAIL_SYSPARAM_ORDER* sysInParam)
232 {
233  UINT error = CHANNEL_RC_OK;
234  RAIL_SYSPARAM_ORDER sysparam;
235 
236  if (!context || !sysInParam)
237  return ERROR_INVALID_PARAMETER;
238 
239  sysparam = *sysInParam;
240 
241  if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
242  {
243  sysparam.param = SPI_SET_HIGH_CONTRAST;
244 
245  if ((error = rail_send_client_sysparam(context, &sysparam)))
246  {
247  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
248  return error;
249  }
250  }
251 
252  if (sysparam.params & SPI_MASK_TASKBAR_POS)
253  {
254  sysparam.param = SPI_TASKBAR_POS;
255 
256  if ((error = rail_send_client_sysparam(context, &sysparam)))
257  {
258  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
259  return error;
260  }
261  }
262 
263  if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
264  {
265  sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
266 
267  if ((error = rail_send_client_sysparam(context, &sysparam)))
268  {
269  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
270  return error;
271  }
272  }
273 
274  if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
275  {
276  sysparam.param = SPI_SET_KEYBOARD_PREF;
277 
278  if ((error = rail_send_client_sysparam(context, &sysparam)))
279  {
280  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
281  return error;
282  }
283  }
284 
285  if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
286  {
287  sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
288 
289  if ((error = rail_send_client_sysparam(context, &sysparam)))
290  {
291  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
292  return error;
293  }
294  }
295 
296  if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
297  {
298  sysparam.param = SPI_SET_KEYBOARD_CUES;
299 
300  if ((error = rail_send_client_sysparam(context, &sysparam)))
301  {
302  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
303  return error;
304  }
305  }
306 
307  if (sysparam.params & SPI_MASK_SET_WORK_AREA)
308  {
309  sysparam.param = SPI_SET_WORK_AREA;
310 
311  if ((error = rail_send_client_sysparam(context, &sysparam)))
312  {
313  WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
314  return error;
315  }
316  }
317 
318  return error;
319 }
320 
326 static UINT rail_client_system_command(RailClientContext* context,
327  const RAIL_SYSCOMMAND_ORDER* syscommand)
328 {
329  railPlugin* rail = NULL;
330 
331  if (!context || !syscommand)
332  return ERROR_INVALID_PARAMETER;
333 
334  rail = (railPlugin*)context->handle;
335  return rail_send_client_syscommand_order(rail, syscommand);
336 }
337 
343 static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
344 {
345  railPlugin* rail = NULL;
346 
347  if (!context || !handshake)
348  return ERROR_INVALID_PARAMETER;
349 
350  rail = (railPlugin*)context->handle;
351  return rail_send_handshake_order(rail, handshake);
352 }
353 
359 static UINT rail_client_notify_event(RailClientContext* context,
360  const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
361 {
362  railPlugin* rail = NULL;
363 
364  if (!context || !notifyEvent)
365  return ERROR_INVALID_PARAMETER;
366 
367  rail = (railPlugin*)context->handle;
368  return rail_send_client_notify_event_order(rail, notifyEvent);
369 }
370 
376 static UINT rail_client_window_move(RailClientContext* context,
377  const RAIL_WINDOW_MOVE_ORDER* windowMove)
378 {
379  railPlugin* rail = NULL;
380 
381  if (!context || !windowMove)
382  return ERROR_INVALID_PARAMETER;
383 
384  rail = (railPlugin*)context->handle;
385  return rail_send_client_window_move_order(rail, windowMove);
386 }
387 
393 static UINT rail_client_information(RailClientContext* context,
394  const RAIL_CLIENT_STATUS_ORDER* clientStatus)
395 {
396  railPlugin* rail = NULL;
397 
398  if (!context || !clientStatus)
399  return ERROR_INVALID_PARAMETER;
400 
401  rail = (railPlugin*)context->handle;
402  return rail_send_client_status_order(rail, clientStatus);
403 }
404 
410 static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
411 {
412  railPlugin* rail = NULL;
413 
414  if (!context || !sysmenu)
415  return ERROR_INVALID_PARAMETER;
416 
417  rail = (railPlugin*)context->handle;
418  return rail_send_client_sysmenu_order(rail, sysmenu);
419 }
420 
426 static UINT rail_client_language_bar_info(RailClientContext* context,
427  const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
428 {
429  railPlugin* rail = NULL;
430 
431  if (!context || !langBarInfo)
432  return ERROR_INVALID_PARAMETER;
433 
434  rail = (railPlugin*)context->handle;
435  return rail_send_client_langbar_info_order(rail, langBarInfo);
436 }
437 
438 static UINT rail_client_language_ime_info(RailClientContext* context,
439  const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
440 {
441  railPlugin* rail = NULL;
442 
443  if (!context || !langImeInfo)
444  return ERROR_INVALID_PARAMETER;
445 
446  rail = (railPlugin*)context->handle;
447  return rail_send_client_languageime_info_order(rail, langImeInfo);
448 }
449 
455 static UINT rail_client_get_appid_request(RailClientContext* context,
456  const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
457 {
458  railPlugin* rail = NULL;
459 
460  if (!context || !getAppIdReq || !context->handle)
461  return ERROR_INVALID_PARAMETER;
462 
463  rail = (railPlugin*)context->handle;
464  return rail_send_client_get_appid_req_order(rail, getAppIdReq);
465 }
466 
467 static UINT rail_client_compartment_info(RailClientContext* context,
468  const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
469 {
470  railPlugin* rail = NULL;
471 
472  if (!context || !compartmentInfo || !context->handle)
473  return ERROR_INVALID_PARAMETER;
474 
475  rail = (railPlugin*)context->handle;
476  return rail_send_client_compartment_info_order(rail, compartmentInfo);
477 }
478 
479 static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
480 {
481  railPlugin* rail = NULL;
482 
483  if (!context || !cloak || !context->handle)
484  return ERROR_INVALID_PARAMETER;
485 
486  rail = (railPlugin*)context->handle;
487  return rail_send_client_cloak_order(rail, cloak);
488 }
489 
490 static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
491 {
492  railPlugin* rail = NULL;
493 
494  if (!context || !snap || !context->handle)
495  return ERROR_INVALID_PARAMETER;
496 
497  rail = (railPlugin*)context->handle;
498  return rail_send_client_snap_arrange_order(rail, snap);
499 }
500 
501 static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
502 {
503  if (!context || !context->handle)
504  return ERROR_INVALID_PARAMETER;
505 
506  railPlugin* rail = (railPlugin*)context->handle;
507  return rail_send_client_text_scale_order(rail, textScale);
508 }
509 
510 static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
511 {
512  if (!context || !context->handle)
513  return ERROR_INVALID_PARAMETER;
514 
515  railPlugin* rail = (railPlugin*)context->handle;
516  return rail_send_client_caret_blink_rate_order(rail, rate);
517 }
518 
519 static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
520  UINT event, LPVOID pData,
521  UINT32 dataLength, UINT32 totalLength,
522  UINT32 dataFlags)
523 {
524  UINT error = CHANNEL_RC_OK;
525  railPlugin* rail = (railPlugin*)lpUserParam;
526 
527  switch (event)
528  {
529  case CHANNEL_EVENT_DATA_RECEIVED:
530  if (!rail || (rail->OpenHandle != openHandle))
531  {
532  WLog_ERR(TAG, "error no match");
533  return;
534  }
535 
536  if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
537  totalLength, dataFlags)))
538  {
539  WLog_ERR(TAG,
540  "rail_virtual_channel_event_data_received"
541  " failed with error %" PRIu32 "!",
542  error);
543  }
544 
545  break;
546 
547  case CHANNEL_EVENT_WRITE_CANCELLED:
548  case CHANNEL_EVENT_WRITE_COMPLETE:
549  {
550  wStream* s = (wStream*)pData;
551  Stream_Free(s, TRUE);
552  }
553  break;
554 
555  case CHANNEL_EVENT_USER:
556  break;
557  default:
558  break;
559  }
560 
561  if (error && rail && rail->rdpcontext)
562  setChannelError(rail->rdpcontext, error,
563  "rail_virtual_channel_open_event reported an error");
564 }
565 
571 static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength)
572 {
573  RailClientContext* context = rail_get_client_interface(rail);
574  UINT status = CHANNEL_RC_OK;
575 
576  WINPR_ASSERT(rail);
577 
578  if (context)
579  {
580  IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake);
581 
582  if (status != CHANNEL_RC_OK)
583  WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]",
584  WTSErrorToString(status), status);
585  }
586  rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
587  RAIL_SVC_CHANNEL_NAME);
588  if (!rail->MsgsHandle)
589  return ERROR_INTERNAL_ERROR;
590 
591  return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
592  rail->channelDef.name,
593  rail_virtual_channel_open_event_ex);
594 }
595 
601 static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
602 {
603  UINT rc = 0;
604 
605  channel_client_quit_handler(rail->MsgsHandle);
606  if (rail->OpenHandle == 0)
607  return CHANNEL_RC_OK;
608 
609  WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
610  rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
611 
612  if (CHANNEL_RC_OK != rc)
613  {
614  WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
615  rc);
616  return rc;
617  }
618 
619  rail->OpenHandle = 0;
620 
621  return CHANNEL_RC_OK;
622 }
623 
624 static void rail_virtual_channel_event_terminated(railPlugin* rail)
625 {
626  rail->InitHandle = 0;
627  free(rail->context);
628  free(rail);
629 }
630 
631 static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
632  UINT event, LPVOID pData, UINT dataLength)
633 {
634  UINT error = CHANNEL_RC_OK;
635  railPlugin* rail = (railPlugin*)lpUserParam;
636 
637  if (!rail || (rail->InitHandle != pInitHandle))
638  {
639  WLog_ERR(TAG, "error no match");
640  return;
641  }
642 
643  switch (event)
644  {
645  case CHANNEL_EVENT_CONNECTED:
646  if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
647  WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
648  error);
649 
650  break;
651 
652  case CHANNEL_EVENT_DISCONNECTED:
653  if ((error = rail_virtual_channel_event_disconnected(rail)))
654  WLog_ERR(TAG,
655  "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
656  error);
657 
658  break;
659 
660  case CHANNEL_EVENT_TERMINATED:
661  rail_virtual_channel_event_terminated(rail);
662  break;
663 
664  case CHANNEL_EVENT_ATTACHED:
665  case CHANNEL_EVENT_DETACHED:
666  default:
667  break;
668  }
669 
670  if (error && rail->rdpcontext)
671  setChannelError(rail->rdpcontext, error,
672  "rail_virtual_channel_init_event_ex reported an error");
673 }
674 
675 /* rail is always built-in */
676 #define VirtualChannelEntryEx rail_VirtualChannelEntryEx
677 
678 FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
679  PVOID pInitHandle))
680 {
681  UINT rc = 0;
682  railPlugin* rail = NULL;
683  RailClientContext* context = NULL;
684  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
685  BOOL isFreerdp = FALSE;
686  rail = (railPlugin*)calloc(1, sizeof(railPlugin));
687 
688  if (!rail)
689  {
690  WLog_ERR(TAG, "calloc failed!");
691  return FALSE;
692  }
693 
694  /* Default to automatically replying to server handshakes */
695  rail->sendHandshake = TRUE;
696  rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
697  CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
698  (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
699  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
700 
701  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
702  (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
703  {
704  context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
705 
706  if (!context)
707  {
708  WLog_ERR(TAG, "calloc failed!");
709  free(rail);
710  return FALSE;
711  }
712 
713  context->handle = (void*)rail;
714  context->custom = NULL;
715  context->ClientExecute = rail_client_execute;
716  context->ClientActivate = rail_client_activate;
717  context->ClientSystemParam = rail_client_system_param;
718  context->ClientSystemCommand = rail_client_system_command;
719  context->ClientHandshake = rail_client_handshake;
720  context->ClientNotifyEvent = rail_client_notify_event;
721  context->ClientWindowMove = rail_client_window_move;
722  context->ClientInformation = rail_client_information;
723  context->ClientSystemMenu = rail_client_system_menu;
724  context->ClientLanguageBarInfo = rail_client_language_bar_info;
725  context->ClientLanguageIMEInfo = rail_client_language_ime_info;
726  context->ClientGetAppIdRequest = rail_client_get_appid_request;
727  context->ClientSnapArrange = rail_client_snap_arrange;
728  context->ClientCloak = rail_client_cloak;
729  context->ClientCompartmentInfo = rail_client_compartment_info;
730  context->ClientTextScale = rail_client_text_scale;
731  context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
732  rail->rdpcontext = pEntryPointsEx->context;
733  rail->context = context;
734  isFreerdp = TRUE;
735  }
736 
737  rail->log = WLog_Get("com.freerdp.channels.rail.client");
738  WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
739  CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
740  rail->InitHandle = pInitHandle;
741  rc = rail->channelEntryPoints.pVirtualChannelInitEx(
742  rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
743  rail_virtual_channel_init_event_ex);
744 
745  if (CHANNEL_RC_OK != rc)
746  {
747  WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
748  goto error_out;
749  }
750 
751  rail->channelEntryPoints.pInterface = context;
752  return TRUE;
753 error_out:
754 
755  if (isFreerdp)
756  free(rail->context);
757 
758  free(rail);
759  return FALSE;
760 }
Definition: svc.h:61