Remmina - The GTK+ Remote Desktop Client  v1.4.2
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
rdp_plugin.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 
38 #define _GNU_SOURCE
39 
40 #include "rdp_plugin.h"
41 #include "rdp_event.h"
42 #include "rdp_graphics.h"
43 #include "rdp_file.h"
44 #include "rdp_settings.h"
45 #include "rdp_cliprdr.h"
46 #include "rdp_channels.h"
47 
48 #include <errno.h>
49 #include <pthread.h>
50 #include <time.h>
51 #include <cairo/cairo-xlib.h>
52 #include <freerdp/addin.h>
53 #include <freerdp/settings.h>
54 #include <freerdp/freerdp.h>
55 #include <freerdp/constants.h>
56 #include <freerdp/client/cliprdr.h>
57 #include <freerdp/client/channels.h>
58 #include <freerdp/client/cmdline.h>
59 #include <freerdp/error.h>
60 #include <freerdp/event.h>
61 #include <winpr/memory.h>
62 #include <ctype.h>
63 
64 #ifdef HAVE_CUPS
65 #include <cups/cups.h>
66 #endif
67 
68 #include <string.h>
69 
70 #ifdef GDK_WINDOWING_X11
71 #include <X11/Xlib.h>
72 #include <X11/XKBlib.h>
73 #include <gdk/gdkx.h>
74 #endif
75 
76 #if defined(__FreeBSD__)
77 #include <pthread_np.h>
78 #endif
79 
80 #define REMMINA_RDP_FEATURE_TOOL_REFRESH 1
81 #define REMMINA_RDP_FEATURE_SCALE 2
82 #define REMMINA_RDP_FEATURE_UNFOCUS 3
83 #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4
84 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5
85 
86 /* Some string settings of FreeRDP are preallocated buffers of N bytes */
87 #define FREERDP_CLIENTHOSTNAME_LEN 32
88 
90 static char remmina_rdp_plugin_default_drive_name[] = "RemminaDisk";
91 
92 static BOOL gfx_h264_available = FALSE;
93 
95 {
96  TRACE_CALL(__func__);
97  UINT16 flags;
98  rdpInput *input;
99  rfContext *rfi = GET_PLUGIN_DATA(gp);
100  RemminaPluginRdpEvent *event;
101  DISPLAY_CONTROL_MONITOR_LAYOUT *dcml;
102  CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
103 
104  if (rfi->event_queue == NULL)
105  return True;
106 
107  input = rfi->instance->input;
108 
109  while ((event = (RemminaPluginRdpEvent *)g_async_queue_try_pop(rfi->event_queue)) != NULL) {
110  switch (event->type) {
112  flags = event->key_event.extended ? KBD_FLAGS_EXTENDED : 0;
113  flags |= event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
114  input->KeyboardEvent(input, flags, event->key_event.key_code);
115  break;
116 
118  /*
119  * TS_UNICODE_KEYBOARD_EVENT RDP message, see https://msdn.microsoft.com/en-us/library/cc240585.aspx
120  */
121  flags = event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
122  input->UnicodeKeyboardEvent(input, flags, event->key_event.unicode_code);
123  break;
124 
126  if (event->mouse_event.extended)
127  input->ExtendedMouseEvent(input, event->mouse_event.flags,
128  event->mouse_event.x, event->mouse_event.y);
129  else
130  input->MouseEvent(input, event->mouse_event.flags,
131  event->mouse_event.x, event->mouse_event.y);
132  break;
133 
135  rfi->clipboard.context->ClientFormatList(rfi->clipboard.context, event->clipboard_formatlist.pFormatList);
136  free(event->clipboard_formatlist.pFormatList);
137  break;
138 
140  response.msgFlags = (event->clipboard_formatdataresponse.data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
141  response.dataLen = event->clipboard_formatdataresponse.size;
142  response.requestedFormatData = event->clipboard_formatdataresponse.data;
143  rfi->clipboard.context->ClientFormatDataResponse(rfi->clipboard.context, &response);
144  break;
145 
147  rfi->clipboard.context->ClientFormatDataRequest(rfi->clipboard.context, event->clipboard_formatdatarequest.pFormatDataRequest);
148  free(event->clipboard_formatdatarequest.pFormatDataRequest);
149  break;
150 
152  dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
153  if (dcml) {
154  dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
155  dcml->Width = event->monitor_layout.width;
156  dcml->Height = event->monitor_layout.height;
157  dcml->Orientation = event->monitor_layout.desktopOrientation;
158  dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
159  dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
160  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml);
161  g_free(dcml);
162  }
163  break;
165  /* Disconnect requested via GUI (i.e: tab destroy/close) */
166  freerdp_abort_connect(rfi->instance);
167  break;
168  }
169 
170  g_free(event);
171  }
172 
173  return True;
174 }
175 
177 {
178  TRACE_CALL(__func__);
179 
180  /* Opens the optional SSH tunnel if needed.
181  * Used also when reopening the same tunnel for a FreeRDP reconnect.
182  * Returns TRUE if all OK, and setups correct rfi->Settings values
183  * with connection and certificate parameters */
184 
185  gchar *hostport;
186  gchar *s;
187  gchar *host;
188  gchar *cert_host;
189  gint cert_port;
190  gint port;
191 
192  rfContext *rfi = GET_PLUGIN_DATA(gp);
193  remmina_plugin_service->debug("Tunnel init");
194  hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 3389, FALSE);
195  if (hostport == NULL)
196  return FALSE;
197 
198  remmina_plugin_service->get_server_port(hostport, 3389, &host, &port);
199 
200  remmina_plugin_service->debug("protocol_plugin_start_direct_tunnel() returned %s", hostport);
201 
202  cert_host = host;
203  cert_port = port;
204 
205  if (!rfi->is_reconnecting) {
206  /* settings->CertificateName and settings->ServerHostname is created
207  * only on 1st connect, not on reconnections */
208 
209  rfi->settings->ServerHostname = strdup(host);
210 
211  if (cert_port == 3389) {
212  rfi->settings->CertificateName = strdup(cert_host);
213  } else {
214  s = g_strdup_printf("%s:%d", cert_host, cert_port);
215  rfi->settings->CertificateName = strdup(s);
216  g_free(s);
217  }
218  }
219 
220  remmina_plugin_service->debug("Tunnel has been optionally initialized. Now connecting to %s:%d", host, port);
221 
222  if (cert_host != host) g_free(cert_host);
223  g_free(host);
224  g_free(hostport);
225 
226  rfi->settings->ServerPort = port;
227 
228 
229 
230  return TRUE;
231 }
232 
234 {
235  TRACE_CALL(__func__);
236  rdpSettings *settings = rfi->instance->settings;
238  time_t treconn;
239 
240  rfi->is_reconnecting = TRUE;
241  rfi->reconnect_maxattempts = settings->AutoReconnectMaxRetries;
242  rfi->reconnect_nattempt = 0;
243 
244  /* Only auto reconnect on network disconnects. */
245  if (freerdp_error_info(rfi->instance) != 0) {
246  rfi->is_reconnecting = FALSE;
247  return FALSE;
248  }
249 
250  if (!settings->AutoReconnectionEnabled) {
251  /* No auto-reconnect - just quit */
252  rfi->is_reconnecting = FALSE;
253  return FALSE;
254  }
255 
256  /* A network disconnect was detected and we should try to reconnect */
257  remmina_plugin_service->debug("[%s] network disconnection detected, initiating reconnection attempt",
258  rfi->settings->ServerHostname);
259 
260  ui = g_new0(RemminaPluginRdpUiObject, 1);
263 
264  /* Sleep half a second to allow:
265  * - processing of the UI event we just pushed on the queue
266  * - better network conditions
267  * Remember: We hare on a thread, so the main gui won’t lock */
268 
269  usleep(500000);
270 
271  /* Perform an auto-reconnect. */
272  while (TRUE) {
273  /* Quit retrying if max retries has been exceeded */
274  if (rfi->reconnect_nattempt++ >= rfi->reconnect_maxattempts) {
275  remmina_plugin_service->debug("[%s] maximum number of reconnection attempts exceeded.",
276  rfi->settings->ServerHostname);
277  break;
278  }
279 
280  /* Attempt the next reconnect */
281  remmina_plugin_service->debug("[%s] reconnection, attempt #%d of %d",
282  rfi->settings->ServerHostname, rfi->reconnect_nattempt, rfi->reconnect_maxattempts);
283 
284  ui = g_new0(RemminaPluginRdpUiObject, 1);
287 
288  treconn = time(NULL);
289 
290  /* Reconnect the SSH tunnel, if needed */
292  remmina_plugin_service->debug("[%s] unable to recreate tunnel with remmina_rdp_tunnel_init.",
293  rfi->settings->ServerHostname);
294  } else {
295  if (freerdp_reconnect(rfi->instance)) {
296  /* Reconnection is successful */
297  remmina_plugin_service->debug("[%s] reconnected.", rfi->settings->ServerHostname);
298  rfi->is_reconnecting = FALSE;
299  return TRUE;
300  }
301  }
302 
303  /* Wait until 5 secs have elapsed from last reconnect attempt */
304  while (time(NULL) - treconn < 5)
305  sleep(1);
306  }
307 
308  rfi->is_reconnecting = FALSE;
309  return FALSE;
310 }
311 
312 BOOL rf_begin_paint(rdpContext *context)
313 {
314  TRACE_CALL(__func__);
315  rdpGdi *gdi;
316 
317  if (!context)
318  return FALSE;
319 
320  gdi = context->gdi;
321  if (!gdi || !gdi->primary || !gdi->primary->hdc || !gdi->primary->hdc->hwnd)
322  return FALSE;
323 
324  return TRUE;
325 }
326 
327 BOOL rf_end_paint(rdpContext *context)
328 {
329  TRACE_CALL(__func__);
330  rdpGdi *gdi;
331  rfContext *rfi;
333  int i, ninvalid;
334  region *reg;
335  HGDI_RGN cinvalid;
336 
337  gdi = context->gdi;
338  rfi = (rfContext *)context;
339 
340  if (gdi->primary->hdc->hwnd->invalid->null)
341  return TRUE;
342 
343  if (gdi->primary->hdc->hwnd->ninvalid < 1)
344  return TRUE;
345 
346  ninvalid = gdi->primary->hdc->hwnd->ninvalid;
347  cinvalid = gdi->primary->hdc->hwnd->cinvalid;
348  reg = (region *)g_malloc(sizeof(region) * ninvalid);
349  for (i = 0; i < ninvalid; i++) {
350  reg[i].x = cinvalid[i].x;
351  reg[i].y = cinvalid[i].y;
352  reg[i].w = cinvalid[i].w;
353  reg[i].h = cinvalid[i].h;
354  }
355 
356  ui = g_new0(RemminaPluginRdpUiObject, 1);
358  ui->reg.ninvalid = ninvalid;
359  ui->reg.ureg = reg;
360 
362 
363 
364  gdi->primary->hdc->hwnd->invalid->null = TRUE;
365  gdi->primary->hdc->hwnd->ninvalid = 0;
366 
367 
368  return TRUE;
369 }
370 
371 static BOOL rf_desktop_resize(rdpContext *context)
372 {
373  TRACE_CALL(__func__);
374  rfContext *rfi;
377 
378  rfi = (rfContext *)context;
379  gp = rfi->protocol_widget;
380 
381  remmina_plugin_service->protocol_plugin_set_width(gp, rfi->settings->DesktopWidth);
382  remmina_plugin_service->protocol_plugin_set_height(gp, rfi->settings->DesktopHeight);
383 
384  ui = g_new0(RemminaPluginRdpUiObject, 1);
388 
389  /* Tell libfreerdp to change its internal GDI bitmap width and heigt,
390  * this will also destroy gdi->primary_buffer, making our rfi->surface invalid */
391  gdi_resize(((rdpContext *)rfi)->gdi, rfi->settings->DesktopWidth, rfi->settings->DesktopHeight);
392 
393  /* Call to remmina_rdp_event_update_scale(gp) on the main UI thread,
394  * this will recreate rfi->surface from gdi->primary_buffer */
395 
396  ui = g_new0(RemminaPluginRdpUiObject, 1);
400 
401  remmina_plugin_service->protocol_plugin_desktop_resize(gp);
402 
403  return TRUE;
404 }
405 
406 static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
407 {
408  TRACE_CALL(__func__);
409  rfContext *rfi;
411  GdkDisplay *disp;
412 
413  rfi = (rfContext *)context;
414  gp = rfi->protocol_widget;
415 
416  disp = gtk_widget_get_display(GTK_WIDGET(gp));
417  gdk_display_beep(disp);
418 
419  return TRUE;
420 }
421 
422 static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
423 {
424  TRACE_CALL(__func__);
425  rfContext *rfi;
427  GdkDisplay *disp;
428 
429  rfi = (rfContext *)context;
430  gp = rfi->protocol_widget;
431  disp = gtk_widget_get_display(GTK_WIDGET(gp));
432 
433 #ifdef GDK_WINDOWING_X11
434  if (GDK_IS_X11_DISPLAY(disp)) {
435  /* TODO: We are not on the main thread. Will X.Org complain? */
436  Display *x11_display;
437  x11_display = gdk_x11_display_get_xdisplay(disp);
438  XkbLockModifiers(x11_display, XkbUseCoreKbd,
439  LockMask | Mod2Mask,
440  ((led_flags & KBD_SYNC_CAPS_LOCK) ? LockMask : 0) |
441  ((led_flags & KBD_SYNC_NUM_LOCK) ? Mod2Mask : 0)
442  );
443 
444  /* TODO: Add support to KANA_LOCK and SCROLL_LOCK */
445  }
446 #endif
447 
448  return TRUE;
449 }
450 
451 BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState,
452  UINT32 imeConvMode)
453 {
454  TRACE_CALL(__func__);
455  if (!context)
456  return FALSE;
457 
458  /* Unimplemented, we ignore it */
459 
460  return TRUE;
461 }
462 
463 
464 static BOOL remmina_rdp_pre_connect(freerdp *instance)
465 {
466  TRACE_CALL(__func__);
467  rfContext *rfi;
468  ALIGN64 rdpSettings *settings;
469 
470  rfi = (rfContext *)instance->context;
471  settings = instance->settings;
472 
473  settings->OsMajorType = OSMAJORTYPE_UNIX;
474  settings->OsMinorType = OSMINORTYPE_UNSPECIFIED;
475 
476  settings->BitmapCacheEnabled = True;
477  settings->OffscreenSupportLevel = True;
478 
479  if (settings->RemoteFxCodec == True) {
480  settings->FrameAcknowledge = False;
481  settings->LargePointerFlag = True;
482  settings->PerformanceFlags = PERF_FLAG_NONE;
483 
484  rfi->rfx_context = rfx_context_new(FALSE);
485  }
486 
487  PubSub_SubscribeChannelConnected(instance->context->pubSub,
488  (pChannelConnectedEventHandler)remmina_rdp_OnChannelConnectedEventHandler);
489  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
490  (pChannelDisconnectedEventHandler)remmina_rdp_OnChannelDisconnectedEventHandler);
491 
492  freerdp_client_load_addins(instance->context->channels, instance->settings);
493 
494  return True;
495 }
496 
497 static BOOL remmina_rdp_post_connect(freerdp *instance)
498 {
499  TRACE_CALL(__func__);
500  rfContext *rfi;
503  UINT32 freerdp_local_color_format;
504 
505  rfi = (rfContext *)instance->context;
506  gp = rfi->protocol_widget;
507  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_OK;
508 
509  rfi->attempt_interactive_authentication = FALSE; // We authenticated!
510 
511  rfi->srcBpp = rfi->settings->ColorDepth;
512 
513  if (rfi->settings->RemoteFxCodec == FALSE)
514  rfi->sw_gdi = TRUE;
515 
516  rf_register_graphics(instance->context->graphics);
517 
518  if (rfi->bpp == 32) {
519  freerdp_local_color_format = PIXEL_FORMAT_BGRA32;
520  rfi->cairo_format = CAIRO_FORMAT_ARGB32;
521  } else if (rfi->bpp == 24) {
522  /* CAIRO_FORMAT_RGB24 is 32bit aligned, so we map it to libfreerdp’s PIXEL_FORMAT_BGRX32 */
523  freerdp_local_color_format = PIXEL_FORMAT_BGRX32;
524  rfi->cairo_format = CAIRO_FORMAT_RGB24;
525  } else {
526  freerdp_local_color_format = PIXEL_FORMAT_RGB16;
527  rfi->cairo_format = CAIRO_FORMAT_RGB16_565;
528  }
529 
530  if (!gdi_init(instance, freerdp_local_color_format)) {
531  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_GDI_INIT;
532  return FALSE;
533  }
534 
535  if (instance->context->codecs->h264 == NULL && rfi->settings->GfxH264) {
536  gdi_free(instance);
537  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_NO_H264;
538  return FALSE;
539  }
540 
541  // pointer_cache_register_callbacks(instance->update);
542 
543  instance->update->BeginPaint = rf_begin_paint;
544  instance->update->EndPaint = rf_end_paint;
545  instance->update->DesktopResize = rf_desktop_resize;
546 
547  instance->update->PlaySound = rf_play_sound;
548  instance->update->SetKeyboardIndicators = rf_keyboard_set_indicators;
549  instance->update->SetKeyboardImeStatus = rf_keyboard_set_ime_status;
550 
552  rfi->connected = True;
553 
554  ui = g_new0(RemminaPluginRdpUiObject, 1);
557 
558  return TRUE;
559 }
560 
561 static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
562 {
563  TRACE_CALL(__func__);
564  gchar *s_username, *s_password, *s_domain;
565  gint ret;
566  rfContext *rfi;
568  gboolean save;
569  gboolean disablepasswordstoring;
570  RemminaFile *remminafile;
571 
572  rfi = (rfContext *)instance->context;
573  gp = rfi->protocol_widget;
574  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
575  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
576 
577  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
579  _("Enter RDP authentication credentials"),
580  remmina_plugin_service->file_get_string(remminafile, "username"),
581  remmina_plugin_service->file_get_string(remminafile, "password"),
582  remmina_plugin_service->file_get_string(remminafile, "domain"),
583  NULL);
584  if (ret == GTK_RESPONSE_OK) {
585  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
586  if (s_username) rfi->settings->Username = strdup(s_username);
587 
588  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
589  if (s_password) rfi->settings->Password = strdup(s_password);
590 
591  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
592  if (s_domain) rfi->settings->Domain = strdup(s_domain);
593 
594  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
595  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
596 
597  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
598  if (save) {
599  // User has requested to save credentials. We put the password
600  // into remminafile->settings. It will be saved later, on successful connection, by
601  // rcw.c
602  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
603  } else {
604  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
605  }
606 
607 
608  if (s_username) g_free(s_username);
609  if (s_password) g_free(s_password);
610  if (s_domain) g_free(s_domain);
611 
612  return TRUE;
613  } else {
614  return FALSE;
615  }
616 
617  return TRUE;
618 }
619 
620 static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
621 {
622  TRACE_CALL(__func__);
623  gchar *s_username, *s_password, *s_domain;
624  gint ret;
625  rfContext *rfi;
627  gboolean save;
628  gboolean disablepasswordstoring;
629  RemminaFile *remminafile;
630 
631  rfi = (rfContext *)instance->context;
632  gp = rfi->protocol_widget;
633  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
634 
635  if (!remmina_plugin_service->file_get_string(remminafile, "gateway_server"))
636  return False;
637  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
638 
639  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
641  _("Enter RDP gateway authentication credentials"),
642  remmina_plugin_service->file_get_string(remminafile, "gateway_username"),
643  remmina_plugin_service->file_get_string(remminafile, "gateway_password"),
644  remmina_plugin_service->file_get_string(remminafile, "gateway_domain"),
645  NULL);
646 
647  if (ret == GTK_RESPONSE_OK) {
648  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
649  if (s_username) rfi->settings->GatewayUsername = strdup(s_username);
650 
651  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
652  if (s_password) rfi->settings->GatewayPassword = strdup(s_password);
653 
654  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
655  if (s_domain) rfi->settings->GatewayDomain = strdup(s_domain);
656 
657  remmina_plugin_service->file_set_string(remminafile, "gateway_username", s_username);
658  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", s_domain);
659 
660  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
661  if (save) {
662  remmina_plugin_service->file_set_string(remminafile, "gateway_password", s_password);
663  } else {
664  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
665  }
666 
667  if (s_username) g_free(s_username);
668  if (s_password) g_free(s_password);
669  if (s_domain) g_free(s_domain);
670 
671  return True;
672  } else {
673  return False;
674  }
675 
676  return True;
677 }
678 
679 
680 static DWORD remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject,
681  const char *issuer, const char *fingerprint, BOOL host_mismatch)
682 {
683  TRACE_CALL(__func__);
684  gint status;
685  rfContext *rfi;
687 
688  rfi = (rfContext *)instance->context;
689  gp = rfi->protocol_widget;
690 
691  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
692 
693  if (status == GTK_RESPONSE_OK)
694  return 1;
695 
696  return 0;
697 }
698 static DWORD remmina_rdp_verify_changed_certificate(freerdp *instance,
699  const char *common_name, const char *subject, const char *issuer,
700  const char *new_fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint)
701 {
702  TRACE_CALL(__func__);
703  gint status;
704  rfContext *rfi;
706 
707  rfi = (rfContext *)instance->context;
708  gp = rfi->protocol_widget;
709 
710  status = remmina_plugin_service->protocol_plugin_changed_certificate(gp, subject, issuer, new_fingerprint, old_fingerprint);
711 
712  if (status == GTK_RESPONSE_OK)
713  return 1;
714 
715  return 0;
716 }
717 
718 static void remmina_rdp_post_disconnect(freerdp *instance)
719 {
720  TRACE_CALL(__func__);
721 
722  if (!instance || !instance->context)
723  return;
724 
725  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
726  (pChannelConnectedEventHandler)remmina_rdp_OnChannelConnectedEventHandler);
727  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
728  (pChannelDisconnectedEventHandler)remmina_rdp_OnChannelDisconnectedEventHandler);
729 
730  /* The remaining cleanup will be continued on main thread by complete_cleanup_on_main_thread() */
731 
732 }
733 
735 {
736  TRACE_CALL(__func__);
737  DWORD nCount;
738  DWORD status;
739  HANDLE handles[64];
740  gchar buf[100];
741  rfContext *rfi = GET_PLUGIN_DATA(gp);
742 
743 
744  while (!freerdp_shall_disconnect(rfi->instance)) {
745  nCount = freerdp_get_event_handles(rfi->instance->context, &handles[0], 64);
746  if (rfi->event_handle)
747  handles[nCount++] = rfi->event_handle;
748 
749  handles[nCount++] = rfi->instance->context->abortEvent;
750 
751  if (nCount == 0) {
752  fprintf(stderr, "freerdp_get_event_handles failed\n");
753  break;
754  }
755 
756  status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
757 
758  if (status == WAIT_FAILED) {
759  fprintf(stderr, "WaitForMultipleObjects failed with %lu\n", (unsigned long)status);
760  break;
761  }
762 
763  if (rfi->event_handle && WaitForSingleObject(rfi->event_handle, 0) == WAIT_OBJECT_0) {
764  if (!rf_process_event_queue(gp)) {
765  fprintf(stderr, "Could not process local keyboard/mouse event queue\n");
766  break;
767  }
768  if (read(rfi->event_pipe[0], buf, sizeof(buf))) {
769  }
770  }
771 
772  /* Check if a processed event called freerdp_abort_connect() and exit if true */
773  if (WaitForSingleObject(rfi->instance->context->abortEvent, 0) == WAIT_OBJECT_0)
774  /* Session disconnected by local user action */
775  break;
776 
777  if (!freerdp_check_event_handles(rfi->instance->context)) {
778  if (rf_auto_reconnect(rfi)) {
779  /* Reset the possible reason/error which made us doing many reconnection reattempts and continue */
780  remmina_plugin_service->protocol_plugin_set_error(gp, NULL);
781  continue;
782  }
783  if (freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS)
784  fprintf(stderr, "Could not check FreeRDP file descriptor\n");
785  break;
786  }
787  }
788  freerdp_disconnect(rfi->instance);
789  remmina_plugin_service->debug("RDP client disconnected");
790 }
791 
792 int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
793 {
794  TRACE_CALL(__func__);
795  PVIRTUALCHANNELENTRY entry = NULL;
796  PVIRTUALCHANNELENTRYEX entryEx = NULL;
797  entryEx = (PVIRTUALCHANNELENTRYEX)(void*)freerdp_load_channel_addin_entry(
798  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
799 
800  if (!entryEx)
801  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
802 
803  if (entryEx)
804  {
805  if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0)
806  {
807  fprintf(stderr, "loading channel %s\n", name);
808  return TRUE;
809  }
810  }
811  else if (entry)
812  {
813  if (freerdp_channels_client_load(channels, settings, entry, data) == 0)
814  {
815  fprintf(stderr, "loading channel %s\n", name);
816  return TRUE;
817  }
818  }
819 
820  return FALSE;
821 }
822 
823 gchar *remmina_rdp_find_prdriver(char *smap, char *prn)
824 {
825  char c, *p, *dr;
826  int matching;
827  size_t sz;
828 
829  enum { S_WAITPR,
830  S_INPRINTER,
831  S_WAITCOLON,
832  S_WAITDRIVER,
833  S_INDRIVER,
834  S_WAITSEMICOLON } state = S_WAITPR;
835 
836  matching = 0;
837  while ((c = *smap++) != 0) {
838  switch (state) {
839  case S_WAITPR:
840  if (c != '\"') return NULL;
841  state = S_INPRINTER;
842  p = prn;
843  matching = 1;
844  break;
845  case S_INPRINTER:
846  if (matching && c == *p && *p != 0) {
847  p++;
848  } else if (c == '\"') {
849  if (*p != 0)
850  matching = 0;
851  state = S_WAITCOLON;
852  } else {
853  matching = 0;
854  }
855  break;
856  case S_WAITCOLON:
857  if (c != ':')
858  return NULL;
859  state = S_WAITDRIVER;
860  break;
861  case S_WAITDRIVER:
862  if (c != '\"')
863  return NULL;
864  state = S_INDRIVER;
865  dr = smap;
866  break;
867  case S_INDRIVER:
868  if (c == '\"') {
869  if (matching)
870  goto found;
871  else
872  state = S_WAITSEMICOLON;
873  }
874  break;
875  case S_WAITSEMICOLON:
876  if (c != ';')
877  return NULL;
878  state = S_WAITPR;
879  break;
880  }
881  }
882  return NULL;
883 
884 found:
885  sz = smap - dr;
886  p = (char *)malloc(sz);
887  memcpy(p, dr, sz);
888  p[sz - 1] = 0;
889  return p;
890 }
891 
892 #ifdef HAVE_CUPS
893 
898 int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
899 {
900  rfContext *rfi = (rfContext *)user_data;
902  rdpChannels *channels;
903 
904  channels = rfi->instance->context->channels;
905 
919  const char *model = NULL;
920 
921  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
922  const gchar *s = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
923 
924  RDPDR_PRINTER *printer;
925  printer = (RDPDR_PRINTER *)calloc(1, sizeof(RDPDR_PRINTER));
926 
927  printer->Type = RDPDR_DTYP_PRINT;
928  remmina_plugin_service->debug("Printer Type: %d", printer->Type);
929 
930  rfi->settings->RedirectPrinters = TRUE;
931  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdpdr", rfi->settings);
932 
933  remmina_plugin_service->debug("Destination: %s", dest->name);
934  if (!(printer->Name = _strdup(dest->name))) {
935  free(printer);
936  return 1;
937  }
938 
939  remmina_plugin_service->debug("Printer Name: %s", printer->Name);
940 
941  if (s) {
942  gchar *d = remmina_rdp_find_prdriver(strdup(s), printer->Name);
943  if (d) {
944  printer->DriverName = strdup(d);
945  remmina_plugin_service->debug("Printer DriverName set to: %s", printer->DriverName);
946  g_free(d);
947  } else {
953  free(printer->Name);
954  free(printer);
955  return 1;
956  }
957  } else {
958  /* We set to a default driver*/
959  model = _strdup("MS Publisher Imagesetter");
960  printer->DriverName = _strdup(model);
961  }
962 
963  remmina_plugin_service->debug("Printer Driver: %s", printer->DriverName);
964  if (!freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)printer)) {
965  free(printer->DriverName);
966  free(printer->Name);
967  free(printer);
968  return 1;
969  }
970  rfi->settings->DeviceRedirection = TRUE;
971  return 1;
972 }
973 #endif /* HAVE_CUPS */
974 
975 /* Send Ctrl+Alt+Del keystrokes to the plugin drawing_area widget */
977 {
978  TRACE_CALL(__func__);
979  guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
980  rfContext *rfi = GET_PLUGIN_DATA(gp);
981 
982  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
983  keys, G_N_ELEMENTS(keys), GDK_KEY_PRESS | GDK_KEY_RELEASE);
984 }
985 
987 {
988  TRACE_CALL(__func__);
989  const gchar *s;
990  gchar *sm;
991  gchar *value;
992  gint rdpsnd_rate;
993  gint rdpsnd_channel;
994  char *rdpsnd_params[3];
995  int rdpsnd_nparams;
996  char rdpsnd_param1[16];
997  char rdpsnd_param2[16];
998  const gchar *cs;
999  RemminaFile *remminafile;
1000  rfContext *rfi = GET_PLUGIN_DATA(gp);
1001  rdpChannels *channels;
1002  gchar *gateway_host;
1003  gint gateway_port;
1004 
1005  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
1006 
1007  channels = rfi->instance->context->channels;
1008 
1009  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1010 
1011 #if defined(PROXY_TYPE_IGNORE)
1012  if (!remmina_plugin_service->file_get_int(remminafile, "useproxyenv", FALSE) ? TRUE : FALSE) {
1013  remmina_plugin_service->debug("Not using system proxy settings");
1014  rfi->settings->ProxyType = PROXY_TYPE_IGNORE;
1015  }
1016 #endif
1017 
1018  if (!remmina_rdp_tunnel_init(gp))
1019  return FALSE;
1020 
1021  rfi->settings->AutoReconnectionEnabled = (remmina_plugin_service->file_get_int(remminafile, "disableautoreconnect", FALSE) ? FALSE : TRUE);
1022  /* Disable RDP auto reconnection when SSH tunnel is enabled */
1023  if (remmina_plugin_service->file_get_int(remminafile, "ssh_tunnel_enabled", FALSE))
1024  rfi->settings->AutoReconnectionEnabled = FALSE;
1025 
1026  rfi->settings->ColorDepth = remmina_plugin_service->file_get_int(remminafile, "colordepth", 66);
1027 
1028  rfi->settings->SoftwareGdi = TRUE;
1029 
1030  /* Avoid using H.264 modes if they are not available on libfreerdp */
1031  if (!gfx_h264_available && (rfi->settings->ColorDepth == 65 || rfi->settings->ColorDepth == 66))
1032  rfi->settings->ColorDepth = 64; // Fallback to GFX RFX
1033 
1034  if (rfi->settings->ColorDepth == 0) {
1035  /* RFX (Win7)*/
1036  rfi->settings->RemoteFxCodec = TRUE;
1037  rfi->settings->SupportGraphicsPipeline = FALSE;
1038  rfi->settings->ColorDepth = 32;
1039  } else if (rfi->settings->ColorDepth == 64) {
1040  /* /gfx:rfx (Win8) */
1041  rfi->settings->ColorDepth = 32;
1042  rfi->settings->SupportGraphicsPipeline = TRUE;
1043  rfi->settings->GfxH264 = FALSE;
1044  rfi->settings->GfxAVC444 = FALSE;
1045  } else if (rfi->settings->ColorDepth == 65) {
1046  /* /gfx:avc420 (Win8.1) */
1047  rfi->settings->ColorDepth = 32;
1048  rfi->settings->SupportGraphicsPipeline = TRUE;
1049  rfi->settings->GfxH264 = TRUE;
1050  rfi->settings->GfxAVC444 = FALSE;
1051  } else if (rfi->settings->ColorDepth >= 66) {
1052  /* /gfx:avc444 (Win10) */
1053  rfi->settings->ColorDepth = 32;
1054  rfi->settings->SupportGraphicsPipeline = TRUE;
1055  rfi->settings->GfxH264 = TRUE;
1056  rfi->settings->GfxAVC444 = TRUE;
1057  }
1058 
1059  rfi->settings->DesktopWidth = remmina_plugin_service->get_profile_remote_width(gp);
1060  rfi->settings->DesktopHeight = remmina_plugin_service->get_profile_remote_height(gp);
1061 
1062  /* Workaround for FreeRDP issue #5417: in GFX AVC modes we can't go under
1063  * AVC_MIN_DESKTOP_WIDTH x AVC_MIN_DESKTOP_HEIGHT */
1064  if (rfi->settings->SupportGraphicsPipeline && rfi->settings->GfxH264) {
1065  if (rfi->settings->DesktopWidth < AVC_MIN_DESKTOP_WIDTH)
1066  rfi->settings->DesktopWidth = AVC_MIN_DESKTOP_WIDTH;
1067  if (rfi->settings->DesktopHeight < AVC_MIN_DESKTOP_HEIGHT)
1068  rfi->settings->DesktopHeight = AVC_MIN_DESKTOP_HEIGHT;
1069  }
1070 
1071  /* Workaround for FreeRDP issue #5119. This will make our horizontal resolution
1072  * an even value, but it will add a vertical black 1 pixel line on the
1073  * right of the desktop */
1074  if ((rfi->settings->DesktopWidth & 1) != 0)
1075  rfi->settings->DesktopWidth -= 1;
1076 
1077  remmina_plugin_service->protocol_plugin_set_width(gp, rfi->settings->DesktopWidth);
1078  remmina_plugin_service->protocol_plugin_set_height(gp, rfi->settings->DesktopHeight);
1079 
1080 
1081  if (remmina_plugin_service->file_get_string(remminafile, "username"))
1082  rfi->settings->Username = strdup(remmina_plugin_service->file_get_string(remminafile, "username"));
1083 
1084  if (remmina_plugin_service->file_get_string(remminafile, "domain"))
1085  rfi->settings->Domain = strdup(remmina_plugin_service->file_get_string(remminafile, "domain"));
1086 
1087  s = remmina_plugin_service->file_get_string(remminafile, "password");
1088  if (s) rfi->settings->Password = strdup(s);
1089 
1090  rfi->settings->AutoLogonEnabled = 1;
1091 
1096  gchar *proxy_type = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_type"));
1097  gchar *proxy_username = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_username"));
1098  gchar *proxy_password = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_password"));
1099  gchar *proxy_hostname = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_hostname"));
1100  gint proxy_port = remmina_plugin_service->file_get_int(remminafile, "proxy_port", 80);
1101  remmina_plugin_service->debug("proxy_type: %s", proxy_type);
1102  remmina_plugin_service->debug("proxy_username: %s", proxy_username);
1103  remmina_plugin_service->debug("proxy_password: %s", proxy_password);
1104  remmina_plugin_service->debug("proxy_hostname: %s", proxy_hostname);
1105  remmina_plugin_service->debug("proxy_port: %d", proxy_port);
1106  if (proxy_type && proxy_hostname) {
1107  if (g_strcmp0(proxy_type, "no_proxy") == 0)
1108  rfi->settings->ProxyType = PROXY_TYPE_IGNORE;
1109  else if (g_strcmp0(proxy_type, "http") == 0)
1110  rfi->settings->ProxyType = PROXY_TYPE_HTTP;
1111  else if (g_strcmp0(proxy_type, "socks5") == 0)
1112  rfi->settings->ProxyType = PROXY_TYPE_SOCKS;
1113  else
1114  g_warning("Invalid proxy protocol, at the moment only no_proxy, HTTP and SOCKS5 are supported");
1115  remmina_plugin_service->debug("ProxyType set to: %d", rfi->settings->ProxyType);
1116  rfi->settings->ProxyHostname = proxy_hostname;
1117  if (proxy_username)
1118  rfi->settings->ProxyUsername = proxy_username;
1119  if (proxy_password)
1120  rfi->settings->ProxyPassword = proxy_password;
1121  if (proxy_port)
1122  rfi->settings->ProxyPort = proxy_port;
1123  }
1124 
1125  /* Remote Desktop Gateway server address */
1126  rfi->settings->GatewayEnabled = FALSE;
1127  s = remmina_plugin_service->file_get_string(remminafile, "gateway_server");
1128  if (s) {
1129  cs = remmina_plugin_service->file_get_string(remminafile, "gwtransp");
1130  if (g_strcmp0(cs, "http") == 0) {
1131  rfi->settings->GatewayRpcTransport = False;
1132  rfi->settings->GatewayHttpTransport = True;
1133  } else if (g_strcmp0(cs, "rpc") == 0) {
1134  rfi->settings->GatewayRpcTransport = True;
1135  rfi->settings->GatewayHttpTransport = False;
1136  } else if (g_strcmp0(cs, "auto") == 0) {
1137  rfi->settings->GatewayRpcTransport = True;
1138  rfi->settings->GatewayHttpTransport = True;
1139  }
1140  remmina_plugin_service->get_server_port(s, 443, &gateway_host, &gateway_port);
1141  rfi->settings->GatewayHostname = gateway_host;
1142  rfi->settings->GatewayPort = gateway_port;
1143  rfi->settings->GatewayEnabled = TRUE;
1144  rfi->settings->GatewayUseSameCredentials = TRUE;
1145  }
1146  /* Remote Desktop Gateway domain */
1147  if (remmina_plugin_service->file_get_string(remminafile, "gateway_domain")) {
1148  rfi->settings->GatewayDomain = strdup(remmina_plugin_service->file_get_string(remminafile, "gateway_domain"));
1149  rfi->settings->GatewayUseSameCredentials = FALSE;
1150  }
1151  /* Remote Desktop Gateway username */
1152  if (remmina_plugin_service->file_get_string(remminafile, "gateway_username")) {
1153  rfi->settings->GatewayUsername = strdup(remmina_plugin_service->file_get_string(remminafile, "gateway_username"));
1154  rfi->settings->GatewayUseSameCredentials = FALSE;
1155  }
1156  /* Remote Desktop Gateway password */
1157  s = remmina_plugin_service->file_get_string(remminafile, "gateway_password");
1158  if (s) {
1159  rfi->settings->GatewayPassword = strdup(s);
1160  rfi->settings->GatewayUseSameCredentials = FALSE;
1161  }
1162  /* If no different credentials were provided for the Remote Desktop Gateway
1163  * use the same authentication credentials for the host */
1164  if (rfi->settings->GatewayEnabled && rfi->settings->GatewayUseSameCredentials) {
1165  g_free(rfi->settings->GatewayDomain);
1166  rfi->settings->GatewayDomain = g_strdup(rfi->settings->Domain);
1167  g_free(rfi->settings->GatewayUsername);
1168  rfi->settings->GatewayUsername = g_strdup(rfi->settings->Username);
1169  g_free(rfi->settings->GatewayPassword);
1170  rfi->settings->GatewayPassword = g_strdup(rfi->settings->Password);
1171  }
1172  /* Remote Desktop Gateway usage */
1173  if (rfi->settings->GatewayEnabled)
1174  freerdp_set_gateway_usage_method(rfi->settings,
1175  remmina_plugin_service->file_get_int(remminafile, "gateway_usage", FALSE) ? TSC_PROXY_MODE_DETECT : TSC_PROXY_MODE_DIRECT);
1176 
1177 #ifdef WITH_FREERDP_MASTER
1178 #pragma message "Using FreeRDP master branch!"
1179  /* TODO: As soon as FreeRDP 2.0.0-rc5 will be available, implement an ifdef with that version */
1180  freerdp_settings_set_string(rfi->settings, (size_t)FreeRDP_GatewayAccessToken,
1181  remmina_plugin_service->file_get_string(remminafile, "gatewayaccesstoken"));
1182 #else
1183  rfi->settings->GatewayAccessToken = g_strdup(
1184  remmina_plugin_service->file_get_string(remminafile, "gatewayaccesstoken"));
1185 #endif
1186 
1187  rfi->settings->AuthenticationLevel = remmina_plugin_service->file_get_int(
1188  remminafile, "authentication level", rfi->settings->AuthenticationLevel);
1189 
1190  /* Certificate ignore */
1191  rfi->settings->IgnoreCertificate = remmina_plugin_service->file_get_int(remminafile, "cert_ignore", 0);
1192 
1193  rfi->settings->OldLicenseBehaviour = remmina_plugin_service->file_get_int(remminafile, "old-license", 0);
1194 
1195  rfi->settings->AllowUnanouncedOrdersFromServer = remmina_plugin_service->file_get_int(remminafile, "relax-order-checks", 0);
1196 
1197  rfi->settings->GlyphSupportLevel = (remmina_plugin_service->file_get_int(remminafile, "glyph-cache", 0) ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE);
1198 
1199  /* ClientHostname is internally preallocated to 32 bytes by libfreerdp */
1200  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientname")))
1201  strncpy(rfi->settings->ClientHostname, cs, FREERDP_CLIENTHOSTNAME_LEN - 1);
1202  else
1203  strncpy(rfi->settings->ClientHostname, g_get_host_name(), FREERDP_CLIENTHOSTNAME_LEN - 1);
1204  rfi->settings->ClientHostname[FREERDP_CLIENTHOSTNAME_LEN - 1] = 0;
1205 
1206  /* Client Build number is optional, if not specified defaults to 0, allow for comments to appear after number */
1207  if ((cs=remmina_plugin_service->file_get_string(remminafile, "clientbuild"))) {
1208  if (*cs)
1209  rfi->settings->ClientBuild = strtoul(cs, NULL, 0);
1210  }
1211 
1212 
1213  if (remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo")) {
1214  rfi->settings->LoadBalanceInfo = (BYTE *)strdup(remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo"));
1215  rfi->settings->LoadBalanceInfoLength = (UINT32)strlen((char *)rfi->settings->LoadBalanceInfo);
1216  }
1217 
1218  if (remmina_plugin_service->file_get_string(remminafile, "exec"))
1219  rfi->settings->AlternateShell = strdup(remmina_plugin_service->file_get_string(remminafile, "exec"));
1220 
1221  if (remmina_plugin_service->file_get_string(remminafile, "execpath"))
1222  rfi->settings->ShellWorkingDirectory = strdup(remmina_plugin_service->file_get_string(remminafile, "execpath"));
1223 
1224  sm = g_strdup_printf("rdp_quality_%i", remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0));
1225  value = remmina_plugin_service->pref_get_value(sm);
1226  g_free(sm);
1227 
1228  if (value && value[0]) {
1229  rfi->settings->PerformanceFlags = strtoul(value, NULL, 16);
1230  } else {
1231  switch (remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0)) {
1232  case 9:
1233  rfi->settings->PerformanceFlags = DEFAULT_QUALITY_9;
1234  break;
1235 
1236  case 2:
1237  rfi->settings->PerformanceFlags = DEFAULT_QUALITY_2;
1238  break;
1239 
1240  case 1:
1241  rfi->settings->PerformanceFlags = DEFAULT_QUALITY_1;
1242  break;
1243 
1244  case 0:
1245  default:
1246  rfi->settings->PerformanceFlags = DEFAULT_QUALITY_0;
1247  break;
1248  }
1249  }
1250  g_free(value);
1251 
1252  /* PerformanceFlags bitmask need also to be splitted into BOOL variables
1253  * like rfi->settings->DisableWallpaper, rfi->settings->AllowFontSmoothing…
1254  * or freerdp_get_param_bool() function will return the wrong value
1255  */
1256  freerdp_performance_flags_split(rfi->settings);
1257 
1258  rfi->settings->KeyboardLayout = remmina_rdp_settings_get_keyboard_layout();
1259 
1260  if (remmina_plugin_service->file_get_int(remminafile, "console", FALSE))
1261  rfi->settings->ConsoleSession = True;
1262 
1263  cs = remmina_plugin_service->file_get_string(remminafile, "security");
1264  if (g_strcmp0(cs, "rdp") == 0) {
1265  rfi->settings->RdpSecurity = True;
1266  rfi->settings->TlsSecurity = False;
1267  rfi->settings->NlaSecurity = False;
1268  rfi->settings->ExtSecurity = False;
1269  rfi->settings->UseRdpSecurityLayer = True;
1270  } else if (g_strcmp0(cs, "tls") == 0) {
1271  rfi->settings->RdpSecurity = False;
1272  rfi->settings->TlsSecurity = True;
1273  rfi->settings->NlaSecurity = False;
1274  rfi->settings->ExtSecurity = False;
1275  } else if (g_strcmp0(cs, "nla") == 0) {
1276  rfi->settings->RdpSecurity = False;
1277  rfi->settings->TlsSecurity = False;
1278  rfi->settings->NlaSecurity = True;
1279  rfi->settings->ExtSecurity = False;
1280  } else if (g_strcmp0(cs, "ext") == 0) {
1281  rfi->settings->RdpSecurity = False;
1282  rfi->settings->TlsSecurity = False;
1283  rfi->settings->NlaSecurity = False;
1284  rfi->settings->ExtSecurity = True;
1285  } else
1286  /* This is "-nego" switch of xfreerdp */
1287  rfi->settings->NegotiateSecurityLayer = True;
1288 
1289 
1290  rfi->settings->CompressionEnabled = True;
1291  if (remmina_plugin_service->file_get_int(remminafile, "disable_fastpath", FALSE)) {
1292  rfi->settings->FastPathInput = False;
1293  rfi->settings->FastPathOutput = False;
1294  } else {
1295  rfi->settings->FastPathInput = True;
1296  rfi->settings->FastPathOutput = True;
1297  }
1298 
1299  /* Orientation and scaling settings */
1300  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
1301 
1302  rfi->settings->DesktopOrientation = desktopOrientation;
1303  if (desktopScaleFactor != 0 && deviceScaleFactor != 0) {
1304  rfi->settings->DesktopScaleFactor = desktopScaleFactor;
1305  rfi->settings->DeviceScaleFactor = deviceScaleFactor;
1306  }
1307 
1308  /* Try to enable "Display Control Virtual Channel Extension", needed to
1309  * dynamically resize remote desktop. This will automatically open
1310  * the "disp" dynamic channel, if available */
1311  rfi->settings->SupportDisplayControl = TRUE;
1312 
1313  /* Sound settings */
1314 
1315  cs = remmina_plugin_service->file_get_string(remminafile, "sound");
1316 
1317  if (g_strcmp0(cs, "remote") == 0) {
1318  rfi->settings->RemoteConsoleAudio = TRUE;
1319  } else if (g_str_has_prefix(cs, "local")) {
1320  rfi->settings->AudioPlayback = TRUE;
1321  rfi->settings->DeviceRedirection = TRUE; /* rdpsnd requires rdpdr to be registered */
1322 
1323  rdpsnd_nparams = 0;
1324  rdpsnd_params[rdpsnd_nparams++] = "rdpsnd";
1325 
1326  cs = strchr(cs, ',');
1327  if (cs) {
1328  rdpsnd_rate = atoi(cs + 1);
1329  if (rdpsnd_rate > 1000 && rdpsnd_rate < 150000) {
1330  snprintf(rdpsnd_param1, sizeof(rdpsnd_param1), "rate:%d", rdpsnd_rate);
1331  rdpsnd_params[rdpsnd_nparams++] = rdpsnd_param1;
1332  cs = strchr(cs + 1, ',');
1333  if (cs) {
1334  rdpsnd_channel = atoi(cs + 1);
1335  if (rdpsnd_channel >= 1 && rdpsnd_channel <= 2) {
1336  snprintf(rdpsnd_param2, sizeof(rdpsnd_param2), "channel:%d", rdpsnd_channel);
1337  rdpsnd_params[rdpsnd_nparams++] = rdpsnd_param2;
1338  }
1339  }
1340  }
1341  }
1342 
1343  freerdp_client_add_static_channel(rfi->settings, rdpsnd_nparams, (char **)rdpsnd_params);
1344  } else {
1345  /* Disable sound */
1346  rfi->settings->AudioPlayback = FALSE;
1347  rfi->settings->RemoteConsoleAudio = FALSE;
1348  }
1349 
1350  if (remmina_plugin_service->file_get_int(remminafile, "microphone", FALSE) ? TRUE : FALSE) {
1351  char *p[1];
1352  int count;
1353 
1354  count = 1;
1355  p[0] = "audin";
1356 
1357  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1358  }
1359 
1360  if (remmina_plugin_service->file_get_int(remminafile, "preferipv6", FALSE) ? TRUE : FALSE)
1361  rfi->settings->PreferIPv6OverIPv4 = TRUE;
1362 
1363  rfi->settings->RedirectClipboard = (remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE) ? FALSE : TRUE);
1364 
1365  cs = remmina_plugin_service->file_get_string(remminafile, "sharefolder");
1366 
1367  if (cs && cs[0] == '/') {
1368  RDPDR_DRIVE *drive;
1369  gsize sz;
1370 
1371  drive = (RDPDR_DRIVE *)calloc(1, sizeof(RDPDR_DRIVE));
1372 
1373  rfi->settings->DeviceRedirection = TRUE;
1374  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdpdr", rfi->settings);
1375 
1376  s = strrchr(cs, '/');
1377  if (s == NULL || s[1] == 0)
1379  else
1380  s++;
1381  sm = g_convert_with_fallback(s, -1, "ascii", "utf-8", "_", NULL, &sz, NULL);
1382 
1383  drive->Type = RDPDR_DTYP_FILESYSTEM;
1384  drive->Name = _strdup(sm);
1385  drive->Path = _strdup(cs);
1386  g_free(sm);
1387 
1388  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)drive);
1389  rfi->settings->DeviceRedirection = TRUE;
1390  }
1391 
1392  if (remmina_plugin_service->file_get_int(remminafile, "shareprinter", FALSE)) {
1393 #ifdef HAVE_CUPS
1394  remmina_plugin_service->debug("Sharing printers");
1395  if (cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, remmina_rdp_set_printers, rfi))
1396  remmina_plugin_service->debug("All printers have been shared");
1397 
1398  else
1399  remmina_plugin_service->debug("Cannot share printers, are there any available?");
1400 
1401 #endif /* HAVE_CUPS */
1402  }
1403 
1404  if (remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE)) {
1405  RDPDR_SMARTCARD *smartcard;
1406  smartcard = (RDPDR_SMARTCARD *)calloc(1, sizeof(RDPDR_SMARTCARD));
1407 
1408  smartcard->Type = RDPDR_DTYP_SMARTCARD;
1409 
1410  rfi->settings->DeviceRedirection = TRUE;
1411  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdpdr", rfi->settings);
1412 
1413  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "smartcardname");
1414  if (sn != NULL && sn[0] != '\0')
1415  smartcard->Name = _strdup(sn);
1416 
1417  rfi->settings->RedirectSmartCards = TRUE;
1418 
1419  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)smartcard);
1420  }
1421 
1422  if (remmina_plugin_service->file_get_int(remminafile, "passwordispin", FALSE))
1423  /* Option works only combined with Username and Domain, because FreeRDP
1424  * doesn’t know anything about info on smart card */
1425  rfi->settings->PasswordIsSmartcardPin = TRUE;
1426 
1427  /* /serial[:<name>[,<path>[,<driver>[,permissive]]]] */
1428  if (remmina_plugin_service->file_get_int(remminafile, "shareserial", FALSE)) {
1429  RDPDR_SERIAL *serial;
1430  serial = (RDPDR_SERIAL *)calloc(1, sizeof(RDPDR_SERIAL));
1431 
1432  serial->Type = RDPDR_DTYP_SERIAL;
1433 
1434  rfi->settings->DeviceRedirection = TRUE;
1435  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdpdr", rfi->settings);
1436 
1437  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "serialname");
1438  if (sn != NULL && sn[0] != '\0')
1439  serial->Name = _strdup(sn);
1440 
1441  const gchar *sd = remmina_plugin_service->file_get_string(remminafile, "serialdriver");
1442  if (sd != NULL && sd[0] != '\0')
1443  serial->Driver = _strdup(sd);
1444 
1445  const gchar *sp = remmina_plugin_service->file_get_string(remminafile, "serialpath");
1446  if (sp != NULL && sp[0] != '\0')
1447  serial->Path = _strdup(sp);
1448 
1449  if (remmina_plugin_service->file_get_int(remminafile, "serialpermissive", FALSE))
1450  serial->Permissive = _strdup("permissive");
1451 
1452  rfi->settings->RedirectSerialPorts = TRUE;
1453 
1454  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)serial);
1455  }
1456 
1457  if (remmina_plugin_service->file_get_int(remminafile, "shareparallel", FALSE)) {
1458  RDPDR_PARALLEL *parallel;
1459  parallel = (RDPDR_PARALLEL *)calloc(1, sizeof(RDPDR_PARALLEL));
1460 
1461  parallel->Type = RDPDR_DTYP_PARALLEL;
1462 
1463  rfi->settings->DeviceRedirection = TRUE;
1464  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdpdr", rfi->settings);
1465 
1466  rfi->settings->RedirectParallelPorts = TRUE;
1467 
1468  const gchar *pn = remmina_plugin_service->file_get_string(remminafile, "parallelname");
1469  if (pn != NULL && pn[0] != '\0')
1470  parallel->Name = _strdup(pn);
1471  const gchar *dp = remmina_plugin_service->file_get_string(remminafile, "parallelpath");
1472  if (dp != NULL && dp[0] != '\0')
1473  parallel->Path = _strdup(dp);
1474 
1475  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)parallel);
1476  }
1477 
1481  if (remmina_plugin_service->file_get_int(remminafile, "multitransport", FALSE)) {
1482  rfi->settings->DeviceRedirection = TRUE;
1483  rfi->settings->SupportMultitransport = TRUE;
1484  rfi->settings->MultitransportFlags =
1485  (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED);
1486  } else {
1487  rfi->settings->MultitransportFlags = 0;
1488  }
1489 
1490  /* If needed, force interactive authentication by deleting all authentication fields,
1491  * forcing libfreerdp to call our callbacks for authentication.
1492  * This usually happens from a second attempt of connection, never on the 1st one. */
1494  if (rfi->settings->Username) free(rfi->settings->Username);
1495  rfi->settings->Username = NULL;
1496  if (rfi->settings->Password) free(rfi->settings->Password);
1497  rfi->settings->Password = NULL;
1498  if (rfi->settings->Domain) free(rfi->settings->Domain);
1499  rfi->settings->Domain = NULL;
1500 
1501  if (rfi->settings->GatewayDomain) free(rfi->settings->GatewayDomain);
1502  rfi->settings->GatewayDomain = NULL;
1503  if (rfi->settings->GatewayUsername) free(rfi->settings->GatewayUsername);
1504  rfi->settings->GatewayUsername = NULL;
1505  if (rfi->settings->GatewayPassword) free(rfi->settings->GatewayPassword);
1506  rfi->settings->GatewayPassword = NULL;
1507  rfi->settings->GatewayUseSameCredentials = FALSE;
1508  }
1509 
1510  gboolean orphaned;
1511 
1512  if (!freerdp_connect(rfi->instance)) {
1513  if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = True; else orphaned = False;
1514  if (!orphaned) {
1515  UINT32 e;
1516 
1517  e = freerdp_get_last_error(rfi->instance->context);
1518 
1519  switch (e) {
1520  case FREERDP_ERROR_AUTHENTICATION_FAILED:
1521  case STATUS_LOGON_FAILURE: // wrong return code from FreeRDP introduced at the end of July 2016? (fixed with b86c0ba)
1522 #ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE
1523  case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1524 #endif
1525  /* Logon failure, will retry with interactive authentication */
1527  break;
1528  case STATUS_ACCOUNT_LOCKED_OUT:
1529 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT
1530  case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1531 #endif
1532  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nAccount locked out."),
1533  rfi->settings->ServerHostname);
1534  break;
1535  case STATUS_ACCOUNT_EXPIRED:
1536 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED
1537  case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1538 #endif
1539  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nAccount expired."),
1540  rfi->settings->ServerHostname);
1541  break;
1542  case STATUS_PASSWORD_EXPIRED:
1543 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED
1544  case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
1545 #endif
1546  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nPassword expired."),
1547  rfi->settings->ServerHostname);
1548  break;
1549  case STATUS_ACCOUNT_DISABLED:
1550 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED
1551  case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
1552 #endif
1553  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nAccount disabled."),
1554  rfi->settings->ServerHostname);
1555  break;
1556 #ifdef FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES
1557  /* https://msdn.microsoft.com/en-us/library/ee392247.aspx */
1558  case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
1559  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nInsufficient user privileges."),
1560  rfi->settings->ServerHostname);
1561  break;
1562 #endif
1563  case STATUS_ACCOUNT_RESTRICTION:
1564 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION
1565  case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1566 #endif
1567  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nAccount restricted."),
1568  rfi->settings->ServerHostname);
1569  break;
1570 
1571  case STATUS_PASSWORD_MUST_CHANGE:
1572 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE
1573  case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
1574 #endif
1575  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server \"%s\".\nChange user password before connecting."),
1576  rfi->settings->ServerHostname);
1577  break;
1578 
1579  case FREERDP_ERROR_CONNECT_FAILED:
1580  remmina_plugin_service->protocol_plugin_set_error(gp, _("Lost connection to the RDP server \"%s\"."), rfi->settings->ServerHostname);
1581  break;
1582  case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
1583  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not find the address for the RDP server \"%s\"."), rfi->settings->ServerHostname);
1584  break;
1585  case FREERDP_ERROR_TLS_CONNECT_FAILED:
1586  remmina_plugin_service->protocol_plugin_set_error(gp,
1587  _("Could not connect to the RDP server \"%s\" via TLS. Check that client and server support a common TLS version."), rfi->settings->ServerHostname);
1588  break;
1589  case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
1590  remmina_plugin_service->protocol_plugin_set_error(gp, _("Unable to establish a connection to the RDP server. Check \"Security protocol negotiation\" \"%s\"."), rfi->settings->ServerHostname);
1591  break;
1592 #ifdef FREERDP_ERROR_POST_CONNECT_FAILED
1593  case FREERDP_ERROR_POST_CONNECT_FAILED:
1594  /* remmina_rdp_post_connect() returned FALSE to libfreerdp. We saved the error on rfi->postconnect_error */
1595  switch (rfi->postconnect_error) {
1596  case REMMINA_POSTCONNECT_ERROR_OK:
1597  /* We should never come here */
1598  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the RDP server \"%s\"."), rfi->settings->ServerHostname);
1599  break;
1600  case REMMINA_POSTCONNECT_ERROR_GDI_INIT:
1601  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not start libfreerdp-gdi."));
1602  break;
1603  case REMMINA_POSTCONNECT_ERROR_NO_H264:
1604  remmina_plugin_service->protocol_plugin_set_error(gp, _("You requested a H.264 GFX mode for the server \"%s\", but your libfreerdp does not support H.264. Please use a non-AVC colour depth setting."), rfi->settings->ServerHostname);
1605  break;
1606  }
1607  break;
1608 #endif
1609 #ifdef FREERDP_ERROR_SERVER_DENIED_CONNECTION
1610  case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
1611  remmina_plugin_service->protocol_plugin_set_error(gp, _("The \"%s\" server refused the connection."), rfi->settings->ServerHostname);
1612  break;
1613 #endif
1614  case 0x800759DB:
1615  // E_PROXY_NAP_ACCESSDENIED https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsgu/84cd92e4-592c-4219-95d8-18021ac654b0
1616  remmina_plugin_service->protocol_plugin_set_error(gp, _("The Remote Desktop Gateway \"%s\" denied the user \"%s\\%s\" access due to policy."),
1617  rfi->settings->GatewayHostname, rfi->settings->GatewayDomain, rfi->settings->GatewayUsername);
1618  break;
1619 
1620  case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1621  rfi->user_cancelled = TRUE;
1622  break;
1623 
1624  default:
1625  g_printf("libfreerdp returned code is %08X\n", e);
1626  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the \"%s\" RDP server."), rfi->settings->ServerHostname);
1627  break;
1628  }
1629  }
1630 
1631  return FALSE;
1632  }
1633 
1634  if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = True; else orphaned = False;
1635  if (!orphaned && freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS && !rfi->user_cancelled)
1637 
1638  return TRUE;
1639 }
1640 
1641 static void rfi_uninit(rfContext *rfi)
1642 {
1643  freerdp *instance;
1644 
1645  instance = rfi->instance;
1646 
1647  if (rfi->remmina_plugin_thread) {
1648  rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run
1649  pthread_cancel(rfi->remmina_plugin_thread);
1650  if (rfi->remmina_plugin_thread)
1651  pthread_join(rfi->remmina_plugin_thread, NULL);
1652  }
1653 
1654  if (instance) {
1655  if (rfi->connected) {
1656  freerdp_abort_connect(instance);
1657  rfi->connected = False;
1658  }
1659  }
1660 
1661 
1662  if (rfi->rfx_context) {
1663  rfx_context_free(rfi->rfx_context);
1664  rfi->rfx_context = NULL;
1665  }
1666  if (instance) {
1667  RDP_CLIENT_ENTRY_POINTS *pEntryPoints = instance->pClientEntryPoints;
1668  if (pEntryPoints)
1669  IFCALL(pEntryPoints->GlobalUninit);
1670  free(instance->pClientEntryPoints);
1671  freerdp_context_free(instance); /* context is rfContext* rfi */
1672  freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */
1673  }
1674 }
1675 
1676 static gboolean complete_cleanup_on_main_thread(gpointer data)
1677 {
1678  TRACE_CALL(__func__);
1679 
1680  gboolean orphaned;
1681  rfContext *rfi = (rfContext *)data;
1683 
1685 
1686  gdi_free(rfi->instance);
1687 
1688  gp = rfi->protocol_widget;
1689  if (GET_PLUGIN_DATA(gp) == NULL) orphaned = True; else orphaned = False;
1690 
1692  if (!orphaned) remmina_rdp_event_uninit(gp);
1693 
1694  if (!orphaned) g_object_steal_data(G_OBJECT(gp), "plugin-data");
1695 
1696  rfi_uninit(rfi);
1697 
1698  /* Notify the RemminaProtocolWidget that we closed our connection, and the GUI interface
1699  * can be removed */
1700  if (!orphaned)
1701  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
1702 
1703  return G_SOURCE_REMOVE;
1704 }
1705 
1706 static gpointer remmina_rdp_main_thread(gpointer data)
1707 {
1708  TRACE_CALL(__func__);
1710  rfContext *rfi;
1711 
1712  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1713  CANCEL_ASYNC
1714 
1715  gp = (RemminaProtocolWidget *)data;
1716  rfi = GET_PLUGIN_DATA(gp);
1717 
1719  do
1720  remmina_rdp_main(gp);
1721  while (!remmina_plugin_service->protocol_plugin_has_error(gp) && rfi->attempt_interactive_authentication == TRUE && !rfi->user_cancelled);
1722 
1723  rfi->remmina_plugin_thread = 0;
1724 
1725  /* cleanup */
1726  g_idle_add(complete_cleanup_on_main_thread, (gpointer)rfi);
1727 
1728 
1729  return NULL;
1730 }
1731 
1733 {
1734  TRACE_CALL(__func__);
1735  freerdp *instance;
1736  rfContext *rfi;
1737 
1738  instance = freerdp_new();
1739  instance->PreConnect = remmina_rdp_pre_connect;
1740  instance->PostConnect = remmina_rdp_post_connect;
1741  instance->PostDisconnect = remmina_rdp_post_disconnect;
1742  instance->Authenticate = remmina_rdp_authenticate;
1743  instance->GatewayAuthenticate = remmina_rdp_gw_authenticate;
1744  instance->VerifyCertificate = remmina_rdp_verify_certificate;
1745  instance->VerifyChangedCertificate = remmina_rdp_verify_changed_certificate;
1746 
1747  instance->ContextSize = sizeof(rfContext);
1748  freerdp_context_new(instance);
1749  rfi = (rfContext *)instance->context;
1750 
1751  g_object_set_data_full(G_OBJECT(gp), "plugin-data", rfi, free);
1752 
1753  rfi->protocol_widget = gp;
1754  rfi->instance = instance;
1755  rfi->settings = instance->settings;
1756  rfi->connected = False;
1757  rfi->is_reconnecting = False;
1758  rfi->user_cancelled = FALSE;
1759 
1760  freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
1761 
1763 }
1764 
1766 {
1767  TRACE_CALL(__func__);
1768  rfContext *rfi = GET_PLUGIN_DATA(gp);
1769  RemminaFile *remminafile;
1770  const gchar *profile_name, *p;
1771  gchar thname[16], c;
1772  gint nthname;
1773 
1774  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
1775 
1776  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1777 
1778 
1779  if (pthread_create(&rfi->remmina_plugin_thread, NULL, remmina_rdp_main_thread, gp)) {
1780  remmina_plugin_service->protocol_plugin_set_error(gp, "%s",
1781  "Could not start pthread. Falling back to non-thread mode…");
1782 
1783  rfi->remmina_plugin_thread = 0;
1784 
1785  return FALSE;
1786  }
1787 
1788  /* Generate a thread name to be used with pthread_setname_np() for debugging */
1789  profile_name = remmina_plugin_service->file_get_string(remminafile, "name");
1790  p = profile_name;
1791  strcpy(thname, "RemmRDP:");
1792  nthname = strlen(thname);
1793  while((c = *p) != 0 && nthname < sizeof(thname) - 1 ) {
1794  if (isalnum(c))
1795  thname[nthname++] = c;
1796  p++;
1797  }
1798  thname[nthname] = 0;
1799 #if defined(__linux__)
1800  pthread_setname_np(rfi->remmina_plugin_thread, thname);
1801 #elif defined(__FreeBSD__)
1802  pthread_set_name_np(rfi->remmina_plugin_thread, thname);
1803 #endif
1804 
1805  return TRUE;
1806 }
1807 
1809 {
1810  TRACE_CALL(__func__);
1811 
1812  RemminaPluginRdpEvent rdp_event = { 0 };
1813  rfContext *rfi = GET_PLUGIN_DATA(gp);
1814 
1815  if (!remmina_plugin_service->is_main_thread())
1816  g_warning("WARNING: %s called on a subthread, which may not work or crash Remmina.", __func__);
1817 
1818  if (rfi && !rfi->connected) {
1819  /* libfreerdp is attempting to connect, we cannot interrupt our main thread
1820  * in the connect phase.
1821  * So we remove "plugin-data" from gp, so our rfi remains "orphan"
1822  */
1824  g_object_steal_data(G_OBJECT(gp), "plugin-data");
1825  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
1826  return FALSE;
1827  }
1828 
1829 
1830  if (rfi && rfi->clipboard.srv_clip_data_wait == SCDW_BUSY_WAIT) {
1831  remmina_plugin_service->debug("[RDP] requesting clipboard transfer to abort");
1832  /* Allow clipboard transfer from server to terminate */
1833  rfi->clipboard.srv_clip_data_wait = SCDW_ABORTING;
1834  usleep(100000);
1835  }
1836 
1837  rdp_event.type = REMMINA_RDP_EVENT_DISCONNECT;
1838  remmina_rdp_event_event_push(gp, &rdp_event);
1839 
1840  return FALSE;
1841 }
1842 
1844 {
1845  TRACE_CALL(__func__);
1846  return TRUE;
1847 }
1848 
1850 {
1851  TRACE_CALL(__func__);
1852  rfContext *rfi = GET_PLUGIN_DATA(gp);
1853 
1854  switch (feature->id) {
1855  case REMMINA_RDP_FEATURE_UNFOCUS:
1857  break;
1858 
1859  case REMMINA_RDP_FEATURE_SCALE:
1860  if (rfi) {
1861  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
1863  } else {
1864  printf("Remmina RDP plugin warning: Null value for rfi in %s REMMINA_RDP_FEATURE_SCALE\n", __func__);
1865  }
1866  break;
1867 
1868  case REMMINA_RDP_FEATURE_DYNRESUPDATE:
1869  break;
1870 
1871  case REMMINA_RDP_FEATURE_TOOL_REFRESH:
1872  if (rfi) {
1873  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0,
1874  remmina_plugin_service->protocol_plugin_get_width(gp),
1875  remmina_plugin_service->protocol_plugin_get_height(gp));
1876  } else {
1877  printf("Remmina RDP plugin warning: Null value for rfi in %s REMMINA_RDP_FEATURE_TOOL_REFRESH\n", __func__);
1878  }
1879  break;
1880 
1881  case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL:
1883  break;
1884 
1885  default:
1886  break;
1887  }
1888 }
1889 
1890 /* Send a keystroke to the plugin window */
1891 static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
1892 {
1893  TRACE_CALL(__func__);
1894  rfContext *rfi = GET_PLUGIN_DATA(gp);
1895  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
1896  keystrokes, keylen, GDK_KEY_PRESS | GDK_KEY_RELEASE);
1897  return;
1898 }
1899 
1901 {
1902  rfContext *rfi = GET_PLUGIN_DATA(gp);
1903  rdpGdi *gdi;
1904  size_t szmem;
1905 
1906  UINT32 bytesPerPixel;
1907  UINT32 bitsPerPixel;
1908 
1909  if (!rfi)
1910  return FALSE;
1911 
1912  gdi = ((rdpContext *)rfi)->gdi;
1913 
1914  bytesPerPixel = GetBytesPerPixel(gdi->hdc->format);
1915  bitsPerPixel = GetBitsPerPixel(gdi->hdc->format);
1916 
1920  szmem = gdi->width * gdi->height * bytesPerPixel;
1921 
1922  remmina_plugin_service->debug("allocating %zu bytes for a full screenshot", szmem);
1923  rpsd->buffer = malloc(szmem);
1924  if (!rpsd->buffer) {
1925  remmina_plugin_service->debug("could not set aside %zu bytes for a full screenshot", szmem);
1926  return FALSE;
1927  }
1928  rpsd->width = gdi->width;
1929  rpsd->height = gdi->height;
1930  rpsd->bitsPerPixel = bitsPerPixel;
1931  rpsd->bytesPerPixel = bytesPerPixel;
1932 
1933  memcpy(rpsd->buffer, gdi->primary_buffer, szmem);
1934 
1935  /* Returning TRUE instruct also the caller to deallocate rpsd->buffer */
1936  return TRUE;
1937 }
1938 
1939 /* Array of key/value pairs for colour depths */
1940 static gpointer colordepth_list[] =
1941 {
1942  /* 1st one is the default in a new install */
1943  "66", N_("GFX AVC444 (32 bpp)"),
1944  "65", N_("GFX AVC420 (32 bpp)"),
1945  "64", N_("GFX RFX (32 bpp)"),
1946  "0", N_("RemoteFX (32 bpp)"),
1947  "32", N_("True colour (32 bpp)"),
1948  "24", N_("True colour (24 bpp)"),
1949  "16", N_("High colour (16 bpp)"),
1950  "15", N_("High colour (15 bpp)"),
1951  "8", N_("256 colours (8 bpp)"),
1952  NULL
1953 };
1954 
1955 /* Array of key/value pairs for quality selection */
1956 static gpointer quality_list[] =
1957 {
1958  "0", N_("Poor (fastest)"),
1959  "1", N_("Medium"),
1960  "2", N_("Good"),
1961  "9", N_("Best (slowest)"),
1962  NULL
1963 };
1964 
1965 /* Array of key/value pairs for sound options */
1966 static gpointer sound_list[] =
1967 {
1968  "off", N_("Off"),
1969  "local", N_("Local"),
1970  "local,11025,1", N_("Local - low quality"),
1971  "local,22050,2", N_("Local - medium quality"),
1972  "local,44100,2", N_("Local - high quality"),
1973  "remote", N_("Remote"),
1974  NULL
1975 };
1976 
1977 /* Array of key/value pairs for security */
1978 static gpointer security_list[] =
1979 {
1980  "", N_("Negotiate protocol security"),
1981  "nla", N_("NLA protocol security"),
1982  "tls", N_("TLS protocol security"),
1983  "rdp", N_("RDP protocol security"),
1984  "ext", N_("NLA extended protocol security"),
1985  NULL
1986 };
1987 
1988 static gpointer gwtransp_list[] =
1989 {
1990  "http", "HTTP",
1991  "rpc", "RPC",
1992  "auto", "Auto",
1993  NULL
1994 };
1995 
1996 static gchar clientbuild_list[] =
1997  N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)");
1998 
1999 static gchar clientbuild_tooltip[] =
2000  N_("Used i.a. by terminal services in smart card channel to distinguish client capabilities:\n"
2001  " • < 4034: Windows XP base smart card functions\n"
2002  " • 4034-7064: Windows Vista/7: SCardReadCache(), SCardWriteCache(),\n"
2003  " SCardGetTransmitCount()\n"
2004  " • >= 7065: Windows 8 and newer: SCardGetReaderIcon(), SCardGetDeviceTypeId()");
2005 
2006 /* Array of RemminaProtocolSetting for basic settings.
2007  * Each item is composed by:
2008  * a) RemminaProtocolSettingType for setting type
2009  * b) Setting name
2010  * c) Setting description
2011  * d) Compact disposition
2012  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
2013  * f) Setting Tooltip
2014  */
2016 {
2017  { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL },
2018  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL },
2019  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL },
2020  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL },
2021  { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL },
2022  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL },
2023  { REMMINA_PROTOCOL_SETTING_TYPE_FOLDER, "sharefolder", N_("Share folder"), FALSE, NULL, NULL },
2024  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
2025 };
2026 
2027 /* Array of RemminaProtocolSetting for advanced settings.
2028  * Each item is composed by:
2029  * a) RemminaProtocolSettingType for setting type
2030  * b) Setting name
2031  * c) Setting description
2032  * d) Compact disposition
2033  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
2034  * f) Setting Tooltip
2035  */
2037 {
2038  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "quality", N_("Quality"), FALSE, quality_list, NULL },
2039  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "sound", N_("Sound"), FALSE, sound_list, NULL },
2040  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "security", N_("Security protocol negotiation"), FALSE, security_list, NULL },
2041  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "gwtransp", N_("Gateway transport type"), FALSE, gwtransp_list, NULL },
2042  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_server", N_("Remote Desktop Gateway server"), FALSE, NULL, NULL },
2043  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_username", N_("Remote Desktop Gateway username"), FALSE, NULL, NULL },
2044  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "gateway_password", N_("Remote Desktop Gateway password"), FALSE, NULL, NULL },
2045  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_domain", N_("Remote Desktop Gateway domain"), FALSE, NULL, NULL },
2046  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "clientname", N_("Client name"), FALSE, NULL, NULL },
2047  { REMMINA_PROTOCOL_SETTING_TYPE_COMBO, "clientbuild", N_("Client build"), FALSE, clientbuild_list, clientbuild_tooltip },
2048  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Startup program"), FALSE, NULL, NULL },
2049  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Startup path"), FALSE, NULL, NULL },
2050  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "loadbalanceinfo", N_("Load balance info"), FALSE, NULL, NULL },
2051  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "printer_overrides", N_("Override printer drivers"), FALSE, NULL, N_("\"Samsung_CLX-3300_Series\":\"Samsung CLX-3300 Series PS\";\"Canon MF410\":\"Canon MF410 Series UFR II\"") },
2052  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialname", N_("Local serial name"), FALSE, NULL, N_("COM1, COM2, etc.") },
2053  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialdriver", N_("Local serial driver"), FALSE, NULL, N_("Serial") },
2054  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialpath", N_("Local serial path"), FALSE, NULL, N_("/dev/ttyS0, /dev/ttyS1, etc.") },
2055  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelname", N_("Local parallel name"), FALSE, NULL, NULL },
2056  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelpath", N_("Local parallel device"), FALSE, NULL, NULL },
2057  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "smartcardname", N_("Name of smart card"), FALSE, NULL, NULL },
2058  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "preferipv6", N_("Prefer IPv6 AAAA record over IPv4 A record"), TRUE, NULL, NULL },
2059  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareprinter", N_("Share printers"), TRUE, NULL, NULL },
2060  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareserial", N_("Share serial ports"), TRUE, NULL, NULL },
2061  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "serialpermissive", N_("(SELinux) permissive mode for serial ports"), TRUE, NULL, NULL },
2062  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareparallel", N_("Share parallel ports"), TRUE, NULL, NULL },
2063  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sharesmartcard", N_("Share a smart card"), TRUE, NULL, NULL },
2064  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "microphone", N_("Redirect local microphone"), TRUE, NULL, NULL },
2065  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableclipboard", N_("Turn off clipboard sync"), TRUE, NULL, NULL },
2066  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "cert_ignore", N_("Ignore certificate"), TRUE, NULL, NULL },
2067  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "old-license", N_("Use the old license workflow"), TRUE, NULL, N_("It disables CAL and hwId is set to 0") },
2068  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), TRUE, NULL, NULL },
2069  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "console", N_("Attach to console (2003/2003 R2)"), TRUE, NULL, NULL },
2070  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable_fastpath", N_("Turn off fast-path"), TRUE, NULL, NULL },
2071  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "gateway_usage", N_("Server detection using Remote Desktop Gateway"), TRUE, NULL, NULL },
2072 #if defined(PROXY_TYPE_IGNORE)
2073  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "useproxyenv", N_("Use system proxy settings"), TRUE, NULL, NULL },
2074 #endif
2075  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableautoreconnect", N_("Turn off automatic reconnection"), TRUE, NULL, NULL },
2076  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "relax-order-checks", N_("Relax order checks"), TRUE, NULL, NULL },
2077  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "glyph-cache", N_("Glyph cache"), TRUE, NULL, NULL },
2078  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multitransport", N_("Enable multitransport protocol (UDP)"), TRUE, NULL, N_("Using the UDP protocol may improve performance") },
2079  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
2080 };
2081 
2082 /* Array for available features.
2083  * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */
2085 {
2086  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_REFRESH, N_("Refresh"), NULL, NULL },
2087  { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_RDP_FEATURE_SCALE, NULL, NULL, NULL },
2088  { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, REMMINA_RDP_FEATURE_DYNRESUPDATE, NULL, NULL, NULL },
2089  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+Delete"), NULL, NULL },
2090  { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_RDP_FEATURE_UNFOCUS, NULL, NULL, NULL },
2091  { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL }
2092 };
2093 
2094 /* This will be filled with version info string */
2096 
2097 /* Protocol plugin definition and features */
2099 {
2101  "RDP", // Name
2102  N_("RDP - Remote Desktop Protocol"), // Description
2103  GETTEXT_PACKAGE, // Translation domain
2104  remmina_plugin_rdp_version, // Version number
2105  "remmina-rdp-symbolic", // Icon for normal connection
2106  "remmina-rdp-ssh-symbolic", // Icon for SSH connection
2107  remmina_rdp_basic_settings, // Array for basic settings
2108  remmina_rdp_advanced_settings, // Array for advanced settings
2109  REMMINA_PROTOCOL_SSH_SETTING_TUNNEL, // SSH settings type
2110  remmina_rdp_features, // Array for available features
2111  remmina_rdp_init, // Plugin initialization
2112  remmina_rdp_open_connection, // Plugin open connection
2113  remmina_rdp_close_connection, // Plugin close connection
2114  remmina_rdp_query_feature, // Query for available features
2115  remmina_rdp_call_feature, // Call a feature
2116  remmina_rdp_keystroke, // Send a keystroke
2117  remmina_rdp_get_screenshot // Screenshot
2118 };
2119 
2120 /* File plugin definition and features */
2122 {
2123  REMMINA_PLUGIN_TYPE_FILE, // Type
2124  "RDPF", // Name
2125  N_("RDP - RDP File Handler"), // Description
2126  GETTEXT_PACKAGE, // Translation domain
2127  remmina_plugin_rdp_version, // Version number
2128  remmina_rdp_file_import_test, // Test import function
2129  remmina_rdp_file_import, // Import function
2130  remmina_rdp_file_export_test, // Test export function
2131  remmina_rdp_file_export, // Export function
2132  NULL
2133 };
2134 
2135 /* Preferences plugin definition and features */
2137 {
2138  REMMINA_PLUGIN_TYPE_PREF, // Type
2139  "RDPS", // Name
2140  N_("RDP - Preferences"), // Description
2141  GETTEXT_PACKAGE, // Translation domain
2142  remmina_plugin_rdp_version, // Version number
2143  "RDP", // Label
2144  remmina_rdp_settings_new // Preferences body function
2145 };
2146 
2147 static char *buildconfig_strstr(const char *bc, const char *option)
2148 {
2149  TRACE_CALL(__func__);
2150 
2151  char *p, *n;
2152 
2153  p = strcasestr(bc, option);
2154  if (p == NULL)
2155  return NULL;
2156 
2157  if (p > bc && *(p - 1) > ' ')
2158  return NULL;
2159 
2160  n = p + strlen(option);
2161  if (*n > ' ')
2162  return NULL;
2163 
2164  return p;
2165 }
2166 
2167 G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
2168 {
2169  int vermaj, vermin, verrev;
2170 
2171  TRACE_CALL(__func__);
2172  remmina_plugin_service = service;
2173 
2174  /* Check that we are linked to the correct version of libfreerdp */
2175 
2176  freerdp_get_version(&vermaj, &vermin, &verrev);
2177  if (vermaj < FREERDP_REQUIRED_MAJOR ||
2178  (vermaj == FREERDP_REQUIRED_MAJOR && (vermin < FREERDP_REQUIRED_MINOR ||
2179  (vermin == FREERDP_REQUIRED_MINOR && verrev < FREERDP_REQUIRED_REVISION)))) {
2180  g_printf("Upgrade your FreeRDP library version from %d.%d.%d to at least libfreerdp %d.%d.%d "
2181  "to run the RDP plugin.\n",
2182  FREERDP_REQUIRED_MAJOR, FREERDP_REQUIRED_MINOR, FREERDP_REQUIRED_REVISION,
2183  vermaj, vermin, verrev);
2184  return FALSE;
2185  }
2186 
2187  bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
2188  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
2189 
2190  if (!service->register_plugin((RemminaPlugin *)&remmina_rdp))
2191  return FALSE;
2192 
2193  remmina_rdpf.export_hints = _("Export connection in Windows .rdp file format");
2194 
2195  if (!service->register_plugin((RemminaPlugin *)&remmina_rdpf))
2196  return FALSE;
2197 
2198  if (!service->register_plugin((RemminaPlugin *)&remmina_rdps))
2199  return FALSE;
2200 
2201  if (buildconfig_strstr(freerdp_get_build_config(), "WITH_GFX_H264=ON")) {
2202  gfx_h264_available = TRUE;
2203  } else {
2204  gfx_h264_available = FALSE;
2205  /* Remove values 65 and 66 from colordepth_list array by shifting it */
2206  gpointer *src, *dst;
2207  dst = src = colordepth_list;
2208  while (*src) {
2209  if (strcmp(*src, "66") != 0 && strcmp(*src, "65") != 0) {
2210  if (dst != src) {
2211  *dst = *src;
2212  *(dst + 1) = *(src + 1);
2213  }
2214  dst += 2;
2215  }
2216  src += 2;
2217  }
2218  *dst = NULL;
2219  }
2220 
2222  "RDP plugin: %s (Git %s), Compiled with libfreerdp: %s (%s), Running with libfreerdp: %s (rev %s), H.264: %s",
2223  VERSION, REMMINA_GIT_REVISION,
2224  FREERDP_VERSION_FULL, GIT_REVISION,
2225  freerdp_get_version_string(),
2226  freerdp_get_build_revision(),
2227  gfx_h264_available ? "Yes" : "No"
2228  );
2229 
2231 
2232  return TRUE;
2233 }
CliprdrClientContext * context
Definition: rdp_plugin.h:72
gint w
Definition: rdp_plugin.h:186
struct remmina_plugin_rdp_event::@40::@44 clipboard_formatlist
gboolean thread_cancelled
Definition: rdp_plugin.h:256
struct remmina_plugin_rdp_event::@40::@46 clipboard_formatdatarequest
gboolean is_reconnecting
Definition: rdp_plugin.h:269
gint y
Definition: rdp_plugin.h:186
RemminaScaleMode(* remmina_protocol_widget_get_current_scale_mode)(RemminaProtocolWidget *gp)
Definition: plugin.h:154
void(* debug)(const gchar *fmt,...)
Definition: plugin.h:214
static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:1765
gboolean user_cancelled
Definition: rdp_plugin.h:255
static gpointer quality_list[]
Definition: rdp_plugin.c:1956
static void remmina_rdp_send_ctrlaltdel(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:976
gboolean attempt_interactive_authentication
Definition: rdp_plugin.h:312
void(* protocol_plugin_set_error)(RemminaProtocolWidget *gp, const gchar *fmt,...)
Definition: plugin.h:158
gint event_pipe[2]
Definition: rdp_plugin.h:305
static RemminaProtocolPlugin remmina_rdp
Definition: rdp_plugin.c:2098
void remmina_rdp_OnChannelDisconnectedEventHandler(rdpContext *context, ChannelConnectedEventArgs *e)
Definition: rdp_channels.c:85
enum rf_context::@57 postconnect_error
enum rf_clipboard::@39 srv_clip_data_wait
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:41
pthread_t remmina_plugin_thread
Definition: rdp_plugin.h:253
const gchar * export_hints
Definition: plugin.h:105
void remmina_rdp_cliprdr_detach_owner(RemminaProtocolWidget *gp)
Definition: rdp_cliprdr.c:763
void(* protocol_plugin_set_width)(RemminaProtocolWidget *gp, gint width)
Definition: plugin.h:151
static BOOL gfx_h264_available
Definition: rdp_plugin.c:92
void remmina_rdp_settings_get_orientation_scale_prefs(int *desktopOrientation, int *desktopScaleFactor, int *deviceScaleFactor)
Definition: rdp_settings.c:608
static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:1843
static DWORD remmina_rdp_verify_changed_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *new_fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint)
Definition: rdp_plugin.c:698
gint(* protocol_plugin_init_certificate)(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
Definition: plugin.h:173
static BOOL rf_desktop_resize(rdpContext *context)
Definition: rdp_plugin.c:371
void rf_register_graphics(rdpGraphics *graphics)
Definition: rdp_graphics.c:381
gint h
Definition: rdp_plugin.h:186
void remmina_rdp_settings_init(void)
Definition: rdp_settings.c:51
static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
Definition: rdp_plugin.c:561
static gboolean complete_cleanup_on_main_thread(gpointer data)
Definition: rdp_plugin.c:1676
static gboolean remmina_rdp_main(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:986
void remmina_rdp_clipboard_init(rfContext *rfi)
Definition: rdp_cliprdr.c:802
static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
Definition: rdp_plugin.c:2036
RemminaProtocolWidget * protocol_widget
Definition: rdp_plugin.h:247
int reconnect_nattempt
Definition: rdp_plugin.h:276
void(* protocol_plugin_send_keys_signals)(GtkWidget *widget, const guint *keyvals, int length, GdkEventType action)
Definition: plugin.h:193
int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
Callback function used by cupsEnumDests.
Definition: rdp_plugin.c:898
void(* protocol_plugin_signal_connection_closed)(RemminaProtocolWidget *gp)
Definition: plugin.h:167
gint(* protocol_plugin_get_width)(RemminaProtocolWidget *gp)
Definition: plugin.h:150
static void remmina_rdp_init(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:1732
void(* get_server_port)(const gchar *server, gint defaultport, gchar **host, gint *port)
Definition: plugin.h:221
gboolean remmina_rdp_file_export(RemminaFile *remminafile, const gchar *to_file)
Definition: rdp_file.c:278
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: plugin.h:203
static void remmina_rdp_post_disconnect(freerdp *instance)
Definition: rdp_plugin.c:718
gchar * remmina_rdp_find_prdriver(char *smap, char *prn)
Definition: rdp_plugin.c:823
struct remmina_plugin_rdp_ui_object::@48::@50 reg
GtkWidget * remmina_rdp_settings_new(void)
Definition: rdp_settings.c:597
struct remmina_plugin_rdp_event::@40::@43 mouse_event
int reconnect_maxattempts
Definition: rdp_plugin.h:275
gint(* protocol_plugin_changed_certificate)(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
Definition: plugin.h:174
gboolean remmina_rdp_file_export_test(RemminaFile *remminafile)
Definition: rdp_file.c:207
static gchar clientbuild_tooltip[]
Definition: rdp_plugin.c:1999
RemminaPluginRdpEventType type
Definition: rdp_plugin.h:118
gboolean(* protocol_plugin_init_get_savepassword)(RemminaProtocolWidget *gp)
Definition: plugin.h:178
static void rfi_uninit(rfContext *rfi)
Definition: rdp_plugin.c:1641
static char remmina_rdp_plugin_default_drive_name[]
Definition: rdp_plugin.c:90
gboolean(* register_plugin)(RemminaPlugin *plugin)
Definition: plugin.h:148
BOOL rf_begin_paint(rdpContext *context)
Definition: rdp_plugin.c:312
RemminaFile * remmina_rdp_file_import(const gchar *from_file)
Definition: rdp_file.c:187
GtkWidget * drawing_area
Definition: rdp_plugin.h:279
static gpointer sound_list[]
Definition: rdp_plugin.c:1966
cairo_format_t cairo_format
Definition: rdp_plugin.h:291
struct remmina_plugin_rdp_event::@40::@42 key_event
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1268
void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:742
gboolean(* protocol_plugin_has_error)(RemminaProtocolWidget *gp)
Definition: plugin.h:157
gchar *(* pref_get_value)(const gchar *key)
Definition: plugin.h:207
static const RemminaProtocolFeature remmina_rdp_features[]
Definition: rdp_plugin.c:2084
static RemminaFilePlugin remmina_rdpf
Definition: rdp_plugin.c:2121
G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
Definition: rdp_plugin.c:2167
static gpointer security_list[]
Definition: rdp_plugin.c:1978
static BOOL rf_process_event_queue(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:94
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1262
static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: rdp_plugin.c:1891
static gpointer colordepth_list[]
Definition: rdp_plugin.c:1940
gint(* protocol_plugin_get_height)(RemminaProtocolWidget *gp)
Definition: plugin.h:152
gint(* protocol_plugin_init_auth)(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
Definition: plugin.h:172
GAsyncQueue * event_queue
Definition: rdp_plugin.h:304
static void remmina_rdp_main_loop(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:734
static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
Definition: rdp_plugin.c:406
gint x
Definition: rdp_plugin.h:186
rfClipboard clipboard
Definition: rdp_plugin.h:308
gint(* get_profile_remote_height)(RemminaProtocolWidget *gp)
Definition: plugin.h:225
HANDLE event_handle
Definition: rdp_plugin.h:306
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:855
RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
Definition: plugin.h:160
void(* protocol_plugin_desktop_resize)(RemminaProtocolWidget *gp)
Definition: plugin.h:171
static BOOL remmina_rdp_post_connect(freerdp *instance)
Definition: rdp_plugin.c:497
BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
Definition: rdp_plugin.c:451
static RemminaPrefPlugin remmina_rdps
Definition: rdp_plugin.c:2136
gint srcBpp
Definition: rdp_plugin.h:287
gchar *(* protocol_plugin_init_get_username)(RemminaProtocolWidget *gp)
Definition: plugin.h:175
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:1808
void remmina_rdp_clipboard_free(rfContext *rfi)
Definition: rdp_cliprdr.c:807
gint(* get_profile_remote_width)(RemminaProtocolWidget *gp)
Definition: plugin.h:224
gboolean connected
Definition: rdp_plugin.h:268
gchar *(* protocol_plugin_init_get_password)(RemminaProtocolWidget *gp)
Definition: plugin.h:176
RemminaScaleMode scale
Definition: rdp_plugin.h:254
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2095
freerdp * instance
Definition: rdp_plugin.h:251
gboolean remmina_rdp_file_import_test(const gchar *from_file)
Definition: rdp_file.c:41
static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
Definition: rdp_plugin.c:422
static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
Definition: rdp_plugin.c:620
DispClientContext * dispcontext
Definition: rdp_plugin.h:259
BOOL rf_end_paint(rdpContext *context)
Definition: rdp_plugin.c:327
static char * buildconfig_strstr(const char *bc, const char *option)
Definition: rdp_plugin.c:2147
struct remmina_plugin_rdp_ui_object::@48::@55 event
static gchar clientbuild_list[]
Definition: rdp_plugin.c:1996
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:927
rdpSettings * settings
Definition: rdp_plugin.h:250
void(* file_set_string)(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: plugin.h:199
void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
Definition: plugin.h:153
static gpointer remmina_rdp_main_thread(gpointer data)
Definition: rdp_plugin.c:1706
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1114
static BOOL remmina_rdp_pre_connect(freerdp *instance)
Definition: rdp_plugin.c:464
int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
Definition: rdp_plugin.c:792
static gboolean remmina_rdp_tunnel_init(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:176
gchar *(* protocol_plugin_start_direct_tunnel)(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
Definition: plugin.h:163
static const RemminaProtocolSetting remmina_rdp_basic_settings[]
Definition: rdp_plugin.c:2015
static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: rdp_plugin.c:1900
void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
Definition: rdp_event.c:92
BOOL rf_auto_reconnect(rfContext *rfi)
Definition: rdp_plugin.c:233
const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
Definition: plugin.h:200
static DWORD remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch)
Definition: rdp_plugin.c:680
RFX_CONTEXT * rfx_context
Definition: rdp_plugin.h:265
void remmina_rdp_OnChannelConnectedEventHandler(rdpContext *context, ChannelConnectedEventArgs *e)
Definition: rdp_channels.c:46
RemminaPluginService * remmina_plugin_service
Definition: rdp_plugin.c:89
unsigned char * buffer
Definition: types.h:65
static gpointer gwtransp_list[]
Definition: rdp_plugin.c:1988
rdpContext context
Definition: rdp_plugin.h:244
static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:1849
gchar *(* protocol_plugin_init_get_domain)(RemminaProtocolWidget *gp)
Definition: plugin.h:177
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:907
gboolean(* is_main_thread)(void)
Definition: plugin.h:222
struct rf_context rfContext
Definition: rdp_plugin.h:59
gboolean sw_gdi
Definition: rdp_plugin.h:278
RemminaPluginRdpUiType type
Definition: rdp_plugin.h:190
guint remmina_rdp_settings_get_keyboard_layout(void)
Definition: rdp_settings.c:66