From 3b370aac1164a45edad04bbb77b8ee245972f518 Mon Sep 17 00:00:00 2001 From: Antenore Gatta Date: Thu, 7 Sep 2023 13:00:21 +0000 Subject: Automatic doc build by remmina-ci --- public/remmina__plugin__native_8c_source.html | 2 +- public/remmina__ssh_8c_source.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/remmina__plugin__native_8c_source.html b/public/remmina__plugin__native_8c_source.html index ceb97a214..dd669b3fd 100644 --- a/public/remmina__plugin__native_8c_source.html +++ b/public/remmina__plugin__native_8c_source.html @@ -86,7 +86,7 @@ $(document).ready(function(){initNavTree('remmina__plugin__native_8c_source.html
remmina_plugin_native.c
-Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * In addition, as a special exception, the copyright holders give
21  * permission to link the code of portions of this program with the
22  * OpenSSL library under certain conditions as described in each
23  * individual source file, and distribute linked combinations
24  * including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL. * If you modify
27  * file(s) with this exception, you may extend this exception to your
28  * version of the file(s), but you are not obligated to do so. * If you
29  * do not wish to do so, delete this exception statement from your
30  * version. * If you delete this exception statement from all source
31  * files in the program, then also delete it here.
32  *
33  */
34 
35 #include "config.h"
36 
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 #include <gio/gio.h>
40 #include <string.h>
41 
42 #ifdef GDK_WINDOWING_X11
43 #include <gdk/gdkx.h>
44 #elif defined(GDK_WINDOWING_WAYLAND)
45 #include <gdk/gdkwayland.h>
46 #endif
47 
48 #include "remmina_public.h"
49 #include "remmina_file_manager.h"
50 #include "remmina_pref.h"
52 #include "remmina_log.h"
53 #include "remmina_widget_pool.h"
54 #include "rcw.h"
55 #include "remmina_public.h"
56 #include "remmina_plugin_native.h"
59 
60 gboolean remmina_plugin_native_load(RemminaPluginService* service, const char* name)
61 {
62  TRACE_CALL(__func__);
63  GModule* module;
65 
66  //Python plugins cannot be lazy loaded, so hande their loading seperately
67  //TODO: Figure out how to properly load python plugins without breaking others
68  if (strstr(name, "remmina-plugin-python_wrapper") != NULL ){
69  module = g_module_open(name, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
70  }
71  else{
72  module = g_module_open(name, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
73  }
74 
75  if (!module)
76  {
77  g_print("Failed to load plugin: %s.\n", name);
78  g_print("Error: %s\n", g_module_error());
79  return FALSE;
80  }
81 
82  if (!g_module_symbol(module, "remmina_plugin_entry", (gpointer*)&entry))
83  {
84  g_print("Failed to locate plugin entry: %s.\n", name);
85  return FALSE;
86  }
87 
88  if (!entry(service))
89  {
90  g_print("Plugin entry returned false: %s.\n", name);
91  return FALSE;
92  }
93 
94  return TRUE;
95  /* We don’t close the module because we will need it throughout the process lifetime */
96 }
gboolean remmina_plugin_native_load(RemminaPluginService *service, const char *name)
+Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * In addition, as a special exception, the copyright holders give
21  * permission to link the code of portions of this program with the
22  * OpenSSL library under certain conditions as described in each
23  * individual source file, and distribute linked combinations
24  * including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL. * If you modify
27  * file(s) with this exception, you may extend this exception to your
28  * version of the file(s), but you are not obligated to do so. * If you
29  * do not wish to do so, delete this exception statement from your
30  * version. * If you delete this exception statement from all source
31  * files in the program, then also delete it here.
32  *
33  */
34 
35 #include "config.h"
36 
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 #include <gio/gio.h>
40 #include <string.h>
41 
42 #ifdef GDK_WINDOWING_X11
43 #include <gdk/gdkx.h>
44 #elif defined(GDK_WINDOWING_WAYLAND)
45 #include <gdk/gdkwayland.h>
46 #endif
47 
48 #include "remmina_public.h"
49 #include "remmina_file_manager.h"
50 #include "remmina_pref.h"
52 #include "remmina_log.h"
53 #include "remmina_widget_pool.h"
54 #include "rcw.h"
55 #include "remmina_public.h"
56 #include "remmina_plugin_native.h"
59 
60 gboolean remmina_plugin_native_load(RemminaPluginService* service, const char* name)
61 {
62  TRACE_CALL(__func__);
63  GModule* module;
65 
66  //Python plugins cannot be lazy loaded, so hande their loading seperately
67  if (strstr(name, "remmina-plugin-python_wrapper") != NULL ){
68  module = g_module_open(name, 0);
69  }
70  else{
71  module = g_module_open(name, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
72  }
73 
74  if (!module)
75  {
76  g_print("Failed to load plugin: %s.\n", name);
77  g_print("Error: %s\n", g_module_error());
78  return FALSE;
79  }
80 
81  if (!g_module_symbol(module, "remmina_plugin_entry", (gpointer*)&entry))
82  {
83  g_print("Failed to locate plugin entry: %s.\n", name);
84  return FALSE;
85  }
86 
87  if (!entry(service))
88  {
89  g_print("Plugin entry returned false: %s.\n", name);
90  return FALSE;
91  }
92 
93  return TRUE;
94  /* We don’t close the module because we will need it throughout the process lifetime */
95 }
gboolean remmina_plugin_native_load(RemminaPluginService *service, const char *name)
diff --git a/public/remmina__ssh_8c_source.html b/public/remmina__ssh_8c_source.html index df40206de..ee45cc4b1 100644 --- a/public/remmina__ssh_8c_source.html +++ b/public/remmina__ssh_8c_source.html @@ -86,7 +86,7 @@ $(document).ready(function(){initNavTree('remmina__ssh_8c_source.html','');});
remmina_ssh.c
-Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 #include "config.h"
39 
40 #ifdef HAVE_LIBSSH
41 
42 /* To get definitions of NI_MAXHOST and NI_MAXSERV from <netdb.h> */
43 #define _DEFAULT_SOURCE
44 #define _DARWIN_C_SOURCE
45 
46 /* Define this before stdlib.h to have posix_openpt */
47 #define _XOPEN_SOURCE 600
48 
49 #include <errno.h>
50 #define LIBSSH_STATIC 1
51 #include <libssh/libssh.h>
52 #include <gtk/gtk.h>
53 #include <glib/gi18n.h>
54 #include <poll.h>
55 #include <stdlib.h>
56 #include <signal.h>
57 #include <time.h>
58 #include <sys/types.h>
59 #include <pthread.h>
60 #ifdef HAVE_NETDB_H
61 #include <netdb.h>
62 #endif
63 #ifdef HAVE_ARPA_INET_H
64 #include <arpa/inet.h>
65 #endif
66 #ifdef HAVE_NETINET_IN_H
67 #include <netinet/in.h>
68 #endif
69 #ifdef HAVE_SYS_SOCKET_H
70 #include <sys/socket.h>
71 #endif
72 #ifdef HAVE_FCNTL_H
73 #include <fcntl.h>
74 #endif
75 #ifdef HAVE_ERRNO_H
76 #include <errno.h>
77 #endif
78 #ifdef HAVE_TERMIOS_H
79 #include <termios.h>
80 #endif
81 #ifdef HAVE_UNISTD_H
82 #include <unistd.h>
83 #endif
84 #ifdef HAVE_PTY_H
85 #include <pty.h>
86 #endif
87 #ifdef HAVE_SYS_UN_H
88 #include <sys/un.h>
89 #endif
90 #include "remmina_public.h"
91 #include "remmina/types.h"
92 #include "remmina_file.h"
93 #include "remmina_log.h"
94 #include "remmina_pref.h"
95 #include "remmina_ssh.h"
98 
99 
100 #ifdef HAVE_NETINET_TCP_H
101 #include <netinet/tcp.h>
102 
103 #if defined(__FreeBSD__) || defined(__OpenBSD__)
104 #ifndef SOL_TCP
105 #define SOL_TCP IPPROTO_TCP
106 #endif
107 #endif
108 
109 #endif
110 
111 /*-----------------------------------------------------------------------------*
112 * SSH Base *
113 *-----------------------------------------------------------------------------*/
114 
115 #define LOCK_SSH(ssh) pthread_mutex_lock(&REMMINA_SSH(ssh)->ssh_mutex);
116 #define UNLOCK_SSH(ssh) pthread_mutex_unlock(&REMMINA_SSH(ssh)->ssh_mutex);
117 
118 static const gchar *common_identities[] =
119 {
120  ".ssh/id_ed25519",
121  ".ssh/id_rsa",
122  ".ssh/id_dsa",
123  ".ssh/identity",
124  NULL
125 };
126 
127 /*-----------------------------------------------------------------------------*
128 * X11 Channels *
129 *-----------------------------------------------------------------------------*/
130 #define _PATH_UNIX_X "/tmp/.X11-unix/X%d"
131 #define _XAUTH_CMD "/usr/bin/xauth list %s 2>/dev/null"
132 
133 typedef struct item {
134  ssh_channel channel;
135  gint fd_in;
136  gint fd_out;
137  gboolean protected;
138  pthread_t thread;
139  struct item *next;
140 } node_t;
141 
142 node_t *node = NULL;
143 
144 // Mutex
145 pthread_mutex_t mutex;
146 
147 // Linked nodes to manage channel/fd tuples
148 static void remmina_ssh_insert_item(ssh_channel channel, gint fd_in, gint fd_out, gboolean protected, pthread_t thread);
149 static void remmina_ssh_delete_item(ssh_channel channel);
150 static node_t * remmina_ssh_search_item(ssh_channel channel);
151 
152 // X11 Display
153 const char * remmina_ssh_ssh_gai_strerror(int gaierr);
154 static int remmina_ssh_x11_get_proto(const char *display, char **_proto, char **_data);
155 static void remmina_ssh_set_nodelay(int fd);
156 static int remmina_ssh_connect_local_xsocket_path(const char *pathname);
157 static int remmina_ssh_connect_local_xsocket(int display_number);
159 
160 // Send data to channel
161 static int remmina_ssh_cp_to_ch_cb(int fd, int revents, void *userdata);
162 
163 // Read data from channel
164 static int remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata);
165 
166 // EOF&Close channel
167 static void remmina_ssh_ch_close_cb(ssh_session session, ssh_channel channel, void *userdata);
168 
169 // Close all X11 channel
170 static void remmina_ssh_close_all_x11_ch(pthread_t thread);
171 
172 // X11 Request
173 static ssh_channel remmina_ssh_x11_open_request_cb(ssh_session session, const char *shost, int sport, void *userdata);
174 
175 // SSH Channel Callbacks
176 struct ssh_channel_callbacks_struct channel_cb =
177 {
178  .channel_data_function = remmina_ssh_cp_to_fd_cb,
179  .channel_eof_function = remmina_ssh_ch_close_cb,
180  .channel_close_function = remmina_ssh_ch_close_cb,
181  .userdata = NULL
182 };
183 
184 // SSH Event Context
185 short events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
186 
187 // Functions
188 static void
189 remmina_ssh_insert_item(ssh_channel channel, gint fd_in, gint fd_out, gboolean protected, pthread_t thread)
190 {
191  TRACE_CALL(__func__);
192 
193  pthread_mutex_lock(&mutex);
194 
195  REMMINA_DEBUG("insert node - fd_in: %d - fd_out: %d - protected %d", fd_in, fd_out, protected);
196 
197  node_t *node_iterator, *new;
198  if (node == NULL) {
199  /* Calloc ensure that node is full of 0 */
200  node = (node_t *) calloc(1, sizeof(node_t));
201  node->channel = channel;
202  node->fd_in = fd_in;
203  node->fd_out = fd_out;
204  node->protected = protected;
205  node->thread = thread;
206  node->next = NULL;
207  } else {
208  node_iterator = node;
209  while (node_iterator->next != NULL)
210  node_iterator = node_iterator->next;
211  /* Create the new node */
212  new = (node_t *) malloc(sizeof(node_t));
213  new->channel = channel;
214  new->fd_in = fd_in;
215  new->fd_out = fd_out;
216  new->protected = protected;
217  new->thread = thread;
218  new->next = NULL;
219  node_iterator->next = new;
220  }
221 
222  pthread_mutex_unlock(&mutex);
223 }
224 
225 static void
227 {
228  TRACE_CALL(__func__);
229 
230  REMMINA_DEBUG("delete node");
231 
232  pthread_mutex_lock(&mutex);
233 
234  node_t *current, *previous = NULL;
235  for (current = node; current; previous = current, current = current->next) {
236  if (current->channel != channel)
237  continue;
238 
239  if (previous == NULL)
240  node = current->next;
241  else
242  previous->next = current->next;
243 
244  free(current);
245  pthread_mutex_unlock(&mutex);
246  return;
247  }
248 
249  pthread_mutex_unlock(&mutex);
250 }
251 
252 static node_t *
254 {
255  TRACE_CALL(__func__);
256 
257  // TODO: too verbose REMMINA_DEBUG("search node");
258 
259  pthread_mutex_lock(&mutex);
260 
261  node_t *current = node;
262  while (current != NULL) {
263  if (current->channel == channel) {
264  pthread_mutex_unlock(&mutex);
265  // TODO: too verbose REMMINA_DEBUG("found node - fd_in: %d - fd_out: %d - protected: %d", current->fd_in, current->fd_out, current->protected);
266  return current;
267  } else {
268  current = current->next;
269  }
270  }
271 
272  pthread_mutex_unlock(&mutex);
273 
274  return NULL;
275 }
276 
277 static void
279 {
280  TRACE_CALL(__func__);
281  int opt;
282  socklen_t optlen;
283 
284  optlen = sizeof(opt);
285  if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
286  REMMINA_WARNING("getsockopt TCP_NODELAY: %.100s", strerror(errno));
287  return;
288  }
289  if (opt == 1) {
290  REMMINA_DEBUG("fd %d is TCP_NODELAY", fd);
291  return;
292  }
293  opt = 1;
294  REMMINA_DEBUG("fd %d setting TCP_NODELAY", fd);
295  if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1)
296  REMMINA_WARNING("setsockopt TCP_NODELAY: %.100s", strerror(errno));
297 }
298 
299 const char *
301 {
302  TRACE_CALL(__func__);
303 
304  if (gaierr == EAI_SYSTEM && errno != 0)
305  return strerror(errno);
306  return gai_strerror(gaierr);
307 }
308 
309 static int
310 remmina_ssh_x11_get_proto(const char *display, char **_proto, char **_cookie)
311 {
312  TRACE_CALL(__func__);
313 
314  char cmd[1024], line[512], xdisplay[512];
315  static char proto[512], cookie[512];
316  FILE *f;
317  int ret = 0, r;
318 
319  *_proto = proto;
320  *_cookie = cookie;
321 
322  proto[0] = cookie[0] = '\0';
323 
324  if (strncmp(display, "localhost:", 10) == 0) {
325  if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", display + 10)) < 0 || (size_t)r >= sizeof(xdisplay)) {
326  REMMINA_WARNING("display name too long. display: %s", display);
327  return -1;
328  }
329  display = xdisplay;
330  }
331 
332  snprintf(cmd, sizeof(cmd), _XAUTH_CMD, display);
333  REMMINA_DEBUG("xauth cmd: %s", cmd);
334 
335  f = popen(cmd, "r");
336  if (f && fgets(line, sizeof(line), f) && sscanf(line, "%*s %511s %511s", proto, cookie) == 2) {
337  ret = 0;
338  } else {
339  ret = 1;
340  }
341 
342  if (f) pclose(f);
343 
344  REMMINA_DEBUG("proto: %s - cookie: %s - ret: %d", proto, cookie, ret);
345 
346  return ret;
347 }
348 
349 static int
351 {
352  TRACE_CALL(__func__);
353 
354  int sock;
355  struct sockaddr_un addr;
356 
357  sock = socket(AF_UNIX, SOCK_STREAM, 0);
358  if (sock == -1)
359  REMMINA_WARNING("socket: %.100s", strerror(errno));
360 
361  memset(&addr, 0, sizeof(addr));
362  addr.sun_family = AF_UNIX;
363  addr.sun_path[0] = '\0';
364  memcpy(addr.sun_path + 1, pathname, strlen(pathname));
365  if (connect(sock, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(pathname)) == 0) {
366  REMMINA_DEBUG("sock: %d", sock);
367  return sock;
368  }
369 
370  REMMINA_WARNING("connect %.100s: %.100s", addr.sun_path, strerror(errno));
371  close(sock);
372 
373  return -1;
374 }
375 
376 static int
378 {
379  TRACE_CALL(__func__);
380 
381  char buf[1024];
382  snprintf(buf, sizeof(buf), _PATH_UNIX_X, display_number);
384 }
385 
386 static int
388 {
389  TRACE_CALL(__func__);
390 
391  unsigned int display_number;
392  const char *display;
393  char buf[1024], *cp;
394  struct addrinfo hints, *ai, *aitop;
395  char strport[NI_MAXSERV];
396  int gaierr, sock = 0;
397 
398  /* Try to open a socket for the local X server. */
399  display = getenv("DISPLAY");
400  if (!display) {
401  return -1;
402  }
403 
404  REMMINA_DEBUG("display: %s", display);
405 
406  /* Check if it is a unix domain socket. */
407  if (strncmp(display, "unix:", 5) == 0 || display[0] == ':') {
408  /* Connect to the unix domain socket. */
409  if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
410  REMMINA_WARNING("Could not parse display number from DISPLAY: %.100s", display);
411  return -1;
412  }
413 
414  REMMINA_DEBUG("display_number: %d", display_number);
415 
416  /* Create a socket. */
417  sock = remmina_ssh_connect_local_xsocket(display_number);
418 
419  REMMINA_DEBUG("socket: %d", sock);
420 
421  if (sock < 0)
422  return -1;
423 
424  /* OK, we now have a connection to the display. */
425  return sock;
426  }
427 
428  /* Connect to an inet socket. */
429  strncpy(buf, display, sizeof(buf) - 1);
430  cp = strchr(buf, ':');
431  if (!cp) {
432  REMMINA_WARNING("Could not find ':' in DISPLAY: %.100s", display);
433  return -1;
434  }
435  *cp = 0;
436  if (sscanf(cp + 1, "%u", &display_number) != 1) {
437  REMMINA_WARNING("Could not parse display number from DISPLAY: %.100s", display);
438  return -1;
439  }
440 
441  /* Look up the host address */
442  memset(&hints, 0, sizeof(hints));
443  hints.ai_family = AF_INET;
444  hints.ai_socktype = SOCK_STREAM;
445  snprintf(strport, sizeof(strport), "%u", 6000 + display_number);
446  if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
447  REMMINA_WARNING("%.100s: unknown host. (%s)", buf, remmina_ssh_ssh_gai_strerror(gaierr));
448  return -1;
449  }
450  for (ai = aitop; ai; ai = ai->ai_next) {
451  /* Create a socket. */
452  sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
453  if (sock == -1) {
454  REMMINA_WARNING("socket: %.100s", strerror(errno));
455  continue;
456  }
457  /* Connect it to the display. */
458  if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
459  REMMINA_WARNING("connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno));
460  close(sock);
461  continue;
462  }
463  /* Success */
464  break;
465  }
466  freeaddrinfo(aitop);
467  if (!ai) {
468  REMMINA_WARNING("connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno));
469  return -1;
470  }
472 
473  REMMINA_DEBUG("sock: %d", sock);
474 
475  return sock;
476 }
477 
478 static int
479 remmina_ssh_cp_to_ch_cb(int fd, int revents, void *userdata)
480 {
481  TRACE_CALL(__func__);
482  ssh_channel channel = (ssh_channel)userdata;
483  gchar *buf = (gchar *) g_malloc ( sizeof(gchar) * 0x200000 );
484  if (buf ==NULL){
485  return -1;
486  }
487  gint sz = 0, ret = 0;
488 
489  node_t *temp_node = remmina_ssh_search_item(channel);
490 
491  if (!channel) {
492  if (!temp_node->protected) {
493  shutdown(fd, SHUT_RDWR);
494  close(fd);
495  REMMINA_DEBUG("fd %d closed.", fd);
496  }
497  REMMINA_WARNING("channel does not exist.");
498  return -1;
499  }
500 
501  if ((revents & POLLIN) || (revents & POLLPRI)) {
502  sz = read(fd, buf, sizeof(buf));
503  if (sz > 0) {
504  ret = ssh_channel_write(channel, buf, sz);
505  if (ret != sz){
506  g_free(buf);
507  return -1;
508  }
509 
510  //TODO: too verbose REMMINA_DEBUG("ssh_channel_write ret: %d sz: %d", ret, sz);
511  } else if (sz < 0) {
512  // TODO: too verbose REMMINA_WARNING("fd bytes read: %d", sz);
513  g_free(buf);
514  return -1;
515  } else {
516  REMMINA_WARNING("Why the hell am I here?");
517  if (!temp_node->protected) {
518  shutdown(fd, SHUT_RDWR);
519  close(fd);
520  REMMINA_DEBUG("fd %d closed.", fd);
521  }
522  g_free(buf);
523  return -1;
524  }
525  }
526 
527  if ((revents & POLLHUP) || (revents & POLLNVAL) || (revents & POLLERR)) {
528  REMMINA_DEBUG("Closing channel.");
529  ssh_channel_close(channel);
530  ret = -1;
531  }
532  g_free(buf);
533  return ret;
534 }
535 
536 static int
537 remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata)
538 {
539  TRACE_CALL(__func__);
540  (void)session;
541  (void)is_stderr;
542  // Expecting userdata to be type RemminaSSHShell *, but it is unused
543  // in this function.
544  (void)userdata;
545 
546  node_t *temp_node = remmina_ssh_search_item(channel);
547  gint fd = temp_node->fd_out;
548  gint sz = 0;
549 
550  sz = write(fd, data, len);
551  // TODO: too verbose REMMINA_DEBUG("fd bytes written: %d", sz);
552 
553  return sz;
554 }
555 
556 static void
557 remmina_ssh_ch_close_cb(ssh_session session, ssh_channel channel, void *userdata)
558 {
559  TRACE_CALL(__func__);
560  (void)session;
561 
562  RemminaSSHShell *shell = (RemminaSSHShell *)userdata;
563 
564  node_t *temp_node = remmina_ssh_search_item(channel);
565 
566  if (temp_node != NULL) {
567  int fd = temp_node->fd_in;
568 
569  if (!temp_node->protected) {
570  remmina_ssh_delete_item(channel);
571  ssh_event_remove_fd(shell->event, fd);
572  shutdown(fd, SHUT_RDWR);
573  close(fd);
574  REMMINA_DEBUG("fd %d closed.", fd);
575  }
576  }
577  REMMINA_DEBUG("Channel closed.");
578 }
579 
580 static void
582 {
583  TRACE_CALL(__func__);
584 
585  REMMINA_DEBUG("Close all X11 channels");
586 
587  node_t *current = node;
588  while (current != NULL) {
589  if (current->thread == thread && !current->protected) {
590  shutdown(current->fd_in, SHUT_RDWR);
591  close(current->fd_in);
592  REMMINA_DEBUG("thread: %d - fd %d closed.", thread, current->fd_in);
593  if (current->fd_in != current->fd_out) {
594  shutdown(current->fd_out, SHUT_RDWR);
595  close(current->fd_out);
596  REMMINA_DEBUG("thread: %d - fd %d closed.", thread, current->fd_out);
597  }
598  }
599  current = current->next;
600  }
601 }
602 
603 static ssh_channel
604 remmina_ssh_x11_open_request_cb(ssh_session session, const char *shost, int sport, void *userdata)
605 {
606  TRACE_CALL(__func__);
607 
608  (void)shost;
609  (void)sport;
610 
611  RemminaSSHShell *shell = (RemminaSSHShell *)userdata;
612 
613  ssh_channel channel = ssh_channel_new(session);
614 
615  int sock = remmina_ssh_x11_connect_display();
616 
617  remmina_ssh_insert_item(channel, sock, sock, FALSE, shell->thread);
618 
619  ssh_event_add_fd(shell->event, sock, events, remmina_ssh_cp_to_ch_cb, channel);
620  ssh_event_add_session(shell->event, session);
621 
622  ssh_add_channel_callbacks(channel, &channel_cb);
623 
624  return channel;
625 }
626 
627 gchar *
629 {
630  TRACE_CALL(__func__);
631  if (id == NULL) return NULL;
632  if (id[0] == '/') return g_strdup(id);
633  return g_strdup_printf("%s/%s", g_get_home_dir(), id);
634 }
635 
636 gchar *
638 {
639  TRACE_CALL(__func__);
640  gchar *path;
641  gint i;
642 
643  for (i = 0; common_identities[i]; i++) {
645  if (g_file_test(path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))
646  return path;
647  g_free(path);
648  }
649  return NULL;
650 }
651 
652 void
653 remmina_ssh_set_error(RemminaSSH *ssh, const gchar *fmt)
654 {
655  TRACE_CALL(__func__);
656  const gchar *err;
657 
658  err = ssh_get_error(ssh->session);
659  ssh->error = g_strdup_printf(fmt, err);
660 }
661 
662 void
663 remmina_ssh_set_application_error(RemminaSSH *ssh, const gchar *fmt, ...)
664 {
665  TRACE_CALL(__func__);
666  va_list args;
667 
668  va_start(args, fmt);
669  ssh->error = g_strdup_vprintf(fmt, args);
670  va_end(args);
671 }
672 
673 static enum remmina_ssh_auth_result
675 {
676  TRACE_CALL(__func__);
677  gint ret;
678  gint n;
679  gint i;
680  const gchar *name, *instruction = NULL;
681  //gchar *prompt,*ptr;
682 
683  ret = SSH_AUTH_ERROR;
684  if (ssh->authenticated) return REMMINA_SSH_AUTH_SUCCESS;
685  /* TODO: What if I have an empty password? */
686  if (ssh->password == NULL) {
687  remmina_ssh_set_error(ssh, "OTP code is empty");
688  REMMINA_DEBUG("OTP code is empty, returning");
690  }
691  REMMINA_DEBUG("OTP code has been set to: %s", ssh->password);
692 
693  ret = ssh_userauth_kbdint(ssh->session, NULL, NULL);
694  while (ret == SSH_AUTH_INFO) {
695  name = ssh_userauth_kbdint_getname(ssh->session);
696  if (strlen(name) > 0)
697  REMMINA_DEBUG("SSH kbd-interactive name: %s", name);
698  else
699  REMMINA_DEBUG("SSH kbd-interactive name is empty");
700  instruction = ssh_userauth_kbdint_getinstruction(ssh->session);
701  if (strlen(instruction) > 0)
702  REMMINA_DEBUG("SSH kbd-interactive instruction: %s", instruction);
703  else
704  REMMINA_DEBUG("SSH kbd-interactive instruction is empty");
705  n = ssh_userauth_kbdint_getnprompts(ssh->session);
706  for (i = 0; i < n; i++)
707  ssh_userauth_kbdint_setanswer(ssh->session, i, ssh->password);
708  ret = ssh_userauth_kbdint(ssh->session, NULL, NULL);
709  }
710 
711 
712  REMMINA_DEBUG("ssh_userauth_kbdint returned %d", ret);
713  switch (ret) {
714  case SSH_AUTH_PARTIAL:
715  if (ssh->password) {
716  g_free(ssh->password);
717  ssh->password = NULL;
718  }
719  //You've been partially authenticated, you still have to use another method
720  REMMINA_DEBUG("Authenticated with SSH keyboard interactive. Another method is required. %d", ret);
721  ssh->is_multiauth = TRUE;
723  break;
724  case SSH_AUTH_SUCCESS:
725  //Authentication success
726  ssh->authenticated = TRUE;
727  REMMINA_DEBUG("Authenticated with SSH keyboard interactive. %s", ssh->error);
729  break;
730  case SSH_AUTH_INFO:
731  //The server asked some questions. Use ssh_userauth_kbdint_getnprompts() and such.
732  REMMINA_DEBUG("Authenticating aagin with SSH keyboard interactive??? %s", ssh->error);
733  break;
734  case SSH_AUTH_AGAIN:
735  //In nonblocking mode, you've got to call this again later.
736  REMMINA_DEBUG("Authenticated with keyboard interactive, Requested to authenticate again. %s", ssh->error);
738  break;
739  case SSH_AUTH_DENIED:
740  case SSH_AUTH_ERROR:
741  default:
742  //A serious error happened
743  ssh->authenticated = FALSE;
744  remmina_ssh_set_error(ssh, _("Could not authenticate with TOTP/OTP/2FA. %s"));
745  REMMINA_DEBUG("Cannot authenticate with TOTP/OTP/2FA. Error is %s", ssh->error);
747  }
748  ssh->authenticated = FALSE;
750 }
751 
752 static enum remmina_ssh_auth_result
754 {
755  TRACE_CALL(__func__);
756  gint ret;
757 
758  REMMINA_DEBUG("Password authentication");
759 
760  ret = SSH_AUTH_ERROR;
761  if (ssh->authenticated) {
762  REMMINA_DEBUG("Already authenticated");
764  }
765  if (ssh->password == NULL) {
766  remmina_ssh_set_error(ssh, "Password is null");
767  REMMINA_DEBUG("Password is null, returning");
769  }
770 
771  ret = ssh_userauth_password(ssh->session, NULL, ssh->password);
772  REMMINA_DEBUG("Authentication with SSH password returned: %d", ret);
773 
774  switch (ret) {
775  case SSH_AUTH_PARTIAL:
776  if (ssh->password) {
777  g_free(ssh->password);
778  ssh->password = NULL;
779  }
780  //You've been partially authenticated, you still have to use another method.
781  REMMINA_DEBUG("Authenticated with SSH password, Another method is required. %d", ret);
782  ssh->is_multiauth = TRUE;
784  break;
785  case SSH_AUTH_SUCCESS:
786  //The public key is accepted.
787  ssh->authenticated = TRUE;
788  REMMINA_DEBUG("Authenticated with SSH password. %s", ssh->error);
790  break;
791  case SSH_AUTH_AGAIN:
792  //In nonblocking mode, you've got to call this again later.
793  REMMINA_DEBUG("Authenticated with SSH password, Requested to authenticate again. %s", ssh->error);
794  ssh->authenticated = FALSE;
795  return REMMINA_SSH_AUTH_AGAIN;
796  break;
797  case SSH_AUTH_DENIED:
798  case SSH_AUTH_ERROR:
799  default:
800  //A serious error happened.
801  ssh->authenticated = FALSE;
802  REMMINA_DEBUG("Cannot authenticate with password. Error is %s", ssh->error);
803  remmina_ssh_set_error(ssh, _("Could not authenticate with SSH password. %s"));
805  }
806  ssh->authenticated = FALSE;
808 }
809 
810 static enum remmina_ssh_auth_result
812 {
813  TRACE_CALL(__func__);
814 
815  ssh_key key = NULL;
816  ssh_key cert = NULL;
817  gchar pubkey[132] = { 0 }; // +".pub"
818  gint ret;
819 
820  if (ssh->authenticated) return REMMINA_SSH_AUTH_SUCCESS;
821 
822  REMMINA_DEBUG("SSH certificate file: %s", ssh->certfile);
823  REMMINA_DEBUG("File for private SSH key: %s", ssh->privkeyfile);
824  if (ssh->certfile != NULL) {
825 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
826  /* First we import the private key */
827  if (ssh_pki_import_privkey_file(ssh->privkeyfile, (ssh->passphrase ? ssh->passphrase : ""),
828  NULL, NULL, &key) != SSH_OK) {
829  if (ssh->passphrase == NULL || ssh->passphrase[0] == '\0') {
830  remmina_ssh_set_error(ssh, _("No saved SSH password supplied. Asking user to enter it."));
832  }
833 
834  // TRANSLATORS: The placeholder %s is an error message
835  remmina_ssh_set_error(ssh, _("Could not authenticate with public SSH key. %s"));
837  }
838  REMMINA_DEBUG ("Imported private SSH key file");
839  /* First we import the certificate */
840  ret = ssh_pki_import_cert_file(ssh->certfile, &cert );
841  if (ret != SSH_OK) {
842  REMMINA_DEBUG ("Certificate import returned: %d", ret);
843  // TRANSLATORS: The placeholder %s is an error message
844  remmina_ssh_set_error(ssh, _("SSH certificate cannot be imported. %s"));
846  }
847  REMMINA_DEBUG ("certificate imported correctly");
848  /* We copy th certificate in the private key */
849  ret = ssh_pki_copy_cert_to_privkey(cert, key);
850  if (ret != SSH_OK) {
851  REMMINA_DEBUG ("Copying the certificate into a key returned: %d", ret);
852  // TRANSLATORS: The placeholder %s is an error message
853  remmina_ssh_set_error(ssh, _("SSH certificate cannot be copied into the private SSH key. %s"));
854  ssh_key_free(cert);
856  }
857  REMMINA_DEBUG ("%s certificate copied into the private SSH key", ssh->certfile);
858  /* We try to authenticate */
859  ret = ssh_userauth_try_publickey(ssh->session, NULL, cert);
860  if (ret != SSH_AUTH_SUCCESS && ret != SSH_AUTH_AGAIN ) {
861  REMMINA_DEBUG ("Trying to authenticate with the new key returned: %d", ret);
862  // TRANSLATORS: The placeholder %s is an error message
863  remmina_ssh_set_error(ssh, _("Could not authenticate using SSH certificate. %s"));
864  ssh_key_free(key);
865  ssh_key_free(cert);
867  }
868  REMMINA_DEBUG ("Authentication with a certificate file works, we can authenticate");
869 #else
870  REMMINA_DEBUG ("lbssh >= 0.9.0 is required to authenticate with certificate file");
871 #endif
872  /* if it goes well we authenticate (later on) with the key, not the cert*/
873  } else {
874  if (ssh->privkeyfile == NULL) {
875  // TRANSLATORS: The placeholder %s is an error message
876  ssh->error = g_strdup_printf(_("Could not authenticate with public SSH key. %s"),
877  _("SSH identity file not selected."));
879  }
880 
881  g_snprintf(pubkey, sizeof(pubkey), "%s.pub", ssh->privkeyfile);
882 
883  /*G_FILE_TEST_EXISTS*/
884  if (g_file_test(pubkey, G_FILE_TEST_EXISTS)) {
885  ret = ssh_pki_import_pubkey_file(pubkey, &key);
886  if (ret != SSH_OK) {
887  // TRANSLATORS: The placeholder %s is an error message
888  remmina_ssh_set_error(ssh, _("Public SSH key cannot be imported. %s"));
889  ssh_key_free(key);
891  }
892  }
893 
894  if (ssh_pki_import_privkey_file(ssh->privkeyfile, (ssh->passphrase ? ssh->passphrase : ""),
895  NULL, NULL, &key) != SSH_OK) {
896  if (ssh->passphrase == NULL || ssh->passphrase[0] == '\0') {
897  remmina_ssh_set_error(ssh, _("No saved SSH password supplied. Asking user to enter it."));
899  }
900 
901  // TRANSLATORS: The placeholder %s is an error message
902  remmina_ssh_set_error(ssh, _("Could not authenticate with public SSH key. %s"));
904  }
905  }
906 
907  ret = ssh_userauth_publickey(ssh->session, NULL, key);
908  ssh_key_free(key);
909  ssh_key_free(cert);
910  REMMINA_DEBUG("Authentication with public SSH key returned: %d", ret);
911 
912  switch (ret) {
913  case SSH_AUTH_PARTIAL:
914  if (ssh->password) {
915  g_free(ssh->password);
916  ssh->password = NULL;
917  }
918  //You've been partially authenticated, you still have to use another method.
919  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
920  ssh->is_multiauth = TRUE;
922  break;
923  case SSH_AUTH_SUCCESS:
924  //The public key is accepted.
925  ssh->authenticated = TRUE;
926  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
928  break;
929  case SSH_AUTH_AGAIN:
930  //In nonblocking mode, you've got to call this again later.
931  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
932  ssh->authenticated = FALSE;
934  break;
935  case SSH_AUTH_DENIED:
936  case SSH_AUTH_ERROR:
937  default:
938  //A serious error happened.
939  ssh->authenticated = FALSE;
940  REMMINA_DEBUG("Could not authenticate with public SSH key. %s", ssh->error);
941  remmina_ssh_set_error(ssh, _("Could not authenticate with public SSH key. %s"));
943  }
945 }
946 
947 static enum remmina_ssh_auth_result
949 {
950  TRACE_CALL(__func__);
951 
952  gint ret;
953  ret = ssh_userauth_publickey_auto(ssh->session, NULL, (ssh->passphrase ? ssh->passphrase : NULL));
954 
955  REMMINA_DEBUG("Authentication with public SSH key returned: %d", ret);
956 
957  switch (ret) {
958  case SSH_AUTH_PARTIAL:
959  if (ssh->password) {
960  g_free(ssh->password);
961  ssh->password = NULL;
962  }
963  //You've been partially authenticated, you still have to use another method.
964  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
965  ssh->is_multiauth = TRUE;
967  break;
968  case SSH_AUTH_SUCCESS:
969  //The public key is accepted.
970  ssh->authenticated = TRUE;
971  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
973  break;
974  case SSH_AUTH_AGAIN:
975  //In nonblocking mode, you've got to call this again later.
976  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
977  ssh->authenticated = FALSE;
979  break;
980  case SSH_AUTH_DENIED:
981  case SSH_AUTH_ERROR:
982  default:
983  //A serious error happened.
984  ssh->authenticated = FALSE;
985  REMMINA_DEBUG("Cannot authenticate automatically with public SSH key. %s", ssh->error);
986  remmina_ssh_set_error(ssh, _("Could not authenticate automatically with public SSH key. %s"));
988  }
989  ssh->authenticated = FALSE;
991 }
992 
993 static enum remmina_ssh_auth_result
995 {
996  TRACE_CALL(__func__);
997  gint ret;
998  ret = ssh_userauth_agent(ssh->session, NULL);
999 
1000  REMMINA_DEBUG("Authentication with SSH agent returned: %d", ret);
1001 
1002  switch (ret) {
1003  case SSH_AUTH_PARTIAL:
1004  if (ssh->password) {
1005  g_free(ssh->password);
1006  ssh->password = NULL;
1007  }
1008  //You've been partially authenticated, you still have to use another method.
1009  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
1010  ssh->is_multiauth = TRUE;
1011  return REMMINA_SSH_AUTH_PARTIAL;
1012  break;
1013  case SSH_AUTH_SUCCESS:
1014  //The public key is accepted.
1015  ssh->authenticated = TRUE;
1016  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
1017  return REMMINA_SSH_AUTH_SUCCESS;
1018  break;
1019  case SSH_AUTH_AGAIN:
1020  //In nonblocking mode, you've got to call this again later.
1021  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
1022  ssh->authenticated = FALSE;
1024  break;
1025  case SSH_AUTH_DENIED:
1026  case SSH_AUTH_ERROR:
1027  default:
1028  //A serious error happened.
1029  ssh->authenticated = FALSE;
1030  REMMINA_DEBUG("Cannot authenticate automatically with SSH agent. %s", ssh->error);
1031  remmina_ssh_set_error(ssh, _("Could not authenticate automatically with SSH agent. %s"));
1033  }
1034  ssh->authenticated = FALSE;
1036 
1037 }
1038 
1039 static enum remmina_ssh_auth_result
1041 {
1042  TRACE_CALL(__func__);
1043  gint ret;
1044 
1045  ret = ssh_userauth_gssapi(ssh->session);
1046  REMMINA_DEBUG("Authentication with SSH GSSAPI/Kerberos: %d", ret);
1047 
1048  switch (ret) {
1049  case SSH_AUTH_PARTIAL:
1050  if (ssh->password) {
1051  g_free(ssh->password);
1052  ssh->password = NULL;
1053  }
1054  //You've been partially authenticated, you still have to use another method.
1055  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
1056  ssh->is_multiauth = TRUE;
1057  return REMMINA_SSH_AUTH_PARTIAL;
1058  break;
1059  case SSH_AUTH_SUCCESS:
1060  //The public key is accepted.
1061  ssh->authenticated = TRUE;
1062  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
1063  return REMMINA_SSH_AUTH_SUCCESS;
1064  break;
1065  case SSH_AUTH_AGAIN:
1066  //In nonblocking mode, you've got to call this again later.
1067  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
1068  ssh->authenticated = FALSE;
1070  break;
1071  case SSH_AUTH_DENIED:
1072  case SSH_AUTH_ERROR:
1073  default:
1074  //A serious error happened.
1075  ssh->authenticated = FALSE;
1076  REMMINA_DEBUG("Cannot authenticate with SSH GSSAPI/Kerberos. %s", ssh->error);
1077  remmina_ssh_set_error(ssh, _("Could not authenticate with SSH GSSAPI/Kerberos. %s"));
1079  }
1080  ssh->authenticated = FALSE;
1082 }
1083 
1085 remmina_ssh_auth(RemminaSSH *ssh, const gchar *password, RemminaProtocolWidget *gp, RemminaFile *remminafile)
1086 {
1087  TRACE_CALL(__func__);
1088  gint method;
1090 
1091  /* Check known host again to ensure it’s still the original server when user forks
1092  * a new session from existing one */
1093 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1094  /* TODO: Add error checking
1095  * SSH_KNOWN_HOSTS_OK: The server is known and has not changed.
1096  * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you are under attack or the administrator changed the key. You HAVE to warn the user about a possible attack.
1097  * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while we had an other type recorded. It is a possible attack.
1098  * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should confirm the public key hash is correct.
1099  * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The host is thus unknown. File will be created if host key is accepted.
1100  * SSH_KNOWN_HOSTS_ERROR: There had been an error checking the host.
1101  */
1102  if (ssh_session_is_known_server(ssh->session) != SSH_KNOWN_HOSTS_OK) {
1103 #else
1104  if (ssh_is_server_known(ssh->session) != SSH_SERVER_KNOWN_OK) {
1105 #endif
1106  remmina_ssh_set_application_error(ssh, _("The public SSH key changed!"));
1108  }
1109 
1110  if (password) {
1111  if (password != ssh->password) {
1112  g_free(ssh->password);
1113  ssh->password = NULL;
1114  }
1115  if (password != ssh->passphrase) g_free(ssh->passphrase);
1116  ssh->password = g_strdup(password);
1117  ssh->passphrase = g_strdup(password);
1118  }
1119 
1134  method = ssh_userauth_list(ssh->session, NULL);
1135  REMMINA_DEBUG("Methods supported by server: %s%s%s%s%s%s%s",
1136  (method & SSH_AUTH_METHOD_NONE) ? "SSH_AUTH_METHOD_NONE " : "",
1137  (method & SSH_AUTH_METHOD_UNKNOWN) ? "SSH_AUTH_METHOD_UNKNOWN " : "",
1138  (method & SSH_AUTH_METHOD_PASSWORD) ? "SSH_AUTH_METHOD_PASSWORD " : "",
1139  (method & SSH_AUTH_METHOD_PUBLICKEY) ? "SSH_AUTH_METHOD_PUBLICKEY " : "",
1140  (method & SSH_AUTH_METHOD_HOSTBASED) ? "SSH_AUTH_METHOD_HOSTBASED " : "",
1141  (method & SSH_AUTH_METHOD_INTERACTIVE) ? "SSH_AUTH_METHOD_INTERACTIVE " : "",
1142  (method & SSH_AUTH_METHOD_GSSAPI_MIC) ? "SSH_AUTH_METHOD_GSSAPI_MIC " : ""
1143  );
1144  switch (ssh->auth) {
1145  case SSH_AUTH_PASSWORD:
1146  /* This authentication method is normally disabled on SSHv2 server. You should use keyboard-interactive mode. */
1147  REMMINA_DEBUG("SSH_AUTH_PASSWORD (%d)", ssh->auth);
1148  if (ssh->authenticated)
1149  return REMMINA_SSH_AUTH_SUCCESS;
1150  if (method & SSH_AUTH_METHOD_PASSWORD) {
1151  REMMINA_DEBUG("SSH using remmina_ssh_auth_password");
1152  rv = remmina_ssh_auth_password(ssh);
1153  }
1154  if (!ssh->authenticated && (method & SSH_AUTH_METHOD_INTERACTIVE)) {
1155  /* SSH server is requesting us to do interactive auth. */
1156  REMMINA_DEBUG("SSH using remmina_ssh_auth_interactive after password has failed");
1157  rv = remmina_ssh_auth_interactive(ssh);
1158  }
1159  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1160  if (ssh->password) {
1161  g_free(ssh->password);
1162  ssh->password = NULL;
1163  }
1164  switch (ssh_userauth_list(ssh->session, NULL)) {
1165  case SSH_AUTH_METHOD_PASSWORD:
1166  ssh->auth = SSH_AUTH_PASSWORD;
1167  break;
1168  case SSH_AUTH_METHOD_PUBLICKEY:
1169  ssh->auth = SSH_AUTH_PUBLICKEY;
1170  break;
1171  case SSH_AUTH_METHOD_HOSTBASED:
1172  REMMINA_DEBUG("Host-based authentication method not implemented: %d", ssh->auth);
1173  break;
1174  case SSH_AUTH_METHOD_INTERACTIVE:
1176  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1177  break;
1178  case SSH_AUTH_METHOD_UNKNOWN:
1179  default:
1180  REMMINA_DEBUG("User-based authentication method not supported: %d", ssh->auth);
1182  }
1183  }
1184  ssh->error = g_strdup_printf(_("Could not authenticate with SSH password. %s"), "");
1185  return rv;
1186  break;
1187 
1189  REMMINA_DEBUG("SSH using remmina_ssh_auth_interactive");
1190  if (method & SSH_AUTH_METHOD_INTERACTIVE) {
1191  rv = remmina_ssh_auth_interactive(ssh);
1192  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1193  if (ssh->password) {
1194  g_free(ssh->password);
1195  ssh->password = NULL;
1196  }
1197  switch (ssh_userauth_list(ssh->session, NULL)) {
1198  case SSH_AUTH_METHOD_PASSWORD:
1199  ssh->auth = SSH_AUTH_PASSWORD;
1200  break;
1201  case SSH_AUTH_METHOD_PUBLICKEY:
1202  ssh->auth = SSH_AUTH_PUBLICKEY;
1203  break;
1204  case SSH_AUTH_METHOD_HOSTBASED:
1205  REMMINA_DEBUG("Host-based authentication method not implemented: %d", ssh->auth);
1206  break;
1207  case SSH_AUTH_METHOD_INTERACTIVE:
1209  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1210  break;
1211  case SSH_AUTH_METHOD_UNKNOWN:
1212  default:
1213  REMMINA_DEBUG("User-based authentication method not supported: %d", ssh->auth);
1215  }
1216  }
1217  return rv;
1218  }
1219  ssh->error = g_strdup_printf(_("Could not authenticate with keyboard-interactive. %s"), "");
1220  break;
1221 
1222  case SSH_AUTH_PUBLICKEY:
1223  REMMINA_DEBUG("SSH_AUTH_PUBLICKEY (%d)", ssh->auth);
1224  if (method & SSH_AUTH_METHOD_PUBLICKEY) {
1225  rv = remmina_ssh_auth_pubkey(ssh, gp, remminafile);
1226  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1227  if (ssh->password) {
1228  g_free(ssh->password);
1229  ssh->password = NULL;
1230  }
1231  switch (ssh_userauth_list(ssh->session, NULL)) {
1232  case SSH_AUTH_METHOD_PASSWORD:
1233  ssh->auth = SSH_AUTH_PASSWORD;
1234  break;
1235  case SSH_AUTH_METHOD_PUBLICKEY:
1236  ssh->auth = SSH_AUTH_PUBLICKEY;
1237  break;
1238  case SSH_AUTH_METHOD_HOSTBASED:
1239  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1240  break;
1241  case SSH_AUTH_METHOD_INTERACTIVE:
1243  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1244  break;
1245  case SSH_AUTH_METHOD_UNKNOWN:
1246  default:
1247  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1249  }
1250  }
1251  return rv;
1252  }
1253  // The real error here should be: "The SSH server %s:%d does not support public key authentication"
1254  ssh->error = g_strdup_printf(_("Could not authenticate with public SSH key. %s"), "");
1255  break;
1256 
1257  case SSH_AUTH_AGENT:
1258  REMMINA_DEBUG("SSH_AUTH_AGENT (%d)", ssh->auth);
1259  rv = remmina_ssh_auth_agent(ssh);
1260  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1261  if (ssh->password) {
1262  g_free(ssh->password);
1263  ssh->password = NULL;
1264  }
1265  switch (ssh_userauth_list(ssh->session, NULL)) {
1266  case SSH_AUTH_METHOD_PASSWORD:
1267  ssh->auth = SSH_AUTH_PASSWORD;
1268  break;
1269  case SSH_AUTH_METHOD_PUBLICKEY:
1270  ssh->auth = SSH_AUTH_PUBLICKEY;
1271  break;
1272  case SSH_AUTH_METHOD_HOSTBASED:
1273  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1274  break;
1275  case SSH_AUTH_METHOD_INTERACTIVE:
1277  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1278  break;
1279  case SSH_AUTH_METHOD_UNKNOWN:
1280  default:
1281  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1283  }
1284  }
1285  return rv;
1286  break;
1287 
1289  REMMINA_DEBUG("SSH_AUTH_AUTO_PUBLICKEY (%d)", ssh->auth);
1290  rv = remmina_ssh_auth_auto_pubkey(ssh, gp, remminafile);
1291  /* ssh_agent or none */
1292  if (method & SSH_AUTH_METHOD_PUBLICKEY) {
1293  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1294  if (ssh->password) {
1295  g_free(ssh->password);
1296  ssh->password = NULL;
1297  }
1298  switch (ssh_userauth_list(ssh->session, NULL)) {
1299  case SSH_AUTH_METHOD_PASSWORD:
1300  ssh->auth = SSH_AUTH_PASSWORD;
1301  break;
1302  case SSH_AUTH_METHOD_PUBLICKEY:
1303  ssh->auth = SSH_AUTH_PUBLICKEY;
1304  break;
1305  case SSH_AUTH_METHOD_HOSTBASED:
1306  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1307  break;
1308  case SSH_AUTH_METHOD_INTERACTIVE:
1310  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1311  break;
1312  case SSH_AUTH_METHOD_UNKNOWN:
1313  default:
1314  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1316  }
1317  }
1318  return rv;
1319  }
1320  // The real error here should be: "The SSH server %s:%d does not support public key authentication"
1321  ssh->error = g_strdup_printf(_("Could not authenticate with automatic public SSH key. %s"), "");
1322  break;
1323 
1324 #if 0
1325  /* Not yet supported by libssh */
1326  case SSH_AUTH_HOSTBASED:
1327  if (method & SSH_AUTH_METHOD_HOSTBASED)
1328  //return remmina_ssh_auth_hostbased;
1329  return 0;
1330 #endif
1331 
1332  case SSH_AUTH_GSSAPI:
1333  REMMINA_DEBUG("SSH_AUTH_GSSAPI (%d)", ssh->auth);
1334  if (method & SSH_AUTH_METHOD_GSSAPI_MIC) {
1335  rv = remmina_ssh_auth_gssapi(ssh);
1336  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1337  if (ssh->password) {
1338  g_free(ssh->password);
1339  ssh->password = NULL;
1340  }
1341  switch (ssh_userauth_list(ssh->session, NULL)) {
1342  case SSH_AUTH_METHOD_PASSWORD:
1343  ssh->auth = SSH_AUTH_PASSWORD;
1344  break;
1345  case SSH_AUTH_METHOD_PUBLICKEY:
1346  ssh->auth = SSH_AUTH_PUBLICKEY;
1347  break;
1348  case SSH_AUTH_METHOD_HOSTBASED:
1349  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1350  break;
1351  case SSH_AUTH_METHOD_INTERACTIVE:
1353  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1354  break;
1355  case SSH_AUTH_METHOD_UNKNOWN:
1356  default:
1357  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1359  }
1360  }
1361  return rv;
1362  }
1363  // The real error here should be: "The SSH server %s:%d does not support SSH GSSAPI/Kerberos authentication"
1364  ssh->error = g_strdup_printf(_("Could not authenticate with SSH GSSAPI/Kerberos. %s"), "");
1365  break;
1366 
1367  default:
1368  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1370  }
1371 
1372  // We come here after a "break". ssh->error should be already set
1374 }
1375 
1378 {
1379  TRACE_CALL(__func__);
1380  gchar *keyname;
1381  gchar *pwdfkey = NULL;
1382  gchar *message;
1383  gchar *current_pwd;
1384  gchar *current_user;
1385  const gchar *instruction = NULL;
1386  gint ret;
1387  size_t len;
1388  guchar *pubkey;
1389  ssh_key server_pubkey;
1390  gboolean disablepasswordstoring;
1391  gboolean save_password;
1392  gint attempt;
1393 
1394  /* Check if the server’s public key is known */
1395 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1396  /* TODO: Add error checking
1397  * SSH_KNOWN_HOSTS_OK: The server is known and has not changed.
1398  * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you are under attack or the administrator changed the key. You HAVE to warn the user about a possible attack.
1399  * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while we had an other type recorded. It is a possible attack.
1400  * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should confirm the public key hash is correct.
1401  * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The host is thus unknown. File will be created if host key is accepted.
1402  * SSH_KNOWN_HOSTS_ERROR: There had been an error checking the host.
1403  */
1404  ret = ssh_session_is_known_server(ssh->session);
1405  switch (ret) {
1406  case SSH_KNOWN_HOSTS_OK:
1407  break; /* ok */
1408 
1409  /* TODO: These are all wrong, we should deal with each of them */
1410  case SSH_KNOWN_HOSTS_CHANGED:
1411  case SSH_KNOWN_HOSTS_OTHER:
1412  case SSH_KNOWN_HOSTS_UNKNOWN:
1413  case SSH_KNOWN_HOSTS_NOT_FOUND:
1414 #else
1415  ret = ssh_is_server_known(ssh->session);
1416  switch (ret) {
1417  case SSH_SERVER_KNOWN_OK:
1418  break; /* ok */
1419 
1420  /* fallback to SSH_SERVER_NOT_KNOWN behavior */
1421  case SSH_SERVER_KNOWN_CHANGED:
1422  case SSH_SERVER_FOUND_OTHER:
1423  case SSH_SERVER_NOT_KNOWN:
1424  case SSH_SERVER_FILE_NOT_FOUND:
1425 #endif
1426 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 8, 6)
1427  if (ssh_get_server_publickey(ssh->session, &server_pubkey) != SSH_OK) {
1428  // TRANSLATORS: The placeholder %s is an error message
1429  remmina_ssh_set_error(ssh, _("Could not fetch the server\'s public SSH key. %s"));
1430  REMMINA_DEBUG("ssh_get_server_publickey() has failed");
1432  }
1433 #else
1434  if (ssh_get_publickey(ssh->session, &server_pubkey) != SSH_OK) {
1435  // TRANSLATORS: The placeholder %s is an error message
1436  remmina_ssh_set_error(ssh, _("Could not fetch public SSH key. %s"));
1437  REMMINA_DEBUG("ssh_get_publickey() has failed");
1439  }
1440 #endif
1441  if (ssh_get_publickey_hash(server_pubkey, SSH_PUBLICKEY_HASH_MD5, &pubkey, &len) != 0) {
1442  ssh_key_free(server_pubkey);
1443  // TRANSLATORS: The placeholder %s is an error message
1444  remmina_ssh_set_error(ssh, _("Could not fetch checksum of the public SSH key. %s"));
1445  REMMINA_DEBUG("ssh_get_publickey_hash() has failed");
1447  }
1448  ssh_key_free(server_pubkey);
1449  keyname = ssh_get_hexa(pubkey, len);
1450 
1451 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1452  if (ret == SSH_KNOWN_HOSTS_UNKNOWN || ret == SSH_KNOWN_HOSTS_NOT_FOUND) {
1453 #else
1454  if (ret == SSH_SERVER_NOT_KNOWN || ret == SSH_SERVER_FILE_NOT_FOUND) {
1455 #endif
1456  message = g_strdup_printf("%s\n%s\n\n%s",
1457  _("The server is unknown. The public key fingerprint is:"),
1458  keyname,
1459  _("Do you trust the new public key?"));
1460  } else {
1461  message = g_strdup_printf("%s\n%s\n\n%s",
1462  _("Warning: The server has changed its public key. This means you are either under attack,\n"
1463  "or the administrator has changed the key. The new public key fingerprint is:"),
1464  keyname,
1465  _("Do you trust the new public key?"));
1466  }
1467 
1469  g_free(message);
1470 
1471  ssh_string_free_char(keyname);
1472  ssh_clean_pubkey_hash(&pubkey);
1473  if (ret != GTK_RESPONSE_YES) return REMMINA_SSH_AUTH_USERCANCEL;
1474 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1475  ssh_session_update_known_hosts(ssh->session);
1476 #else
1477  ssh_write_knownhost(ssh->session);
1478 #endif
1479  break;
1480 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1481  case SSH_KNOWN_HOSTS_ERROR:
1482 #else
1483  case SSH_SERVER_ERROR:
1484 #endif
1485  default:
1486  // TRANSLATORS: The placeholder %s is an error message
1487  remmina_ssh_set_error(ssh, _("Could not check list of known SSH hosts. %s"));
1488  REMMINA_DEBUG("Could not check list of known SSH hosts");
1490  }
1491 
1492  enum { REMMINA_SSH_AUTH_PASSWORD, REMMINA_SSH_AUTH_PKPASSPHRASE, REMMINA_SSH_AUTH_KRBTOKEN, REMMINA_SSH_AUTH_KBDINTERACTIVE } remmina_ssh_auth_type;
1493 
1494  switch (ssh->auth) {
1495  case SSH_AUTH_PASSWORD:
1496  keyname = _("SSH password");
1497  pwdfkey = ssh->is_tunnel ? "ssh_tunnel_password" : "password";
1498  remmina_ssh_auth_type = REMMINA_SSH_AUTH_PASSWORD;
1499  break;
1500  case SSH_AUTH_PUBLICKEY:
1501  case SSH_AUTH_AGENT:
1503  keyname = _("Password for private SSH key");
1504  pwdfkey = ssh->is_tunnel ? "ssh_tunnel_passphrase" : "ssh_passphrase";
1505  remmina_ssh_auth_type = REMMINA_SSH_AUTH_PKPASSPHRASE;
1506  break;
1507  case SSH_AUTH_GSSAPI:
1508  keyname = _("SSH Kerberos/GSSAPI");
1509  pwdfkey = ssh->is_tunnel ? "ssh_tunnel_kerberos_token" : "ssh_kerberos_token";
1510  remmina_ssh_auth_type = REMMINA_SSH_AUTH_KRBTOKEN;
1511  break;
1513  instruction = _("Enter TOTP/OTP/2FA code");
1514  remmina_ssh_auth_type = REMMINA_SSH_AUTH_KBDINTERACTIVE;
1515  break;
1516  default:
1518  }
1519 
1520  disablepasswordstoring = remmina_file_get_int(remminafile, "disablepasswordstoring", FALSE);
1521 
1522 
1523  current_pwd = g_strdup(remmina_file_get_string(remminafile, pwdfkey));
1524 
1525  /* Try existing password/passphrase first */
1526  ret = remmina_ssh_auth(ssh, current_pwd, gp, remminafile);
1527  REMMINA_DEBUG("Returned %d at 1st attempt with the following message:", ret);
1528  REMMINA_DEBUG("%s", ssh->error);
1529 
1530  /* It seems that functions like ssh_userauth_password() can only be called 3 times
1531  * on a ssh connection. And the 3rd failed attempt will block the calling thread forever.
1532  * So we retry only 2 extra time authentication. */
1533  for (attempt = 0;
1534  attempt < 2 && ret == REMMINA_SSH_AUTH_AUTHFAILED_RETRY_AFTER_PROMPT;
1535  attempt++) {
1536  if (ssh->error)
1537  REMMINA_DEBUG("Retrying auth because %s", ssh->error);
1538 
1539  if (remmina_ssh_auth_type == REMMINA_SSH_AUTH_PKPASSPHRASE) {
1541  (disablepasswordstoring ? 0 :
1543  ssh->is_tunnel ? _("SSH tunnel credentials") : _("SSH credentials"),
1544  NULL,
1545  remmina_file_get_string(remminafile, pwdfkey),
1546  NULL,
1547  _("Password for private SSH key"));
1548  if (ret == GTK_RESPONSE_OK) {
1549  g_free(current_pwd);
1550  current_pwd = remmina_protocol_widget_get_password(gp);
1551  save_password = remmina_protocol_widget_get_savepassword(gp);
1552  if (save_password)
1553  remmina_file_set_string(remminafile, pwdfkey, current_pwd);
1554  else
1555  remmina_file_set_string(remminafile, pwdfkey, NULL);
1556  } else {
1557  g_free(current_pwd);
1559  }
1560  } else if (remmina_ssh_auth_type == REMMINA_SSH_AUTH_PASSWORD) {
1561  /* Ask for user credentials. Username cannot be changed here,
1562  * because we already sent it when opening the connection */
1563  REMMINA_DEBUG("Showing panel for password\n");
1564  current_user = g_strdup(remmina_file_get_string(remminafile, ssh->is_tunnel ? "ssh_tunnel_username" : "username"));
1566  (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD)
1569  ssh->is_tunnel ? _("SSH tunnel credentials") : _("SSH credentials"),
1570  current_user,
1571  current_pwd,
1572  NULL,
1573  NULL);
1574  if (ret == GTK_RESPONSE_OK) {
1575  g_free(current_pwd);
1576  current_pwd = remmina_protocol_widget_get_password(gp);
1577  save_password = remmina_protocol_widget_get_savepassword(gp);
1578  if (save_password)
1579  remmina_file_set_string(remminafile, pwdfkey, current_pwd);
1580  else
1581  remmina_file_set_string(remminafile, pwdfkey, NULL);
1582 
1583  if (!ssh->is_tunnel && !ssh->is_multiauth) {
1584  g_free(current_user);
1585  current_user = remmina_protocol_widget_get_username(gp);
1586  remmina_file_set_string(remminafile, "username", current_user);
1587  if (ssh->user != NULL) {
1588  g_free(ssh->user);
1589  ssh->user = NULL;
1590  }
1591  ssh->user = g_strdup(current_user);
1592  if (ssh->password != NULL) {
1593  g_free(ssh->password);
1594  ssh->password = NULL;
1595  }
1596  ssh->password = g_strdup(current_pwd);
1597  g_free(current_user);
1599  }
1600  g_free(current_user);
1601  } else {
1602  g_free(current_pwd);
1603  g_free(current_user);
1605  }
1606  } else if (remmina_ssh_auth_type == REMMINA_SSH_AUTH_KBDINTERACTIVE) {
1607  REMMINA_DEBUG("Showing panel for keyboard interactive login\n");
1618  gp,
1619  0,
1620  _("Keyboard interactive login, TOTP/OTP/2FA"),
1621  NULL,
1622  NULL,
1623  NULL,
1624  instruction);
1625  if (ret == GTK_RESPONSE_OK) {
1626  g_free(current_pwd);
1627  current_pwd = remmina_protocol_widget_get_password(gp);
1628  REMMINA_DEBUG("OTP code is: %s", current_pwd);
1629  ssh->password = g_strdup(current_pwd);
1630  } else {
1631  g_free(current_pwd);
1633  }
1634  } else {
1635  g_print("Unimplemented.");
1636  g_free(current_pwd);
1638  }
1639  REMMINA_DEBUG("Retrying authentication");
1640  ret = remmina_ssh_auth(ssh, current_pwd, gp, remminafile);
1641  REMMINA_DEBUG("Authentication attempt n° %d returned %d with the following message:", attempt + 2, ret);
1642  REMMINA_DEBUG("%s", ssh->error);
1643  }
1644 
1645  g_free(current_pwd); current_pwd = NULL;
1646 
1647  /* After attempting the max number of times, REMMINA_SSH_AUTH_AUTHFAILED_RETRY_AFTER_PROMPT
1648  * becomes REMMINA_SSH_AUTH_FATAL_ERROR */
1650  REMMINA_DEBUG("SSH Authentication failed");
1652  }
1653 
1654  return ret;
1655 }
1656 
1657 void
1658 remmina_ssh_log_callback(ssh_session session, int priority, const char *message, void *userdata)
1659 {
1660  TRACE_CALL(__func__);
1661  REMMINA_DEBUG(message);
1662 }
1663 
1664 gboolean
1666 {
1667  TRACE_CALL(__func__);
1668  gint verbosity;
1669  gint rc;
1670  gchar *parsed_config;
1671 #ifdef HAVE_NETINET_TCP_H
1672  socket_t sshsock;
1673  gint optval;
1674 #endif
1675  // Handle IPv4 / IPv6 dual stack
1676  char *hostname;
1677  struct addrinfo hints,*aitop,*ai;
1678  char ipstr[INET6_ADDRSTRLEN];
1679  void *addr4=NULL;
1680  void *addr6=NULL;
1681 
1682  ssh->callback = g_new0(struct ssh_callbacks_struct, 1);
1683 
1684  /* Init & startup the SSH session */
1685  REMMINA_DEBUG("server=%s port=%d is_tunnel=%s tunnel_entrance_host=%s tunnel_entrance_port=%d",
1686  ssh->server,
1687  ssh->port,
1688  ssh->is_tunnel ? "Yes" : "No",
1690 
1691  ssh->session = ssh_new();
1692 
1693  /* Tunnel sanity checks */
1694  if (ssh->is_tunnel && ssh->tunnel_entrance_host != NULL) {
1695  ssh->error = g_strdup_printf("Internal error in %s: is_tunnel and tunnel_entrance != NULL", __func__);
1696  REMMINA_DEBUG(ssh->error);
1697  return FALSE;
1698  }
1699  if (!ssh->is_tunnel && ssh->tunnel_entrance_host == NULL) {
1700  ssh->error = g_strdup_printf("Internal error in %s: is_tunnel == false and tunnel_entrance == NULL", __func__);
1701  REMMINA_DEBUG(ssh->error);
1702  return FALSE;
1703  }
1704 
1705  /* Set connection host/port */
1706  if (ssh->is_tunnel) {
1707  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->server);
1708  ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->port);
1709  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to %s and SSH_OPTIONS_PORT to %d", ssh->server, ssh->port);
1710  } else {
1711  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->tunnel_entrance_host);
1712  ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->tunnel_entrance_port);
1713  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to %s and SSH_OPTIONS_PORT to %d", ssh->tunnel_entrance_host, ssh->tunnel_entrance_port);
1714  }
1715 
1716  if (ssh->privkeyfile && *ssh->privkeyfile != 0) {
1717  rc = ssh_options_set(ssh->session, SSH_OPTIONS_IDENTITY, ssh->privkeyfile);
1718  if (rc == 0)
1719  REMMINA_DEBUG("SSH_OPTIONS_IDENTITY is now %s", ssh->privkeyfile);
1720  else
1721  REMMINA_DEBUG("SSH_OPTIONS_IDENTITY is not set, by default the files “identity”, “id_dsa” and “id_rsa” are used.");
1722  }
1723 
1724 #ifdef SNAP_BUILD
1725  ssh_options_set(ssh->session, SSH_OPTIONS_SSH_DIR, g_strdup_printf("%s/.ssh", g_getenv("SNAP_USER_COMMON")));
1726 #endif
1727  ssh_callbacks_init(ssh->callback);
1728  if (remmina_log_running()) {
1729  verbosity = remmina_pref.ssh_loglevel;
1730  ssh_options_set(ssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
1731  ssh->callback->log_function = remmina_ssh_log_callback;
1732  /* Reset libssh legacy userdata. This is a workaround for a libssh bug */
1733  ssh_set_log_userdata(ssh->session);
1734  }
1735  ssh->callback->userdata = ssh;
1736  ssh_set_callbacks(ssh->session, ssh->callback);
1737 
1738  /* As the latest parse the ~/.ssh/config file */
1739  if (g_strcmp0(ssh->tunnel_entrance_host, "127.0.0.1") == 0) {
1740  REMMINA_DEBUG("SSH_OPTIONS_HOST temporary set to the destination host as ssh->tunnel_entrance_host is 127.0.0.1,");
1741  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->server);
1742  }
1744  if (ssh_options_parse_config(ssh->session, NULL) == 0)
1745  REMMINA_DEBUG("ssh_config have been correctly parsed");
1746  else
1747  REMMINA_DEBUG("Cannot parse ssh_config: %s", ssh_get_error(ssh->session));
1748  }
1749  if (g_strcmp0(ssh->tunnel_entrance_host, "127.0.0.1") == 0) {
1750  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to ssh->tunnel_entrance_host is 127.0.0.1,");
1751  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->tunnel_entrance_host);
1752  }
1753  if (!ssh->user || *ssh->user == 0) {
1754  rc = ssh_options_get(ssh->session, SSH_OPTIONS_USER, &parsed_config);
1755  if (rc == SSH_OK) {
1756  if (ssh->user)
1757  g_free(ssh->user);
1758  ssh->user = g_strdup(parsed_config);
1759  ssh_string_free_char(parsed_config);
1760  } else {
1761  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_USER returned an error: %s", ssh_get_error(ssh->session));
1762  }
1763  }
1764  ssh_options_set(ssh->session, SSH_OPTIONS_USER, ssh->user);
1765  REMMINA_DEBUG("SSH_OPTIONS_USER is now %s", ssh->user);
1766 
1767  /* SSH_OPTIONS_PROXYCOMMAND */
1768  rc = ssh_options_get(ssh->session, SSH_OPTIONS_PROXYCOMMAND, &parsed_config);
1769  if (rc == SSH_OK) {
1770  ssh->proxycommand = g_strdup(parsed_config);
1771  ssh_string_free_char(parsed_config);
1772  } else {
1773  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_PROXYCOMMAND returned an error: %s", ssh_get_error(ssh->session));
1774  }
1775  rc = ssh_options_set(ssh->session, SSH_OPTIONS_PROXYCOMMAND, ssh->proxycommand);
1776  if (rc == 0)
1777  REMMINA_DEBUG("SSH_OPTIONS_PROXYCOMMAND is now %s", ssh->proxycommand);
1778  else
1779  REMMINA_DEBUG("SSH_OPTIONS_PROXYCOMMAND does not have a valid value. %s", ssh->proxycommand);
1780 
1781  /* SSH_OPTIONS_HOSTKEYS */
1782  rc = ssh_options_get(ssh->session, SSH_OPTIONS_HOSTKEYS, &parsed_config);
1783  if (rc == SSH_OK) {
1784  ssh->hostkeytypes = g_strdup(parsed_config);
1785  ssh_string_free_char(parsed_config);
1786  } else {
1787  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_HOSTKEYS returned an error: %s", ssh_get_error(ssh->session));
1788  }
1789  rc = ssh_options_set(ssh->session, SSH_OPTIONS_HOSTKEYS, ssh->hostkeytypes);
1790  if (rc == 0)
1791  REMMINA_DEBUG("SSH_OPTIONS_HOSTKEYS is now %s", ssh->hostkeytypes);
1792  else
1793  REMMINA_DEBUG("SSH_OPTIONS_HOSTKEYS does not have a valid value. %s", ssh->hostkeytypes);
1794 
1795  /* SSH_OPTIONS_KEY_EXCHANGE */
1796  rc = ssh_options_get(ssh->session, SSH_OPTIONS_KEY_EXCHANGE, &parsed_config);
1797  if (rc == SSH_OK) {
1798  ssh->kex_algorithms = g_strdup(parsed_config);
1799  ssh_string_free_char(parsed_config);
1800  } else {
1801  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_KEY_EXCHANGE returned an error: %s", ssh_get_error(ssh->session));
1802  }
1803  rc = ssh_options_set(ssh->session, SSH_OPTIONS_KEY_EXCHANGE, ssh->kex_algorithms);
1804  if (rc == 0)
1805  REMMINA_DEBUG("SSH_OPTIONS_KEY_EXCHANGE is now %s", ssh->kex_algorithms);
1806  else
1807  REMMINA_DEBUG("SSH_OPTIONS_KEY_EXCHANGE does not have a valid value. %s", ssh->kex_algorithms);
1808 
1809  /* SSH_OPTIONS_CIPHERS_C_S */
1810  rc = ssh_options_get(ssh->session, SSH_OPTIONS_CIPHERS_C_S, &parsed_config);
1811  if (rc == SSH_OK) {
1812  ssh->ciphers = g_strdup(parsed_config);
1813  ssh_string_free_char(parsed_config);
1814  } else {
1815  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_CIPHERS_C_S returned an error: %s", ssh_get_error(ssh->session));
1816  }
1817  rc = ssh_options_set(ssh->session, SSH_OPTIONS_CIPHERS_C_S, ssh->ciphers);
1818  if (rc == 0)
1819  REMMINA_DEBUG("SSH_OPTIONS_CIPHERS_C_S has been set to %s", ssh->ciphers);
1820  else
1821  REMMINA_DEBUG("SSH_OPTIONS_CIPHERS_C_S does not have a valid value. %s", ssh->ciphers);
1822  /* SSH_OPTIONS_STRICTHOSTKEYCHECK */
1823  rc = ssh_options_get(ssh->session, SSH_OPTIONS_STRICTHOSTKEYCHECK, &parsed_config);
1824  if (rc == SSH_OK) {
1825  ssh->stricthostkeycheck = atoi(parsed_config);
1826  ssh_string_free_char(parsed_config);
1827  } else {
1828  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_STRICTHOSTKEYCHECK returned an error: %s", ssh_get_error(ssh->session));
1829  }
1830  rc = ssh_options_set(ssh->session, SSH_OPTIONS_STRICTHOSTKEYCHECK, &ssh->stricthostkeycheck);
1831  if (rc == 0)
1832  REMMINA_DEBUG("SSH_OPTIONS_STRICTHOSTKEYCHECK is now %d", ssh->stricthostkeycheck);
1833  else
1834  REMMINA_DEBUG("SSH_OPTIONS_STRICTHOSTKEYCHECK does not have a valid value. %d", ssh->stricthostkeycheck);
1835  /* SSH_OPTIONS_COMPRESSION */
1836  rc = ssh_options_get(ssh->session, SSH_OPTIONS_COMPRESSION, &parsed_config);
1837  if (rc == SSH_OK) {
1838  ssh->compression = g_strdup(parsed_config);
1839  ssh_string_free_char(parsed_config);
1840  } else {
1841  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_COMPRESSION returned an error: %s", ssh_get_error(ssh->session));
1842  }
1843  rc = ssh_options_set(ssh->session, SSH_OPTIONS_COMPRESSION, ssh->compression);
1844  if (rc == 0)
1845  REMMINA_DEBUG("SSH_OPTIONS_COMPRESSION is now %s", ssh->compression);
1846  else
1847  REMMINA_DEBUG("SSH_OPTIONS_COMPRESSION does not have a valid value. %s", ssh->compression);
1848 
1849  // Handle the dual IPv4 / IPv6 stack
1850  // Prioritize IPv6 and fallback to IPv4
1851 
1852  // Run the DNS resolution
1853  // First retrieve host from the ssh->session structure
1854  ssh_options_get(ssh->session, SSH_OPTIONS_HOST, &hostname);
1855  // Call getaddrinfo
1856  memset(&hints, 0, sizeof(hints));
1857  hints.ai_family = AF_UNSPEC;
1858  hints.ai_socktype = SOCK_STREAM;
1859  if ((getaddrinfo(hostname, NULL, &hints, &aitop)) != 0) {
1860  ssh->error = g_strdup_printf("Could not resolve hostname %s", hostname);
1861  REMMINA_DEBUG(ssh->error);
1862  return FALSE;
1863  }
1864 
1865  // We have one or more addesses now, extract them
1866  ai = aitop;
1867  while (ai != NULL) {
1868  if (ai->ai_family == AF_INET) { // IPv4
1869  struct sockaddr_in *ipv4 = (struct sockaddr_in *)ai->ai_addr;
1870  addr4 = &(ipv4->sin_addr);
1871  } else { // IPv6
1872  struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)ai->ai_addr;
1873  addr6 = &(ipv6->sin6_addr);
1874  }
1875  ai = ai->ai_next;
1876  }
1877  freeaddrinfo(aitop);
1878 
1879  unsigned short int success6 = 0;
1880  if (addr6 != NULL) {
1881  // Try IPv6 first
1882  inet_ntop(AF_INET6, addr6, ipstr, sizeof ipstr);
1883  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ipstr);
1884  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to IPv6 %s", ipstr);
1885  if (ssh_connect(ssh->session)) {
1886  ssh_disconnect(ssh->session);
1887  REMMINA_DEBUG("IPv6 session failed");
1888  } else {
1889  success6 = 1;
1890  REMMINA_DEBUG("IPv6 session success !");
1891  }
1892  }
1893  if (success6 == 0) {
1894  // Fallback to IPv4
1895  inet_ntop(AF_INET, addr4, ipstr, sizeof ipstr);
1896  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ipstr);
1897  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to IPv4 %s", ipstr);
1898  if (ssh_connect(ssh->session)) {
1899  // TRANSLATORS: The placeholder %s is an error message
1900  remmina_ssh_set_error(ssh, _("Could not start SSH session. %s"));
1901  return FALSE;
1902  }
1903  }
1904 
1905 #ifdef HAVE_NETINET_TCP_H
1906  /* Set keepalive on SSH socket, so we can keep firewalls awaken and detect
1907  * when we loss the tunnel */
1908  sshsock = ssh_get_fd(ssh->session);
1909  if (sshsock >= 0) {
1910  optval = 1;
1911  if (setsockopt(sshsock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
1912  REMMINA_DEBUG("TCP KeepAlive not set");
1913  else
1914  REMMINA_DEBUG("TCP KeepAlive enabled");
1915 
1916 #ifdef TCP_KEEPIDLE
1917  optval = remmina_pref.ssh_tcp_keepidle;
1918  if (setsockopt(sshsock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) < 0)
1919  REMMINA_DEBUG("TCP_KEEPIDLE not set");
1920  else
1921  REMMINA_DEBUG("TCP_KEEPIDLE set to %i", optval);
1922 
1923 #endif
1924 #ifdef TCP_KEEPCNT
1925  optval = remmina_pref.ssh_tcp_keepcnt;
1926  if (setsockopt(sshsock, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)) < 0)
1927  REMMINA_DEBUG("TCP_KEEPCNT not set");
1928  else
1929  REMMINA_DEBUG("TCP_KEEPCNT set to %i", optval);
1930 
1931 #endif
1932 #ifdef TCP_KEEPINTVL
1934  if (setsockopt(sshsock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)) < 0)
1935  REMMINA_DEBUG("TCP_KEEPINTVL not set");
1936  else
1937  REMMINA_DEBUG("TCP_KEEPINTVL set to %i", optval);
1938 
1939 #endif
1940 #ifdef TCP_USER_TIMEOUT
1942  if (setsockopt(sshsock, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval)) < 0)
1943  REMMINA_DEBUG("TCP_USER_TIMEOUT not set");
1944  else
1945  REMMINA_DEBUG("TCP_USER_TIMEOUT set to %i", optval);
1946 
1947 #endif
1948  }
1949 #endif
1950 
1951  /* Try the "none" authentication */
1952  if (ssh_userauth_none(ssh->session, NULL) == SSH_AUTH_SUCCESS)
1953  ssh->authenticated = TRUE;
1954  return TRUE;
1955 }
1956 
1957 gboolean
1958 remmina_ssh_init_from_file(RemminaSSH *ssh, RemminaFile *remminafile, gboolean is_tunnel)
1959 {
1960  TRACE_CALL(__func__);
1961  const gchar *username;
1962  const gchar *privatekey;
1963  const gchar *server;
1964  gchar *s;
1965 
1966  ssh->session = NULL;
1967  ssh->callback = NULL;
1968  ssh->authenticated = FALSE;
1969  ssh->error = NULL;
1970  ssh->passphrase = NULL;
1971  ssh->is_tunnel = is_tunnel;
1972  pthread_mutex_init(&ssh->ssh_mutex, NULL);
1973 
1974  ssh->tunnel_entrance_host = NULL;
1975  ssh->tunnel_entrance_port = 0;
1976 
1977  username = remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_username" : "username");
1978  privatekey = remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_privatekey" : "ssh_privatekey");
1979  ssh->certfile = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_certfile" : "ssh_certfile"));
1980 
1981  /* The ssh->server and ssh->port values */
1982  if (is_tunnel) {
1983  REMMINA_DEBUG("We are initializing an SSH tunnel session");
1984  server = remmina_file_get_string(remminafile, "ssh_tunnel_server");
1985  if (server == NULL || server[0] == 0) {
1986  // ssh_tunnel_server empty or invalid, we are opening a tunnel, it means that "Same server at port 22" has been selected
1987  server = remmina_file_get_string(remminafile, "server");
1988  if (server == NULL || server[0] == 0)
1989  server = "localhost";
1990  REMMINA_DEBUG("Calling remmina_public_get_server_port");
1991  remmina_public_get_server_port(server, 22, &ssh->server, &ssh->port);
1992  ssh->port = 22;
1993  } else {
1994  REMMINA_DEBUG("Calling remmina_public_get_server_port");
1995  remmina_public_get_server_port(server, 22, &ssh->server, &ssh->port);
1996  }
1997  REMMINA_DEBUG("server:port = %s, server = %s, port = %d", server, ssh->server, ssh->port);
1998  } else {
1999  REMMINA_DEBUG("We are initializing an SSH session");
2000  server = remmina_file_get_string(remminafile, "server");
2001  if (server == NULL || server[0] == 0)
2002  server = "localhost";
2003  REMMINA_DEBUG("Calling remmina_public_get_server_port");
2004  remmina_public_get_server_port(server, 22, &ssh->server, &ssh->port);
2005  REMMINA_DEBUG("server:port = %s, server = %s, port = %d", server, ssh->server, ssh->port);
2006  }
2007 
2008  if (ssh->server[0] == '\0') {
2009  g_free(ssh->server);
2010  // ???
2011  REMMINA_DEBUG("Calling remmina_public_get_server_port");
2012  remmina_public_get_server_port(server, 0, &ssh->server, NULL);
2013  }
2014 
2015  REMMINA_DEBUG("Initialized SSH struct from file with ssh->server = %s and SSH->port = %d", ssh->server, ssh->port);
2016 
2017  ssh->user = g_strdup(username ? username : NULL);
2018  ssh->password = NULL;
2019  ssh->auth = remmina_file_get_int(remminafile, is_tunnel ? "ssh_tunnel_auth" : "ssh_auth", 0);
2020  ssh->charset = g_strdup(remmina_file_get_string(remminafile, "ssh_charset"));
2021  ssh->kex_algorithms = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_kex_algorithms" : "ssh_kex_algorithms"));
2022  ssh->ciphers = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_ciphers" : "ssh_ciphers"));
2023  ssh->hostkeytypes = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_hostkeytypes" : "ssh_hostkeytypes"));
2024  ssh->proxycommand = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_proxycommand" : "ssh_proxycommand"));
2025  ssh->stricthostkeycheck = remmina_file_get_int(remminafile, is_tunnel ? "ssh_tunnel_stricthostkeycheck" : "ssh_stricthostkeycheck", 0);
2026  gint c = remmina_file_get_int(remminafile, is_tunnel ? "ssh_tunnel_compression" : "ssh_compression", 0);
2027  ssh->compression = (c == 1) ? "yes" : "no";
2028 
2029  REMMINA_DEBUG("ssh->user: %s", ssh->user);
2030  REMMINA_DEBUG("ssh->password: %s", ssh->password);
2031  REMMINA_DEBUG("ssh->auth: %d", ssh->auth);
2032  REMMINA_DEBUG("ssh->charset: %s", ssh->charset);
2033  REMMINA_DEBUG("ssh->kex_algorithms: %s", ssh->kex_algorithms);
2034  REMMINA_DEBUG("ssh->ciphers: %s", ssh->ciphers);
2035  REMMINA_DEBUG("ssh->hostkeytypes: %s", ssh->hostkeytypes);
2036  REMMINA_DEBUG("ssh->proxycommand: %s", ssh->proxycommand);
2037  REMMINA_DEBUG("ssh->stricthostkeycheck: %d", ssh->stricthostkeycheck);
2038  REMMINA_DEBUG("ssh->compression: %s", ssh->compression);
2039 
2040  /* Public/Private keys */
2041  s = (privatekey ? g_strdup(privatekey) : remmina_ssh_find_identity());
2042  if (s) {
2044  REMMINA_DEBUG("ssh->privkeyfile: %s", ssh->privkeyfile);
2045  g_free(s);
2046  } else {
2047  ssh->privkeyfile = NULL;
2048  }
2049 
2050  return TRUE;
2051 }
2052 
2053 static gboolean
2054 remmina_ssh_init_from_ssh(RemminaSSH *ssh, const RemminaSSH *ssh_src)
2055 {
2056  TRACE_CALL(__func__);
2057  ssh->session = NULL;
2058  ssh->authenticated = FALSE;
2059  ssh->error = NULL;
2060  pthread_mutex_init(&ssh->ssh_mutex, NULL);
2061 
2062  ssh->is_tunnel = ssh_src->is_tunnel;
2063  ssh->server = g_strdup(ssh_src->server);
2064  ssh->port = ssh_src->port;
2065  ssh->user = g_strdup(ssh_src->user ? ssh_src->user : NULL);
2066  ssh->auth = ssh_src->auth;
2067  ssh->password = g_strdup(ssh_src->password);
2068  ssh->passphrase = g_strdup(ssh_src->passphrase);
2069  ssh->privkeyfile = g_strdup(ssh_src->privkeyfile);
2070  ssh->certfile = g_strdup(ssh_src->certfile);
2071  ssh->charset = g_strdup(ssh_src->charset);
2072  ssh->proxycommand = g_strdup(ssh_src->proxycommand);
2073  ssh->kex_algorithms = g_strdup(ssh_src->kex_algorithms);
2074  ssh->ciphers = g_strdup(ssh_src->ciphers);
2075  ssh->hostkeytypes = g_strdup(ssh_src->hostkeytypes);
2076  ssh->stricthostkeycheck = ssh_src->stricthostkeycheck;
2077  ssh->compression = ssh_src->compression;
2078  ssh->tunnel_entrance_host = g_strdup(ssh_src->tunnel_entrance_host);
2080 
2081  return TRUE;
2082 }
2083 
2084 gchar *
2085 remmina_ssh_convert(RemminaSSH *ssh, const gchar *from)
2086 {
2087  TRACE_CALL(__func__);
2088  gchar *to = NULL;
2089 
2090  if (ssh->charset && from)
2091  to = g_convert(from, -1, "UTF-8", ssh->charset, NULL, NULL, NULL);
2092  if (!to) to = g_strdup(from);
2093  return to;
2094 }
2095 
2096 gchar *
2097 remmina_ssh_unconvert(RemminaSSH *ssh, const gchar *from)
2098 {
2099  TRACE_CALL(__func__);
2100  gchar *to = NULL;
2101 
2102  if (ssh->charset && from)
2103  to = g_convert(from, -1, ssh->charset, "UTF-8", NULL, NULL, NULL);
2104  if (!to) to = g_strdup(from);
2105  return to;
2106 }
2107 
2108 void
2110 {
2111  TRACE_CALL(__func__);
2112  if (ssh->session) {
2113  REMMINA_DEBUG("Disconnecting SSH session");
2114  ssh_disconnect(ssh->session);
2115  ssh_free(ssh->session);
2116  ssh->session = NULL;
2117  }
2118  g_free(ssh->callback);
2119  g_free(ssh->server);
2120  g_free(ssh->user);
2121  g_free(ssh->password);
2122  g_free(ssh->privkeyfile);
2123  g_free(ssh->certfile);
2124  g_free(ssh->charset);
2125  g_free(ssh->error);
2126  pthread_mutex_destroy(&ssh->ssh_mutex);
2127  g_free(ssh);
2128 }
2129 
2130 /*-----------------------------------------------------------------------------*
2131 * SSH Tunnel *
2132 *-----------------------------------------------------------------------------*/
2133 struct _RemminaSSHTunnelBuffer {
2134  gchar * data;
2135  gchar * ptr;
2136  ssize_t len;
2137 };
2138 
2139 static RemminaSSHTunnelBuffer *
2140 remmina_ssh_tunnel_buffer_new(ssize_t len)
2141 {
2142  TRACE_CALL(__func__);
2143  RemminaSSHTunnelBuffer *buffer;
2144 
2145  buffer = g_new(RemminaSSHTunnelBuffer, 1);
2146  buffer->data = (gchar *)g_malloc(len);
2147  buffer->ptr = buffer->data;
2148  buffer->len = len;
2149  return buffer;
2150 }
2151 
2152 static void
2153 remmina_ssh_tunnel_buffer_free(RemminaSSHTunnelBuffer *buffer)
2154 {
2155  TRACE_CALL(__func__);
2156  if (buffer) {
2157  g_free(buffer->data);
2158  g_free(buffer);
2159  }
2160 }
2161 
2164 {
2165  TRACE_CALL(__func__);
2166  RemminaSSHTunnel *tunnel;
2167 
2168  tunnel = g_new(RemminaSSHTunnel, 1);
2169 
2170  remmina_ssh_init_from_file(REMMINA_SSH(tunnel), remminafile, TRUE);
2171 
2172  tunnel->tunnel_type = -1;
2173  tunnel->channels = NULL;
2174  tunnel->sockets = NULL;
2175  tunnel->socketbuffers = NULL;
2176  tunnel->num_channels = 0;
2177  tunnel->max_channels = 0;
2178  tunnel->thread = 0;
2179  tunnel->running = FALSE;
2180  tunnel->server_sock = -1;
2181  tunnel->dest = NULL;
2182  tunnel->port = 0;
2183  tunnel->buffer = NULL;
2184  tunnel->buffer_len = 0;
2185  tunnel->channels_out = NULL;
2186  tunnel->remotedisplay = 0;
2187  tunnel->localdisplay = NULL;
2188  tunnel->init_func = NULL;
2189  tunnel->connect_func = NULL;
2190  tunnel->disconnect_func = NULL;
2191  tunnel->callback_data = NULL;
2192 
2193  return tunnel;
2194 }
2195 
2196 static void
2197 remmina_ssh_tunnel_close_all_channels(RemminaSSHTunnel *tunnel)
2198 {
2199  TRACE_CALL(__func__);
2200  int i;
2201 
2202  for (i = 0; i < tunnel->num_channels; i++) {
2203  close(tunnel->sockets[i]);
2204  remmina_ssh_tunnel_buffer_free(tunnel->socketbuffers[i]);
2205  ssh_channel_close(tunnel->channels[i]);
2206  ssh_channel_send_eof(tunnel->channels[i]);
2207  ssh_channel_free(tunnel->channels[i]);
2208  }
2209 
2210  g_free(tunnel->channels);
2211  tunnel->channels = NULL;
2212  g_free(tunnel->sockets);
2213  tunnel->sockets = NULL;
2214  g_free(tunnel->socketbuffers);
2215  tunnel->socketbuffers = NULL;
2216 
2217  tunnel->num_channels = 0;
2218  tunnel->max_channels = 0;
2219 }
2220 
2221 static void
2222 remmina_ssh_tunnel_remove_channel(RemminaSSHTunnel *tunnel, gint n)
2223 {
2224  TRACE_CALL(__func__);
2225  ssh_channel_close(tunnel->channels[n]);
2226  ssh_channel_send_eof(tunnel->channels[n]);
2227  ssh_channel_free(tunnel->channels[n]);
2228  close(tunnel->sockets[n]);
2229  remmina_ssh_tunnel_buffer_free(tunnel->socketbuffers[n]);
2230  tunnel->num_channels--;
2231  tunnel->channels[n] = tunnel->channels[tunnel->num_channels];
2232  tunnel->channels[tunnel->num_channels] = NULL;
2233  tunnel->sockets[n] = tunnel->sockets[tunnel->num_channels];
2234  tunnel->socketbuffers[n] = tunnel->socketbuffers[tunnel->num_channels];
2235 }
2236 
2237 /* Register the new channel/socket pair */
2238 static void
2239 remmina_ssh_tunnel_add_channel(RemminaSSHTunnel *tunnel, ssh_channel channel, gint sock)
2240 {
2241  TRACE_CALL(__func__);
2242  gint flags;
2243  gint i;
2244 
2245  i = tunnel->num_channels++;
2246  if (tunnel->num_channels > tunnel->max_channels) {
2247  /* Allocate an extra NULL pointer in channels for ssh_select */
2248  tunnel->channels = (ssh_channel *)g_realloc(tunnel->channels,
2249  sizeof(ssh_channel) * (tunnel->num_channels + 1));
2250  tunnel->sockets = (gint *)g_realloc(tunnel->sockets,
2251  sizeof(gint) * tunnel->num_channels);
2252  tunnel->socketbuffers = (RemminaSSHTunnelBuffer **)g_realloc(tunnel->socketbuffers,
2253  sizeof(RemminaSSHTunnelBuffer *) * tunnel->num_channels);
2254  tunnel->max_channels = tunnel->num_channels;
2255 
2256  tunnel->channels_out = (ssh_channel *)g_realloc(tunnel->channels_out,
2257  sizeof(ssh_channel) * (tunnel->num_channels + 1));
2258  }
2259  tunnel->channels[i] = channel;
2260  tunnel->channels[i + 1] = NULL;
2261  tunnel->sockets[i] = sock;
2262  tunnel->socketbuffers[i] = NULL;
2263 
2264  flags = fcntl(sock, F_GETFL, 0);
2265  fcntl(sock, F_SETFL, flags | O_NONBLOCK);
2266 }
2267 
2268 static int
2269 remmina_ssh_tunnel_accept_local_connection(RemminaSSHTunnel *tunnel, gboolean blocking)
2270 {
2271  gint sock, sock_flags;
2272 
2273  sock_flags = fcntl(tunnel->server_sock, F_GETFL, 0);
2274  if (blocking)
2275  sock_flags &= ~O_NONBLOCK;
2276  else
2277  sock_flags |= O_NONBLOCK;
2278  fcntl(tunnel->server_sock, F_SETFL, sock_flags);
2279 
2280  /* Accept a local connection */
2281  sock = accept(tunnel->server_sock, NULL, NULL);
2282  if (sock < 0) {
2283  if (blocking) {
2284  g_free(REMMINA_SSH(tunnel)->error);
2285  REMMINA_SSH(tunnel)->error = g_strdup("Local socket not accepted");
2286  }
2287  }
2288 
2289  return sock;
2290 }
2291 
2292 static ssh_channel
2293 remmina_ssh_tunnel_create_forward_channel(RemminaSSHTunnel *tunnel)
2294 {
2295  ssh_channel channel = NULL;
2296 
2297  channel = ssh_channel_new(tunnel->ssh.session);
2298  if (!channel) {
2299  // TRANSLATORS: The placeholder %s is an error message
2300  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not create channel. %s"));
2301  return NULL;
2302  }
2303 
2304  /* Request the SSH server to connect to the destination */
2305  REMMINA_DEBUG("SSH tunnel destination is %s", tunnel->dest);
2306  if (ssh_channel_open_forward(channel, tunnel->dest, tunnel->port, "127.0.0.1", 0) != SSH_OK) {
2307  ssh_channel_close(channel);
2308  ssh_channel_send_eof(channel);
2309  ssh_channel_free(channel);
2310  // TRANSLATORS: The placeholder %s is an error message
2311  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not connect to SSH tunnel. %s"));
2312  return NULL;
2313  }
2314 
2315  return channel;
2316 }
2317 
2318 static gpointer
2319 remmina_ssh_tunnel_main_thread_proc(gpointer data)
2320 {
2321  TRACE_CALL(__func__);
2322  RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data;
2323  gchar *ptr;
2324  ssize_t len = 0, lenw = 0;
2325  fd_set set;
2326  struct timeval timeout;
2327  g_autoptr(GDateTime) t1 = NULL;
2328  g_autoptr(GDateTime) t2 = NULL;
2329  GTimeSpan diff; // microseconds
2330  ssh_channel channel = NULL;
2331  gboolean first = TRUE;
2332  gboolean disconnected;
2333  gint sock;
2334  gint maxfd;
2335  gint i;
2336  gint ret;
2337  struct sockaddr_in sin;
2338 
2339  t1 = t2 = g_date_time_new_now_local();
2340 
2341  switch (tunnel->tunnel_type) {
2343  sock = remmina_ssh_tunnel_accept_local_connection(tunnel, TRUE);
2344  if (sock < 0) {
2345  if (tunnel)
2346  tunnel->thread = 0;
2347  return NULL;
2348  }
2349 
2350  channel = remmina_ssh_tunnel_create_forward_channel(tunnel);
2351  if (!tunnel) {
2352  close(sock);
2353  tunnel->thread = 0;
2354  return NULL;
2355  }
2356 
2357  remmina_ssh_tunnel_add_channel(tunnel, channel, sock);
2358  break;
2359 
2361  /* Detect the next available port starting from 6010 on the server */
2362  for (i = 10; i <= MAX_X_DISPLAY_NUMBER; i++) {
2363 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2364  if (ssh_channel_listen_forward(REMMINA_SSH(tunnel)->session, (tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL)) {
2365  continue;
2366  } else {
2367  tunnel->remotedisplay = i;
2368  break;
2369  }
2370 #else
2371  if (ssh_forward_listen(REMMINA_SSH(tunnel)->session, (tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL)) {
2372  continue;
2373  } else {
2374  tunnel->remotedisplay = i;
2375  break;
2376  }
2377 #endif
2378  }
2379  if (tunnel->remotedisplay < 1) {
2380  // TRANSLATORS: The placeholder %s is an error message
2381  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not request port forwarding. %s"));
2382  if (tunnel->disconnect_func)
2383  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2384  tunnel->thread = 0;
2385  return NULL;
2386  }
2387 
2388  if (tunnel->init_func &&
2389  !(*tunnel->init_func)(tunnel, tunnel->callback_data)) {
2390  if (tunnel->disconnect_func)
2391  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2392  tunnel->thread = 0;
2393  return NULL;
2394  }
2395 
2396  break;
2397 
2399 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2400  if (ssh_channel_listen_forward(REMMINA_SSH(tunnel)->session, NULL, tunnel->port, NULL)) {
2401  // TRANSLATORS: The placeholder %s is an error message
2402  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not request port forwarding. %s"));
2403  if (tunnel->disconnect_func)
2404  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2405  tunnel->thread = 0;
2406  return NULL;
2407  }
2408 #else
2409  if (ssh_forward_listen(REMMINA_SSH(tunnel)->session, NULL, tunnel->port, NULL)) {
2410  // TRANSLATORS: The placeholder %s is an error message
2411  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not request port forwarding. %s"));
2412  if (tunnel->disconnect_func)
2413  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2414  tunnel->thread = 0;
2415  return NULL;
2416  }
2417 #endif
2418 
2419  if (tunnel->init_func &&
2420  !(*tunnel->init_func)(tunnel, tunnel->callback_data)) {
2421  if (tunnel->disconnect_func)
2422  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2423  tunnel->thread = 0;
2424  return NULL;
2425  }
2426 
2427  break;
2428  }
2429 
2430  tunnel->buffer_len = 10240;
2431  tunnel->buffer = g_malloc(tunnel->buffer_len);
2432 
2433  /* Start the tunnel data transmission */
2434  while (tunnel->running) {
2435  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT ||
2437  if (first) {
2438  first = FALSE;
2439  channel = ssh_channel_accept_forward(REMMINA_SSH(tunnel)->session, 15000, &tunnel->port);
2440  if (!channel) {
2441  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("The server did not respond."));
2442  if (tunnel->disconnect_func)
2443  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2444  tunnel->thread = 0;
2445  return NULL;
2446  }
2447  if (tunnel->connect_func)
2448  (*tunnel->connect_func)(tunnel, tunnel->callback_data);
2449  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) {
2450  /* For reverse tunnel, we only need one connection. */
2451 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2452  ssh_channel_cancel_forward(REMMINA_SSH(tunnel)->session, NULL, tunnel->port);
2453 #else
2454  ssh_forward_cancel(REMMINA_SSH(tunnel)->session, NULL, tunnel->port);
2455 #endif
2456  }
2457  } else if (tunnel->tunnel_type != REMMINA_SSH_TUNNEL_REVERSE) {
2458  /* Poll once per some period of time if no incoming connections.
2459  * Don’t try to poll continuously as it will significantly slow down the loop */
2460  t1 = g_date_time_new_now_local();
2461  diff = g_date_time_difference(t1, t2) * 10000000
2462  + g_date_time_difference(t1, t2) / 100000;
2463  if (diff > 1) {
2464  REMMINA_DEBUG("Polling tunnel channels");
2465  channel = ssh_channel_accept_forward(REMMINA_SSH(tunnel)->session, 0, &tunnel->port);
2466  if (channel == NULL)
2467  t2 = t1;
2468  }
2469  g_date_time_unref(t1);
2470  g_date_time_unref(t2);
2471  }
2472 
2473  if (channel) {
2474  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) {
2475  sin.sin_family = AF_INET;
2476  sin.sin_port = htons(tunnel->localport);
2477  sin.sin_addr.s_addr = inet_addr("127.0.0.1");
2478  sock = socket(AF_INET, SOCK_STREAM, 0);
2479  if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
2480  remmina_ssh_set_application_error(REMMINA_SSH(tunnel),
2481  _("Cannot connect to local port %i."), tunnel->localport);
2482  close(sock);
2483  sock = -1;
2484  }
2485  } else
2487  if (sock >= 0)
2488  remmina_ssh_tunnel_add_channel(tunnel, channel, sock);
2489  else {
2490  /* Failed to create unix socket. Will this happen? */
2491  ssh_channel_close(channel);
2492  ssh_channel_send_eof(channel);
2493  ssh_channel_free(channel);
2494  }
2495  channel = NULL;
2496  }
2497  }
2498 
2499  if (tunnel->num_channels <= 0)
2500  /* No more connections. We should quit */
2501  break;
2502 
2503  timeout.tv_sec = 0;
2504  timeout.tv_usec = 200000;
2505 
2506  FD_ZERO(&set);
2507  maxfd = 0;
2508  for (i = 0; i < tunnel->num_channels; i++) {
2509  if (tunnel->sockets[i] > maxfd)
2510  maxfd = tunnel->sockets[i];
2511  FD_SET(tunnel->sockets[i], &set);
2512  }
2513 
2514  ret = ssh_select(tunnel->channels, tunnel->channels_out, maxfd + 1, &set, &timeout);
2515  if (!tunnel->running) break;
2516  if (ret == SSH_EINTR) continue;
2517  if (ret == -1) break;
2518 
2519  i = 0;
2520  while (tunnel->running && i < tunnel->num_channels) {
2521  disconnected = FALSE;
2522  if (FD_ISSET(tunnel->sockets[i], &set)) {
2523  while (!disconnected &&
2524  (len = read(tunnel->sockets[i], tunnel->buffer, tunnel->buffer_len)) > 0) {
2525  for (ptr = tunnel->buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw) {
2526  lenw = ssh_channel_write(tunnel->channels[i], (char *)ptr, len);
2527  if (lenw <= 0) {
2528  disconnected = TRUE;
2529  // TRANSLATORS: The placeholder %s is an error message
2530  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not write to SSH channel. %s"));
2531  break;
2532  }
2533  }
2534  }
2535  if (len == 0) {
2536  // TRANSLATORS: The placeholder %s is an error message
2537  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not read from tunnel listening socket. %s"));
2538  disconnected = TRUE;
2539  }
2540  }
2541  if (disconnected) {
2542  REMMINA_DEBUG("tunnel disconnected because %s", REMMINA_SSH(tunnel)->error);
2543  remmina_ssh_tunnel_remove_channel(tunnel, i);
2544  continue;
2545  }
2546  i++;
2547  }
2548  if (!tunnel->running) break;
2549 
2550  i = 0;
2551  while (tunnel->running && i < tunnel->num_channels) {
2552  disconnected = FALSE;
2553  if (!tunnel->socketbuffers[i]) {
2554  len = ssh_channel_poll(tunnel->channels[i], 0);
2555  if (len == SSH_ERROR || len == SSH_EOF) {
2556  // TRANSLATORS: The placeholder %s is an error message
2557  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not poll SSH channel. %s"));
2558  disconnected = TRUE;
2559  } else if (len > 0) {
2560  tunnel->socketbuffers[i] = remmina_ssh_tunnel_buffer_new(len);
2561  len = ssh_channel_read_nonblocking(tunnel->channels[i], tunnel->socketbuffers[i]->data, len, 0);
2562  if (len <= 0) {
2563  // TRANSLATORS: The placeholder %s is an error message
2564  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not read SSH channel in a non-blocking way. %s"));
2565  disconnected = TRUE;
2566  } else {
2567  tunnel->socketbuffers[i]->len = len;
2568  }
2569  }
2570  }
2571 
2572  if (!disconnected && tunnel->socketbuffers[i]) {
2573  for (lenw = 0; tunnel->socketbuffers[i]->len > 0;
2574  tunnel->socketbuffers[i]->len -= lenw, tunnel->socketbuffers[i]->ptr += lenw) {
2575  lenw = write(tunnel->sockets[i], tunnel->socketbuffers[i]->ptr, tunnel->socketbuffers[i]->len);
2576  if (lenw == -1 && errno == EAGAIN && tunnel->running)
2577  /* Sometimes we cannot write to a socket (always EAGAIN), probably because it’s internal
2578  * buffer is full. We need read the pending bytes from the socket first. so here we simply
2579  * break, leave the buffer there, and continue with other data */
2580  break;
2581  if (lenw <= 0) {
2582  // TRANSLATORS: The placeholder %s is an error message
2583  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not send data to tunnel listening socket. %s"));
2584  disconnected = TRUE;
2585  break;
2586  }
2587  }
2588  if (tunnel->socketbuffers[i]->len <= 0) {
2589  remmina_ssh_tunnel_buffer_free(tunnel->socketbuffers[i]);
2590  tunnel->socketbuffers[i] = NULL;
2591  }
2592  }
2593 
2594  if (disconnected) {
2595  REMMINA_DEBUG("Connection to SSH tunnel dropped. %s", REMMINA_SSH(tunnel)->error);
2596  remmina_ssh_tunnel_remove_channel(tunnel, i);
2597  continue;
2598  }
2599  i++;
2600  }
2605  sock = remmina_ssh_tunnel_accept_local_connection(tunnel, FALSE);
2606  if (sock > 0) {
2607  channel = remmina_ssh_tunnel_create_forward_channel(tunnel);
2608  if (!channel) {
2609  REMMINA_DEBUG("Could not open new SSH connection. %s", REMMINA_SSH(tunnel)->error);
2610  close(sock);
2611  /* Leave thread loop */
2612  tunnel->running = FALSE;
2613  } else {
2614  remmina_ssh_tunnel_add_channel(tunnel, channel, sock);
2615  }
2616  }
2617  }
2618 
2619  remmina_ssh_tunnel_close_all_channels(tunnel);
2620 
2621  tunnel->running = FALSE;
2622 
2623  /* Notify tunnel owner of disconnection */
2624  if (tunnel->disconnect_func)
2625  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2626 
2627  return NULL;
2628 }
2629 
2630 static gboolean remmina_ssh_notify_tunnel_main_thread_end(gpointer data)
2631 {
2632  TRACE_CALL(__func__);
2633  RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data;
2634 
2635  /* Ask tunnel owner to destroy tunnel object */
2636  if (tunnel->destroy_func)
2637  (*tunnel->destroy_func)(tunnel, tunnel->destroy_func_callback_data);
2638 
2639  return FALSE;
2640 }
2641 
2642 static gpointer
2643 remmina_ssh_tunnel_main_thread(gpointer data)
2644 {
2645  TRACE_CALL(__func__);
2646  RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data;
2647 
2648  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
2649 
2650  while (TRUE) {
2651  remmina_ssh_tunnel_main_thread_proc(data);
2652  if (tunnel->server_sock < 0 || tunnel->thread == 0 || !tunnel->running) break;
2653  }
2654  tunnel->thread = 0;
2655 
2656  /* Do after tunnel thread cleanup */
2657  IDLE_ADD((GSourceFunc)remmina_ssh_notify_tunnel_main_thread_end, (gpointer)tunnel);
2658 
2659  return NULL;
2660 }
2661 
2662 
2663 void
2665 {
2666  TRACE_CALL(__func__);
2667  if (tunnel->server_sock >= 0) {
2668  close(tunnel->server_sock);
2669  tunnel->server_sock = -1;
2670  }
2671 }
2672 
2673 gboolean
2674 remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port)
2675 {
2676  TRACE_CALL(__func__);
2677  gint sock;
2678  gint sockopt = 1;
2679  struct sockaddr_in sin;
2680 
2682  tunnel->dest = g_strdup(host);
2683  tunnel->port = port;
2684  if (tunnel->port == 0) {
2685  REMMINA_SSH(tunnel)->error = g_strdup(_("Assign a destination port."));
2686  return FALSE;
2687  }
2688 
2689  /* Create the server socket that listens on the local port */
2690  sock = socket(AF_INET, SOCK_STREAM, 0);
2691  if (sock < 0) {
2692  REMMINA_SSH(tunnel)->error = g_strdup(_("Could not create socket."));
2693  return FALSE;
2694  }
2695  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
2696 
2697  sin.sin_family = AF_INET;
2698  sin.sin_port = htons(local_port);
2699  sin.sin_addr.s_addr = inet_addr("127.0.0.1");
2700 
2701  if (bind(sock, (struct sockaddr *)&sin, sizeof(sin))) {
2702  REMMINA_SSH(tunnel)->error = g_strdup(_("Could not bind server socket to local port."));
2703  close(sock);
2704  return FALSE;
2705  }
2706 
2707  if (listen(sock, 1)) {
2708  REMMINA_SSH(tunnel)->error = g_strdup(_("Could not listen to local port."));
2709  close(sock);
2710  return FALSE;
2711  }
2712 
2713  tunnel->server_sock = sock;
2714  tunnel->running = TRUE;
2715 
2716  if (pthread_create(&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) {
2717  // TRANSLATORS: Do not translate pthread
2718  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("Could not start pthread."));
2719  tunnel->thread = 0;
2720  return FALSE;
2721  }
2722  return TRUE;
2723 }
2724 
2725 gboolean
2726 remmina_ssh_tunnel_xport(RemminaSSHTunnel *tunnel, gboolean bindlocalhost)
2727 {
2728  TRACE_CALL(__func__);
2730  tunnel->bindlocalhost = bindlocalhost;
2731  tunnel->running = TRUE;
2732 
2733  if (pthread_create(&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) {
2734  // TRANSLATORS: Do not translate pthread
2735  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("Could not start pthread."));
2736  tunnel->thread = 0;
2737  return FALSE;
2738  }
2739  return TRUE;
2740 }
2741 
2742 gboolean
2743 remmina_ssh_tunnel_reverse(RemminaSSHTunnel *tunnel, gint port, gint local_port)
2744 {
2745  TRACE_CALL(__func__);
2747  tunnel->port = port;
2748  tunnel->localport = local_port;
2749  tunnel->running = TRUE;
2750 
2751  if (pthread_create(&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) {
2752  // TRANSLATORS: Do not translate pthread
2753  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("Could not start pthread."));
2754  tunnel->thread = 0;
2755  return FALSE;
2756  }
2757  return TRUE;
2758 }
2759 
2760 gboolean
2762 {
2763  TRACE_CALL(__func__);
2764  return tunnel->thread == 0;
2765 }
2766 
2767 void
2769 {
2770  TRACE_CALL(__func__);
2771  pthread_t thread;
2772 
2773  REMMINA_DEBUG("tunnel->thread = %lX\n", tunnel->thread);
2774 
2775  thread = tunnel->thread;
2776  if (thread != 0) {
2777  tunnel->running = FALSE;
2778  pthread_cancel(thread);
2779  pthread_join(thread, NULL);
2780  tunnel->thread = 0;
2781  }
2782 
2783  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT && tunnel->remotedisplay > 0) {
2784 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2785  ssh_channel_cancel_forward(REMMINA_SSH(tunnel)->session, NULL, 6000 + tunnel->remotedisplay);
2786 #else
2787  ssh_forward_cancel(REMMINA_SSH(tunnel)->session, NULL, 6000 + tunnel->remotedisplay);
2788 #endif
2789  }
2790  if (tunnel->server_sock >= 0) {
2791  close(tunnel->server_sock);
2792  tunnel->server_sock = -1;
2793  }
2794 
2795  remmina_ssh_tunnel_close_all_channels(tunnel);
2796 
2797  g_free(tunnel->buffer);
2798  g_free(tunnel->channels_out);
2799  g_free(tunnel->dest);
2800  g_free(tunnel->localdisplay);
2801 
2802  remmina_ssh_free((RemminaSSH *)tunnel);
2803 }
2804 
2805 /*-----------------------------------------------------------------------------*
2806 * SSH SFTP *
2807 *-----------------------------------------------------------------------------*/
2808 RemminaSFTP *
2810 {
2811  TRACE_CALL(__func__);
2812  RemminaSFTP *sftp;
2813 
2814  sftp = g_new(RemminaSFTP, 1);
2815 
2816  remmina_ssh_init_from_file(REMMINA_SSH(sftp), remminafile, FALSE);
2817 
2818  sftp->sftp_sess = NULL;
2819 
2820  return sftp;
2821 }
2822 
2823 RemminaSFTP *
2825 {
2826  TRACE_CALL(__func__);
2827  RemminaSFTP *sftp;
2828 
2829  sftp = g_new(RemminaSFTP, 1);
2830 
2831  remmina_ssh_init_from_ssh(REMMINA_SSH(sftp), ssh);
2832 
2833  sftp->sftp_sess = NULL;
2834 
2835  return sftp;
2836 }
2837 
2838 gboolean
2840 {
2841  TRACE_CALL(__func__);
2842  sftp->sftp_sess = sftp_new(sftp->ssh.session);
2843  if (!sftp->sftp_sess) {
2844  // TRANSLATORS: The placeholder %s is an error message
2845  remmina_ssh_set_error(REMMINA_SSH(sftp), _("Could not create SFTP session. %s"));
2846  return FALSE;
2847  }
2848  if (sftp_init(sftp->sftp_sess)) {
2849  // TRANSLATORS: The placeholder %s is an error message
2850  remmina_ssh_set_error(REMMINA_SSH(sftp), _("Could not start SFTP session. %s"));
2851  return FALSE;
2852  }
2853  return TRUE;
2854 }
2855 
2856 void
2858 {
2859  TRACE_CALL(__func__);
2860  if (sftp->sftp_sess) {
2861  sftp_free(sftp->sftp_sess);
2862  sftp->sftp_sess = NULL;
2863  }
2864  remmina_ssh_free(REMMINA_SSH(sftp));
2865 }
2866 
2867 /*-----------------------------------------------------------------------------*
2868 * SSH Shell *
2869 *-----------------------------------------------------------------------------*/
2872 {
2873  TRACE_CALL(__func__);
2874  RemminaSSHShell *shell;
2875 
2876  shell = g_new0(RemminaSSHShell, 1);
2877 
2878  remmina_ssh_init_from_file(REMMINA_SSH(shell), remminafile, FALSE);
2879 
2880  shell->master = -1;
2881  shell->slave = -1;
2882  shell->exec = g_strdup(remmina_file_get_string(remminafile, "exec"));
2883  shell->run_line = g_strdup(remmina_file_get_string(remminafile, "run_line"));
2884 
2885  return shell;
2886 }
2887 
2890 {
2891  TRACE_CALL(__func__);
2892  RemminaSSHShell *shell;
2893 
2894  shell = g_new0(RemminaSSHShell, 1);
2895 
2896  remmina_ssh_init_from_ssh(REMMINA_SSH(shell), ssh);
2897 
2898  shell->master = -1;
2899  shell->slave = -1;
2900 
2901  return shell;
2902 }
2903 
2904 static gboolean
2905 remmina_ssh_call_exit_callback_on_main_thread(gpointer data)
2906 {
2907  TRACE_CALL(__func__);
2908 
2909  RemminaSSHShell *shell = (RemminaSSHShell *)data;
2910  if (shell->exit_callback)
2911  shell->exit_callback(shell->user_data);
2912  if (shell) {
2913  remmina_ssh_shell_free(shell);
2914  shell = NULL;
2915  }
2916  return FALSE;
2917 }
2918 
2919 static gpointer
2920 remmina_ssh_shell_thread(gpointer data)
2921 {
2922  TRACE_CALL(__func__);
2923  RemminaSSHShell *shell = (RemminaSSHShell *)data;
2925  RemminaFile *remminafile;
2926  remminafile = remmina_protocol_widget_get_file(gp);
2927  ssh_channel channel = NULL;
2928  gint ret;
2929  gchar *filename;
2930  const gchar *dir;
2931  const gchar *sshlogname;
2932  FILE *fp = NULL;
2933 
2934  //gint screen;
2935 
2936  LOCK_SSH(shell)
2937 
2938  if ((channel = ssh_channel_new(REMMINA_SSH(shell)->session)) == NULL ||
2939  ssh_channel_open_session(channel)) {
2940  UNLOCK_SSH(shell)
2941  // TRANSLATORS: The placeholder %s is an error message
2942  remmina_ssh_set_error(REMMINA_SSH(shell), _("Could not open channel. %s"));
2943  if (channel) ssh_channel_free(channel);
2944  shell->thread = 0;
2945  return NULL;
2946  }
2947 
2948  ssh_channel_request_pty(channel);
2949 
2950  // SSH Callbacks
2951  struct ssh_callbacks_struct cb =
2952  {
2953  .channel_open_request_x11_function = remmina_ssh_x11_open_request_cb,
2954  .userdata = shell,
2955  };
2956 
2957  if (remmina_file_get_int(remminafile, "ssh_forward_x11", FALSE)) {
2958  ssh_callbacks_init(&cb);
2959  ssh_set_callbacks(REMMINA_SSH(shell)->session, &cb);
2960 
2961  const char *display = getenv("DISPLAY");
2962  char *proto = NULL, *cookie = NULL;
2963  if (remmina_ssh_x11_get_proto(display, &proto, &cookie) != 0) {
2964  REMMINA_DEBUG("Using fake authentication data for X11 forwarding");
2965  proto = NULL;
2966  cookie = NULL;
2967  }
2968 
2969  REMMINA_DEBUG("proto: %s - cookie: %s", proto, cookie);
2970  ret = ssh_channel_request_x11(channel, 0, proto, cookie, 0);
2971  if (ret != SSH_OK) return NULL;
2972  }
2973 
2974  if (shell->exec && shell->exec[0]) {
2975  REMMINA_DEBUG ("Requesting an SSH exec channel");
2976  ret = ssh_channel_request_exec(channel, shell->exec);
2977  } else {
2978  REMMINA_DEBUG ("Requesting an SSH shell channel");
2979  ret = ssh_channel_request_shell(channel);
2980  }
2981  if (ret != SSH_OK) {
2982  UNLOCK_SSH(shell)
2983  REMMINA_WARNING ("Could not request shell");
2984  // TRANSLATORS: The placeholder %s is an error message
2985  remmina_ssh_set_error(REMMINA_SSH(shell), _("Could not request shell. %s"));
2986  ssh_channel_close(channel);
2987  ssh_channel_send_eof(channel);
2988  ssh_channel_free(channel);
2989  shell->thread = 0;
2990  return NULL;
2991  }
2992 
2993  shell->channel = channel;
2994 
2995  UNLOCK_SSH(shell)
2996 
2997  GFile *rf = g_file_new_for_path(remminafile->filename);
2998 
2999  if (remmina_file_get_string(remminafile, "sshlogfolder") == NULL)
3000  dir = g_build_path("/", g_get_user_cache_dir(), "remmina", NULL);
3001  else
3002  dir = remmina_file_get_string(remminafile, "sshlogfolder");
3003 
3004  if (remmina_file_get_string(remminafile, "sshlogname") == NULL)
3005  sshlogname = g_strconcat(g_file_get_basename(rf), ".", "log", NULL);
3006  else
3007  sshlogname = remmina_file_get_string(remminafile, "sshlogname");
3008  sshlogname = remmina_file_format_properties(remminafile, sshlogname);
3009  filename = g_strconcat(dir, "/", sshlogname, NULL);
3010 
3011  if (remmina_file_get_int (remminafile, "sshsavesession", FALSE)) {
3012  REMMINA_DEBUG("Saving session log to %s", filename);
3013  fp = fopen(filename, "w");
3014  }
3015 
3016  g_free(filename);
3017 
3018  REMMINA_DEBUG("Run_line: %s", shell->run_line);
3019  if (!shell->closed && shell->run_line && shell->run_line[0]) {
3020  LOCK_SSH(shell)
3021  //TODO: Confirm assumption - assuming null terminated gchar string
3022  ssh_channel_write(channel, shell->run_line, (gint)strlen(shell->run_line));
3023  ssh_channel_write(channel, "\n", (gint)1); //TODO: Test this
3024  UNLOCK_SSH(shell)
3025  REMMINA_DEBUG("Run_line written to channel");
3026  }
3027 
3028  LOCK_SSH(shell)
3029 
3030  // Create new event context.
3031  shell->event = ssh_event_new();
3032  if (shell->event == NULL) {
3033  REMMINA_WARNING("Internal error in %s: Couldn't get a event.", __func__);
3034  return NULL;
3035  }
3036 
3037  REMMINA_DEBUG("shell->slave: %d", shell->slave);
3038 
3039  // Add the fd to the event and assign it the callback.
3040  if (ssh_event_add_fd(shell->event, shell->slave, events, remmina_ssh_cp_to_ch_cb, channel) != SSH_OK) {
3041  REMMINA_WARNING("Internal error in %s: Couldn't add an fd to the event.", __func__);
3042  return NULL;
3043  }
3044 
3045  // Remove the poll handle from session and assign them to the event.
3046  if (ssh_event_add_session(shell->event, REMMINA_SSH(shell)->session) != SSH_OK) {
3047  REMMINA_WARNING("Internal error in %s: Couldn't add the session to the event.", __func__);
3048  return NULL;
3049  }
3050 
3051  remmina_ssh_insert_item(shell->channel, shell->slave, shell->slave, TRUE, shell->thread);
3052 
3053  // Initializes the ssh_callbacks_struct.
3054  channel_cb.userdata = &shell;
3055  ssh_callbacks_init(&channel_cb);
3056  // Set the channel callback functions.
3057  ssh_set_channel_callbacks(shell->channel, &channel_cb);
3058  UNLOCK_SSH(shell)
3059 
3060  do {
3061  ssh_event_dopoll(shell->event, 1000);
3062  } while(!ssh_channel_is_closed(shell->channel));
3063 
3064  // Close all OPENED X11 channel
3066 
3067  shell->closed = TRUE;
3068 
3069  LOCK_SSH(shell)
3070 
3071  // Remove socket fd from event context.
3072  ret = ssh_event_remove_fd(shell->event, shell->slave);
3073  REMMINA_DEBUG("Remove socket fd from event context: %d", ret);
3074 
3075  // Remove session object from event context.
3076  ret = ssh_event_remove_session(shell->event, REMMINA_SSH(shell)->session);
3077  REMMINA_DEBUG("Remove session object from event context: %d", ret);
3078 
3079  // Free event context.
3080  ssh_event_free(shell->event);
3081  REMMINA_DEBUG("Free event context");
3082 
3083  // Remove channel callback.
3084  ret = ssh_remove_channel_callbacks(shell->channel, &channel_cb);
3085  REMMINA_DEBUG("Remove channel callback: %d", ret);
3086 
3087  if (remmina_file_get_int (remminafile, "sshsavesession", FALSE))
3088  fclose(fp);
3089  shell->channel = NULL;
3090  ssh_channel_close(channel);
3091  ssh_channel_send_eof(channel);
3092  ssh_channel_free(channel);
3093  UNLOCK_SSH(shell)
3094 
3095  shell->thread = 0;
3096 
3097  if (shell->exit_callback)
3098  IDLE_ADD((GSourceFunc)remmina_ssh_call_exit_callback_on_main_thread, (gpointer)shell);
3099  return NULL;
3100 }
3101 
3102 gboolean
3103 remmina_ssh_shell_open(RemminaSSHShell *shell, RemminaSSHExitFunc exit_callback, gpointer data)
3104 {
3105  TRACE_CALL(__func__);
3106  gchar *slavedevice;
3107  struct termios stermios;
3108 
3109  shell->master = posix_openpt(O_RDWR | O_NOCTTY);
3110  if (shell->master == -1 ||
3111  grantpt(shell->master) == -1 ||
3112  unlockpt(shell->master) == -1 ||
3113  (slavedevice = ptsname(shell->master)) == NULL ||
3114  (shell->slave = open(slavedevice, O_RDWR | O_NOCTTY)) < 0) {
3115  REMMINA_SSH(shell)->error = g_strdup(_("Could not create PTY device."));
3116  return FALSE;
3117  }
3118 
3119  /* As per libssh documentation */
3120  tcgetattr(shell->slave, &stermios);
3121  stermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
3122  stermios.c_oflag &= ~OPOST;
3123  stermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
3124  stermios.c_cflag &= ~(CSIZE | PARENB);
3125  stermios.c_cflag |= CS8;
3126  tcsetattr(shell->slave, TCSANOW, &stermios);
3127 
3128  shell->exit_callback = exit_callback;
3129  shell->user_data = data;
3130 
3131  /* Once the process started, we should always TRUE and assume the pthread will be created always */
3132  pthread_create(&shell->thread, NULL, remmina_ssh_shell_thread, shell);
3133 
3134  return TRUE;
3135 }
3136 
3137 void
3138 remmina_ssh_shell_set_size(RemminaSSHShell *shell, gint columns, gint rows)
3139 {
3140  TRACE_CALL(__func__);
3141  LOCK_SSH(shell)
3142  if (shell->channel)
3143  ssh_channel_change_pty_size(shell->channel, columns, rows);
3144  UNLOCK_SSH(shell)
3145 }
3146 
3147 void
3149 {
3150  TRACE_CALL(__func__);
3151  //pthread_t thread = shell->thread;
3152 
3153  // Close all OPENED X11 channel
3155 
3156  shell->exit_callback = NULL;
3157  shell->closed = TRUE;
3158  REMMINA_DEBUG("Cancelling the shell thread if needed");
3159  if (shell->thread) {
3160  pthread_cancel(shell->thread);
3161  if (shell->thread) pthread_join(shell->thread, NULL);
3162  }
3163  close(shell->slave);
3164  if (shell->exec) {
3165  g_free(shell->exec);
3166  shell->exec = NULL;
3167  }
3168  if (shell->run_line) {
3169  g_free(shell->run_line);
3170  shell->run_line = NULL;
3171  }
3172  /* It’s not necessary to close shell->slave since the other end (vte) will close it */;
3173  remmina_ssh_free(REMMINA_SSH(shell));
3174 }
3175 
3176 #endif /* HAVE_LIBSSH */
+Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 #include "config.h"
39 
40 #ifdef HAVE_LIBSSH
41 
42 /* To get definitions of NI_MAXHOST and NI_MAXSERV from <netdb.h> */
43 #define _DEFAULT_SOURCE
44 #define _DARWIN_C_SOURCE
45 
46 /* Define this before stdlib.h to have posix_openpt */
47 #define _XOPEN_SOURCE 600
48 
49 #include <errno.h>
50 #define LIBSSH_STATIC 1
51 #include <libssh/libssh.h>
52 #include <gtk/gtk.h>
53 #include <glib/gi18n.h>
54 #include <poll.h>
55 #include <stdlib.h>
56 #include <signal.h>
57 #include <time.h>
58 #include <sys/types.h>
59 #include <pthread.h>
60 #ifdef HAVE_NETDB_H
61 #include <netdb.h>
62 #endif
63 #ifdef HAVE_ARPA_INET_H
64 #include <arpa/inet.h>
65 #endif
66 #ifdef HAVE_NETINET_IN_H
67 #include <netinet/in.h>
68 #endif
69 #ifdef HAVE_SYS_SOCKET_H
70 #include <sys/socket.h>
71 #endif
72 #ifdef HAVE_FCNTL_H
73 #include <fcntl.h>
74 #endif
75 #ifdef HAVE_ERRNO_H
76 #include <errno.h>
77 #endif
78 #ifdef HAVE_TERMIOS_H
79 #include <termios.h>
80 #endif
81 #ifdef HAVE_UNISTD_H
82 #include <unistd.h>
83 #endif
84 #ifdef HAVE_PTY_H
85 #include <pty.h>
86 #endif
87 #ifdef HAVE_SYS_UN_H
88 #include <sys/un.h>
89 #endif
90 #include "remmina_public.h"
91 #include "remmina/types.h"
92 #include "remmina_file.h"
93 #include "remmina_log.h"
94 #include "remmina_pref.h"
95 #include "remmina_ssh.h"
98 
99 
100 #ifdef HAVE_NETINET_TCP_H
101 #include <netinet/tcp.h>
102 
103 #if defined(__FreeBSD__) || defined(__OpenBSD__)
104 #ifndef SOL_TCP
105 #define SOL_TCP IPPROTO_TCP
106 #endif
107 #endif
108 
109 #endif
110 
111 /*-----------------------------------------------------------------------------*
112 * SSH Base *
113 *-----------------------------------------------------------------------------*/
114 
115 #define LOCK_SSH(ssh) pthread_mutex_lock(&REMMINA_SSH(ssh)->ssh_mutex);
116 #define UNLOCK_SSH(ssh) pthread_mutex_unlock(&REMMINA_SSH(ssh)->ssh_mutex);
117 
118 static const gchar *common_identities[] =
119 {
120  ".ssh/id_ed25519",
121  ".ssh/id_rsa",
122  ".ssh/id_dsa",
123  ".ssh/identity",
124  NULL
125 };
126 
127 /*-----------------------------------------------------------------------------*
128 * X11 Channels *
129 *-----------------------------------------------------------------------------*/
130 #define _PATH_UNIX_X "/tmp/.X11-unix/X%d"
131 #define _XAUTH_CMD "/usr/bin/xauth list %s 2>/dev/null"
132 
133 typedef struct item {
134  ssh_channel channel;
135  gint fd_in;
136  gint fd_out;
137  gboolean protected;
138  pthread_t thread;
139  struct item *next;
140 } node_t;
141 
142 node_t *node = NULL;
143 
144 // Mutex
145 pthread_mutex_t mutex;
146 
147 // Linked nodes to manage channel/fd tuples
148 static void remmina_ssh_insert_item(ssh_channel channel, gint fd_in, gint fd_out, gboolean protected, pthread_t thread);
149 static void remmina_ssh_delete_item(ssh_channel channel);
150 static node_t * remmina_ssh_search_item(ssh_channel channel);
151 
152 // X11 Display
153 const char * remmina_ssh_ssh_gai_strerror(int gaierr);
154 static int remmina_ssh_x11_get_proto(const char *display, char **_proto, char **_data);
155 static void remmina_ssh_set_nodelay(int fd);
156 static int remmina_ssh_connect_local_xsocket_path(const char *pathname);
157 static int remmina_ssh_connect_local_xsocket(int display_number);
159 
160 // Send data to channel
161 static int remmina_ssh_cp_to_ch_cb(int fd, int revents, void *userdata);
162 
163 // Read data from channel
164 static int remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata);
165 
166 // EOF&Close channel
167 static void remmina_ssh_ch_close_cb(ssh_session session, ssh_channel channel, void *userdata);
168 
169 // Close all X11 channel
170 static void remmina_ssh_close_all_x11_ch(pthread_t thread);
171 
172 // X11 Request
173 static ssh_channel remmina_ssh_x11_open_request_cb(ssh_session session, const char *shost, int sport, void *userdata);
174 
175 // SSH Channel Callbacks
176 struct ssh_channel_callbacks_struct channel_cb =
177 {
178  .channel_data_function = remmina_ssh_cp_to_fd_cb,
179  .channel_eof_function = remmina_ssh_ch_close_cb,
180  .channel_close_function = remmina_ssh_ch_close_cb,
181  .userdata = NULL
182 };
183 
184 // SSH Event Context
185 short events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
186 
187 // Functions
188 static void
189 remmina_ssh_insert_item(ssh_channel channel, gint fd_in, gint fd_out, gboolean protected, pthread_t thread)
190 {
191  TRACE_CALL(__func__);
192 
193  pthread_mutex_lock(&mutex);
194 
195  REMMINA_DEBUG("insert node - fd_in: %d - fd_out: %d - protected %d", fd_in, fd_out, protected);
196 
197  node_t *node_iterator, *new;
198  if (node == NULL) {
199  /* Calloc ensure that node is full of 0 */
200  node = (node_t *) calloc(1, sizeof(node_t));
201  node->channel = channel;
202  node->fd_in = fd_in;
203  node->fd_out = fd_out;
204  node->protected = protected;
205  node->thread = thread;
206  node->next = NULL;
207  } else {
208  node_iterator = node;
209  while (node_iterator->next != NULL)
210  node_iterator = node_iterator->next;
211  /* Create the new node */
212  new = (node_t *) malloc(sizeof(node_t));
213  new->channel = channel;
214  new->fd_in = fd_in;
215  new->fd_out = fd_out;
216  new->protected = protected;
217  new->thread = thread;
218  new->next = NULL;
219  node_iterator->next = new;
220  }
221 
222  pthread_mutex_unlock(&mutex);
223 }
224 
225 static void
227 {
228  TRACE_CALL(__func__);
229 
230  REMMINA_DEBUG("delete node");
231 
232  pthread_mutex_lock(&mutex);
233 
234  node_t *current, *previous = NULL;
235  for (current = node; current; previous = current, current = current->next) {
236  if (current->channel != channel)
237  continue;
238 
239  if (previous == NULL)
240  node = current->next;
241  else
242  previous->next = current->next;
243 
244  free(current);
245  pthread_mutex_unlock(&mutex);
246  return;
247  }
248 
249  pthread_mutex_unlock(&mutex);
250 }
251 
252 static node_t *
254 {
255  TRACE_CALL(__func__);
256 
257  // TODO: too verbose REMMINA_DEBUG("search node");
258 
259  pthread_mutex_lock(&mutex);
260 
261  node_t *current = node;
262  while (current != NULL) {
263  if (current->channel == channel) {
264  pthread_mutex_unlock(&mutex);
265  // TODO: too verbose REMMINA_DEBUG("found node - fd_in: %d - fd_out: %d - protected: %d", current->fd_in, current->fd_out, current->protected);
266  return current;
267  } else {
268  current = current->next;
269  }
270  }
271 
272  pthread_mutex_unlock(&mutex);
273 
274  return NULL;
275 }
276 
277 static void
279 {
280  TRACE_CALL(__func__);
281  int opt;
282  socklen_t optlen;
283 
284  optlen = sizeof(opt);
285  if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
286  REMMINA_WARNING("getsockopt TCP_NODELAY: %.100s", strerror(errno));
287  return;
288  }
289  if (opt == 1) {
290  REMMINA_DEBUG("fd %d is TCP_NODELAY", fd);
291  return;
292  }
293  opt = 1;
294  REMMINA_DEBUG("fd %d setting TCP_NODELAY", fd);
295  if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1)
296  REMMINA_WARNING("setsockopt TCP_NODELAY: %.100s", strerror(errno));
297 }
298 
299 const char *
301 {
302  TRACE_CALL(__func__);
303 
304  if (gaierr == EAI_SYSTEM && errno != 0)
305  return strerror(errno);
306  return gai_strerror(gaierr);
307 }
308 
309 static int
310 remmina_ssh_x11_get_proto(const char *display, char **_proto, char **_cookie)
311 {
312  TRACE_CALL(__func__);
313 
314  char cmd[1024], line[512], xdisplay[512];
315  static char proto[512], cookie[512];
316  FILE *f;
317  int ret = 0, r;
318 
319  *_proto = proto;
320  *_cookie = cookie;
321 
322  proto[0] = cookie[0] = '\0';
323 
324  if (strncmp(display, "localhost:", 10) == 0) {
325  if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", display + 10)) < 0 || (size_t)r >= sizeof(xdisplay)) {
326  REMMINA_WARNING("display name too long. display: %s", display);
327  return -1;
328  }
329  display = xdisplay;
330  }
331 
332  snprintf(cmd, sizeof(cmd), _XAUTH_CMD, display);
333  REMMINA_DEBUG("xauth cmd: %s", cmd);
334 
335  f = popen(cmd, "r");
336  if (f && fgets(line, sizeof(line), f) && sscanf(line, "%*s %511s %511s", proto, cookie) == 2) {
337  ret = 0;
338  } else {
339  ret = 1;
340  }
341 
342  if (f) pclose(f);
343 
344  REMMINA_DEBUG("proto: %s - cookie: %s - ret: %d", proto, cookie, ret);
345 
346  return ret;
347 }
348 
349 static int
351 {
352  TRACE_CALL(__func__);
353 
354  int sock;
355  struct sockaddr_un addr;
356 
357  sock = socket(AF_UNIX, SOCK_STREAM, 0);
358  if (sock == -1)
359  REMMINA_WARNING("socket: %.100s", strerror(errno));
360 
361  memset(&addr, 0, sizeof(addr));
362  addr.sun_family = AF_UNIX;
363  addr.sun_path[0] = '\0';
364  memcpy(addr.sun_path + 1, pathname, strlen(pathname));
365  if (connect(sock, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(pathname)) == 0) {
366  REMMINA_DEBUG("sock: %d", sock);
367  return sock;
368  }
369 
370  REMMINA_WARNING("connect %.100s: %.100s", addr.sun_path, strerror(errno));
371  close(sock);
372 
373  return -1;
374 }
375 
376 static int
378 {
379  TRACE_CALL(__func__);
380 
381  char buf[1024];
382  snprintf(buf, sizeof(buf), _PATH_UNIX_X, display_number);
384 }
385 
386 static int
388 {
389  TRACE_CALL(__func__);
390 
391  unsigned int display_number;
392  const char *display;
393  char buf[1024], *cp;
394  struct addrinfo hints, *ai, *aitop;
395  char strport[NI_MAXSERV];
396  int gaierr, sock = 0;
397 
398  /* Try to open a socket for the local X server. */
399  display = getenv("DISPLAY");
400  if (!display) {
401  return -1;
402  }
403 
404  REMMINA_DEBUG("display: %s", display);
405 
406  /* Check if it is a unix domain socket. */
407  if (strncmp(display, "unix:", 5) == 0 || display[0] == ':') {
408  /* Connect to the unix domain socket. */
409  if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
410  REMMINA_WARNING("Could not parse display number from DISPLAY: %.100s", display);
411  return -1;
412  }
413 
414  REMMINA_DEBUG("display_number: %d", display_number);
415 
416  /* Create a socket. */
417  sock = remmina_ssh_connect_local_xsocket(display_number);
418 
419  REMMINA_DEBUG("socket: %d", sock);
420 
421  if (sock < 0)
422  return -1;
423 
424  /* OK, we now have a connection to the display. */
425  return sock;
426  }
427 
428  /* Connect to an inet socket. */
429  strncpy(buf, display, sizeof(buf) - 1);
430  cp = strchr(buf, ':');
431  if (!cp) {
432  REMMINA_WARNING("Could not find ':' in DISPLAY: %.100s", display);
433  return -1;
434  }
435  *cp = 0;
436  if (sscanf(cp + 1, "%u", &display_number) != 1) {
437  REMMINA_WARNING("Could not parse display number from DISPLAY: %.100s", display);
438  return -1;
439  }
440 
441  /* Look up the host address */
442  memset(&hints, 0, sizeof(hints));
443  hints.ai_family = AF_INET;
444  hints.ai_socktype = SOCK_STREAM;
445  snprintf(strport, sizeof(strport), "%u", 6000 + display_number);
446  if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
447  REMMINA_WARNING("%.100s: unknown host. (%s)", buf, remmina_ssh_ssh_gai_strerror(gaierr));
448  return -1;
449  }
450  for (ai = aitop; ai; ai = ai->ai_next) {
451  /* Create a socket. */
452  sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
453  if (sock == -1) {
454  REMMINA_WARNING("socket: %.100s", strerror(errno));
455  continue;
456  }
457  /* Connect it to the display. */
458  if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
459  REMMINA_WARNING("connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno));
460  close(sock);
461  continue;
462  }
463  /* Success */
464  break;
465  }
466  freeaddrinfo(aitop);
467  if (!ai) {
468  REMMINA_WARNING("connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno));
469  return -1;
470  }
472 
473  REMMINA_DEBUG("sock: %d", sock);
474 
475  return sock;
476 }
477 
478 static int
479 remmina_ssh_cp_to_ch_cb(int fd, int revents, void *userdata)
480 {
481  TRACE_CALL(__func__);
482  ssh_channel channel = (ssh_channel)userdata;
483  gchar *buf = (gchar *) g_malloc ( sizeof(gchar) * 0x200000 );
484  if (buf ==NULL){
485  return -1;
486  }
487  gint sz = 0, ret = 0;
488 
489  node_t *temp_node = remmina_ssh_search_item(channel);
490 
491  if (!channel) {
492  if (!temp_node->protected) {
493  shutdown(fd, SHUT_RDWR);
494  close(fd);
495  REMMINA_DEBUG("fd %d closed.", fd);
496  }
497  REMMINA_WARNING("channel does not exist.");
498  return -1;
499  }
500 
501  if ((revents & POLLIN) || (revents & POLLPRI)) {
502  sz = read(fd, buf, sizeof(buf));
503  if (sz > 0) {
504  ret = ssh_channel_write(channel, buf, sz);
505  if (ret != sz){
506  g_free(buf);
507  return -1;
508  }
509 
510  //TODO: too verbose REMMINA_DEBUG("ssh_channel_write ret: %d sz: %d", ret, sz);
511  } else if (sz < 0) {
512  // TODO: too verbose REMMINA_WARNING("fd bytes read: %d", sz);
513  g_free(buf);
514  return -1;
515  } else {
516  REMMINA_WARNING("Why the hell am I here?");
517  if (!temp_node->protected) {
518  shutdown(fd, SHUT_RDWR);
519  close(fd);
520  REMMINA_DEBUG("fd %d closed.", fd);
521  }
522  g_free(buf);
523  return -1;
524  }
525  }
526 
527  if ((revents & POLLHUP) || (revents & POLLNVAL) || (revents & POLLERR)) {
528  REMMINA_DEBUG("Closing channel.");
529  ssh_channel_close(channel);
530  ret = -1;
531  }
532  g_free(buf);
533  return ret;
534 }
535 
536 static int
537 remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata)
538 {
539  TRACE_CALL(__func__);
540  (void)session;
541  (void)is_stderr;
542  // Expecting userdata to be type RemminaSSHShell *, but it is unused
543  // in this function.
544  (void)userdata;
545 
546  node_t *temp_node = remmina_ssh_search_item(channel);
547  gint fd = temp_node->fd_out;
548  gint sz = 0;
549 
550  sz = write(fd, data, len);
551  // TODO: too verbose REMMINA_DEBUG("fd bytes written: %d", sz);
552 
553  return sz;
554 }
555 
556 static void
557 remmina_ssh_ch_close_cb(ssh_session session, ssh_channel channel, void *userdata)
558 {
559  TRACE_CALL(__func__);
560  (void)session;
561 
562  RemminaSSHShell *shell = (RemminaSSHShell *)userdata;
563 
564  node_t *temp_node = remmina_ssh_search_item(channel);
565 
566  if (temp_node != NULL) {
567  int fd = temp_node->fd_in;
568 
569  if (!temp_node->protected) {
570  remmina_ssh_delete_item(channel);
571  ssh_event_remove_fd(shell->event, fd);
572  shutdown(fd, SHUT_RDWR);
573  close(fd);
574  REMMINA_DEBUG("fd %d closed.", fd);
575  }
576  }
577  REMMINA_DEBUG("Channel closed.");
578 }
579 
580 static void
582 {
583  TRACE_CALL(__func__);
584 
585  REMMINA_DEBUG("Close all X11 channels");
586 
587  node_t *current = node;
588  while (current != NULL) {
589  if (current->thread == thread && !current->protected) {
590  shutdown(current->fd_in, SHUT_RDWR);
591  close(current->fd_in);
592  REMMINA_DEBUG("thread: %d - fd %d closed.", thread, current->fd_in);
593  if (current->fd_in != current->fd_out) {
594  shutdown(current->fd_out, SHUT_RDWR);
595  close(current->fd_out);
596  REMMINA_DEBUG("thread: %d - fd %d closed.", thread, current->fd_out);
597  }
598  }
599  current = current->next;
600  }
601 }
602 
603 static ssh_channel
604 remmina_ssh_x11_open_request_cb(ssh_session session, const char *shost, int sport, void *userdata)
605 {
606  TRACE_CALL(__func__);
607 
608  (void)shost;
609  (void)sport;
610 
611  RemminaSSHShell *shell = (RemminaSSHShell *)userdata;
612 
613  ssh_channel channel = ssh_channel_new(session);
614 
615  int sock = remmina_ssh_x11_connect_display();
616 
617  remmina_ssh_insert_item(channel, sock, sock, FALSE, shell->thread);
618 
619  ssh_event_add_fd(shell->event, sock, events, remmina_ssh_cp_to_ch_cb, channel);
620  ssh_event_add_session(shell->event, session);
621 
622  ssh_add_channel_callbacks(channel, &channel_cb);
623 
624  return channel;
625 }
626 
627 gchar *
629 {
630  TRACE_CALL(__func__);
631  if (id == NULL) return NULL;
632  if (id[0] == '/') return g_strdup(id);
633  return g_strdup_printf("%s/%s", g_get_home_dir(), id);
634 }
635 
636 gchar *
638 {
639  TRACE_CALL(__func__);
640  gchar *path;
641  gint i;
642 
643  for (i = 0; common_identities[i]; i++) {
645  if (g_file_test(path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))
646  return path;
647  g_free(path);
648  }
649  return NULL;
650 }
651 
652 void
653 remmina_ssh_set_error(RemminaSSH *ssh, const gchar *fmt)
654 {
655  TRACE_CALL(__func__);
656  const gchar *err;
657 
658  err = ssh_get_error(ssh->session);
659  ssh->error = g_strdup_printf(fmt, err);
660 }
661 
662 void
663 remmina_ssh_set_application_error(RemminaSSH *ssh, const gchar *fmt, ...)
664 {
665  TRACE_CALL(__func__);
666  va_list args;
667 
668  va_start(args, fmt);
669  ssh->error = g_strdup_vprintf(fmt, args);
670  va_end(args);
671 }
672 
673 static enum remmina_ssh_auth_result
675 {
676  TRACE_CALL(__func__);
677  gint ret;
678  gint n;
679  gint i;
680  const gchar *name, *instruction = NULL;
681  //gchar *prompt,*ptr;
682 
683  ret = SSH_AUTH_ERROR;
684  if (ssh->authenticated) return REMMINA_SSH_AUTH_SUCCESS;
685  /* TODO: What if I have an empty password? */
686  if (ssh->password == NULL) {
687  remmina_ssh_set_error(ssh, "OTP code is empty");
688  REMMINA_DEBUG("OTP code is empty, returning");
690  }
691  REMMINA_DEBUG("OTP code has been set to: %s", ssh->password);
692 
693  ret = ssh_userauth_kbdint(ssh->session, NULL, NULL);
694  while (ret == SSH_AUTH_INFO) {
695  name = ssh_userauth_kbdint_getname(ssh->session);
696  if (strlen(name) > 0)
697  REMMINA_DEBUG("SSH kbd-interactive name: %s", name);
698  else
699  REMMINA_DEBUG("SSH kbd-interactive name is empty");
700  instruction = ssh_userauth_kbdint_getinstruction(ssh->session);
701  if (strlen(instruction) > 0)
702  REMMINA_DEBUG("SSH kbd-interactive instruction: %s", instruction);
703  else
704  REMMINA_DEBUG("SSH kbd-interactive instruction is empty");
705  n = ssh_userauth_kbdint_getnprompts(ssh->session);
706  for (i = 0; i < n; i++)
707  ssh_userauth_kbdint_setanswer(ssh->session, i, ssh->password);
708  ret = ssh_userauth_kbdint(ssh->session, NULL, NULL);
709  }
710 
711 
712  REMMINA_DEBUG("ssh_userauth_kbdint returned %d", ret);
713  switch (ret) {
714  case SSH_AUTH_PARTIAL:
715  if (ssh->password) {
716  g_free(ssh->password);
717  ssh->password = NULL;
718  }
719  //You've been partially authenticated, you still have to use another method
720  REMMINA_DEBUG("Authenticated with SSH keyboard interactive. Another method is required. %d", ret);
721  ssh->is_multiauth = TRUE;
723  break;
724  case SSH_AUTH_SUCCESS:
725  //Authentication success
726  ssh->authenticated = TRUE;
727  REMMINA_DEBUG("Authenticated with SSH keyboard interactive. %s", ssh->error);
729  break;
730  case SSH_AUTH_INFO:
731  //The server asked some questions. Use ssh_userauth_kbdint_getnprompts() and such.
732  REMMINA_DEBUG("Authenticating aagin with SSH keyboard interactive??? %s", ssh->error);
733  break;
734  case SSH_AUTH_AGAIN:
735  //In nonblocking mode, you've got to call this again later.
736  REMMINA_DEBUG("Authenticated with keyboard interactive, Requested to authenticate again. %s", ssh->error);
738  break;
739  case SSH_AUTH_DENIED:
740  case SSH_AUTH_ERROR:
741  default:
742  //A serious error happened
743  ssh->authenticated = FALSE;
744  remmina_ssh_set_error(ssh, _("Could not authenticate with TOTP/OTP/2FA. %s"));
745  REMMINA_DEBUG("Cannot authenticate with TOTP/OTP/2FA. Error is %s", ssh->error);
747  }
748  ssh->authenticated = FALSE;
750 }
751 
752 static enum remmina_ssh_auth_result
754 {
755  TRACE_CALL(__func__);
756  gint ret;
757 
758  REMMINA_DEBUG("Password authentication");
759 
760  ret = SSH_AUTH_ERROR;
761  if (ssh->authenticated) {
762  REMMINA_DEBUG("Already authenticated");
764  }
765  if (ssh->password == NULL) {
766  remmina_ssh_set_error(ssh, "Password is null");
767  REMMINA_DEBUG("Password is null, returning");
769  }
770 
771  ret = ssh_userauth_password(ssh->session, NULL, ssh->password);
772  REMMINA_DEBUG("Authentication with SSH password returned: %d", ret);
773 
774  switch (ret) {
775  case SSH_AUTH_PARTIAL:
776  if (ssh->password) {
777  g_free(ssh->password);
778  ssh->password = NULL;
779  }
780  //You've been partially authenticated, you still have to use another method.
781  REMMINA_DEBUG("Authenticated with SSH password, Another method is required. %d", ret);
782  ssh->is_multiauth = TRUE;
784  break;
785  case SSH_AUTH_SUCCESS:
786  //The public key is accepted.
787  ssh->authenticated = TRUE;
788  REMMINA_DEBUG("Authenticated with SSH password. %s", ssh->error);
790  break;
791  case SSH_AUTH_AGAIN:
792  //In nonblocking mode, you've got to call this again later.
793  REMMINA_DEBUG("Authenticated with SSH password, Requested to authenticate again. %s", ssh->error);
794  ssh->authenticated = FALSE;
795  return REMMINA_SSH_AUTH_AGAIN;
796  break;
797  case SSH_AUTH_DENIED:
798  case SSH_AUTH_ERROR:
799  default:
800  //A serious error happened.
801  ssh->authenticated = FALSE;
802  REMMINA_DEBUG("Cannot authenticate with password. Error is %s", ssh->error);
803  remmina_ssh_set_error(ssh, _("Could not authenticate with SSH password. %s"));
805  }
806  ssh->authenticated = FALSE;
808 }
809 
810 static enum remmina_ssh_auth_result
812 {
813  TRACE_CALL(__func__);
814 
815  ssh_key key = NULL;
816  ssh_key cert = NULL;
817  gchar pubkey[132] = { 0 }; // +".pub"
818  gint ret;
819 
820  if (ssh->authenticated) return REMMINA_SSH_AUTH_SUCCESS;
821 
822  REMMINA_DEBUG("SSH certificate file: %s", ssh->certfile);
823  REMMINA_DEBUG("File for private SSH key: %s", ssh->privkeyfile);
824  if (ssh->certfile != NULL) {
825 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
826  /* First we import the private key */
827  if (ssh_pki_import_privkey_file(ssh->privkeyfile, (ssh->passphrase ? ssh->passphrase : ""),
828  NULL, NULL, &key) != SSH_OK) {
829  if (ssh->passphrase == NULL || ssh->passphrase[0] == '\0') {
830  remmina_ssh_set_error(ssh, _("No saved SSH password supplied. Asking user to enter it."));
832  }
833 
834  // TRANSLATORS: The placeholder %s is an error message
835  remmina_ssh_set_error(ssh, _("Could not authenticate with public SSH key. %s"));
837  }
838  REMMINA_DEBUG ("Imported private SSH key file");
839  /* First we import the certificate */
840  ret = ssh_pki_import_cert_file(ssh->certfile, &cert );
841  if (ret != SSH_OK) {
842  REMMINA_DEBUG ("Certificate import returned: %d", ret);
843  // TRANSLATORS: The placeholder %s is an error message
844  remmina_ssh_set_error(ssh, _("SSH certificate cannot be imported. %s"));
846  }
847  REMMINA_DEBUG ("certificate imported correctly");
848  /* We copy th certificate in the private key */
849  ret = ssh_pki_copy_cert_to_privkey(cert, key);
850  if (ret != SSH_OK) {
851  REMMINA_DEBUG ("Copying the certificate into a key returned: %d", ret);
852  // TRANSLATORS: The placeholder %s is an error message
853  remmina_ssh_set_error(ssh, _("SSH certificate cannot be copied into the private SSH key. %s"));
854  ssh_key_free(cert);
856  }
857  REMMINA_DEBUG ("%s certificate copied into the private SSH key", ssh->certfile);
858  /* We try to authenticate */
859  ret = ssh_userauth_try_publickey(ssh->session, NULL, cert);
860  if (ret != SSH_AUTH_SUCCESS && ret != SSH_AUTH_AGAIN ) {
861  REMMINA_DEBUG ("Trying to authenticate with the new key returned: %d", ret);
862  // TRANSLATORS: The placeholder %s is an error message
863  remmina_ssh_set_error(ssh, _("Could not authenticate using SSH certificate. %s"));
864  ssh_key_free(key);
865  ssh_key_free(cert);
867  }
868  REMMINA_DEBUG ("Authentication with a certificate file works, we can authenticate");
869 #else
870  REMMINA_DEBUG ("lbssh >= 0.9.0 is required to authenticate with certificate file");
871 #endif
872  /* if it goes well we authenticate (later on) with the key, not the cert*/
873  } else {
874  if (ssh->privkeyfile == NULL) {
875  // TRANSLATORS: The placeholder %s is an error message
876  ssh->error = g_strdup_printf(_("Could not authenticate with public SSH key. %s"),
877  _("SSH identity file not selected."));
879  }
880 
881  g_snprintf(pubkey, sizeof(pubkey), "%s.pub", ssh->privkeyfile);
882 
883  /*G_FILE_TEST_EXISTS*/
884  if (g_file_test(pubkey, G_FILE_TEST_EXISTS)) {
885  ret = ssh_pki_import_pubkey_file(pubkey, &key);
886  if (ret != SSH_OK) {
887  // TRANSLATORS: The placeholder %s is an error message
888  remmina_ssh_set_error(ssh, _("Public SSH key cannot be imported. %s"));
889  ssh_key_free(key);
891  }
892  }
893 
894  if (ssh_pki_import_privkey_file(ssh->privkeyfile, (ssh->passphrase ? ssh->passphrase : ""),
895  NULL, NULL, &key) != SSH_OK) {
896  if (ssh->passphrase == NULL || ssh->passphrase[0] == '\0') {
897  remmina_ssh_set_error(ssh, _("No saved SSH password supplied. Asking user to enter it."));
899  }
900 
901  // TRANSLATORS: The placeholder %s is an error message
902  remmina_ssh_set_error(ssh, _("Could not authenticate with public SSH key. %s"));
904  }
905  }
906 
907  ret = ssh_userauth_publickey(ssh->session, NULL, key);
908  ssh_key_free(key);
909  ssh_key_free(cert);
910  REMMINA_DEBUG("Authentication with public SSH key returned: %d", ret);
911 
912  switch (ret) {
913  case SSH_AUTH_PARTIAL:
914  if (ssh->password) {
915  g_free(ssh->password);
916  ssh->password = NULL;
917  }
918  //You've been partially authenticated, you still have to use another method.
919  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
920  ssh->is_multiauth = TRUE;
922  break;
923  case SSH_AUTH_SUCCESS:
924  //The public key is accepted.
925  ssh->authenticated = TRUE;
926  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
928  break;
929  case SSH_AUTH_AGAIN:
930  //In nonblocking mode, you've got to call this again later.
931  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
932  ssh->authenticated = FALSE;
934  break;
935  case SSH_AUTH_DENIED:
936  case SSH_AUTH_ERROR:
937  default:
938  //A serious error happened.
939  ssh->authenticated = FALSE;
940  REMMINA_DEBUG("Could not authenticate with public SSH key. %s", ssh->error);
941  remmina_ssh_set_error(ssh, _("Could not authenticate with public SSH key. %s"));
943  }
945 }
946 
947 static enum remmina_ssh_auth_result
949 {
950  TRACE_CALL(__func__);
951 
952  gint ret;
953  ret = ssh_userauth_publickey_auto(ssh->session, NULL, (ssh->passphrase ? ssh->passphrase : NULL));
954 
955  REMMINA_DEBUG("Authentication with public SSH key returned: %d", ret);
956 
957  switch (ret) {
958  case SSH_AUTH_PARTIAL:
959  if (ssh->password) {
960  g_free(ssh->password);
961  ssh->password = NULL;
962  }
963  //You've been partially authenticated, you still have to use another method.
964  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
965  ssh->is_multiauth = TRUE;
967  break;
968  case SSH_AUTH_SUCCESS:
969  //The public key is accepted.
970  ssh->authenticated = TRUE;
971  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
973  break;
974  case SSH_AUTH_AGAIN:
975  //In nonblocking mode, you've got to call this again later.
976  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
977  ssh->authenticated = FALSE;
979  break;
980  case SSH_AUTH_DENIED:
981  case SSH_AUTH_ERROR:
982  default:
983  //A serious error happened.
984  ssh->authenticated = FALSE;
985  REMMINA_DEBUG("Cannot authenticate automatically with public SSH key. %s", ssh->error);
986  remmina_ssh_set_error(ssh, _("Could not authenticate automatically with public SSH key. %s"));
988  }
989  ssh->authenticated = FALSE;
991 }
992 
993 static enum remmina_ssh_auth_result
995 {
996  TRACE_CALL(__func__);
997  gint ret;
998  ret = ssh_userauth_agent(ssh->session, NULL);
999 
1000  REMMINA_DEBUG("Authentication with SSH agent returned: %d", ret);
1001 
1002  switch (ret) {
1003  case SSH_AUTH_PARTIAL:
1004  if (ssh->password) {
1005  g_free(ssh->password);
1006  ssh->password = NULL;
1007  }
1008  //You've been partially authenticated, you still have to use another method.
1009  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
1010  ssh->is_multiauth = TRUE;
1011  return REMMINA_SSH_AUTH_PARTIAL;
1012  break;
1013  case SSH_AUTH_SUCCESS:
1014  //The public key is accepted.
1015  ssh->authenticated = TRUE;
1016  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
1017  return REMMINA_SSH_AUTH_SUCCESS;
1018  break;
1019  case SSH_AUTH_AGAIN:
1020  //In nonblocking mode, you've got to call this again later.
1021  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
1022  ssh->authenticated = FALSE;
1024  break;
1025  case SSH_AUTH_DENIED:
1026  case SSH_AUTH_ERROR:
1027  default:
1028  //A serious error happened.
1029  ssh->authenticated = FALSE;
1030  REMMINA_DEBUG("Cannot authenticate automatically with SSH agent. %s", ssh->error);
1031  remmina_ssh_set_error(ssh, _("Could not authenticate automatically with SSH agent. %s"));
1033  }
1034  ssh->authenticated = FALSE;
1036 
1037 }
1038 
1039 static enum remmina_ssh_auth_result
1041 {
1042  TRACE_CALL(__func__);
1043  gint ret;
1044 
1045  ret = ssh_userauth_gssapi(ssh->session);
1046  REMMINA_DEBUG("Authentication with SSH GSSAPI/Kerberos: %d", ret);
1047 
1048  switch (ret) {
1049  case SSH_AUTH_PARTIAL:
1050  if (ssh->password) {
1051  g_free(ssh->password);
1052  ssh->password = NULL;
1053  }
1054  //You've been partially authenticated, you still have to use another method.
1055  REMMINA_DEBUG("Authenticated with public SSH key, Another method is required. %d", ret);
1056  ssh->is_multiauth = TRUE;
1057  return REMMINA_SSH_AUTH_PARTIAL;
1058  break;
1059  case SSH_AUTH_SUCCESS:
1060  //The public key is accepted.
1061  ssh->authenticated = TRUE;
1062  REMMINA_DEBUG("Authenticated with public SSH key. %s", ssh->error);
1063  return REMMINA_SSH_AUTH_SUCCESS;
1064  break;
1065  case SSH_AUTH_AGAIN:
1066  //In nonblocking mode, you've got to call this again later.
1067  REMMINA_DEBUG("Authenticated with public SSH key, Requested to authenticate again. %s", ssh->error);
1068  ssh->authenticated = FALSE;
1070  break;
1071  case SSH_AUTH_DENIED:
1072  case SSH_AUTH_ERROR:
1073  default:
1074  //A serious error happened.
1075  ssh->authenticated = FALSE;
1076  REMMINA_DEBUG("Cannot authenticate with SSH GSSAPI/Kerberos. %s", ssh->error);
1077  remmina_ssh_set_error(ssh, _("Could not authenticate with SSH GSSAPI/Kerberos. %s"));
1079  }
1080  ssh->authenticated = FALSE;
1082 }
1083 
1085 remmina_ssh_auth(RemminaSSH *ssh, const gchar *password, RemminaProtocolWidget *gp, RemminaFile *remminafile)
1086 {
1087  TRACE_CALL(__func__);
1088  gint method;
1090 
1091  /* Check known host again to ensure it’s still the original server when user forks
1092  * a new session from existing one */
1093 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1094  /* TODO: Add error checking
1095  * SSH_KNOWN_HOSTS_OK: The server is known and has not changed.
1096  * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you are under attack or the administrator changed the key. You HAVE to warn the user about a possible attack.
1097  * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while we had an other type recorded. It is a possible attack.
1098  * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should confirm the public key hash is correct.
1099  * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The host is thus unknown. File will be created if host key is accepted.
1100  * SSH_KNOWN_HOSTS_ERROR: There had been an error checking the host.
1101  */
1102  if (ssh_session_is_known_server(ssh->session) != SSH_KNOWN_HOSTS_OK) {
1103 #else
1104  if (ssh_is_server_known(ssh->session) != SSH_SERVER_KNOWN_OK) {
1105 #endif
1106  remmina_ssh_set_application_error(ssh, _("The public SSH key changed!"));
1108  }
1109 
1110  if (password) {
1111  if (password != ssh->password) {
1112  g_free(ssh->password);
1113  ssh->password = NULL;
1114  }
1115  if (password != ssh->passphrase) g_free(ssh->passphrase);
1116  ssh->password = g_strdup(password);
1117  ssh->passphrase = g_strdup(password);
1118  }
1119 
1134  method = ssh_userauth_list(ssh->session, NULL);
1135  REMMINA_DEBUG("Methods supported by server: %s%s%s%s%s%s%s",
1136  (method & SSH_AUTH_METHOD_NONE) ? "SSH_AUTH_METHOD_NONE " : "",
1137  (method & SSH_AUTH_METHOD_UNKNOWN) ? "SSH_AUTH_METHOD_UNKNOWN " : "",
1138  (method & SSH_AUTH_METHOD_PASSWORD) ? "SSH_AUTH_METHOD_PASSWORD " : "",
1139  (method & SSH_AUTH_METHOD_PUBLICKEY) ? "SSH_AUTH_METHOD_PUBLICKEY " : "",
1140  (method & SSH_AUTH_METHOD_HOSTBASED) ? "SSH_AUTH_METHOD_HOSTBASED " : "",
1141  (method & SSH_AUTH_METHOD_INTERACTIVE) ? "SSH_AUTH_METHOD_INTERACTIVE " : "",
1142  (method & SSH_AUTH_METHOD_GSSAPI_MIC) ? "SSH_AUTH_METHOD_GSSAPI_MIC " : ""
1143  );
1144  switch (ssh->auth) {
1145  case SSH_AUTH_PASSWORD:
1146  /* This authentication method is normally disabled on SSHv2 server. You should use keyboard-interactive mode. */
1147  REMMINA_DEBUG("SSH_AUTH_PASSWORD (%d)", ssh->auth);
1148  if (ssh->authenticated)
1149  return REMMINA_SSH_AUTH_SUCCESS;
1150  if (method & SSH_AUTH_METHOD_PASSWORD) {
1151  REMMINA_DEBUG("SSH using remmina_ssh_auth_password");
1152  rv = remmina_ssh_auth_password(ssh);
1153  }
1154  if (!ssh->authenticated && (method & SSH_AUTH_METHOD_INTERACTIVE)) {
1155  /* SSH server is requesting us to do interactive auth. */
1156  REMMINA_DEBUG("SSH using remmina_ssh_auth_interactive after password has failed");
1157  rv = remmina_ssh_auth_interactive(ssh);
1158  }
1159  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1160  if (ssh->password) {
1161  g_free(ssh->password);
1162  ssh->password = NULL;
1163  }
1164  switch (ssh_userauth_list(ssh->session, NULL)) {
1165  case SSH_AUTH_METHOD_PASSWORD:
1166  ssh->auth = SSH_AUTH_PASSWORD;
1167  break;
1168  case SSH_AUTH_METHOD_PUBLICKEY:
1169  ssh->auth = SSH_AUTH_PUBLICKEY;
1170  break;
1171  case SSH_AUTH_METHOD_HOSTBASED:
1172  REMMINA_DEBUG("Host-based authentication method not implemented: %d", ssh->auth);
1173  break;
1174  case SSH_AUTH_METHOD_INTERACTIVE:
1176  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1177  break;
1178  case SSH_AUTH_METHOD_UNKNOWN:
1179  default:
1180  REMMINA_DEBUG("User-based authentication method not supported: %d", ssh->auth);
1182  }
1183  }
1184  ssh->error = g_strdup_printf(_("Could not authenticate with SSH password. %s"), "");
1185  return rv;
1186  break;
1187 
1189  REMMINA_DEBUG("SSH using remmina_ssh_auth_interactive");
1190  if (method & SSH_AUTH_METHOD_INTERACTIVE) {
1191  rv = remmina_ssh_auth_interactive(ssh);
1192  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1193  if (ssh->password) {
1194  g_free(ssh->password);
1195  ssh->password = NULL;
1196  }
1197  switch (ssh_userauth_list(ssh->session, NULL)) {
1198  case SSH_AUTH_METHOD_PASSWORD:
1199  ssh->auth = SSH_AUTH_PASSWORD;
1200  break;
1201  case SSH_AUTH_METHOD_PUBLICKEY:
1202  ssh->auth = SSH_AUTH_PUBLICKEY;
1203  break;
1204  case SSH_AUTH_METHOD_HOSTBASED:
1205  REMMINA_DEBUG("Host-based authentication method not implemented: %d", ssh->auth);
1206  break;
1207  case SSH_AUTH_METHOD_INTERACTIVE:
1209  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1210  break;
1211  case SSH_AUTH_METHOD_UNKNOWN:
1212  default:
1213  REMMINA_DEBUG("User-based authentication method not supported: %d", ssh->auth);
1215  }
1216  }
1217  return rv;
1218  }
1219  ssh->error = g_strdup_printf(_("Could not authenticate with keyboard-interactive. %s"), "");
1220  break;
1221 
1222  case SSH_AUTH_PUBLICKEY:
1223  REMMINA_DEBUG("SSH_AUTH_PUBLICKEY (%d)", ssh->auth);
1224  if (method & SSH_AUTH_METHOD_PUBLICKEY) {
1225  rv = remmina_ssh_auth_pubkey(ssh, gp, remminafile);
1226  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1227  if (ssh->password) {
1228  g_free(ssh->password);
1229  ssh->password = NULL;
1230  }
1231  switch (ssh_userauth_list(ssh->session, NULL)) {
1232  case SSH_AUTH_METHOD_PASSWORD:
1233  ssh->auth = SSH_AUTH_PASSWORD;
1234  break;
1235  case SSH_AUTH_METHOD_PUBLICKEY:
1236  ssh->auth = SSH_AUTH_PUBLICKEY;
1237  break;
1238  case SSH_AUTH_METHOD_HOSTBASED:
1239  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1240  break;
1241  case SSH_AUTH_METHOD_INTERACTIVE:
1243  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1244  break;
1245  case SSH_AUTH_METHOD_UNKNOWN:
1246  default:
1247  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1249  }
1250  }
1251  return rv;
1252  }
1253  // The real error here should be: "The SSH server %s:%d does not support public key authentication"
1254  ssh->error = g_strdup_printf(_("Could not authenticate with public SSH key. %s"), "");
1255  break;
1256 
1257  case SSH_AUTH_AGENT:
1258  REMMINA_DEBUG("SSH_AUTH_AGENT (%d)", ssh->auth);
1259  rv = remmina_ssh_auth_agent(ssh);
1260  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1261  if (ssh->password) {
1262  g_free(ssh->password);
1263  ssh->password = NULL;
1264  }
1265  switch (ssh_userauth_list(ssh->session, NULL)) {
1266  case SSH_AUTH_METHOD_PASSWORD:
1267  ssh->auth = SSH_AUTH_PASSWORD;
1268  break;
1269  case SSH_AUTH_METHOD_PUBLICKEY:
1270  ssh->auth = SSH_AUTH_PUBLICKEY;
1271  break;
1272  case SSH_AUTH_METHOD_HOSTBASED:
1273  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1274  break;
1275  case SSH_AUTH_METHOD_INTERACTIVE:
1277  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1278  break;
1279  case SSH_AUTH_METHOD_UNKNOWN:
1280  default:
1281  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1283  }
1284  }
1285  return rv;
1286  break;
1287 
1289  REMMINA_DEBUG("SSH_AUTH_AUTO_PUBLICKEY (%d)", ssh->auth);
1290  rv = remmina_ssh_auth_auto_pubkey(ssh, gp, remminafile);
1291  /* ssh_agent or none */
1292  if (method & SSH_AUTH_METHOD_PUBLICKEY) {
1293  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1294  if (ssh->password) {
1295  g_free(ssh->password);
1296  ssh->password = NULL;
1297  }
1298  switch (ssh_userauth_list(ssh->session, NULL)) {
1299  case SSH_AUTH_METHOD_PASSWORD:
1300  ssh->auth = SSH_AUTH_PASSWORD;
1301  break;
1302  case SSH_AUTH_METHOD_PUBLICKEY:
1303  ssh->auth = SSH_AUTH_PUBLICKEY;
1304  break;
1305  case SSH_AUTH_METHOD_HOSTBASED:
1306  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1307  break;
1308  case SSH_AUTH_METHOD_INTERACTIVE:
1310  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1311  break;
1312  case SSH_AUTH_METHOD_UNKNOWN:
1313  default:
1314  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1316  }
1317  }
1318  return rv;
1319  }
1320  // The real error here should be: "The SSH server %s:%d does not support public key authentication"
1321  ssh->error = g_strdup_printf(_("Could not authenticate with automatic public SSH key. %s"), "");
1322  break;
1323 
1324 #if 0
1325  /* Not yet supported by libssh */
1326  case SSH_AUTH_HOSTBASED:
1327  if (method & SSH_AUTH_METHOD_HOSTBASED)
1328  //return remmina_ssh_auth_hostbased;
1329  return 0;
1330 #endif
1331 
1332  case SSH_AUTH_GSSAPI:
1333  REMMINA_DEBUG("SSH_AUTH_GSSAPI (%d)", ssh->auth);
1334  if (method & SSH_AUTH_METHOD_GSSAPI_MIC) {
1335  rv = remmina_ssh_auth_gssapi(ssh);
1336  if (rv == REMMINA_SSH_AUTH_PARTIAL) {
1337  if (ssh->password) {
1338  g_free(ssh->password);
1339  ssh->password = NULL;
1340  }
1341  switch (ssh_userauth_list(ssh->session, NULL)) {
1342  case SSH_AUTH_METHOD_PASSWORD:
1343  ssh->auth = SSH_AUTH_PASSWORD;
1344  break;
1345  case SSH_AUTH_METHOD_PUBLICKEY:
1346  ssh->auth = SSH_AUTH_PUBLICKEY;
1347  break;
1348  case SSH_AUTH_METHOD_HOSTBASED:
1349  REMMINA_DEBUG("Host based auth method not implemented: %d", ssh->auth);
1350  break;
1351  case SSH_AUTH_METHOD_INTERACTIVE:
1353  //REMMINA_DEBUG("Interactive auth method not implemented: %d", ssh->auth);
1354  break;
1355  case SSH_AUTH_METHOD_UNKNOWN:
1356  default:
1357  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1359  }
1360  }
1361  return rv;
1362  }
1363  // The real error here should be: "The SSH server %s:%d does not support SSH GSSAPI/Kerberos authentication"
1364  ssh->error = g_strdup_printf(_("Could not authenticate with SSH GSSAPI/Kerberos. %s"), "");
1365  break;
1366 
1367  default:
1368  REMMINA_DEBUG("User auth method not supported: %d", ssh->auth);
1370  }
1371 
1372  // We come here after a "break". ssh->error should be already set
1374 }
1375 
1378 {
1379  TRACE_CALL(__func__);
1380  gchar *keyname;
1381  gchar *pwdfkey = NULL;
1382  gchar *message;
1383  gchar *current_pwd;
1384  gchar *current_user;
1385  const gchar *instruction = NULL;
1386  gint ret;
1387  size_t len;
1388  guchar *pubkey;
1389  ssh_key server_pubkey;
1390  gboolean disablepasswordstoring;
1391  gboolean save_password;
1392  gint attempt;
1393 
1394  /* Check if the server’s public key is known */
1395 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1396  /* TODO: Add error checking
1397  * SSH_KNOWN_HOSTS_OK: The server is known and has not changed.
1398  * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you are under attack or the administrator changed the key. You HAVE to warn the user about a possible attack.
1399  * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while we had an other type recorded. It is a possible attack.
1400  * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should confirm the public key hash is correct.
1401  * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The host is thus unknown. File will be created if host key is accepted.
1402  * SSH_KNOWN_HOSTS_ERROR: There had been an error checking the host.
1403  */
1404  ret = ssh_session_is_known_server(ssh->session);
1405  switch (ret) {
1406  case SSH_KNOWN_HOSTS_OK:
1407  break; /* ok */
1408 
1409  /* TODO: These are all wrong, we should deal with each of them */
1410  case SSH_KNOWN_HOSTS_CHANGED:
1411  case SSH_KNOWN_HOSTS_OTHER:
1412  case SSH_KNOWN_HOSTS_UNKNOWN:
1413  case SSH_KNOWN_HOSTS_NOT_FOUND:
1414 #else
1415  ret = ssh_is_server_known(ssh->session);
1416  switch (ret) {
1417  case SSH_SERVER_KNOWN_OK:
1418  break; /* ok */
1419 
1420  /* fallback to SSH_SERVER_NOT_KNOWN behavior */
1421  case SSH_SERVER_KNOWN_CHANGED:
1422  case SSH_SERVER_FOUND_OTHER:
1423  case SSH_SERVER_NOT_KNOWN:
1424  case SSH_SERVER_FILE_NOT_FOUND:
1425 #endif
1426 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 8, 6)
1427  if (ssh_get_server_publickey(ssh->session, &server_pubkey) != SSH_OK) {
1428  // TRANSLATORS: The placeholder %s is an error message
1429  remmina_ssh_set_error(ssh, _("Could not fetch the server\'s public SSH key. %s"));
1430  REMMINA_DEBUG("ssh_get_server_publickey() has failed");
1432  }
1433 #else
1434  if (ssh_get_publickey(ssh->session, &server_pubkey) != SSH_OK) {
1435  // TRANSLATORS: The placeholder %s is an error message
1436  remmina_ssh_set_error(ssh, _("Could not fetch public SSH key. %s"));
1437  REMMINA_DEBUG("ssh_get_publickey() has failed");
1439  }
1440 #endif
1441  if (ssh_get_publickey_hash(server_pubkey, SSH_PUBLICKEY_HASH_MD5, &pubkey, &len) != 0) {
1442  ssh_key_free(server_pubkey);
1443  // TRANSLATORS: The placeholder %s is an error message
1444  remmina_ssh_set_error(ssh, _("Could not fetch checksum of the public SSH key. %s"));
1445  REMMINA_DEBUG("ssh_get_publickey_hash() has failed");
1447  }
1448  ssh_key_free(server_pubkey);
1449  keyname = ssh_get_hexa(pubkey, len);
1450 
1451 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1452  if (ret == SSH_KNOWN_HOSTS_UNKNOWN || ret == SSH_KNOWN_HOSTS_NOT_FOUND) {
1453 #else
1454  if (ret == SSH_SERVER_NOT_KNOWN || ret == SSH_SERVER_FILE_NOT_FOUND) {
1455 #endif
1456  message = g_strdup_printf("%s\n%s\n\n%s",
1457  _("The server is unknown. The public key fingerprint is:"),
1458  keyname,
1459  _("Do you trust the new public key?"));
1460  } else {
1461  message = g_strdup_printf("%s\n%s\n\n%s",
1462  _("Warning: The server has changed its public key. This means you are either under attack,\n"
1463  "or the administrator has changed the key. The new public key fingerprint is:"),
1464  keyname,
1465  _("Do you trust the new public key?"));
1466  }
1467 
1469  g_free(message);
1470 
1471  ssh_string_free_char(keyname);
1472  ssh_clean_pubkey_hash(&pubkey);
1473  if (ret != GTK_RESPONSE_YES) return REMMINA_SSH_AUTH_USERCANCEL;
1474 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1475  ssh_session_update_known_hosts(ssh->session);
1476 #else
1477  ssh_write_knownhost(ssh->session);
1478 #endif
1479  break;
1480 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1481  case SSH_KNOWN_HOSTS_ERROR:
1482 #else
1483  case SSH_SERVER_ERROR:
1484 #endif
1485  default:
1486  // TRANSLATORS: The placeholder %s is an error message
1487  remmina_ssh_set_error(ssh, _("Could not check list of known SSH hosts. %s"));
1488  REMMINA_DEBUG("Could not check list of known SSH hosts");
1490  }
1491 
1492  enum { REMMINA_SSH_AUTH_PASSWORD, REMMINA_SSH_AUTH_PKPASSPHRASE, REMMINA_SSH_AUTH_KRBTOKEN, REMMINA_SSH_AUTH_KBDINTERACTIVE } remmina_ssh_auth_type;
1493 
1494  switch (ssh->auth) {
1495  case SSH_AUTH_PASSWORD:
1496  keyname = _("SSH password");
1497  pwdfkey = ssh->is_tunnel ? "ssh_tunnel_password" : "password";
1498  remmina_ssh_auth_type = REMMINA_SSH_AUTH_PASSWORD;
1499  break;
1500  case SSH_AUTH_PUBLICKEY:
1501  case SSH_AUTH_AGENT:
1503  keyname = _("Password for private SSH key");
1504  pwdfkey = ssh->is_tunnel ? "ssh_tunnel_passphrase" : "ssh_passphrase";
1505  remmina_ssh_auth_type = REMMINA_SSH_AUTH_PKPASSPHRASE;
1506  break;
1507  case SSH_AUTH_GSSAPI:
1508  keyname = _("SSH Kerberos/GSSAPI");
1509  pwdfkey = ssh->is_tunnel ? "ssh_tunnel_kerberos_token" : "ssh_kerberos_token";
1510  remmina_ssh_auth_type = REMMINA_SSH_AUTH_KRBTOKEN;
1511  break;
1513  instruction = _("Enter TOTP/OTP/2FA code");
1514  remmina_ssh_auth_type = REMMINA_SSH_AUTH_KBDINTERACTIVE;
1515  break;
1516  default:
1518  }
1519 
1520  disablepasswordstoring = remmina_file_get_int(remminafile, "disablepasswordstoring", FALSE);
1521 
1522 
1523  current_pwd = g_strdup(remmina_file_get_string(remminafile, pwdfkey));
1524 
1525  /* Try existing password/passphrase first */
1526  ret = remmina_ssh_auth(ssh, current_pwd, gp, remminafile);
1527  REMMINA_DEBUG("Returned %d at 1st attempt with the following message:", ret);
1528  REMMINA_DEBUG("%s", ssh->error);
1529 
1530  /* It seems that functions like ssh_userauth_password() can only be called 3 times
1531  * on a ssh connection. And the 3rd failed attempt will block the calling thread forever.
1532  * So we retry only 2 extra time authentication. */
1533  for (attempt = 0;
1534  attempt < 2 && ret == REMMINA_SSH_AUTH_AUTHFAILED_RETRY_AFTER_PROMPT;
1535  attempt++) {
1536  if (ssh->error)
1537  REMMINA_DEBUG("Retrying auth because %s", ssh->error);
1538 
1539  if (remmina_ssh_auth_type == REMMINA_SSH_AUTH_PKPASSPHRASE) {
1541  (disablepasswordstoring ? 0 :
1543  ssh->is_tunnel ? _("SSH tunnel credentials") : _("SSH credentials"),
1544  NULL,
1545  remmina_file_get_string(remminafile, pwdfkey),
1546  NULL,
1547  _("Password for private SSH key"));
1548  if (ret == GTK_RESPONSE_OK) {
1549  g_free(current_pwd);
1550  current_pwd = remmina_protocol_widget_get_password(gp);
1551  save_password = remmina_protocol_widget_get_savepassword(gp);
1552  if (save_password)
1553  remmina_file_set_string(remminafile, pwdfkey, current_pwd);
1554  else
1555  remmina_file_set_string(remminafile, pwdfkey, NULL);
1556  } else {
1557  g_free(current_pwd);
1559  }
1560  } else if (remmina_ssh_auth_type == REMMINA_SSH_AUTH_PASSWORD) {
1561  /* Ask for user credentials. Username cannot be changed here,
1562  * because we already sent it when opening the connection */
1563  REMMINA_DEBUG("Showing panel for password\n");
1564  current_user = g_strdup(remmina_file_get_string(remminafile, ssh->is_tunnel ? "ssh_tunnel_username" : "username"));
1566  (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD)
1569  ssh->is_tunnel ? _("SSH tunnel credentials") : _("SSH credentials"),
1570  current_user,
1571  current_pwd,
1572  NULL,
1573  NULL);
1574  if (ret == GTK_RESPONSE_OK) {
1575  g_free(current_pwd);
1576  current_pwd = remmina_protocol_widget_get_password(gp);
1577  save_password = remmina_protocol_widget_get_savepassword(gp);
1578  if (save_password)
1579  remmina_file_set_string(remminafile, pwdfkey, current_pwd);
1580  else
1581  remmina_file_set_string(remminafile, pwdfkey, NULL);
1582 
1583  if (!ssh->is_tunnel && !ssh->is_multiauth) {
1584  g_free(current_user);
1585  current_user = remmina_protocol_widget_get_username(gp);
1586  remmina_file_set_string(remminafile, "username", current_user);
1587  if (ssh->user != NULL) {
1588  g_free(ssh->user);
1589  ssh->user = NULL;
1590  }
1591  ssh->user = g_strdup(current_user);
1592  if (ssh->password != NULL) {
1593  g_free(ssh->password);
1594  ssh->password = NULL;
1595  }
1596  ssh->password = g_strdup(current_pwd);
1597  g_free(current_user);
1599  }
1600  g_free(current_user);
1601  } else {
1602  g_free(current_pwd);
1603  g_free(current_user);
1605  }
1606  } else if (remmina_ssh_auth_type == REMMINA_SSH_AUTH_KBDINTERACTIVE) {
1607  REMMINA_DEBUG("Showing panel for keyboard interactive login\n");
1618  gp,
1619  0,
1620  _("Keyboard interactive login, TOTP/OTP/2FA"),
1621  NULL,
1622  NULL,
1623  NULL,
1624  instruction);
1625  if (ret == GTK_RESPONSE_OK) {
1626  g_free(current_pwd);
1627  current_pwd = remmina_protocol_widget_get_password(gp);
1628  REMMINA_DEBUG("OTP code is: %s", current_pwd);
1629  ssh->password = g_strdup(current_pwd);
1630  } else {
1631  g_free(current_pwd);
1633  }
1634  } else {
1635  g_print("Unimplemented.");
1636  g_free(current_pwd);
1638  }
1639  REMMINA_DEBUG("Retrying authentication");
1640  ret = remmina_ssh_auth(ssh, current_pwd, gp, remminafile);
1641  REMMINA_DEBUG("Authentication attempt n° %d returned %d with the following message:", attempt + 2, ret);
1642  REMMINA_DEBUG("%s", ssh->error);
1643  }
1644 
1645  g_free(current_pwd); current_pwd = NULL;
1646 
1647  /* After attempting the max number of times, REMMINA_SSH_AUTH_AUTHFAILED_RETRY_AFTER_PROMPT
1648  * becomes REMMINA_SSH_AUTH_FATAL_ERROR */
1650  REMMINA_DEBUG("SSH Authentication failed");
1652  }
1653 
1654  return ret;
1655 }
1656 
1657 void
1658 remmina_ssh_log_callback(ssh_session session, int priority, const char *message, void *userdata)
1659 {
1660  TRACE_CALL(__func__);
1661  REMMINA_DEBUG(message);
1662 }
1663 
1664 gboolean
1666 {
1667  TRACE_CALL(__func__);
1668  gint verbosity;
1669  gint rc;
1670  gchar *parsed_config;
1671 #ifdef HAVE_NETINET_TCP_H
1672  socket_t sshsock;
1673  gint optval;
1674 #endif
1675  // Handle IPv4 / IPv6 dual stack
1676  char *hostname;
1677  struct addrinfo hints,*aitop,*ai;
1678  char ipstr[INET6_ADDRSTRLEN];
1679  void *addr4=NULL;
1680  void *addr6=NULL;
1681 
1682  ssh->callback = g_new0(struct ssh_callbacks_struct, 1);
1683 
1684  /* Init & startup the SSH session */
1685  REMMINA_DEBUG("server=%s port=%d is_tunnel=%s tunnel_entrance_host=%s tunnel_entrance_port=%d",
1686  ssh->server,
1687  ssh->port,
1688  ssh->is_tunnel ? "Yes" : "No",
1690 
1691  ssh->session = ssh_new();
1692 
1693  /* Tunnel sanity checks */
1694  if (ssh->is_tunnel && ssh->tunnel_entrance_host != NULL) {
1695  ssh->error = g_strdup_printf("Internal error in %s: is_tunnel and tunnel_entrance != NULL", __func__);
1696  REMMINA_DEBUG(ssh->error);
1697  return FALSE;
1698  }
1699  if (!ssh->is_tunnel && ssh->tunnel_entrance_host == NULL) {
1700  ssh->error = g_strdup_printf("Internal error in %s: is_tunnel == false and tunnel_entrance == NULL", __func__);
1701  REMMINA_DEBUG(ssh->error);
1702  return FALSE;
1703  }
1704 
1705  /* Set connection host/port */
1706  if (ssh->is_tunnel) {
1707  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->server);
1708  ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->port);
1709  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to %s and SSH_OPTIONS_PORT to %d", ssh->server, ssh->port);
1710  } else {
1711  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->tunnel_entrance_host);
1712  ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->tunnel_entrance_port);
1713  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to %s and SSH_OPTIONS_PORT to %d", ssh->tunnel_entrance_host, ssh->tunnel_entrance_port);
1714  }
1715 
1716  if (ssh->privkeyfile && *ssh->privkeyfile != 0) {
1717  rc = ssh_options_set(ssh->session, SSH_OPTIONS_IDENTITY, ssh->privkeyfile);
1718  if (rc == 0)
1719  REMMINA_DEBUG("SSH_OPTIONS_IDENTITY is now %s", ssh->privkeyfile);
1720  else
1721  REMMINA_DEBUG("SSH_OPTIONS_IDENTITY is not set, by default the files “identity”, “id_dsa” and “id_rsa” are used.");
1722  }
1723 
1724 #ifdef SNAP_BUILD
1725  ssh_options_set(ssh->session, SSH_OPTIONS_SSH_DIR, g_strdup_printf("%s/.ssh", g_getenv("SNAP_USER_COMMON")));
1726 #endif
1727  ssh_callbacks_init(ssh->callback);
1728  if (remmina_log_running()) {
1729  verbosity = remmina_pref.ssh_loglevel;
1730  ssh_options_set(ssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
1731  ssh->callback->log_function = remmina_ssh_log_callback;
1732  /* Reset libssh legacy userdata. This is a workaround for a libssh bug */
1733  ssh_set_log_userdata(ssh->session);
1734  }
1735  ssh->callback->userdata = ssh;
1736  ssh_set_callbacks(ssh->session, ssh->callback);
1737 
1738  /* As the latest parse the ~/.ssh/config file */
1739  if (g_strcmp0(ssh->tunnel_entrance_host, "127.0.0.1") == 0) {
1740  REMMINA_DEBUG("SSH_OPTIONS_HOST temporary set to the destination host as ssh->tunnel_entrance_host is 127.0.0.1,");
1741  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->server);
1742  }
1744  if (ssh_options_parse_config(ssh->session, NULL) == 0)
1745  REMMINA_DEBUG("ssh_config have been correctly parsed");
1746  else
1747  REMMINA_DEBUG("Cannot parse ssh_config: %s", ssh_get_error(ssh->session));
1748  }
1749  if (g_strcmp0(ssh->tunnel_entrance_host, "127.0.0.1") == 0) {
1750  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to ssh->tunnel_entrance_host is 127.0.0.1,");
1751  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->tunnel_entrance_host);
1752  }
1753  if (!ssh->user || *ssh->user == 0) {
1754  rc = ssh_options_get(ssh->session, SSH_OPTIONS_USER, &parsed_config);
1755  if (rc == SSH_OK) {
1756  if (ssh->user)
1757  g_free(ssh->user);
1758  ssh->user = g_strdup(parsed_config);
1759  ssh_string_free_char(parsed_config);
1760  } else {
1761  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_USER returned an error: %s", ssh_get_error(ssh->session));
1762  }
1763  }
1764  ssh_options_set(ssh->session, SSH_OPTIONS_USER, ssh->user);
1765  REMMINA_DEBUG("SSH_OPTIONS_USER is now %s", ssh->user);
1766 
1767  /* SSH_OPTIONS_PROXYCOMMAND */
1768  rc = ssh_options_get(ssh->session, SSH_OPTIONS_PROXYCOMMAND, &parsed_config);
1769  if (rc == SSH_OK) {
1770  ssh->proxycommand = g_strdup(parsed_config);
1771  ssh_string_free_char(parsed_config);
1772  } else {
1773  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_PROXYCOMMAND returned an error: %s", ssh_get_error(ssh->session));
1774  }
1775  rc = ssh_options_set(ssh->session, SSH_OPTIONS_PROXYCOMMAND, ssh->proxycommand);
1776  if (rc == 0)
1777  REMMINA_DEBUG("SSH_OPTIONS_PROXYCOMMAND is now %s", ssh->proxycommand);
1778  else
1779  REMMINA_DEBUG("SSH_OPTIONS_PROXYCOMMAND does not have a valid value. %s", ssh->proxycommand);
1780 
1781  /* SSH_OPTIONS_HOSTKEYS */
1782  rc = ssh_options_get(ssh->session, SSH_OPTIONS_HOSTKEYS, &parsed_config);
1783  if (rc == SSH_OK) {
1784  ssh->hostkeytypes = g_strdup(parsed_config);
1785  ssh_string_free_char(parsed_config);
1786  } else {
1787  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_HOSTKEYS returned an error: %s", ssh_get_error(ssh->session));
1788  }
1789  rc = ssh_options_set(ssh->session, SSH_OPTIONS_HOSTKEYS, ssh->hostkeytypes);
1790  if (rc == 0)
1791  REMMINA_DEBUG("SSH_OPTIONS_HOSTKEYS is now %s", ssh->hostkeytypes);
1792  else
1793  REMMINA_DEBUG("SSH_OPTIONS_HOSTKEYS does not have a valid value. %s", ssh->hostkeytypes);
1794 
1795  /* SSH_OPTIONS_KEY_EXCHANGE */
1796  rc = ssh_options_get(ssh->session, SSH_OPTIONS_KEY_EXCHANGE, &parsed_config);
1797  if (rc == SSH_OK) {
1798  ssh->kex_algorithms = g_strdup(parsed_config);
1799  ssh_string_free_char(parsed_config);
1800  } else {
1801  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_KEY_EXCHANGE returned an error: %s", ssh_get_error(ssh->session));
1802  }
1803  rc = ssh_options_set(ssh->session, SSH_OPTIONS_KEY_EXCHANGE, ssh->kex_algorithms);
1804  if (rc == 0)
1805  REMMINA_DEBUG("SSH_OPTIONS_KEY_EXCHANGE is now %s", ssh->kex_algorithms);
1806  else
1807  REMMINA_DEBUG("SSH_OPTIONS_KEY_EXCHANGE does not have a valid value. %s", ssh->kex_algorithms);
1808 
1809  /* SSH_OPTIONS_CIPHERS_C_S */
1810  rc = ssh_options_get(ssh->session, SSH_OPTIONS_CIPHERS_C_S, &parsed_config);
1811  if (rc == SSH_OK) {
1812  ssh->ciphers = g_strdup(parsed_config);
1813  ssh_string_free_char(parsed_config);
1814  } else {
1815  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_CIPHERS_C_S returned an error: %s", ssh_get_error(ssh->session));
1816  }
1817  rc = ssh_options_set(ssh->session, SSH_OPTIONS_CIPHERS_C_S, ssh->ciphers);
1818  if (rc == 0)
1819  REMMINA_DEBUG("SSH_OPTIONS_CIPHERS_C_S has been set to %s", ssh->ciphers);
1820  else
1821  REMMINA_DEBUG("SSH_OPTIONS_CIPHERS_C_S does not have a valid value. %s", ssh->ciphers);
1822  /* SSH_OPTIONS_STRICTHOSTKEYCHECK */
1823  rc = ssh_options_get(ssh->session, SSH_OPTIONS_STRICTHOSTKEYCHECK, &parsed_config);
1824  if (rc == SSH_OK) {
1825  ssh->stricthostkeycheck = atoi(parsed_config);
1826  ssh_string_free_char(parsed_config);
1827  } else {
1828  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_STRICTHOSTKEYCHECK returned an error: %s", ssh_get_error(ssh->session));
1829  }
1830  rc = ssh_options_set(ssh->session, SSH_OPTIONS_STRICTHOSTKEYCHECK, &ssh->stricthostkeycheck);
1831  if (rc == 0)
1832  REMMINA_DEBUG("SSH_OPTIONS_STRICTHOSTKEYCHECK is now %d", ssh->stricthostkeycheck);
1833  else
1834  REMMINA_DEBUG("SSH_OPTIONS_STRICTHOSTKEYCHECK does not have a valid value. %d", ssh->stricthostkeycheck);
1835  /* SSH_OPTIONS_COMPRESSION */
1836  rc = ssh_options_get(ssh->session, SSH_OPTIONS_COMPRESSION, &parsed_config);
1837  if (rc == SSH_OK) {
1838  ssh->compression = g_strdup(parsed_config);
1839  ssh_string_free_char(parsed_config);
1840  } else {
1841  REMMINA_DEBUG("Parsing ssh_config for SSH_OPTIONS_COMPRESSION returned an error: %s", ssh_get_error(ssh->session));
1842  }
1843  rc = ssh_options_set(ssh->session, SSH_OPTIONS_COMPRESSION, ssh->compression);
1844  if (rc == 0)
1845  REMMINA_DEBUG("SSH_OPTIONS_COMPRESSION is now %s", ssh->compression);
1846  else
1847  REMMINA_DEBUG("SSH_OPTIONS_COMPRESSION does not have a valid value. %s", ssh->compression);
1848 
1849  // Handle the dual IPv4 / IPv6 stack
1850  // Prioritize IPv6 and fallback to IPv4
1851 
1852  // Run the DNS resolution
1853  // First retrieve host from the ssh->session structure
1854  ssh_options_get(ssh->session, SSH_OPTIONS_HOST, &hostname);
1855  // Call getaddrinfo
1856  memset(&hints, 0, sizeof(hints));
1857  hints.ai_family = AF_UNSPEC;
1858  hints.ai_socktype = SOCK_STREAM;
1859  if ((getaddrinfo(hostname, NULL, &hints, &aitop)) != 0) {
1860  ssh->error = g_strdup_printf("Could not resolve hostname %s", hostname);
1861  REMMINA_DEBUG(ssh->error);
1862  return FALSE;
1863  }
1864 
1865  // We have one or more addesses now, extract them
1866  ai = aitop;
1867  while (ai != NULL) {
1868  if (ai->ai_family == AF_INET) { // IPv4
1869  struct sockaddr_in *ipv4 = (struct sockaddr_in *)ai->ai_addr;
1870  addr4 = &(ipv4->sin_addr);
1871  } else { // IPv6
1872  struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)ai->ai_addr;
1873  addr6 = &(ipv6->sin6_addr);
1874  }
1875  ai = ai->ai_next;
1876  }
1877  freeaddrinfo(aitop);
1878 
1879  unsigned short int success6 = 0;
1880  if (addr6 != NULL) {
1881  // Try IPv6 first
1882  inet_ntop(AF_INET6, addr6, ipstr, sizeof ipstr);
1883  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ipstr);
1884  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to IPv6 %s", ipstr);
1885  if (ssh_connect(ssh->session)) {
1886  ssh_disconnect(ssh->session);
1887  REMMINA_DEBUG("IPv6 session failed");
1888  } else {
1889  success6 = 1;
1890  REMMINA_DEBUG("IPv6 session success !");
1891  }
1892  }
1893  if (success6 == 0) {
1894  // Fallback to IPv4
1895  inet_ntop(AF_INET, addr4, ipstr, sizeof ipstr);
1896  ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ipstr);
1897  REMMINA_DEBUG("Setting SSH_OPTIONS_HOST to IPv4 %s", ipstr);
1898  if (ssh_connect(ssh->session)) {
1899  // TRANSLATORS: The placeholder %s is an error message
1900  remmina_ssh_set_error(ssh, _("Could not start SSH session. %s"));
1901  return FALSE;
1902  }
1903  }
1904 
1905 #ifdef HAVE_NETINET_TCP_H
1906  /* Set keepalive on SSH socket, so we can keep firewalls awaken and detect
1907  * when we loss the tunnel */
1908  sshsock = ssh_get_fd(ssh->session);
1909  if (sshsock >= 0) {
1910  optval = 1;
1911  if (setsockopt(sshsock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
1912  REMMINA_DEBUG("TCP KeepAlive not set");
1913  else
1914  REMMINA_DEBUG("TCP KeepAlive enabled");
1915 
1916 #ifdef TCP_KEEPIDLE
1917  optval = remmina_pref.ssh_tcp_keepidle;
1918  if (setsockopt(sshsock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) < 0)
1919  REMMINA_DEBUG("TCP_KEEPIDLE not set");
1920  else
1921  REMMINA_DEBUG("TCP_KEEPIDLE set to %i", optval);
1922 
1923 #endif
1924 #ifdef TCP_KEEPCNT
1925  optval = remmina_pref.ssh_tcp_keepcnt;
1926  if (setsockopt(sshsock, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)) < 0)
1927  REMMINA_DEBUG("TCP_KEEPCNT not set");
1928  else
1929  REMMINA_DEBUG("TCP_KEEPCNT set to %i", optval);
1930 
1931 #endif
1932 #ifdef TCP_KEEPINTVL
1934  if (setsockopt(sshsock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)) < 0)
1935  REMMINA_DEBUG("TCP_KEEPINTVL not set");
1936  else
1937  REMMINA_DEBUG("TCP_KEEPINTVL set to %i", optval);
1938 
1939 #endif
1940 #ifdef TCP_USER_TIMEOUT
1942  if (setsockopt(sshsock, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval)) < 0)
1943  REMMINA_DEBUG("TCP_USER_TIMEOUT not set");
1944  else
1945  REMMINA_DEBUG("TCP_USER_TIMEOUT set to %i", optval);
1946 
1947 #endif
1948  }
1949 #endif
1950 
1951  /* Try the "none" authentication */
1952  if (ssh_userauth_none(ssh->session, NULL) == SSH_AUTH_SUCCESS)
1953  ssh->authenticated = TRUE;
1954  return TRUE;
1955 }
1956 
1957 gboolean
1958 remmina_ssh_init_from_file(RemminaSSH *ssh, RemminaFile *remminafile, gboolean is_tunnel)
1959 {
1960  TRACE_CALL(__func__);
1961  const gchar *username;
1962  const gchar *privatekey;
1963  const gchar *server;
1964  gchar *s;
1965 
1966  ssh->session = NULL;
1967  ssh->callback = NULL;
1968  ssh->authenticated = FALSE;
1969  ssh->error = NULL;
1970  ssh->passphrase = NULL;
1971  ssh->is_tunnel = is_tunnel;
1972  pthread_mutex_init(&ssh->ssh_mutex, NULL);
1973 
1974  ssh->tunnel_entrance_host = NULL;
1975  ssh->tunnel_entrance_port = 0;
1976 
1977  username = remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_username" : "username");
1978  privatekey = remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_privatekey" : "ssh_privatekey");
1979  ssh->certfile = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_certfile" : "ssh_certfile"));
1980 
1981  /* The ssh->server and ssh->port values */
1982  if (is_tunnel) {
1983  REMMINA_DEBUG("We are initializing an SSH tunnel session");
1984  server = remmina_file_get_string(remminafile, "ssh_tunnel_server");
1985  if (server == NULL || server[0] == 0) {
1986  // ssh_tunnel_server empty or invalid, we are opening a tunnel, it means that "Same server at port 22" has been selected
1987  server = remmina_file_get_string(remminafile, "server");
1988  if (server == NULL || server[0] == 0)
1989  server = "localhost";
1990  REMMINA_DEBUG("Calling remmina_public_get_server_port");
1991  remmina_public_get_server_port(server, 22, &ssh->server, &ssh->port);
1992  ssh->port = 22;
1993  } else {
1994  REMMINA_DEBUG("Calling remmina_public_get_server_port");
1995  remmina_public_get_server_port(server, 22, &ssh->server, &ssh->port);
1996  }
1997  REMMINA_DEBUG("server:port = %s, server = %s, port = %d", server, ssh->server, ssh->port);
1998  } else {
1999  REMMINA_DEBUG("We are initializing an SSH session");
2000  server = remmina_file_get_string(remminafile, "server");
2001  if (server == NULL || server[0] == 0)
2002  server = "localhost";
2003  REMMINA_DEBUG("Calling remmina_public_get_server_port");
2004  remmina_public_get_server_port(server, 22, &ssh->server, &ssh->port);
2005  REMMINA_DEBUG("server:port = %s, server = %s, port = %d", server, ssh->server, ssh->port);
2006  }
2007 
2008  if (ssh->server[0] == '\0') {
2009  g_free(ssh->server);
2010  // ???
2011  REMMINA_DEBUG("Calling remmina_public_get_server_port");
2012  remmina_public_get_server_port(server, 0, &ssh->server, NULL);
2013  }
2014 
2015  REMMINA_DEBUG("Initialized SSH struct from file with ssh->server = %s and SSH->port = %d", ssh->server, ssh->port);
2016 
2017  ssh->user = g_strdup(username ? username : NULL);
2018  ssh->password = NULL;
2019  ssh->auth = remmina_file_get_int(remminafile, is_tunnel ? "ssh_tunnel_auth" : "ssh_auth", 0);
2020  ssh->charset = g_strdup(remmina_file_get_string(remminafile, "ssh_charset"));
2021  ssh->kex_algorithms = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_kex_algorithms" : "ssh_kex_algorithms"));
2022  ssh->ciphers = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_ciphers" : "ssh_ciphers"));
2023  ssh->hostkeytypes = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_hostkeytypes" : "ssh_hostkeytypes"));
2024  ssh->proxycommand = g_strdup(remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_proxycommand" : "ssh_proxycommand"));
2025  ssh->stricthostkeycheck = remmina_file_get_int(remminafile, is_tunnel ? "ssh_tunnel_stricthostkeycheck" : "ssh_stricthostkeycheck", 0);
2026  gint c = remmina_file_get_int(remminafile, is_tunnel ? "ssh_tunnel_compression" : "ssh_compression", 0);
2027  ssh->compression = (c == 1) ? "yes" : "no";
2028 
2029  REMMINA_DEBUG("ssh->user: %s", ssh->user);
2030  REMMINA_DEBUG("ssh->password: %s", ssh->password);
2031  REMMINA_DEBUG("ssh->auth: %d", ssh->auth);
2032  REMMINA_DEBUG("ssh->charset: %s", ssh->charset);
2033  REMMINA_DEBUG("ssh->kex_algorithms: %s", ssh->kex_algorithms);
2034  REMMINA_DEBUG("ssh->ciphers: %s", ssh->ciphers);
2035  REMMINA_DEBUG("ssh->hostkeytypes: %s", ssh->hostkeytypes);
2036  REMMINA_DEBUG("ssh->proxycommand: %s", ssh->proxycommand);
2037  REMMINA_DEBUG("ssh->stricthostkeycheck: %d", ssh->stricthostkeycheck);
2038  REMMINA_DEBUG("ssh->compression: %s", ssh->compression);
2039 
2040  /* Public/Private keys */
2041  s = (privatekey ? g_strdup(privatekey) : remmina_ssh_find_identity());
2042  if (s) {
2044  REMMINA_DEBUG("ssh->privkeyfile: %s", ssh->privkeyfile);
2045  g_free(s);
2046  } else {
2047  ssh->privkeyfile = NULL;
2048  }
2049 
2050  return TRUE;
2051 }
2052 
2053 static gboolean
2054 remmina_ssh_init_from_ssh(RemminaSSH *ssh, const RemminaSSH *ssh_src)
2055 {
2056  TRACE_CALL(__func__);
2057  ssh->session = NULL;
2058  ssh->authenticated = FALSE;
2059  ssh->error = NULL;
2060  pthread_mutex_init(&ssh->ssh_mutex, NULL);
2061 
2062  ssh->is_tunnel = ssh_src->is_tunnel;
2063  ssh->server = g_strdup(ssh_src->server);
2064  ssh->port = ssh_src->port;
2065  ssh->user = g_strdup(ssh_src->user ? ssh_src->user : NULL);
2066  ssh->auth = ssh_src->auth;
2067  ssh->password = g_strdup(ssh_src->password);
2068  ssh->passphrase = g_strdup(ssh_src->passphrase);
2069  ssh->privkeyfile = g_strdup(ssh_src->privkeyfile);
2070  ssh->certfile = g_strdup(ssh_src->certfile);
2071  ssh->charset = g_strdup(ssh_src->charset);
2072  ssh->proxycommand = g_strdup(ssh_src->proxycommand);
2073  ssh->kex_algorithms = g_strdup(ssh_src->kex_algorithms);
2074  ssh->ciphers = g_strdup(ssh_src->ciphers);
2075  ssh->hostkeytypes = g_strdup(ssh_src->hostkeytypes);
2076  ssh->stricthostkeycheck = ssh_src->stricthostkeycheck;
2077  ssh->compression = ssh_src->compression;
2078  ssh->tunnel_entrance_host = g_strdup(ssh_src->tunnel_entrance_host);
2080 
2081  return TRUE;
2082 }
2083 
2084 gchar *
2085 remmina_ssh_convert(RemminaSSH *ssh, const gchar *from)
2086 {
2087  TRACE_CALL(__func__);
2088  gchar *to = NULL;
2089 
2090  if (ssh->charset && from)
2091  to = g_convert(from, -1, "UTF-8", ssh->charset, NULL, NULL, NULL);
2092  if (!to) to = g_strdup(from);
2093  return to;
2094 }
2095 
2096 gchar *
2097 remmina_ssh_unconvert(RemminaSSH *ssh, const gchar *from)
2098 {
2099  TRACE_CALL(__func__);
2100  gchar *to = NULL;
2101 
2102  if (ssh->charset && from)
2103  to = g_convert(from, -1, ssh->charset, "UTF-8", NULL, NULL, NULL);
2104  if (!to) to = g_strdup(from);
2105  return to;
2106 }
2107 
2108 void
2110 {
2111  TRACE_CALL(__func__);
2112  if (ssh->session) {
2113  REMMINA_DEBUG("Disconnecting SSH session");
2114  ssh_disconnect(ssh->session);
2115  ssh_free(ssh->session);
2116  ssh->session = NULL;
2117  }
2118  g_free(ssh->callback);
2119  g_free(ssh->server);
2120  g_free(ssh->user);
2121  g_free(ssh->password);
2122  g_free(ssh->privkeyfile);
2123  g_free(ssh->certfile);
2124  g_free(ssh->charset);
2125  g_free(ssh->error);
2126  pthread_mutex_destroy(&ssh->ssh_mutex);
2127  g_free(ssh);
2128 }
2129 
2130 /*-----------------------------------------------------------------------------*
2131 * SSH Tunnel *
2132 *-----------------------------------------------------------------------------*/
2133 struct _RemminaSSHTunnelBuffer {
2134  gchar * data;
2135  gchar * ptr;
2136  ssize_t len;
2137 };
2138 
2139 static RemminaSSHTunnelBuffer *
2140 remmina_ssh_tunnel_buffer_new(ssize_t len)
2141 {
2142  TRACE_CALL(__func__);
2143  RemminaSSHTunnelBuffer *buffer;
2144 
2145  buffer = g_new(RemminaSSHTunnelBuffer, 1);
2146  buffer->data = (gchar *)g_malloc(len);
2147  buffer->ptr = buffer->data;
2148  buffer->len = len;
2149  return buffer;
2150 }
2151 
2152 static void
2153 remmina_ssh_tunnel_buffer_free(RemminaSSHTunnelBuffer *buffer)
2154 {
2155  TRACE_CALL(__func__);
2156  if (buffer) {
2157  g_free(buffer->data);
2158  g_free(buffer);
2159  }
2160 }
2161 
2164 {
2165  TRACE_CALL(__func__);
2166  RemminaSSHTunnel *tunnel;
2167 
2168  tunnel = g_new(RemminaSSHTunnel, 1);
2169 
2170  remmina_ssh_init_from_file(REMMINA_SSH(tunnel), remminafile, TRUE);
2171 
2172  tunnel->tunnel_type = -1;
2173  tunnel->channels = NULL;
2174  tunnel->sockets = NULL;
2175  tunnel->socketbuffers = NULL;
2176  tunnel->num_channels = 0;
2177  tunnel->max_channels = 0;
2178  tunnel->thread = 0;
2179  tunnel->running = FALSE;
2180  tunnel->server_sock = -1;
2181  tunnel->dest = NULL;
2182  tunnel->port = 0;
2183  tunnel->buffer = NULL;
2184  tunnel->buffer_len = 0;
2185  tunnel->channels_out = NULL;
2186  tunnel->remotedisplay = 0;
2187  tunnel->localdisplay = NULL;
2188  tunnel->init_func = NULL;
2189  tunnel->connect_func = NULL;
2190  tunnel->disconnect_func = NULL;
2191  tunnel->callback_data = NULL;
2192 
2193  return tunnel;
2194 }
2195 
2196 static void
2197 remmina_ssh_tunnel_close_all_channels(RemminaSSHTunnel *tunnel)
2198 {
2199  TRACE_CALL(__func__);
2200  int i;
2201 
2202  for (i = 0; i < tunnel->num_channels; i++) {
2203  close(tunnel->sockets[i]);
2204  remmina_ssh_tunnel_buffer_free(tunnel->socketbuffers[i]);
2205  ssh_channel_close(tunnel->channels[i]);
2206  ssh_channel_send_eof(tunnel->channels[i]);
2207  ssh_channel_free(tunnel->channels[i]);
2208  }
2209 
2210  g_free(tunnel->channels);
2211  tunnel->channels = NULL;
2212  g_free(tunnel->sockets);
2213  tunnel->sockets = NULL;
2214  g_free(tunnel->socketbuffers);
2215  tunnel->socketbuffers = NULL;
2216 
2217  tunnel->num_channels = 0;
2218  tunnel->max_channels = 0;
2219 }
2220 
2221 static void
2222 remmina_ssh_tunnel_remove_channel(RemminaSSHTunnel *tunnel, gint n)
2223 {
2224  TRACE_CALL(__func__);
2225  ssh_channel_close(tunnel->channels[n]);
2226  ssh_channel_send_eof(tunnel->channels[n]);
2227  ssh_channel_free(tunnel->channels[n]);
2228  close(tunnel->sockets[n]);
2229  remmina_ssh_tunnel_buffer_free(tunnel->socketbuffers[n]);
2230  tunnel->num_channels--;
2231  tunnel->channels[n] = tunnel->channels[tunnel->num_channels];
2232  tunnel->channels[tunnel->num_channels] = NULL;
2233  tunnel->sockets[n] = tunnel->sockets[tunnel->num_channels];
2234  tunnel->socketbuffers[n] = tunnel->socketbuffers[tunnel->num_channels];
2235 }
2236 
2237 /* Register the new channel/socket pair */
2238 static void
2239 remmina_ssh_tunnel_add_channel(RemminaSSHTunnel *tunnel, ssh_channel channel, gint sock)
2240 {
2241  TRACE_CALL(__func__);
2242  gint flags;
2243  gint i;
2244 
2245  i = tunnel->num_channels++;
2246  if (tunnel->num_channels > tunnel->max_channels) {
2247  /* Allocate an extra NULL pointer in channels for ssh_select */
2248  tunnel->channels = (ssh_channel *)g_realloc(tunnel->channels,
2249  sizeof(ssh_channel) * (tunnel->num_channels + 1));
2250  tunnel->sockets = (gint *)g_realloc(tunnel->sockets,
2251  sizeof(gint) * tunnel->num_channels);
2252  tunnel->socketbuffers = (RemminaSSHTunnelBuffer **)g_realloc(tunnel->socketbuffers,
2253  sizeof(RemminaSSHTunnelBuffer *) * tunnel->num_channels);
2254  tunnel->max_channels = tunnel->num_channels;
2255 
2256  tunnel->channels_out = (ssh_channel *)g_realloc(tunnel->channels_out,
2257  sizeof(ssh_channel) * (tunnel->num_channels + 1));
2258  }
2259  tunnel->channels[i] = channel;
2260  tunnel->channels[i + 1] = NULL;
2261  tunnel->sockets[i] = sock;
2262  tunnel->socketbuffers[i] = NULL;
2263 
2264  flags = fcntl(sock, F_GETFL, 0);
2265  fcntl(sock, F_SETFL, flags | O_NONBLOCK);
2266 }
2267 
2268 static int
2269 remmina_ssh_tunnel_accept_local_connection(RemminaSSHTunnel *tunnel, gboolean blocking)
2270 {
2271  gint sock, sock_flags;
2272 
2273  sock_flags = fcntl(tunnel->server_sock, F_GETFL, 0);
2274  if (blocking)
2275  sock_flags &= ~O_NONBLOCK;
2276  else
2277  sock_flags |= O_NONBLOCK;
2278  fcntl(tunnel->server_sock, F_SETFL, sock_flags);
2279 
2280  /* Accept a local connection */
2281  sock = accept(tunnel->server_sock, NULL, NULL);
2282  if (sock < 0) {
2283  if (blocking) {
2284  g_free(REMMINA_SSH(tunnel)->error);
2285  REMMINA_SSH(tunnel)->error = g_strdup("Local socket not accepted");
2286  }
2287  }
2288 
2289  return sock;
2290 }
2291 
2292 static ssh_channel
2293 remmina_ssh_tunnel_create_forward_channel(RemminaSSHTunnel *tunnel)
2294 {
2295  ssh_channel channel = NULL;
2296 
2297  channel = ssh_channel_new(tunnel->ssh.session);
2298  if (!channel) {
2299  // TRANSLATORS: The placeholder %s is an error message
2300  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not create channel. %s"));
2301  return NULL;
2302  }
2303 
2304  /* Request the SSH server to connect to the destination */
2305  REMMINA_DEBUG("SSH tunnel destination is %s", tunnel->dest);
2306  if (ssh_channel_open_forward(channel, tunnel->dest, tunnel->port, "127.0.0.1", 0) != SSH_OK) {
2307  ssh_channel_close(channel);
2308  ssh_channel_send_eof(channel);
2309  ssh_channel_free(channel);
2310  // TRANSLATORS: The placeholder %s is an error message
2311  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not connect to SSH tunnel. %s"));
2312  return NULL;
2313  }
2314 
2315  return channel;
2316 }
2317 
2318 static gpointer
2319 remmina_ssh_tunnel_main_thread_proc(gpointer data)
2320 {
2321  TRACE_CALL(__func__);
2322  RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data;
2323  gchar *ptr;
2324  ssize_t len = 0, lenw = 0;
2325  fd_set set;
2326  struct timeval timeout;
2327  g_autoptr(GDateTime) t1 = NULL;
2328  g_autoptr(GDateTime) t2 = NULL;
2329  GTimeSpan diff; // microseconds
2330  ssh_channel channel = NULL;
2331  gboolean first = TRUE;
2332  gboolean disconnected;
2333  gint sock;
2334  gint maxfd;
2335  gint i;
2336  gint ret;
2337  struct sockaddr_in sin;
2338 
2339  t1 = g_date_time_new_now_local();
2340  t2 = g_date_time_new_now_local();
2341 
2342  switch (tunnel->tunnel_type) {
2344  sock = remmina_ssh_tunnel_accept_local_connection(tunnel, TRUE);
2345  if (sock < 0) {
2346  if (tunnel)
2347  tunnel->thread = 0;
2348  return NULL;
2349  }
2350 
2351  channel = remmina_ssh_tunnel_create_forward_channel(tunnel);
2352  if (!tunnel) {
2353  close(sock);
2354  tunnel->thread = 0;
2355  return NULL;
2356  }
2357 
2358  remmina_ssh_tunnel_add_channel(tunnel, channel, sock);
2359  break;
2360 
2362  /* Detect the next available port starting from 6010 on the server */
2363  for (i = 10; i <= MAX_X_DISPLAY_NUMBER; i++) {
2364 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2365  if (ssh_channel_listen_forward(REMMINA_SSH(tunnel)->session, (tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL)) {
2366  continue;
2367  } else {
2368  tunnel->remotedisplay = i;
2369  break;
2370  }
2371 #else
2372  if (ssh_forward_listen(REMMINA_SSH(tunnel)->session, (tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL)) {
2373  continue;
2374  } else {
2375  tunnel->remotedisplay = i;
2376  break;
2377  }
2378 #endif
2379  }
2380  if (tunnel->remotedisplay < 1) {
2381  // TRANSLATORS: The placeholder %s is an error message
2382  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not request port forwarding. %s"));
2383  if (tunnel->disconnect_func)
2384  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2385  tunnel->thread = 0;
2386  return NULL;
2387  }
2388 
2389  if (tunnel->init_func &&
2390  !(*tunnel->init_func)(tunnel, tunnel->callback_data)) {
2391  if (tunnel->disconnect_func)
2392  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2393  tunnel->thread = 0;
2394  return NULL;
2395  }
2396 
2397  break;
2398 
2400 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2401  if (ssh_channel_listen_forward(REMMINA_SSH(tunnel)->session, NULL, tunnel->port, NULL)) {
2402  // TRANSLATORS: The placeholder %s is an error message
2403  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not request port forwarding. %s"));
2404  if (tunnel->disconnect_func)
2405  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2406  tunnel->thread = 0;
2407  return NULL;
2408  }
2409 #else
2410  if (ssh_forward_listen(REMMINA_SSH(tunnel)->session, NULL, tunnel->port, NULL)) {
2411  // TRANSLATORS: The placeholder %s is an error message
2412  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not request port forwarding. %s"));
2413  if (tunnel->disconnect_func)
2414  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2415  tunnel->thread = 0;
2416  return NULL;
2417  }
2418 #endif
2419 
2420  if (tunnel->init_func &&
2421  !(*tunnel->init_func)(tunnel, tunnel->callback_data)) {
2422  if (tunnel->disconnect_func)
2423  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2424  tunnel->thread = 0;
2425  return NULL;
2426  }
2427 
2428  break;
2429  }
2430 
2431  tunnel->buffer_len = 10240;
2432  tunnel->buffer = g_malloc(tunnel->buffer_len);
2433 
2434  /* Start the tunnel data transmission */
2435  while (tunnel->running) {
2436  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT ||
2438  if (first) {
2439  first = FALSE;
2440  channel = ssh_channel_accept_forward(REMMINA_SSH(tunnel)->session, 15000, &tunnel->port);
2441  if (!channel) {
2442  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("The server did not respond."));
2443  if (tunnel->disconnect_func)
2444  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2445  tunnel->thread = 0;
2446  return NULL;
2447  }
2448  if (tunnel->connect_func)
2449  (*tunnel->connect_func)(tunnel, tunnel->callback_data);
2450  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) {
2451  /* For reverse tunnel, we only need one connection. */
2452 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2453  ssh_channel_cancel_forward(REMMINA_SSH(tunnel)->session, NULL, tunnel->port);
2454 #else
2455  ssh_forward_cancel(REMMINA_SSH(tunnel)->session, NULL, tunnel->port);
2456 #endif
2457  }
2458  } else if (tunnel->tunnel_type != REMMINA_SSH_TUNNEL_REVERSE) {
2459  /* Poll once per some period of time if no incoming connections.
2460  * Don’t try to poll continuously as it will significantly slow down the loop */
2461  t1 = g_date_time_new_now_local();
2462  diff = g_date_time_difference(t1, t2) * 10000000
2463  + g_date_time_difference(t1, t2) / 100000;
2464  if (diff > 1) {
2465  REMMINA_DEBUG("Polling tunnel channels");
2466  channel = ssh_channel_accept_forward(REMMINA_SSH(tunnel)->session, 0, &tunnel->port);
2467  if (channel == NULL)
2468  t2 = g_date_time_new_now_local();
2469  }
2470  }
2471 
2472  if (channel) {
2473  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) {
2474  sin.sin_family = AF_INET;
2475  sin.sin_port = htons(tunnel->localport);
2476  sin.sin_addr.s_addr = inet_addr("127.0.0.1");
2477  sock = socket(AF_INET, SOCK_STREAM, 0);
2478  if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
2479  remmina_ssh_set_application_error(REMMINA_SSH(tunnel),
2480  _("Cannot connect to local port %i."), tunnel->localport);
2481  close(sock);
2482  sock = -1;
2483  }
2484  } else
2486  if (sock >= 0)
2487  remmina_ssh_tunnel_add_channel(tunnel, channel, sock);
2488  else {
2489  /* Failed to create unix socket. Will this happen? */
2490  ssh_channel_close(channel);
2491  ssh_channel_send_eof(channel);
2492  ssh_channel_free(channel);
2493  }
2494  channel = NULL;
2495  }
2496  }
2497 
2498  if (tunnel->num_channels <= 0)
2499  /* No more connections. We should quit */
2500  break;
2501 
2502  timeout.tv_sec = 0;
2503  timeout.tv_usec = 200000;
2504 
2505  FD_ZERO(&set);
2506  maxfd = 0;
2507  for (i = 0; i < tunnel->num_channels; i++) {
2508  if (tunnel->sockets[i] > maxfd)
2509  maxfd = tunnel->sockets[i];
2510  FD_SET(tunnel->sockets[i], &set);
2511  }
2512 
2513  ret = ssh_select(tunnel->channels, tunnel->channels_out, maxfd + 1, &set, &timeout);
2514  if (!tunnel->running) break;
2515  if (ret == SSH_EINTR) continue;
2516  if (ret == -1) break;
2517 
2518  i = 0;
2519  while (tunnel->running && i < tunnel->num_channels) {
2520  disconnected = FALSE;
2521  if (FD_ISSET(tunnel->sockets[i], &set)) {
2522  while (!disconnected &&
2523  (len = read(tunnel->sockets[i], tunnel->buffer, tunnel->buffer_len)) > 0) {
2524  for (ptr = tunnel->buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw) {
2525  lenw = ssh_channel_write(tunnel->channels[i], (char *)ptr, len);
2526  if (lenw <= 0) {
2527  disconnected = TRUE;
2528  // TRANSLATORS: The placeholder %s is an error message
2529  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not write to SSH channel. %s"));
2530  break;
2531  }
2532  }
2533  }
2534  if (len == 0) {
2535  // TRANSLATORS: The placeholder %s is an error message
2536  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not read from tunnel listening socket. %s"));
2537  disconnected = TRUE;
2538  }
2539  }
2540  if (disconnected) {
2541  REMMINA_DEBUG("tunnel disconnected because %s", REMMINA_SSH(tunnel)->error);
2542  remmina_ssh_tunnel_remove_channel(tunnel, i);
2543  continue;
2544  }
2545  i++;
2546  }
2547  if (!tunnel->running) break;
2548 
2549  i = 0;
2550  while (tunnel->running && i < tunnel->num_channels) {
2551  disconnected = FALSE;
2552  if (!tunnel->socketbuffers[i]) {
2553  len = ssh_channel_poll(tunnel->channels[i], 0);
2554  if (len == SSH_ERROR || len == SSH_EOF) {
2555  // TRANSLATORS: The placeholder %s is an error message
2556  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not poll SSH channel. %s"));
2557  disconnected = TRUE;
2558  } else if (len > 0) {
2559  tunnel->socketbuffers[i] = remmina_ssh_tunnel_buffer_new(len);
2560  len = ssh_channel_read_nonblocking(tunnel->channels[i], tunnel->socketbuffers[i]->data, len, 0);
2561  if (len <= 0) {
2562  // TRANSLATORS: The placeholder %s is an error message
2563  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not read SSH channel in a non-blocking way. %s"));
2564  disconnected = TRUE;
2565  } else {
2566  tunnel->socketbuffers[i]->len = len;
2567  }
2568  }
2569  }
2570 
2571  if (!disconnected && tunnel->socketbuffers[i]) {
2572  for (lenw = 0; tunnel->socketbuffers[i]->len > 0;
2573  tunnel->socketbuffers[i]->len -= lenw, tunnel->socketbuffers[i]->ptr += lenw) {
2574  lenw = write(tunnel->sockets[i], tunnel->socketbuffers[i]->ptr, tunnel->socketbuffers[i]->len);
2575  if (lenw == -1 && errno == EAGAIN && tunnel->running)
2576  /* Sometimes we cannot write to a socket (always EAGAIN), probably because it’s internal
2577  * buffer is full. We need read the pending bytes from the socket first. so here we simply
2578  * break, leave the buffer there, and continue with other data */
2579  break;
2580  if (lenw <= 0) {
2581  // TRANSLATORS: The placeholder %s is an error message
2582  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not send data to tunnel listening socket. %s"));
2583  disconnected = TRUE;
2584  break;
2585  }
2586  }
2587  if (tunnel->socketbuffers[i]->len <= 0) {
2588  remmina_ssh_tunnel_buffer_free(tunnel->socketbuffers[i]);
2589  tunnel->socketbuffers[i] = NULL;
2590  }
2591  }
2592 
2593  if (disconnected) {
2594  REMMINA_DEBUG("Connection to SSH tunnel dropped. %s", REMMINA_SSH(tunnel)->error);
2595  remmina_ssh_tunnel_remove_channel(tunnel, i);
2596  continue;
2597  }
2598  i++;
2599  }
2604  sock = remmina_ssh_tunnel_accept_local_connection(tunnel, FALSE);
2605  if (sock > 0) {
2606  channel = remmina_ssh_tunnel_create_forward_channel(tunnel);
2607  if (!channel) {
2608  REMMINA_DEBUG("Could not open new SSH connection. %s", REMMINA_SSH(tunnel)->error);
2609  close(sock);
2610  /* Leave thread loop */
2611  tunnel->running = FALSE;
2612  } else {
2613  remmina_ssh_tunnel_add_channel(tunnel, channel, sock);
2614  }
2615  }
2616  }
2617 
2618  remmina_ssh_tunnel_close_all_channels(tunnel);
2619 
2620  tunnel->running = FALSE;
2621 
2622  /* Notify tunnel owner of disconnection */
2623  if (tunnel->disconnect_func)
2624  (*tunnel->disconnect_func)(tunnel, tunnel->callback_data);
2625 
2626  return NULL;
2627 }
2628 
2629 static gboolean remmina_ssh_notify_tunnel_main_thread_end(gpointer data)
2630 {
2631  TRACE_CALL(__func__);
2632  RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data;
2633 
2634  /* Ask tunnel owner to destroy tunnel object */
2635  if (tunnel->destroy_func)
2636  (*tunnel->destroy_func)(tunnel, tunnel->destroy_func_callback_data);
2637 
2638  return FALSE;
2639 }
2640 
2641 static gpointer
2642 remmina_ssh_tunnel_main_thread(gpointer data)
2643 {
2644  TRACE_CALL(__func__);
2645  RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data;
2646 
2647  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
2648 
2649  while (TRUE) {
2650  remmina_ssh_tunnel_main_thread_proc(data);
2651  if (tunnel->server_sock < 0 || tunnel->thread == 0 || !tunnel->running) break;
2652  }
2653  tunnel->thread = 0;
2654 
2655  /* Do after tunnel thread cleanup */
2656  IDLE_ADD((GSourceFunc)remmina_ssh_notify_tunnel_main_thread_end, (gpointer)tunnel);
2657 
2658  return NULL;
2659 }
2660 
2661 
2662 void
2664 {
2665  TRACE_CALL(__func__);
2666  if (tunnel->server_sock >= 0) {
2667  close(tunnel->server_sock);
2668  tunnel->server_sock = -1;
2669  }
2670 }
2671 
2672 gboolean
2673 remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port)
2674 {
2675  TRACE_CALL(__func__);
2676  gint sock;
2677  gint sockopt = 1;
2678  struct sockaddr_in sin;
2679 
2681  tunnel->dest = g_strdup(host);
2682  tunnel->port = port;
2683  if (tunnel->port == 0) {
2684  REMMINA_SSH(tunnel)->error = g_strdup(_("Assign a destination port."));
2685  return FALSE;
2686  }
2687 
2688  /* Create the server socket that listens on the local port */
2689  sock = socket(AF_INET, SOCK_STREAM, 0);
2690  if (sock < 0) {
2691  REMMINA_SSH(tunnel)->error = g_strdup(_("Could not create socket."));
2692  return FALSE;
2693  }
2694  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
2695 
2696  sin.sin_family = AF_INET;
2697  sin.sin_port = htons(local_port);
2698  sin.sin_addr.s_addr = inet_addr("127.0.0.1");
2699 
2700  if (bind(sock, (struct sockaddr *)&sin, sizeof(sin))) {
2701  REMMINA_SSH(tunnel)->error = g_strdup(_("Could not bind server socket to local port."));
2702  close(sock);
2703  return FALSE;
2704  }
2705 
2706  if (listen(sock, 1)) {
2707  REMMINA_SSH(tunnel)->error = g_strdup(_("Could not listen to local port."));
2708  close(sock);
2709  return FALSE;
2710  }
2711 
2712  tunnel->server_sock = sock;
2713  tunnel->running = TRUE;
2714 
2715  if (pthread_create(&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) {
2716  // TRANSLATORS: Do not translate pthread
2717  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("Could not start pthread."));
2718  tunnel->thread = 0;
2719  return FALSE;
2720  }
2721  return TRUE;
2722 }
2723 
2724 gboolean
2725 remmina_ssh_tunnel_xport(RemminaSSHTunnel *tunnel, gboolean bindlocalhost)
2726 {
2727  TRACE_CALL(__func__);
2729  tunnel->bindlocalhost = bindlocalhost;
2730  tunnel->running = TRUE;
2731 
2732  if (pthread_create(&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) {
2733  // TRANSLATORS: Do not translate pthread
2734  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("Could not start pthread."));
2735  tunnel->thread = 0;
2736  return FALSE;
2737  }
2738  return TRUE;
2739 }
2740 
2741 gboolean
2742 remmina_ssh_tunnel_reverse(RemminaSSHTunnel *tunnel, gint port, gint local_port)
2743 {
2744  TRACE_CALL(__func__);
2746  tunnel->port = port;
2747  tunnel->localport = local_port;
2748  tunnel->running = TRUE;
2749 
2750  if (pthread_create(&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) {
2751  // TRANSLATORS: Do not translate pthread
2752  remmina_ssh_set_application_error(REMMINA_SSH(tunnel), _("Could not start pthread."));
2753  tunnel->thread = 0;
2754  return FALSE;
2755  }
2756  return TRUE;
2757 }
2758 
2759 gboolean
2761 {
2762  TRACE_CALL(__func__);
2763  return tunnel->thread == 0;
2764 }
2765 
2766 void
2768 {
2769  TRACE_CALL(__func__);
2770  pthread_t thread;
2771 
2772  REMMINA_DEBUG("tunnel->thread = %lX\n", tunnel->thread);
2773 
2774  thread = tunnel->thread;
2775  if (thread != 0) {
2776  tunnel->running = FALSE;
2777  pthread_cancel(thread);
2778  pthread_join(thread, NULL);
2779  tunnel->thread = 0;
2780  }
2781 
2782  if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT && tunnel->remotedisplay > 0) {
2783 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 7, 0)
2784  ssh_channel_cancel_forward(REMMINA_SSH(tunnel)->session, NULL, 6000 + tunnel->remotedisplay);
2785 #else
2786  ssh_forward_cancel(REMMINA_SSH(tunnel)->session, NULL, 6000 + tunnel->remotedisplay);
2787 #endif
2788  }
2789  if (tunnel->server_sock >= 0) {
2790  close(tunnel->server_sock);
2791  tunnel->server_sock = -1;
2792  }
2793 
2794  remmina_ssh_tunnel_close_all_channels(tunnel);
2795 
2796  g_free(tunnel->buffer);
2797  g_free(tunnel->channels_out);
2798  g_free(tunnel->dest);
2799  g_free(tunnel->localdisplay);
2800 
2801  remmina_ssh_free((RemminaSSH *)tunnel);
2802 }
2803 
2804 /*-----------------------------------------------------------------------------*
2805 * SSH SFTP *
2806 *-----------------------------------------------------------------------------*/
2807 RemminaSFTP *
2809 {
2810  TRACE_CALL(__func__);
2811  RemminaSFTP *sftp;
2812 
2813  sftp = g_new(RemminaSFTP, 1);
2814 
2815  remmina_ssh_init_from_file(REMMINA_SSH(sftp), remminafile, FALSE);
2816 
2817  sftp->sftp_sess = NULL;
2818 
2819  return sftp;
2820 }
2821 
2822 RemminaSFTP *
2824 {
2825  TRACE_CALL(__func__);
2826  RemminaSFTP *sftp;
2827 
2828  sftp = g_new(RemminaSFTP, 1);
2829 
2830  remmina_ssh_init_from_ssh(REMMINA_SSH(sftp), ssh);
2831 
2832  sftp->sftp_sess = NULL;
2833 
2834  return sftp;
2835 }
2836 
2837 gboolean
2839 {
2840  TRACE_CALL(__func__);
2841  sftp->sftp_sess = sftp_new(sftp->ssh.session);
2842  if (!sftp->sftp_sess) {
2843  // TRANSLATORS: The placeholder %s is an error message
2844  remmina_ssh_set_error(REMMINA_SSH(sftp), _("Could not create SFTP session. %s"));
2845  return FALSE;
2846  }
2847  if (sftp_init(sftp->sftp_sess)) {
2848  // TRANSLATORS: The placeholder %s is an error message
2849  remmina_ssh_set_error(REMMINA_SSH(sftp), _("Could not start SFTP session. %s"));
2850  return FALSE;
2851  }
2852  return TRUE;
2853 }
2854 
2855 void
2857 {
2858  TRACE_CALL(__func__);
2859  if (sftp->sftp_sess) {
2860  sftp_free(sftp->sftp_sess);
2861  sftp->sftp_sess = NULL;
2862  }
2863  remmina_ssh_free(REMMINA_SSH(sftp));
2864 }
2865 
2866 /*-----------------------------------------------------------------------------*
2867 * SSH Shell *
2868 *-----------------------------------------------------------------------------*/
2871 {
2872  TRACE_CALL(__func__);
2873  RemminaSSHShell *shell;
2874 
2875  shell = g_new0(RemminaSSHShell, 1);
2876 
2877  remmina_ssh_init_from_file(REMMINA_SSH(shell), remminafile, FALSE);
2878 
2879  shell->master = -1;
2880  shell->slave = -1;
2881  shell->exec = g_strdup(remmina_file_get_string(remminafile, "exec"));
2882  shell->run_line = g_strdup(remmina_file_get_string(remminafile, "run_line"));
2883 
2884  return shell;
2885 }
2886 
2889 {
2890  TRACE_CALL(__func__);
2891  RemminaSSHShell *shell;
2892 
2893  shell = g_new0(RemminaSSHShell, 1);
2894 
2895  remmina_ssh_init_from_ssh(REMMINA_SSH(shell), ssh);
2896 
2897  shell->master = -1;
2898  shell->slave = -1;
2899 
2900  return shell;
2901 }
2902 
2903 static gboolean
2904 remmina_ssh_call_exit_callback_on_main_thread(gpointer data)
2905 {
2906  TRACE_CALL(__func__);
2907 
2908  RemminaSSHShell *shell = (RemminaSSHShell *)data;
2909  if (shell->exit_callback)
2910  shell->exit_callback(shell->user_data);
2911  if (shell) {
2912  remmina_ssh_shell_free(shell);
2913  shell = NULL;
2914  }
2915  return FALSE;
2916 }
2917 
2918 static gpointer
2919 remmina_ssh_shell_thread(gpointer data)
2920 {
2921  TRACE_CALL(__func__);
2922  RemminaSSHShell *shell = (RemminaSSHShell *)data;
2924  RemminaFile *remminafile;
2925  remminafile = remmina_protocol_widget_get_file(gp);
2926  ssh_channel channel = NULL;
2927  gint ret;
2928  gchar *filename;
2929  const gchar *dir;
2930  const gchar *sshlogname;
2931  FILE *fp = NULL;
2932 
2933  //gint screen;
2934 
2935  LOCK_SSH(shell)
2936 
2937  if ((channel = ssh_channel_new(REMMINA_SSH(shell)->session)) == NULL ||
2938  ssh_channel_open_session(channel)) {
2939  UNLOCK_SSH(shell)
2940  // TRANSLATORS: The placeholder %s is an error message
2941  remmina_ssh_set_error(REMMINA_SSH(shell), _("Could not open channel. %s"));
2942  if (channel) ssh_channel_free(channel);
2943  shell->thread = 0;
2944  return NULL;
2945  }
2946 
2947  ssh_channel_request_pty(channel);
2948 
2949  // SSH Callbacks
2950  struct ssh_callbacks_struct cb =
2951  {
2952  .channel_open_request_x11_function = remmina_ssh_x11_open_request_cb,
2953  .userdata = shell,
2954  };
2955 
2956  if (remmina_file_get_int(remminafile, "ssh_forward_x11", FALSE)) {
2957  ssh_callbacks_init(&cb);
2958  ssh_set_callbacks(REMMINA_SSH(shell)->session, &cb);
2959 
2960  const char *display = getenv("DISPLAY");
2961  char *proto = NULL, *cookie = NULL;
2962  if (remmina_ssh_x11_get_proto(display, &proto, &cookie) != 0) {
2963  REMMINA_DEBUG("Using fake authentication data for X11 forwarding");
2964  proto = NULL;
2965  cookie = NULL;
2966  }
2967 
2968  REMMINA_DEBUG("proto: %s - cookie: %s", proto, cookie);
2969  ret = ssh_channel_request_x11(channel, 0, proto, cookie, 0);
2970  if (ret != SSH_OK) return NULL;
2971  }
2972 
2973  if (shell->exec && shell->exec[0]) {
2974  REMMINA_DEBUG ("Requesting an SSH exec channel");
2975  ret = ssh_channel_request_exec(channel, shell->exec);
2976  } else {
2977  REMMINA_DEBUG ("Requesting an SSH shell channel");
2978  ret = ssh_channel_request_shell(channel);
2979  }
2980  if (ret != SSH_OK) {
2981  UNLOCK_SSH(shell)
2982  REMMINA_WARNING ("Could not request shell");
2983  // TRANSLATORS: The placeholder %s is an error message
2984  remmina_ssh_set_error(REMMINA_SSH(shell), _("Could not request shell. %s"));
2985  ssh_channel_close(channel);
2986  ssh_channel_send_eof(channel);
2987  ssh_channel_free(channel);
2988  shell->thread = 0;
2989  return NULL;
2990  }
2991 
2992  shell->channel = channel;
2993 
2994  UNLOCK_SSH(shell)
2995 
2996  GFile *rf = g_file_new_for_path(remminafile->filename);
2997 
2998  if (remmina_file_get_string(remminafile, "sshlogfolder") == NULL)
2999  dir = g_build_path("/", g_get_user_cache_dir(), "remmina", NULL);
3000  else
3001  dir = remmina_file_get_string(remminafile, "sshlogfolder");
3002 
3003  if (remmina_file_get_string(remminafile, "sshlogname") == NULL)
3004  sshlogname = g_strconcat(g_file_get_basename(rf), ".", "log", NULL);
3005  else
3006  sshlogname = remmina_file_get_string(remminafile, "sshlogname");
3007  sshlogname = remmina_file_format_properties(remminafile, sshlogname);
3008  filename = g_strconcat(dir, "/", sshlogname, NULL);
3009 
3010  if (remmina_file_get_int (remminafile, "sshsavesession", FALSE)) {
3011  REMMINA_DEBUG("Saving session log to %s", filename);
3012  fp = fopen(filename, "w");
3013  }
3014 
3015  g_free(filename);
3016 
3017  REMMINA_DEBUG("Run_line: %s", shell->run_line);
3018  if (!shell->closed && shell->run_line && shell->run_line[0]) {
3019  LOCK_SSH(shell)
3020  //TODO: Confirm assumption - assuming null terminated gchar string
3021  ssh_channel_write(channel, shell->run_line, (gint)strlen(shell->run_line));
3022  ssh_channel_write(channel, "\n", (gint)1); //TODO: Test this
3023  UNLOCK_SSH(shell)
3024  REMMINA_DEBUG("Run_line written to channel");
3025  }
3026 
3027  LOCK_SSH(shell)
3028 
3029  // Create new event context.
3030  shell->event = ssh_event_new();
3031  if (shell->event == NULL) {
3032  REMMINA_WARNING("Internal error in %s: Couldn't get a event.", __func__);
3033  return NULL;
3034  }
3035 
3036  REMMINA_DEBUG("shell->slave: %d", shell->slave);
3037 
3038  // Add the fd to the event and assign it the callback.
3039  if (ssh_event_add_fd(shell->event, shell->slave, events, remmina_ssh_cp_to_ch_cb, channel) != SSH_OK) {
3040  REMMINA_WARNING("Internal error in %s: Couldn't add an fd to the event.", __func__);
3041  return NULL;
3042  }
3043 
3044  // Remove the poll handle from session and assign them to the event.
3045  if (ssh_event_add_session(shell->event, REMMINA_SSH(shell)->session) != SSH_OK) {
3046  REMMINA_WARNING("Internal error in %s: Couldn't add the session to the event.", __func__);
3047  return NULL;
3048  }
3049 
3050  remmina_ssh_insert_item(shell->channel, shell->slave, shell->slave, TRUE, shell->thread);
3051 
3052  // Initializes the ssh_callbacks_struct.
3053  channel_cb.userdata = &shell;
3054  ssh_callbacks_init(&channel_cb);
3055  // Set the channel callback functions.
3056  ssh_set_channel_callbacks(shell->channel, &channel_cb);
3057  UNLOCK_SSH(shell)
3058 
3059  do {
3060  ssh_event_dopoll(shell->event, 1000);
3061  } while(!ssh_channel_is_closed(shell->channel));
3062 
3063  // Close all OPENED X11 channel
3065 
3066  shell->closed = TRUE;
3067 
3068  LOCK_SSH(shell)
3069 
3070  // Remove socket fd from event context.
3071  ret = ssh_event_remove_fd(shell->event, shell->slave);
3072  REMMINA_DEBUG("Remove socket fd from event context: %d", ret);
3073 
3074  // Remove session object from event context.
3075  ret = ssh_event_remove_session(shell->event, REMMINA_SSH(shell)->session);
3076  REMMINA_DEBUG("Remove session object from event context: %d", ret);
3077 
3078  // Free event context.
3079  ssh_event_free(shell->event);
3080  REMMINA_DEBUG("Free event context");
3081 
3082  // Remove channel callback.
3083  ret = ssh_remove_channel_callbacks(shell->channel, &channel_cb);
3084  REMMINA_DEBUG("Remove channel callback: %d", ret);
3085 
3086  if (remmina_file_get_int (remminafile, "sshsavesession", FALSE))
3087  fclose(fp);
3088  shell->channel = NULL;
3089  ssh_channel_close(channel);
3090  ssh_channel_send_eof(channel);
3091  ssh_channel_free(channel);
3092  UNLOCK_SSH(shell)
3093 
3094  shell->thread = 0;
3095 
3096  if (shell->exit_callback)
3097  IDLE_ADD((GSourceFunc)remmina_ssh_call_exit_callback_on_main_thread, (gpointer)shell);
3098  return NULL;
3099 }
3100 
3101 gboolean
3102 remmina_ssh_shell_open(RemminaSSHShell *shell, RemminaSSHExitFunc exit_callback, gpointer data)
3103 {
3104  TRACE_CALL(__func__);
3105  gchar *slavedevice;
3106  struct termios stermios;
3107 
3108  shell->master = posix_openpt(O_RDWR | O_NOCTTY);
3109  if (shell->master == -1 ||
3110  grantpt(shell->master) == -1 ||
3111  unlockpt(shell->master) == -1 ||
3112  (slavedevice = ptsname(shell->master)) == NULL ||
3113  (shell->slave = open(slavedevice, O_RDWR | O_NOCTTY)) < 0) {
3114  REMMINA_SSH(shell)->error = g_strdup(_("Could not create PTY device."));
3115  return FALSE;
3116  }
3117 
3118  /* As per libssh documentation */
3119  tcgetattr(shell->slave, &stermios);
3120  stermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
3121  stermios.c_oflag &= ~OPOST;
3122  stermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
3123  stermios.c_cflag &= ~(CSIZE | PARENB);
3124  stermios.c_cflag |= CS8;
3125  tcsetattr(shell->slave, TCSANOW, &stermios);
3126 
3127  shell->exit_callback = exit_callback;
3128  shell->user_data = data;
3129 
3130  /* Once the process started, we should always TRUE and assume the pthread will be created always */
3131  pthread_create(&shell->thread, NULL, remmina_ssh_shell_thread, shell);
3132 
3133  return TRUE;
3134 }
3135 
3136 void
3137 remmina_ssh_shell_set_size(RemminaSSHShell *shell, gint columns, gint rows)
3138 {
3139  TRACE_CALL(__func__);
3140  LOCK_SSH(shell)
3141  if (shell->channel)
3142  ssh_channel_change_pty_size(shell->channel, columns, rows);
3143  UNLOCK_SSH(shell)
3144 }
3145 
3146 void
3148 {
3149  TRACE_CALL(__func__);
3150  //pthread_t thread = shell->thread;
3151 
3152  // Close all OPENED X11 channel
3154 
3155  shell->exit_callback = NULL;
3156  shell->closed = TRUE;
3157  REMMINA_DEBUG("Cancelling the shell thread if needed");
3158  if (shell->thread) {
3159  pthread_cancel(shell->thread);
3160  if (shell->thread) pthread_join(shell->thread, NULL);
3161  }
3162  close(shell->slave);
3163  if (shell->exec) {
3164  g_free(shell->exec);
3165  shell->exec = NULL;
3166  }
3167  if (shell->run_line) {
3168  g_free(shell->run_line);
3169  shell->run_line = NULL;
3170  }
3171  /* It’s not necessary to close shell->slave since the other end (vte) will close it */;
3172  remmina_ssh_free(REMMINA_SSH(shell));
3173 }
3174 
3175 #endif /* HAVE_LIBSSH */
struct _RemminaSSHTunnelBuffer RemminaSSHTunnelBuffer
Definition: remmina_ssh.h:137
-- cgit v1.2.3