Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/Remmina/Remmina.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntenore Gatta (tmow) <antenore@simbiosi.org>2022-04-05 14:14:30 +0300
committerAntenore Gatta (tmow) <antenore@simbiosi.org>2022-04-05 14:14:30 +0300
commit8d2739b941f29d73d28d02a477230a5186d6d0f3 (patch)
tree70fb4203483c62a52949d2610e4ee5d5a673a4ea
parent6856bbf6bf273c4580270861b9717a756e7ce111 (diff)
WIP: Adding SSH X11Forward support
-rw-r--r--src/remmina_ssh.c590
-rw-r--r--src/remmina_ssh_plugin.c66
2 files changed, 610 insertions, 46 deletions
diff --git a/src/remmina_ssh.c b/src/remmina_ssh.c
index c5419df7c..767191b6f 100644
--- a/src/remmina_ssh.c
+++ b/src/remmina_ssh.c
@@ -38,6 +38,7 @@
#ifdef HAVE_LIBSSH
+#define _DEFAULT_SOURCE /* To get definitions of NI_MAXHOST and NI_MAXSERV from <netdb.h> */
/* Define this before stdlib.h to have posix_openpt */
#define _XOPEN_SOURCE 600
@@ -46,6 +47,7 @@
#include <libssh/libssh.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <poll.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
@@ -78,6 +80,9 @@
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
#include "remmina_public.h"
#include "remmina/types.h"
#include "remmina_file.h"
@@ -99,7 +104,6 @@
#endif
-
/*-----------------------------------------------------------------------------*
* SSH Base *
*-----------------------------------------------------------------------------*/
@@ -116,6 +120,529 @@ static const gchar *common_identities[] =
NULL
};
+/* X11 Forwarding */
+
+#define _PATH_UNIX_X "/tmp/.X11-unix/X%d"
+#define _XAUTH_CMD "/usr/bin/xauth list %s 2>/dev/null"
+
+typedef struct item {
+ ssh_channel channel;
+ int fd_in;
+ int fd_out;
+ struct item *next;
+} node_t;
+
+node_t *node = NULL;
+
+//pthread_mutex_t mutex;
+
+// Linked nodes to manage channel/fd tuples
+static void remmina_ssh_insert_item(RemminaSSHShell *ssh, int fd_in, int fd_out);
+static void remmina_ssh_delete_item(RemminaSSHShell *ssh);
+static node_t * remmina_ssh_search_item(RemminaSSHShell *ssh);
+
+// X11 Display
+const char * remmina_ssh_ssh_gai_strerror(int gaierr);
+static int remmina_ssh_x11_get_proto(const char *display, char **_proto, char **_data);
+static void remmina_ssh_set_nodelay(int fd);
+static int remmina_ssh_connect_local_xsocket_path(const char *pathname);
+static int remmina_ssh_connect_local_xsocket(int display_number);
+static int remmina_ssh_x11_connect_display();
+
+// Send data to channel
+static int remimna_ssh_cp_to_ch_cb(int fd, int revents, void *userdata);
+
+// Read data from channel
+static int remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata);
+
+// EOF&Close channel
+static void remmina_ssh_ch_close_cb(ssh_session session, ssh_channel channel, void *userdata);
+
+// X11 Request
+static ssh_channel remmina_ssh_x11_open_request_cb(ssh_session session, const char *shost, int sport, void *userdata);
+
+// SSH Channel Callbacks
+struct ssh_channel_callbacks_struct channel_cb =
+{
+ .channel_data_function = remmina_ssh_cp_to_fd_cb,
+ .channel_eof_function = remmina_ssh_ch_close_cb,
+ .channel_close_function = remmina_ssh_ch_close_cb,
+ .userdata = NULL
+};
+
+
+/*
+ * SSH Event Context
+*/
+
+short events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
+ssh_event event;
+
+
+/*
+ * Functions
+*/
+
+void
+remmina_ssh_log_cb(int priority, const char *function, const char *buffer, void *userdata)
+{
+ TRACE_CALL(__func__);
+ REMMINA_DEBUG("[%d] (%s) %s", priority, function, buffer);
+}
+
+static void
+remmina_ssh_insert_item(RemminaSSHShell *ssh, int fd_in, int fd_out)
+{
+ TRACE_CALL(__func__);
+ //pthread_mutex_lock(&mutex);
+ LOCK_SSH(ssh);
+
+ node_t *node_iterator, *new;
+ if (node == NULL) {
+ /* Calloc ensure that node is full of 0 */
+ node = (node_t *) calloc(1, sizeof(node_t));
+ node->channel = ssh->channel;
+ node->fd_in = fd_in;
+ node->fd_out = fd_out;
+ node->next = NULL;
+ } else {
+ node_iterator = node;
+ while (node_iterator->next != NULL)
+ node_iterator = node_iterator->next;
+ /* Create the new node */
+ new = (node_t *) malloc(sizeof(node_t));
+ new->channel = ssh->channel;
+ new->fd_in = fd_in;
+ new->fd_out = fd_out;
+ new->next = NULL;
+ node_iterator->next = new;
+
+ }
+
+ UNLOCK_SSH(ssh);
+}
+
+
+static void
+remmina_ssh_delete_item(RemminaSSHShell *ssh)
+{
+ TRACE_CALL(__func__);
+ LOCK_SSH(ssh);
+ node_t *current, *previous = NULL;
+ for (current = node; current; previous = current, current = current->next) {
+ if (current->channel != ssh->channel)
+ continue;
+
+ if (previous == NULL)
+ node = current->next;
+ else
+ previous->next = current->next;
+
+ free(current);
+ UNLOCK_SSH(ssh);
+ return;
+ }
+
+ UNLOCK_SSH(ssh);
+}
+
+
+static node_t *
+remmina_ssh_search_item(RemminaSSHShell *ssh)
+{
+ TRACE_CALL(__func__);
+ LOCK_SSH(ssh);
+
+ node_t *current = node;
+ while (current != NULL) {
+ if (current->channel == ssh->channel) {
+ UNLOCK_SSH(ssh);
+ return current;
+ } else {
+ current = current->next;
+ }
+ }
+
+ UNLOCK_SSH(ssh);
+
+ return NULL;
+}
+
+
+
+static void
+remmina_ssh_set_nodelay(int fd)
+{
+ TRACE_CALL(__func__);
+ int opt;
+ socklen_t optlen;
+
+ optlen = sizeof(opt);
+ if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "getsockopt TCP_NODELAY: %.100s", strerror(errno));
+ return;
+ }
+ if (opt == 1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "fd %d is TCP_NODELAY", fd);
+ return;
+ }
+ opt = 1;
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "fd %d setting TCP_NODELAY", fd);
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1)
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "setsockopt TCP_NODELAY: %.100s", strerror(errno));
+}
+
+
+const char *
+remmina_ssh_ssh_gai_strerror(int gaierr)
+{
+ TRACE_CALL(__func__);
+
+ if (gaierr == EAI_SYSTEM && errno != 0)
+ return strerror(errno);
+ return gai_strerror(gaierr);
+}
+
+
+
+static int
+remmina_ssh_x11_get_proto(const char *display, char **_proto, char **_cookie)
+{
+ TRACE_CALL(__func__);
+ char cmd[256], line[512], xdisplay[512];
+ static char proto[512], cookie[512];
+ FILE *f;
+ int ret = 0, r;
+
+ *_proto = proto;
+ *_cookie = cookie;
+
+ proto[0] = cookie[0] = '\0';
+
+ if (strncmp(display, "localhost:", 10) == 0) {
+ if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", display + 10)) < 0 || (size_t)r >= sizeof(xdisplay)) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "display name too long. display: %s", display);
+ return -1;
+ }
+ display = xdisplay;
+ }
+
+ snprintf(cmd, sizeof(cmd), _XAUTH_CMD, display);
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "xauth cmd: %s", cmd);
+
+ f = popen(cmd, "r");
+ if (f && fgets(line, sizeof(line), f) && sscanf(line, "%*s %511s %511s", proto, cookie) == 2) {
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+
+ if (f) pclose(f);
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "proto: %s - cookie: %s - ret: %d", proto, cookie, ret);
+
+ return ret;
+}
+
+static int
+remmina_ssh_connect_local_xsocket_path(const char *pathname)
+{
+ TRACE_CALL(__func__);
+ REMMINA_DEBUG("Entering function %s", __func__);
+ int sock;
+ struct sockaddr_un addr;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock == -1)
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "socket: %.100s", strerror(errno));
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ strncpy(addr.sun_path + 1, pathname, strlen(pathname));
+ if (connect(sock, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(pathname)) == 0)
+ return sock;
+ close(sock);
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "connect %.100s: %.100s", addr.sun_path, strerror(errno));
+ return -1;
+}
+
+
+static int
+remmina_ssh_connect_local_xsocket(int display_number)
+{
+ TRACE_CALL(__func__);
+ REMMINA_DEBUG("Entering function %s", __func__);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), _PATH_UNIX_X, display_number);
+ return remmina_ssh_connect_local_xsocket_path(buf);
+}
+
+
+static int
+remmina_ssh_x11_connect_display()
+{
+ TRACE_CALL(__func__);
+ REMMINA_DEBUG("Entering function %s", __func__);
+ unsigned int display_number;
+ const char *display;
+ char buf[1024], *cp;
+ struct addrinfo hints, *ai, *aitop;
+ char strport[NI_MAXSERV];
+ int gaierr, sock = 0;
+
+ /* Try to open a socket for the local X server. */
+ display = getenv("DISPLAY");
+ if (!display) {
+ return -1;
+ }
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "display: %s", display);
+
+ /* Check if it is a unix domain socket. */
+ if (strncmp(display, "unix:", 5) == 0 || display[0] == ':') {
+ /* Connect to the unix domain socket. */
+ if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "Could not parse display number from DISPLAY: %.100s", display);
+ return -1;
+ }
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "display_number: %d", display_number);
+
+ /* Create a socket. */
+ sock = remmina_ssh_connect_local_xsocket(display_number);
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "socket: %d", sock);
+
+ if (sock < 0)
+ return -1;
+
+ /* OK, we now have a connection to the display. */
+ return sock;
+ }
+
+ /* Connect to an inet socket. */
+ strncpy(buf, display, sizeof(buf));
+ cp = strchr(buf, ':');
+ if (!cp) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "Could not find ':' in DISPLAY: %.100s", display);
+ return -1;
+ }
+ *cp = 0;
+ if (sscanf(cp + 1, "%u", &display_number) != 1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "Could not parse display number from DISPLAY: %.100s", display);
+ return -1;
+ }
+
+ /* Look up the host address */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf(strport, sizeof(strport), "%u", 6000 + display_number);
+ if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "%.100s: unknown host. (%s)", buf, remmina_ssh_ssh_gai_strerror(gaierr));
+ return -1;
+ }
+ for (ai = aitop; ai; ai = ai->ai_next) {
+ /* Create a socket. */
+ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock == -1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "socket: %.100s", strerror(errno));
+ continue;
+ }
+ /* Connect it to the display. */
+ if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno));
+ close(sock);
+ continue;
+ }
+ /* Success */
+ break;
+ }
+ freeaddrinfo(aitop);
+ if (!ai) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno));
+ return -1;
+ }
+ remmina_ssh_set_nodelay(sock);
+ return sock;
+}
+
+
+
+static int
+remimna_ssh_cp_to_ch_cb(int fd, int revents, void *userdata)
+{
+ TRACE_CALL(__func__);
+ ssh_channel channel = (ssh_channel)userdata;
+ char buf[2097152];
+ int sz, ret = 0;
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "event: %d - fd: %d", revents, fd);
+
+ if (!channel) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "channel does not exist.");
+ close(fd);
+ return -1;
+ }
+
+ if (fcntl(fd, F_GETFD) == -1) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "fcntl error. fd: %d", fd);
+ REMMINA_DEBUG("Closing channel");
+ ssh_channel_close(channel);
+ return -1;
+ }
+
+ if ((revents & POLLIN) || (revents & POLLPRI)) {
+ sz = read(fd, buf, sizeof(buf));
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "sz: %d", sz);
+ if (sz > 0) {
+ ret = ssh_channel_write(channel, buf, sz);
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "channel_write ret: %d", ret);
+ } else if (sz < 0) {
+ REMMINA_DEBUG("Closing channel");
+ ssh_channel_close(channel);
+ return -1;
+ } else {
+ /* sz = 0. Why the hell I'm here? */
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "Why the hell I'm here?: sz: %d", sz);
+ close(fd);
+ return -1;
+ }
+ }
+
+ if ((revents & POLLHUP) || (revents & POLLNVAL) || (revents & POLLERR)) {
+ REMMINA_DEBUG("Closing channel");
+ ssh_channel_close(channel);
+ return -1;
+ }
+
+ return sz;
+}
+
+
+static int
+remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata)
+{
+ TRACE_CALL(__func__);
+ (void)session;
+ (void)is_stderr;
+ RemminaSSHShell *ssh = (RemminaSSHShell *)userdata;
+
+ node_t *temp_node = remmina_ssh_search_item(ssh);
+ int fd = temp_node->fd_out;
+ int sz;
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "len: %d - fd: %d - is_stderr: %d", len, fd, is_stderr);
+
+ sz = write(fd, data, len);
+
+ return sz;
+}
+
+
+static void
+remmina_ssh_ch_close_cb(ssh_session session, ssh_channel channel, void *userdata)
+{
+ TRACE_CALL(__func__);
+ (void)session;
+ //(void)userdata;
+ RemminaSSHShell *ssh = (RemminaSSHShell *)userdata;
+
+ node_t *temp_node = remmina_ssh_search_item(ssh);
+
+ if (temp_node != NULL) {
+ int fd = temp_node->fd_in;
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "fd: %d", fd);
+
+ remmina_ssh_delete_item(ssh);
+ ssh_event_remove_fd(event, fd);
+
+ if (fd !=0) {
+ close(fd);
+ }
+ }
+}
+
+
+static ssh_channel
+remmina_ssh_x11_open_request_cb(ssh_session session, const char *shost, int sport, void *userdata)
+{
+ TRACE_CALL(__func__);
+ REMMINA_DEBUG("Entering function %s", __func__);
+ (void)shost;
+ (void)sport;
+ //(void)userdata;
+ RemminaSSHShell *ssh = (RemminaSSHShell *)userdata;
+
+ ssh_channel channel = ssh_channel_new(session);
+
+ int sock = remmina_ssh_x11_connect_display();
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "sock: %d", sock);
+
+ remmina_ssh_insert_item(ssh, sock, sock);
+
+ ssh_event_add_fd(event, sock, events, remimna_ssh_cp_to_ch_cb, channel);
+ ssh_event_add_session(event, session);
+
+ // SSH Channel Callbacks
+ //ssh_set_channel_callbacks(channel, &channel_cb);
+ ssh_add_channel_callbacks(ssh->channel, &channel_cb);
+
+ return channel;
+}
+
+
+static int
+remmina_ssh_main_loop(RemminaSSHShell *shell)
+{
+ TRACE_CALL(__func__);
+ REMMINA_DEBUG("Entering function %s", __func__);
+ ssh_session session = ssh_channel_get_session(shell->channel);
+
+ //remmina_ssh_insert_item(ssh, fileno(stdin), fileno(stdout));
+ remmina_ssh_insert_item(shell, shell->slave, shell->slave);
+
+ ssh_callbacks_init(&channel_cb);
+ if (channel_cb.userdata == NULL)
+ channel_cb.userdata = shell;
+ ssh_set_channel_callbacks(shell->channel, &channel_cb);
+
+ event = ssh_event_new();
+ if (event == NULL) {
+ REMMINA_DEBUG("Couldn't get a event");
+ return -1;
+ }
+
+ //if (ssh_event_add_fd(event, fileno(stdin), events, remimna_ssh_cp_to_ch_cb, shell->channel) != SSH_OK) {
+ if (ssh_event_add_fd(event, shell->slave, events, remimna_ssh_cp_to_ch_cb, shell->channel) != SSH_OK) {
+ REMMINA_DEBUG("Couldn't add an fd to the event");
+ return -1;
+ }
+
+ if(ssh_event_add_session(event, session) != SSH_OK) {
+ REMMINA_DEBUG("Couldn't add the session to the event");
+ return -1;
+ }
+
+ do {
+ ssh_event_dopoll(event, 1000);
+ } while (!ssh_channel_is_closed(shell->channel));
+
+ remmina_ssh_delete_item(shell);
+ //ssh_event_remove_fd(event, fileno(stdin));
+ ssh_event_remove_fd(event, shell->slave);
+ ssh_event_remove_session(event, session);
+ ssh_event_free(event);
+
+ return 0;
+}
+
+
+
+/* end - X11 Forwarding */
+
gchar *
remmina_ssh_identity_path(const gchar *id)
{
@@ -1146,13 +1673,6 @@ remmina_ssh_auth_gui(RemminaSSH *ssh, RemminaProtocolWidget *gp, RemminaFile *re
return ret;
}
-void
-remmina_ssh_log_callback(ssh_session session, int priority, const char *message, void *userdata)
-{
- TRACE_CALL(__func__);
- REMMINA_DEBUG(message);
-}
-
gboolean
remmina_ssh_init_session(RemminaSSH *ssh)
{
@@ -1211,13 +1731,12 @@ remmina_ssh_init_session(RemminaSSH *ssh)
ssh_options_set(ssh->session, SSH_OPTIONS_SSH_DIR, g_strdup_printf("%s/.ssh", g_getenv("SNAP_USER_COMMON")));
#endif
ssh_callbacks_init(ssh->callback);
- if (remmina_log_running()) {
- verbosity = remmina_pref.ssh_loglevel;
- ssh_options_set(ssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
- ssh->callback->log_function = remmina_ssh_log_callback;
- /* Reset libssh legacy userdata. This is a workaround for a libssh bug */
- ssh_set_log_userdata(ssh->session);
- }
+ verbosity = remmina_pref.ssh_loglevel;
+ ssh_options_set(ssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ //ssh->callback->log_function = remmina_ssh_log_cb;
+ ssh_set_log_callback(remmina_ssh_log_cb);
+ /* Reset libssh legacy userdata. This is a workaround for a libssh bug */
+ ssh_set_log_userdata(ssh->session);
ssh->callback->userdata = ssh;
ssh_set_callbacks(ssh->session, ssh->callback);
@@ -1546,6 +2065,7 @@ remmina_ssh_free(RemminaSSH *ssh)
{
TRACE_CALL(__func__);
if (ssh->session) {
+ REMMINA_DEBUG("Disconnecting SSH session");
ssh_disconnect(ssh->session);
ssh_free(ssh->session);
ssh->session = NULL;
@@ -2375,7 +2895,10 @@ remmina_ssh_shell_thread(gpointer data)
//gint screen;
LOCK_SSH(shell)
-
+ int verbosity = remmina_pref.ssh_loglevel;
+ ssh_options_set(REMMINA_SSH(shell)->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ ssh_set_log_userdata(REMMINA_SSH(shell)->session);
+ ssh_set_log_callback(remmina_ssh_log_cb);
if ((channel = ssh_channel_new(REMMINA_SSH(shell)->session)) == NULL ||
ssh_channel_open_session(channel)) {
UNLOCK_SSH(shell)
@@ -2386,8 +2909,32 @@ remmina_ssh_shell_thread(gpointer data)
return NULL;
}
+ shell->channel = channel;
ssh_channel_request_pty(channel);
+ // SSH Callbacks
+ struct ssh_callbacks_struct cb =
+ {
+ .channel_open_request_x11_function = remmina_ssh_x11_open_request_cb,
+ .userdata = shell,
+ };
+
+ if (remmina_file_get_int(remminafile, "ssh_forward_x11", FALSE)) {
+ ssh_callbacks_init(&cb);
+ ssh_set_callbacks(REMMINA_SSH(shell)->session, &cb);
+
+ const char *display = getenv("DISPLAY");
+ char *proto = NULL, *cookie = NULL;
+ if (remmina_ssh_x11_get_proto(display, &proto, &cookie) != 0) {
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "Using fake authentication data for X11 forwarding");
+ proto = NULL;
+ cookie = NULL;
+ }
+
+ _ssh_log(SSH_LOG_FUNCTIONS, __func__, "proto: %s - cookie: %s", proto, cookie);
+ ret = ssh_channel_request_x11(channel, 0, proto, cookie, 0);
+ if (ret != SSH_OK) return NULL;
+ }
if (shell->exec && shell->exec[0]) {
REMMINA_DEBUG ("Requesting an SSH exec channel");
ret = ssh_channel_request_exec(channel, shell->exec);
@@ -2407,7 +2954,6 @@ remmina_ssh_shell_thread(gpointer data)
return NULL;
}
- shell->channel = channel;
UNLOCK_SSH(shell)
@@ -2447,6 +2993,7 @@ remmina_ssh_shell_thread(gpointer data)
UNLOCK_SSH(shell)
REMMINA_DEBUG("Run_line written to channel");
}
+#if 0
while (!shell->closed) {
timeout.tv_sec = 1;
timeout.tv_usec = 0;
@@ -2499,10 +3046,15 @@ remmina_ssh_shell_thread(gpointer data)
}
}
+#endif
+ ret = remmina_ssh_main_loop(shell);
+ if (ret != SSH_OK) return NULL;
+
LOCK_SSH(shell)
if (remmina_file_get_int (remminafile, "sshsavesession", FALSE))
fclose(fp);
shell->channel = NULL;
+ REMMINA_DEBUG("Closing channel");
ssh_channel_close(channel);
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
@@ -2569,19 +3121,23 @@ remmina_ssh_shell_free(RemminaSSHShell *shell)
shell->exit_callback = NULL;
if (thread) {
+ REMMINA_DEBUG("Closing shell thread");
shell->closed = TRUE;
pthread_join(thread, NULL);
}
close(shell->slave);
if (shell->exec) {
+ REMMINA_DEBUG("Closing exec thread");
g_free(shell->exec);
shell->exec = NULL;
}
if (shell->run_line) {
+ REMMINA_DEBUG("Closing run line thread");
g_free(shell->run_line);
shell->run_line = NULL;
}
/* It’s not necessary to close shell->slave since the other end (vte) will close it */;
+ REMMINA_DEBUG("Freeing SSH resources");
remmina_ssh_free(REMMINA_SSH(shell));
}
diff --git a/src/remmina_ssh_plugin.c b/src/remmina_ssh_plugin.c
index dfc67044f..25cc979f6 100644
--- a/src/remmina_ssh_plugin.c
+++ b/src/remmina_ssh_plugin.c
@@ -395,7 +395,7 @@ BREAK:
remmina_plugin_ssh_vte_terminal_set_encoding_and_pty(VTE_TERMINAL(gpdata->vte), charset, shell->master, shell->slave);
/* TODO: The following call should be moved on the main thread, or something weird could happen */
- remmina_plugin_ssh_on_size_allocate(GTK_WIDGET(gpdata->vte), NULL, gp);
+ //remmina_plugin_ssh_on_size_allocate(GTK_WIDGET(gpdata->vte), NULL, gp);
remmina_plugin_service->protocol_plugin_signal_connection_opened(gp);
@@ -871,32 +871,6 @@ void remmina_plugin_ssh_popup_ui(RemminaProtocolWidget *gp)
gtk_widget_show_all(menu);
}
-static gboolean
-remmina_plugin_ssh_close_connection(RemminaProtocolWidget *gp)
-{
- TRACE_CALL(__func__);
- RemminaPluginSshData *gpdata = GET_PLUGIN_DATA(gp);
-
- RemminaFile *remminafile;
-
- REMMINA_DEBUG("Requesting to close the connection");
- remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
-
- if (remmina_file_get_int(remminafile, "sshlogenabled", FALSE))
- remmina_plugin_ssh_vte_save_session(NULL, gp);
- if (gpdata->thread) {
- pthread_cancel(gpdata->thread);
- if (gpdata->thread) pthread_join(gpdata->thread, NULL);
- }
- if (gpdata->shell) {
- remmina_ssh_shell_free(gpdata->shell);
- gpdata->shell = NULL;
- }
-
- remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
- return FALSE;
-}
-
static void
remmina_plugin_ssh_eof(VteTerminal *vteterminal, RemminaProtocolWidget *gp)
{
@@ -923,6 +897,34 @@ remmina_plugin_ssh_eof(VteTerminal *vteterminal, RemminaProtocolWidget *gp)
gpdata->closed = TRUE;
}
+static gboolean
+remmina_plugin_ssh_close_connection(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
+ RemminaPluginSshData *gpdata = GET_PLUGIN_DATA(gp);
+
+ RemminaFile *remminafile;
+
+ REMMINA_DEBUG("Requesting to close the connection");
+ remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
+
+ if (remmina_file_get_int(remminafile, "sshlogenabled", FALSE))
+ remmina_plugin_ssh_vte_save_session(NULL, gp);
+ remmina_plugin_ssh_eof(VTE_TERMINAL(gpdata->vte), gp);
+
+ if (gpdata->thread) {
+ pthread_cancel(gpdata->thread);
+ if (gpdata->thread) pthread_join(gpdata->thread, NULL);
+ }
+ if (gpdata->shell) {
+ remmina_ssh_shell_free(gpdata->shell);
+ gpdata->shell = NULL;
+ }
+
+ remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
+ return FALSE;
+}
+
/**
* Remmina SSH plugin initialization.
*
@@ -1540,11 +1542,12 @@ static const RemminaProtocolSetting remmina_ssh_advanced_settings[] =
{ REMMINA_PROTOCOL_SETTING_TYPE_FOLDER, "sshlogfolder", N_("Folder for SSH session log"), FALSE, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "sshlogname", N_("Filename for SSH session log"), FALSE, NULL, log_tips },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sshlogenabled", N_("Log SSH session when exiting Remmina"), FALSE, NULL, NULL },
- { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sshsavesession", N_("Log SSH session asynchronously"), FALSE, NULL, N_("Saving the session asynchronously may have a notable performance impact") },
+ { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sshsavesession", N_("Log SSH session asynchronously"), TRUE, NULL, N_("Saving the session asynchronously may have a notable performance impact") },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "audiblebell", N_("Audible terminal bell"), FALSE, NULL, NULL },
+ { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "ssh_forward_x11", N_("SSH ForwardX11"), TRUE, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "ssh_compression", N_("SSH compression"), FALSE, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Don't remember passwords"), TRUE, NULL, NULL },
- { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "ssh_stricthostkeycheck", N_("Strict host key checking"), TRUE, NULL, NULL },
+ { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "ssh_stricthostkeycheck", N_("Strict host key checking"), FALSE, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
};
@@ -1690,6 +1693,7 @@ void
remmina_ssh_plugin_register(void)
{
TRACE_CALL(__func__);
+ REMMINA_DEBUG("Entering function %s", __func__);
remmina_plugin_ssh_features[0].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_copy);
remmina_plugin_ssh_features[1].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_paste);
remmina_plugin_ssh_features[2].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_select_all);
@@ -1702,7 +1706,11 @@ remmina_ssh_plugin_register(void)
RemminaProtocolSettingOpt *settings;
// preset new settings with (old) static remmina_ssh_advanced_settings data
+#if GLIB_CHECK_VERSION(2,68,0)
+ settings = g_memdup2(remmina_ssh_advanced_settings, sizeof(remmina_ssh_advanced_settings));
+#else
settings = g_memdup(remmina_ssh_advanced_settings, sizeof(remmina_ssh_advanced_settings));
+#endif
// create dynamic advanced settings to made replacing of ssh_terminal_palette possible
gpointer ssh_terminal_palette_new = NULL;