diff options
author | Antenore Gatta (tmow) <antenore@simbiosi.org> | 2022-04-05 14:14:30 +0300 |
---|---|---|
committer | Antenore Gatta (tmow) <antenore@simbiosi.org> | 2022-04-05 14:14:30 +0300 |
commit | 8d2739b941f29d73d28d02a477230a5186d6d0f3 (patch) | |
tree | 70fb4203483c62a52949d2610e4ee5d5a673a4ea | |
parent | 6856bbf6bf273c4580270861b9717a756e7ce111 (diff) |
WIP: Adding SSH X11Forward support
-rw-r--r-- | src/remmina_ssh.c | 590 | ||||
-rw-r--r-- | src/remmina_ssh_plugin.c | 66 |
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; |