diff options
author | Giovanni Panozzo <giovanni@panozzo.it> | 2020-03-24 23:24:52 +0300 |
---|---|---|
committer | Giovanni Panozzo <giovanni@panozzo.it> | 2020-03-24 23:24:52 +0300 |
commit | f5eac78f19997d13349c6ee29b2091a48ae1f570 (patch) | |
tree | c79e7dc0ee5638b023d46ab31e7c8dd032bbc1a1 | |
parent | c2c60226d502c6cddcab2f9273be214f0d3de6f2 (diff) |
SFTP with tunnel fixes
-rw-r--r-- | data/reports/postats.html | 8 | ||||
-rw-r--r-- | src/remmina_protocol_widget.c | 184 | ||||
-rw-r--r-- | src/remmina_sftp_client.c | 43 | ||||
-rw-r--r-- | src/remmina_sftp_client.h | 4 | ||||
-rw-r--r-- | src/remmina_sftp_plugin.c | 74 | ||||
-rw-r--r-- | src/remmina_sftp_plugin.h | 1 | ||||
-rw-r--r-- | src/remmina_ssh.c | 73 | ||||
-rw-r--r-- | src/remmina_ssh.h | 11 | ||||
-rw-r--r-- | src/remmina_ssh_plugin.c | 46 |
9 files changed, 292 insertions, 152 deletions
diff --git a/data/reports/postats.html b/data/reports/postats.html index 7e86f6d74..afb2de5a1 100644 --- a/data/reports/postats.html +++ b/data/reports/postats.html @@ -35,11 +35,11 @@ <script type="text/javascript"> new Chartkick.BarChart( "multiple-bar-stacked", [ - { name: "Translated", data: [["ar.po",100],["ast.po",163],["bg.po",97],["bn.po",12],["bs.po",163],["ca.po",317],["ca@valencia.po",90],["cs.po",647],["da.po",647],["de.po",645],["el.po",187],["en_AU.po",169],["en_GB.po",171],["es.po",644],["es_VE.po",302],["et.po",102],["eu.po",165],["fi.po",578],["fr.po",647],["gl.po",172],["he.po",647],["hi.po",0],["hr.po",518],["hu.po",326],["id.po",52],["ie.po",289],["it.po",645],["ja.po",256],["kk.po",52],["km.po",56],["kn.po",11],["ko.po",179],["lt.po",163],["lv.po",163],["mr.po",18],["ms.po",165],["my.po",12],["nb.po",469],["nl.po",229],["oc.po",163],["pl.po",211],["pt.po",188],["pt_BR.po",647],["pt_PT.po",204],["ro.po",170],["ru.po",647],["shn.po",0],["si.po",37],["sk.po",79],["sl.po",165],["sq.po",85],["sr.po",114],["sv.po",318],["te.po",14],["th.po",88],["tr.po",647],["ug.po",162],["uk.po",569],["uz@cyrillic.po",254],["zh_CN.po",610],["zh_TW.po",491]] }, - { name: "Fuzzy", data: [["ar.po",4],["ast.po",104],["bg.po",81],["bn.po",6],["bs.po",104],["ca.po",101],["ca@valencia.po",81],["cs.po",1],["da.po",0],["de.po",1],["el.po",104],["en_AU.po",105],["en_GB.po",105],["es.po",2],["es_VE.po",172],["et.po",45],["eu.po",105],["fi.po",61],["fr.po",1],["gl.po",104],["he.po",1],["hi.po",0],["hr.po",109],["hu.po",196],["id.po",12],["ie.po",92],["it.po",1],["ja.po",91],["kk.po",70],["km.po",24],["kn.po",1],["ko.po",105],["lt.po",104],["lv.po",104],["mr.po",0],["ms.po",104],["my.po",6],["nb.po",177],["nl.po",141],["oc.po",104],["pl.po",105],["pt.po",104],["pt_BR.po",1],["pt_PT.po",114],["ro.po",104],["ru.po",1],["shn.po",0],["si.po",11],["sk.po",81],["sl.po",104],["sq.po",36],["sr.po",78],["sv.po",328],["te.po",1],["th.po",80],["tr.po",1],["ug.po",105],["uk.po",79],["uz@cyrillic.po",122],["zh_CN.po",29],["zh_TW.po",134]] }, - { name: "Untranslated", data: [["ar.po",544],["ast.po",381],["bg.po",470],["bn.po",630],["bs.po",381],["ca.po",230],["ca@valencia.po",477],["cs.po",0],["da.po",1],["de.po",2],["el.po",357],["en_AU.po",374],["en_GB.po",372],["es.po",2],["es_VE.po",174],["et.po",501],["eu.po",378],["fi.po",9],["fr.po",0],["gl.po",372],["he.po",0],["hi.po",648],["hr.po",21],["hu.po",126],["id.po",584],["ie.po",267],["it.po",2],["ja.po",301],["kk.po",526],["km.po",568],["kn.po",636],["ko.po",364],["lt.po",381],["lv.po",381],["mr.po",630],["ms.po",379],["my.po",630],["nb.po",2],["nl.po",278],["oc.po",381],["pl.po",332],["pt.po",356],["pt_BR.po",0],["pt_PT.po",330],["ro.po",374],["ru.po",0],["shn.po",648],["si.po",600],["sk.po",488],["sl.po",379],["sq.po",527],["sr.po",456],["sv.po",2],["te.po",633],["th.po",480],["tr.po",0],["ug.po",381],["uk.po",0],["uz@cyrillic.po",272],["zh_CN.po",9],["zh_TW.po",23]] } + { name: "Translated", data: [["ar.po",100],["ast.po",163],["bg.po",98],["bn.po",12],["bs.po",163],["ca.po",317],["ca@valencia.po",90],["cs.po",649],["da.po",648],["de.po",646],["el.po",187],["en_AU.po",169],["en_GB.po",171],["es.po",643],["es_VE.po",301],["et.po",102],["eu.po",165],["fi.po",649],["fr.po",647],["gl.po",172],["he.po",649],["hi.po",0],["hr.po",518],["hu.po",326],["id.po",52],["ie.po",289],["it.po",644],["ja.po",256],["kk.po",52],["km.po",56],["kn.po",11],["ko.po",179],["lt.po",163],["lv.po",163],["mr.po",18],["ms.po",165],["my.po",12],["nb.po",470],["nl.po",229],["oc.po",163],["pl.po",211],["pt.po",188],["pt_BR.po",649],["pt_PT.po",204],["ro.po",170],["ru.po",647],["shn.po",0],["si.po",37],["sk.po",79],["sl.po",165],["sq.po",85],["sr.po",114],["sv.po",317],["te.po",14],["th.po",88],["tr.po",646],["ug.po",161],["uk.po",649],["uz@cyrillic.po",254],["zh_CN.po",610],["zh_TW.po",491]] }, + { name: "Fuzzy", data: [["ar.po",4],["ast.po",104],["bg.po",80],["bn.po",6],["bs.po",104],["ca.po",101],["ca@valencia.po",81],["cs.po",0],["da.po",0],["de.po",3],["el.po",104],["en_AU.po",105],["en_GB.po",105],["es.po",4],["es_VE.po",173],["et.po",45],["eu.po",105],["fi.po",0],["fr.po",2],["gl.po",104],["he.po",0],["hi.po",0],["hr.po",110],["hu.po",197],["id.po",12],["ie.po",92],["it.po",3],["ja.po",91],["kk.po",70],["km.po",24],["kn.po",1],["ko.po",105],["lt.po",104],["lv.po",104],["mr.po",0],["ms.po",104],["my.po",6],["nb.po",178],["nl.po",142],["oc.po",104],["pl.po",105],["pt.po",104],["pt_BR.po",0],["pt_PT.po",114],["ro.po",104],["ru.po",2],["shn.po",0],["si.po",11],["sk.po",81],["sl.po",104],["sq.po",36],["sr.po",78],["sv.po",330],["te.po",1],["th.po",80],["tr.po",3],["ug.po",106],["uk.po",0],["uz@cyrillic.po",122],["zh_CN.po",30],["zh_TW.po",135]] }, + { name: "Untranslated", data: [["ar.po",545],["ast.po",382],["bg.po",471],["bn.po",631],["bs.po",382],["ca.po",231],["ca@valencia.po",478],["cs.po",0],["da.po",1],["de.po",0],["el.po",358],["en_AU.po",375],["en_GB.po",373],["es.po",2],["es_VE.po",175],["et.po",502],["eu.po",379],["fi.po",0],["fr.po",0],["gl.po",373],["he.po",0],["hi.po",649],["hr.po",21],["hu.po",126],["id.po",585],["ie.po",268],["it.po",2],["ja.po",302],["kk.po",527],["km.po",569],["kn.po",637],["ko.po",365],["lt.po",382],["lv.po",382],["mr.po",631],["ms.po",380],["my.po",631],["nb.po",1],["nl.po",278],["oc.po",382],["pl.po",333],["pt.po",357],["pt_BR.po",0],["pt_PT.po",331],["ro.po",375],["ru.po",0],["shn.po",649],["si.po",601],["sk.po",489],["sl.po",380],["sq.po",528],["sr.po",457],["sv.po",2],["te.po",634],["th.po",481],["tr.po",0],["ug.po",382],["uk.po",0],["uz@cyrillic.po",273],["zh_CN.po",9],["zh_TW.po",23]] } ], - { max: 648, stacked: true } + { max: 649, stacked: true } ); </script> <!--#include virtual="howto-i18n.html" --> diff --git a/src/remmina_protocol_widget.c b/src/remmina_protocol_widget.c index 1ebedf7d2..2bbc11a50 100644 --- a/src/remmina_protocol_widget.c +++ b/src/remmina_protocol_widget.c @@ -70,7 +70,9 @@ struct _RemminaProtocolWidgetPriv { gboolean has_error; gchar * error_message; - RemminaSSHTunnel * ssh_tunnel; + /* ssh_tunnels is an array of RemminaSSHTunnel* + * the 1st one is the "main" tunnel, other tunnels are used for example in sftp commands */ + GPtrArray * ssh_tunnels; RemminaTunnelInitFunc init_func; GtkWidget * chat_window; @@ -143,6 +145,25 @@ static void remmina_protocol_widget_class_init(RemminaProtocolWidgetClass *klass g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } + +static void remmina_protocol_widget_close_all_tunnels(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + int i; + + if (gp->priv->ssh_tunnels) { + for(i = 0;i < gp->priv->ssh_tunnels->len; i++) { +#ifdef HAVE_LIBSSH + remmina_ssh_tunnel_free((RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[i]); +#else + g_debug ("LibSSH support turned off, no need to free SSH tunnel data"); +#endif + } + } + g_ptr_array_set_size(gp->priv->ssh_tunnels, 0); +} + + static void remmina_protocol_widget_destroy(RemminaProtocolWidget *gp, gpointer data) { TRACE_CALL(__func__); @@ -179,9 +200,13 @@ static void remmina_protocol_widget_destroy(RemminaProtocolWidget *gp, gpointer g_free(gp->priv); gp->priv = NULL; -} + remmina_protocol_widget_close_all_tunnels(gp); + g_ptr_array_free(gp->priv->ssh_tunnels, TRUE); + + gp->priv->ssh_tunnels = NULL; +} void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp) { @@ -204,6 +229,7 @@ static void remmina_protocol_widget_init(RemminaProtocolWidget *gp) priv = g_new0(RemminaProtocolWidgetPriv, 1); gp->priv = priv; gp->priv->closed = TRUE; + gp->priv->ssh_tunnels = g_ptr_array_new(); g_signal_connect(G_OBJECT(gp), "destroy", G_CALLBACK(remmina_protocol_widget_destroy), NULL); } @@ -299,15 +325,12 @@ void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp) static gboolean conn_closed(gpointer data) { - /* Close ssh tunnel */ TRACE_CALL(__func__); RemminaProtocolWidget *gp = (RemminaProtocolWidget *)data; #ifdef HAVE_LIBSSH - if (gp->priv->ssh_tunnel) { - remmina_ssh_tunnel_free(gp->priv->ssh_tunnel); - gp->priv->ssh_tunnel = NULL; - } + /* This will close all tunnels */ + remmina_protocol_widget_close_all_tunnels(gp); #endif /* Exec postcommand */ remmina_ext_exec_new(gp->priv->remmina_file, "postcommand"); @@ -329,11 +352,14 @@ static gboolean conn_opened(gpointer data) { TRACE_CALL(__func__); RemminaProtocolWidget *gp = (RemminaProtocolWidget *)data; + guint i; #ifdef HAVE_LIBSSH - if (gp->priv->ssh_tunnel) - remmina_ssh_tunnel_cancel_accept(gp->priv->ssh_tunnel); - + if (gp->priv->ssh_tunnels) { + for(i = 0;i < gp->priv->ssh_tunnels->len; i++) { + remmina_ssh_tunnel_cancel_accept((RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[i]); + } + } #endif if (gp->priv->listen_message_panel) { rco_destroy_message_panel(gp->cnnobj, gp->priv->listen_message_panel); @@ -604,17 +630,19 @@ void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, cons switch (feature->id) { #ifdef HAVE_LIBSSH case REMMINA_PROTOCOL_FEATURE_TOOL_SSH: - if (gp->priv->ssh_tunnel) { + if (gp->priv->ssh_tunnels && gp->priv->ssh_tunnels->len > 0) { rcw_open_from_file_full( - remmina_file_dup_temp_protocol(gp->priv->remmina_file, "SSH"), NULL, gp->priv->ssh_tunnel, NULL); + remmina_file_dup_temp_protocol(gp->priv->remmina_file, "SSH"), NULL, + (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0], NULL); return; } break; case REMMINA_PROTOCOL_FEATURE_TOOL_SFTP: - if (gp->priv->ssh_tunnel) { + if (gp->priv->ssh_tunnels && gp->priv->ssh_tunnels->len > 0) { rcw_open_from_file_full( - remmina_file_dup_temp_protocol(gp->priv->remmina_file, "SFTP"), NULL, gp->priv->ssh_tunnel, NULL); + remmina_file_dup_temp_protocol(gp->priv->remmina_file, "SFTP"), NULL, + gp->priv->ssh_tunnels->pdata[0], NULL); return; } break; @@ -701,7 +729,8 @@ static void cancel_init_tunnel_cb(void *cbdata, int btn) { printf("Remmina: Cancelling an opening tunnel is not implemented\n"); } -static gboolean remmina_protocol_widget_init_tunnel(RemminaProtocolWidget *gp) + +static RemminaSSHTunnel* remmina_protocol_widget_init_tunnel(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); RemminaSSHTunnel *tunnel; @@ -709,38 +738,33 @@ static gboolean remmina_protocol_widget_init_tunnel(RemminaProtocolWidget *gp) gchar *msg; RemminaMessagePanel *mp; - /* Reuse existing SSH connection if it’s reconnecting to destination */ - if (gp->priv->ssh_tunnel == NULL) { - tunnel = remmina_ssh_tunnel_new_from_file(gp->priv->remmina_file); + tunnel = remmina_ssh_tunnel_new_from_file(gp->priv->remmina_file); - g_debug ("Connecting to \"%s\" via SSH…", REMMINA_SSH(tunnel)->server); - msg = g_strdup_printf(_("Connecting to \"%s\" via SSH…"), REMMINA_SSH(tunnel)->server); + g_debug ("[RPW] %s creating SSH tunnel to \"%s\" via SSH…", __func__, REMMINA_SSH(tunnel)->server); + msg = g_strdup_printf(_("Connecting to \"%s\" via SSH…"), REMMINA_SSH(tunnel)->server); - mp = remmina_protocol_widget_mpprogress(gp->cnnobj, msg, cancel_init_tunnel_cb, NULL); - g_free(msg); - - if (!remmina_ssh_init_session(REMMINA_SSH(tunnel), TRUE)) { - g_debug ("[SSH] %s Cannot init SSH session with tunnel struct", __func__); - remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error); - remmina_ssh_tunnel_free(tunnel); - return FALSE; - } - - ret = remmina_ssh_auth_gui(REMMINA_SSH(tunnel), gp, gp->priv->remmina_file); - g_debug ("[SSH] tunnel auth returned %d", ret); - if (ret != REMMINA_SSH_AUTH_SUCCESS) { - if (ret != REMMINA_SSH_AUTH_USERCANCEL) - remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error); - remmina_ssh_tunnel_free(tunnel); - return FALSE; - } + mp = remmina_protocol_widget_mpprogress(gp->cnnobj, msg, cancel_init_tunnel_cb, NULL); + g_free(msg); - remmina_protocol_widget_mpdestroy(gp->cnnobj, mp); + if (!remmina_ssh_init_session(REMMINA_SSH(tunnel))) { + g_debug ("[SSH] %s Cannot init SSH session with tunnel struct", __func__); + remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error); + remmina_ssh_tunnel_free(tunnel); + return NULL; + } - gp->priv->ssh_tunnel = tunnel; + ret = remmina_ssh_auth_gui(REMMINA_SSH(tunnel), gp, gp->priv->remmina_file); + g_debug ("[SSH] tunnel auth returned %d", ret); + if (ret != REMMINA_SSH_AUTH_SUCCESS) { + if (ret != REMMINA_SSH_AUTH_USERCANCEL) + remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error); + remmina_ssh_tunnel_free(tunnel); + return NULL; } - return TRUE; + remmina_protocol_widget_mpdestroy(gp->cnnobj, mp); + + return tunnel; } #endif @@ -752,6 +776,21 @@ static void cancel_start_direct_tunnel_cb(void *cbdata, int btn) } #endif +static gboolean remmina_protocol_widget_tunnel_destroy(RemminaSSHTunnel *tunnel, gpointer data) +{ + TRACE_CALL(__func__); + RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data); + guint idx; + + if (g_ptr_array_find(gp->priv->ssh_tunnels, tunnel, &idx)) { +#ifdef HAVE_LIBSSH + g_debug("[RPW] tunnel with idx %u has been disconnected", idx); + remmina_ssh_tunnel_free(tunnel); +#endif + g_ptr_array_remove(gp->priv->ssh_tunnels, tunnel); + } + return TRUE; +} /** * Start an SSH tunnel if possible and return the host:port string. @@ -786,6 +825,7 @@ gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gi #ifdef HAVE_LIBSSH gchar *msg; RemminaMessagePanel *mp; + RemminaSSHTunnel *tunnel; if (!remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE)) { dest = g_strdup_printf("[%s]:%i", srv_host, srv_port); @@ -794,13 +834,8 @@ gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gi return dest; } - /* If we have a previous SSH tunnel, destroy it */ - if (gp->priv->ssh_tunnel) { - remmina_ssh_tunnel_free(gp->priv->ssh_tunnel); - gp->priv->ssh_tunnel = NULL; - } - - if (!remmina_protocol_widget_init_tunnel(gp)) { + tunnel = remmina_protocol_widget_init_tunnel(gp); + if (!tunnel) { g_free(srv_host); g_free(ssh_tunnel_host); g_debug ("[SSH] %s remmina_protocol_widget_init_tunnel failed with error is %s\n", @@ -820,10 +855,11 @@ gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gi } g_debug ("%s: starting tunnel to: %s, port: %d", __func__, ssh_tunnel_host, ssh_tunnel_port); - if (!remmina_ssh_tunnel_open(gp->priv->ssh_tunnel, srv_host, srv_port, remmina_pref.sshtunnel_port)) { + if (!remmina_ssh_tunnel_open(tunnel, srv_host, srv_port, remmina_pref.sshtunnel_port)) { g_free(srv_host); g_free(ssh_tunnel_host); - remmina_protocol_widget_set_error(gp, REMMINA_SSH(gp->priv->ssh_tunnel)->error); + remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error); + remmina_ssh_tunnel_free(tunnel); return NULL; } g_free(srv_host); @@ -831,6 +867,11 @@ gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gi remmina_protocol_widget_mpdestroy(gp->cnnobj, mp); + tunnel->destroy_func = remmina_protocol_widget_tunnel_destroy; + tunnel->destroy_func_callback_data = (gpointer)gp; + + g_ptr_array_add(gp->priv->ssh_tunnels, tunnel); + return g_strdup_printf("127.0.0.1:%i", remmina_pref.sshtunnel_port); #else @@ -857,22 +898,25 @@ gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, #ifdef HAVE_LIBSSH gchar *msg; RemminaMessagePanel *mp; + RemminaSSHTunnel *tunnel; if (!remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE)) return TRUE; - if (!remmina_protocol_widget_init_tunnel(gp)) + if (!(tunnel = remmina_protocol_widget_init_tunnel(gp))) return FALSE; msg = g_strdup_printf(_("Awaiting incoming SSH connection at port %i…"), remmina_file_get_int(gp->priv->remmina_file, "listenport", 0)); mp = remmina_protocol_widget_mpprogress(gp->cnnobj, msg, cancel_start_reverse_tunnel_cb, NULL); g_free(msg); - if (!remmina_ssh_tunnel_reverse(gp->priv->ssh_tunnel, remmina_file_get_int(gp->priv->remmina_file, "listenport", 0), local_port)) { - remmina_protocol_widget_set_error(gp, REMMINA_SSH(gp->priv->ssh_tunnel)->error); + if (!remmina_ssh_tunnel_reverse(tunnel, remmina_file_get_int(gp->priv->remmina_file, "listenport", 0), local_port)) { + remmina_ssh_tunnel_free(tunnel); + remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error); return FALSE; } remmina_protocol_widget_mpdestroy(gp->cnnobj, mp); + g_ptr_array_add(gp->priv->ssh_tunnels, tunnel); #endif return TRUE; @@ -882,13 +926,18 @@ gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wa { TRACE_CALL(__func__); #ifdef HAVE_LIBSSH - RemminaSSHTunnel *tunnel = gp->priv->ssh_tunnel; + RemminaSSHTunnel *tunnel; ssh_channel channel; gint status; gboolean ret = FALSE; gchar *cmd, *ptr; va_list args; + if (gp->priv->ssh_tunnels->len < 1) + return FALSE; + + tunnel = (RemminaSSHTunnel*)gp->priv->ssh_tunnels->pdata[0]; + if ((channel = ssh_channel_new(REMMINA_SSH(tunnel)->session)) == NULL) return FALSE; @@ -985,30 +1034,33 @@ gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, R gchar *server; gchar *msg; RemminaMessagePanel *mp; + RemminaSSHTunnel* tunnel; - if (!remmina_protocol_widget_init_tunnel(gp)) return FALSE; + if (!(tunnel = remmina_protocol_widget_init_tunnel(gp))) return FALSE; msg = g_strdup_printf(_("Connecting to %s via SSH…"), remmina_file_get_string(gp->priv->remmina_file, "server")); mp = remmina_protocol_widget_mpprogress(gp->cnnobj, msg, cancel_connect_xport_cb, NULL); g_free(msg); gp->priv->init_func = init_func; - gp->priv->ssh_tunnel->init_func = remmina_protocol_widget_xport_tunnel_init_callback; - gp->priv->ssh_tunnel->connect_func = remmina_protocol_widget_xport_tunnel_connect_callback; - gp->priv->ssh_tunnel->disconnect_func = remmina_protocol_widget_xport_tunnel_disconnect_callback; - gp->priv->ssh_tunnel->callback_data = gp; + tunnel->init_func = remmina_protocol_widget_xport_tunnel_init_callback; + tunnel->connect_func = remmina_protocol_widget_xport_tunnel_connect_callback; + tunnel->disconnect_func = remmina_protocol_widget_xport_tunnel_disconnect_callback; + tunnel->callback_data = gp; remmina_public_get_server_port(remmina_file_get_string(gp->priv->remmina_file, "server"), 0, &server, NULL); - bindlocalhost = (g_strcmp0(REMMINA_SSH(gp->priv->ssh_tunnel)->server, server) == 0); + bindlocalhost = (g_strcmp0(REMMINA_SSH(tunnel)->server, server) == 0); g_free(server); - if (!remmina_ssh_tunnel_xport(gp->priv->ssh_tunnel, bindlocalhost)) { + if (!remmina_ssh_tunnel_xport(tunnel, bindlocalhost)) { remmina_protocol_widget_set_error(gp, "Could not open channel, %s", - ssh_get_error(REMMINA_SSH(gp->priv->ssh_tunnel)->session)); + ssh_get_error(REMMINA_SSH(tunnel)->session)); + remmina_ssh_tunnel_free(tunnel); return FALSE; } remmina_protocol_widget_mpdestroy(gp->cnnobj, mp); + g_ptr_array_add(gp->priv->ssh_tunnels, tunnel); return TRUE; @@ -1021,8 +1073,12 @@ void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display { TRACE_CALL(__func__); #ifdef HAVE_LIBSSH - if (gp->priv->ssh_tunnel->localdisplay) g_free(gp->priv->ssh_tunnel->localdisplay); - gp->priv->ssh_tunnel->localdisplay = g_strdup_printf("unix:%i", display); + RemminaSSHTunnel* tunnel; + if (gp->priv->ssh_tunnels->len < 1) + return; + tunnel = (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0]; + if (tunnel->localdisplay) g_free(tunnel->localdisplay); + tunnel->localdisplay = g_strdup_printf("unix:%i", display); #endif } diff --git a/src/remmina_sftp_client.c b/src/remmina_sftp_client.c index b4bc49887..1d4677d7e 100644 --- a/src/remmina_sftp_client.c +++ b/src/remmina_sftp_client.c @@ -50,6 +50,7 @@ #include "remmina_pref.h" #include "remmina_ssh.h" #include "remmina_sftp_client.h" +#include "remmina_sftp_plugin.h" #include "remmina_masterthread_exec.h" #include "remmina/remmina_trace_calls.h" @@ -503,15 +504,41 @@ remmina_sftp_client_thread_main(gpointer data) gchar *refreshdir = NULL; gchar *tmp; gboolean refresh = FALSE; + gchar *host; + int port; task = remmina_sftp_client_thread_get_task(client); while (task) { size = 0; if (!sftp) { sftp = remmina_sftp_new_from_ssh(REMMINA_SSH(client->sftp)); - if (!remmina_ssh_init_session(REMMINA_SSH(sftp), FALSE) || - remmina_ssh_auth(REMMINA_SSH(sftp), NULL, NULL, NULL) <= 0 || - !remmina_sftp_open(sftp)) { + + /* we may need to open a new tunnel too */ + host = NULL; + port = 0; + if (!remmina_plugin_sftp_start_direct_tunnel(client->gp, &host, &port)) + return NULL; + (REMMINA_SSH(sftp))->tunnel_entrance_host = host; + (REMMINA_SSH(sftp))->tunnel_entrance_port = port; + + /* Open a new connection for this subcommand */ + g_debug("[SFTPCLI] %s opening ssh session to %s:%d", __func__, host, port); + if (!remmina_ssh_init_session(REMMINA_SSH(sftp))) { + g_debug("[SFTPCLI] remmina_ssh_init_session returned error %s\n", (REMMINA_SSH(sftp))->error); + remmina_sftp_client_thread_set_error(client, task, (REMMINA_SSH(sftp))->error); + remmina_ftp_task_free(task); + break; + } + + if (remmina_ssh_auth(REMMINA_SSH(sftp), REMMINA_SSH(sftp)->password, client->gp, NULL) != REMMINA_SSH_AUTH_SUCCESS) { + g_debug("[SFTPCLI] remmina_ssh_auth returned error %s\n", (REMMINA_SSH(sftp))->error); + remmina_sftp_client_thread_set_error(client, task, (REMMINA_SSH(sftp))->error); + remmina_ftp_task_free(task); + break; + } + + if (!remmina_sftp_open(sftp)) { + g_debug("[SFTPCLI] remmina_sftp_open returned error %s\n", (REMMINA_SSH(sftp))->error); remmina_sftp_client_thread_set_error(client, task, (REMMINA_SSH(sftp))->error); remmina_ftp_task_free(task); break; @@ -946,11 +973,11 @@ remmina_sftp_client_confirm_resume(RemminaSFTPClient *client, const gchar *path) return response; } -GtkWidget * +RemminaSFTPClient * remmina_sftp_client_new(void) { TRACE_CALL(__func__); - return GTK_WIDGET(g_object_new(REMMINA_TYPE_SFTP_CLIENT, NULL)); + return REMMINA_SFTP_CLIENT(g_object_new(REMMINA_TYPE_SFTP_CLIENT, NULL)); } void @@ -962,6 +989,7 @@ remmina_sftp_client_open(RemminaSFTPClient *client, RemminaSFTP *sftp) g_idle_add((GSourceFunc)remmina_sftp_client_refresh, client); } +/* GtkWidget * remmina_sftp_client_new_init(RemminaSFTP *sftp) { @@ -977,8 +1005,8 @@ remmina_sftp_client_new_init(RemminaSFTP *sftp) SET_CURSOR(gdk_cursor_new_for_display(display, GDK_WATCH)); gdk_display_flush(display); - if (!remmina_ssh_init_session(REMMINA_SSH(sftp), FALSE) || - remmina_ssh_auth(REMMINA_SSH(sftp), NULL, NULL, NULL) <= 0 || + if (!remmina_ssh_init_session(REMMINA_SSH(sftp)) || + remmina_ssh_auth(REMMINA_SSH(sftp), NULL, NULL, NULL) != REMMINA_SSH_AUTH_SUCCESS || !remmina_sftp_open(sftp)) { dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(client)), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, @@ -994,5 +1022,6 @@ remmina_sftp_client_new_init(RemminaSFTP *sftp) g_idle_add((GSourceFunc)remmina_sftp_client_refresh, client); return client; } +*/ #endif diff --git a/src/remmina_sftp_client.h b/src/remmina_sftp_client.h index 362c692e3..4805311e9 100644 --- a/src/remmina_sftp_client.h +++ b/src/remmina_sftp_client.h @@ -61,6 +61,8 @@ typedef struct _RemminaSFTPClient { pthread_t thread; gint taskid; gboolean thread_abort; + RemminaProtocolWidget *gp; + } RemminaSFTPClient; typedef struct _RemminaSFTPClientClass { @@ -69,7 +71,7 @@ typedef struct _RemminaSFTPClientClass { GType remmina_sftp_client_get_type(void) G_GNUC_CONST; -GtkWidget *remmina_sftp_client_new(void); +RemminaSFTPClient *remmina_sftp_client_new(); void remmina_sftp_client_open(RemminaSFTPClient *client, RemminaSFTP *sftp); gint remmina_sftp_client_confirm_resume(RemminaSFTPClient *client, const gchar *path); diff --git a/src/remmina_sftp_plugin.c b/src/remmina_sftp_plugin.c index a6600823e..b247acbeb 100644 --- a/src/remmina_sftp_plugin.c +++ b/src/remmina_sftp_plugin.c @@ -56,13 +56,28 @@ #define GET_PLUGIN_DATA(gp) (RemminaPluginSftpData *)g_object_get_data(G_OBJECT(gp), "plugin-data"); typedef struct _RemminaPluginSftpData { - GtkWidget * client; + RemminaSFTPClient * client; pthread_t thread; RemminaSFTP * sftp; } RemminaPluginSftpData; static RemminaPluginService *remmina_plugin_service = NULL; +gboolean remmina_plugin_sftp_start_direct_tunnel(RemminaProtocolWidget *gp, char **phost, int *pport) +{ + gchar *hostport; + + hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 22, FALSE); + if (hostport == NULL) { + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); + return FALSE; + } + + remmina_plugin_service->get_server_port(hostport, 22, phost, pport); + + return TRUE; +} + static gpointer remmina_plugin_sftp_main_thread(gpointer data) { @@ -75,62 +90,52 @@ remmina_plugin_sftp_main_thread(gpointer data) gboolean cont = FALSE; gint ret; const gchar *cs; - gchar *hostport; - gchar *tunnel_host; - int tunnel_port; + gchar *host; + int port; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); CANCEL_ASYNC - gpdata = GET_PLUGIN_DATA(gp); - - /* remmina_plugin_service->protocol_plugin_start_direct_tunnel start the - * SSH Tunnel and return the server + port string - * Therefore we set the SSH Tunnel username here, before the tunnel - * is established and than set it back to the destination SSH user. - * - * */ + gpdata = GET_PLUGIN_DATA(gp); remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); - // Optionally start the SSH tunnel - hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 22, FALSE); - if (hostport == NULL) { - remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); + /* we may need to open a new tunnel too */ + host = NULL; + port = 0; + if (!remmina_plugin_sftp_start_direct_tunnel(gp, &host, &port)) return NULL; - } - - remmina_plugin_service->get_server_port(hostport, 22, &tunnel_host, &tunnel_port); - g_free(hostport); - ssh = g_object_get_data(G_OBJECT(gp), "user-data"); if (ssh) { /* Create SFTP connection based on existing SSH session */ sftp = remmina_sftp_new_from_ssh(ssh); - if (remmina_ssh_init_session(REMMINA_SSH(sftp), FALSE) && - remmina_ssh_auth(REMMINA_SSH(sftp), NULL, gp, remminafile) > 0 && + ssh->tunnel_entrance_host = host; + ssh->tunnel_entrance_port = port; + if (remmina_ssh_init_session(REMMINA_SSH(sftp)) && + remmina_ssh_auth(REMMINA_SSH(sftp), NULL, gp, remminafile) == REMMINA_SSH_AUTH_SUCCESS && remmina_sftp_open(sftp)) cont = TRUE; } else { /* New SFTP connection */ sftp = remmina_sftp_new_from_file(remminafile); - sftp->ssh.tunnel_host = tunnel_host; - sftp->ssh.tunnel_port = tunnel_port; + ssh = REMMINA_SSH(sftp); + ssh->tunnel_entrance_host = host; + ssh->tunnel_entrance_port = port; while (1) { - if (!remmina_ssh_init_session(REMMINA_SSH(sftp), FALSE)) { - remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(sftp)->error); + if (!remmina_ssh_init_session(ssh)) { + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", ssh->error); break; } - ret = remmina_ssh_auth_gui(REMMINA_SSH(sftp), gp, remminafile); + ret = remmina_ssh_auth_gui(ssh, gp, remminafile); if (ret != REMMINA_SSH_AUTH_SUCCESS) { if (ret != REMMINA_SSH_AUTH_USERCANCEL) - remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(sftp)->error); + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", ssh->error); break; } if (!remmina_sftp_open(sftp)) { - remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(sftp)->error); + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", ssh->error); break; } @@ -142,6 +147,7 @@ remmina_plugin_sftp_main_thread(gpointer data) break; } } + if (!cont) { if (sftp) remmina_sftp_free(sftp); remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); @@ -181,8 +187,9 @@ remmina_plugin_sftp_init(RemminaProtocolWidget *gp) remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); gpdata->client = remmina_sftp_client_new(); - gtk_widget_show(gpdata->client); - gtk_container_add(GTK_CONTAINER(gp), gpdata->client); + gpdata->client->gp = gp; + gtk_widget_show(GTK_WIDGET(gpdata->client)); + gtk_container_add(GTK_CONTAINER(gp), GTK_WIDGET(gpdata->client)); remmina_ftp_client_set_show_hidden(REMMINA_FTP_CLIENT(gpdata->client), remmina_plugin_service->file_get_int(remminafile, "showhidden", FALSE)); @@ -191,7 +198,7 @@ remmina_plugin_sftp_init(RemminaProtocolWidget *gp) remmina_plugin_service->file_get_int(remminafile, REMMINA_PLUGIN_SFTP_FEATURE_PREF_OVERWRITE_ALL_KEY, FALSE)); - remmina_plugin_service->protocol_plugin_register_hostkey(gp, gpdata->client); + remmina_plugin_service->protocol_plugin_register_hostkey(gp, GTK_WIDGET(gpdata->client)); g_signal_connect(G_OBJECT(gpdata->client), "realize", G_CALLBACK(remmina_plugin_sftp_client_on_realize), gp); @@ -318,6 +325,7 @@ static const RemminaProtocolSetting remmina_sftp_basic_settings[] = { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "ssh_auth", N_("Authentication type"), FALSE, ssh_auth, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_FILE, "ssh_privatekey", N_("Identity file"), FALSE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "ssh_passphrase", N_("Password to unlock private key"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "ssh_proxycommand", N_("SSH Proxy Command"), FALSE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL } }; diff --git a/src/remmina_sftp_plugin.h b/src/remmina_sftp_plugin.h index 250cddae3..bd4fe5715 100644 --- a/src/remmina_sftp_plugin.h +++ b/src/remmina_sftp_plugin.h @@ -39,5 +39,6 @@ G_BEGIN_DECLS void remmina_sftp_plugin_register(void); +gboolean remmina_plugin_sftp_start_direct_tunnel(RemminaProtocolWidget *gp, char **phost, int *pport); G_END_DECLS diff --git a/src/remmina_ssh.c b/src/remmina_ssh.c index 7960303c8..c4da45ff7 100644 --- a/src/remmina_ssh.c +++ b/src/remmina_ssh.c @@ -359,8 +359,8 @@ remmina_ssh_auth(RemminaSSH *ssh, const gchar *password, RemminaProtocolWidget * } if (password) { - g_free(ssh->password); - g_free(ssh->passphrase); + if (password != ssh->password) g_free(ssh->password); + if (password != ssh->passphrase) g_free(ssh->passphrase); ssh->password = g_strdup(password); ssh->passphrase = g_strdup(password); } @@ -685,7 +685,7 @@ remmina_ssh_log_callback(ssh_session session, int priority, const char *message, } gboolean -remmina_ssh_init_session(RemminaSSH *ssh, gboolean is_tunnel) +remmina_ssh_init_session(RemminaSSH *ssh) { TRACE_CALL(__func__); gint verbosity; @@ -698,16 +698,31 @@ remmina_ssh_init_session(RemminaSSH *ssh, gboolean is_tunnel) ssh->callback = g_new0(struct ssh_callbacks_struct, 1); /* Init & startup the SSH session */ - g_debug("[SSH] %s server=%s port=%d is_tunnel=%s tunnel_host=%s tunnel_port=%d\n", __func__, - ssh->server, ssh->port, ssh->is_tunnel ? "Yes" : "No", ssh->tunnel_host, ssh->tunnel_port); + g_debug("[SSH] %s server=%s port=%d is_tunnel=%s tunnel_entrance_host=%s tunnel_entrance_port=%d\n", __func__, + ssh->server, ssh->port, ssh->is_tunnel ? "Yes" : "No", ssh->tunnel_entrance_host, ssh->tunnel_entrance_port); + ssh->session = ssh_new(); - if (is_tunnel) { + /* Tunnel sanity checks */ + if (ssh->is_tunnel && ssh->tunnel_entrance_host != NULL) { + ssh->error = g_strdup_printf("Internal error in %s: is_tunnel and tunnel_entrance != NULL", __func__); + g_debug("[SSH] %s", ssh->error); + return FALSE; + } + if (!ssh->is_tunnel && ssh->tunnel_entrance_host == NULL) { + ssh->error = g_strdup_printf("Internal error in %s: is_tunnel == false and tunnel_entrance == NULL", __func__); + g_debug("[SSH] %s", ssh->error); + return FALSE; + } + + /* Set connection host/port */ + if (ssh->is_tunnel) { ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->server); ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->port); } else { - ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->tunnel_host); - ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->tunnel_port); + ssh_options_set(ssh->session, SSH_OPTIONS_HOST, ssh->tunnel_entrance_host); + ssh_options_set(ssh->session, SSH_OPTIONS_PORT, &ssh->tunnel_entrance_port); + g_debug("[SSH] setting SSH_OPTIONS_HOST to %s and SSH_OPTIONS_PORT to %d", ssh->tunnel_entrance_host, ssh->tunnel_entrance_port); } if (*ssh->user != 0) @@ -842,10 +857,11 @@ remmina_ssh_init_from_file(RemminaSSH *ssh, RemminaFile *remminafile, gboolean i ssh->error = NULL; ssh->passphrase = NULL; ssh->is_tunnel = is_tunnel; - ssh->tunnel_host = NULL; - ssh->tunnel_port = 0; pthread_mutex_init(&ssh->ssh_mutex, NULL); + ssh->tunnel_entrance_host = NULL; + ssh->tunnel_entrance_port = 0; + username = remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_username" : "username"); privatekey = remmina_file_get_string(remminafile, is_tunnel ? "ssh_tunnel_privatekey" : "ssh_privatekey"); @@ -916,14 +932,17 @@ remmina_ssh_init_from_ssh(RemminaSSH *ssh, const RemminaSSH *ssh_src) ssh->user = g_strdup(ssh_src->user); ssh->auth = ssh_src->auth; ssh->password = g_strdup(ssh_src->password); + ssh->passphrase = g_strdup(ssh_src->passphrase); ssh->privkeyfile = g_strdup(ssh_src->privkeyfile); ssh->charset = g_strdup(ssh_src->charset); ssh->proxycommand = g_strdup(ssh_src->proxycommand); ssh->kex_algorithms = g_strdup(ssh_src->kex_algorithms); ssh->ciphers = g_strdup(ssh_src->ciphers); ssh->hostkeytypes = g_strdup(ssh_src->hostkeytypes); + ssh->stricthostkeycheck = ssh_src->stricthostkeycheck; ssh->compression = ssh_src->compression; - ssh->tunnel_host = NULL; + ssh->tunnel_entrance_host = g_strdup(ssh_src->tunnel_entrance_host); + ssh->tunnel_entrance_port = ssh_src->tunnel_entrance_port; return TRUE; } @@ -968,7 +987,6 @@ remmina_ssh_free(RemminaSSH *ssh) g_free(ssh->privkeyfile); g_free(ssh->charset); g_free(ssh->error); - g_free(ssh->tunnel_host); pthread_mutex_destroy(&ssh->ssh_mutex); g_free(ssh); } @@ -1070,6 +1088,8 @@ remmina_ssh_tunnel_close_all_channels(RemminaSSHTunnel *tunnel) ssh_channel_free(tunnel->x11_channel); tunnel->x11_channel = NULL; } + + } static void @@ -1517,9 +1537,27 @@ remmina_ssh_tunnel_main_thread_proc(gpointer data) remmina_ssh_tunnel_close_all_channels(tunnel); + tunnel->running = FALSE; + + /* Notify tunnel owner of disconnection */ + if (tunnel->disconnect_func) + (*tunnel->disconnect_func)(tunnel, tunnel->callback_data); + return NULL; } +static gboolean remmina_ssh_notify_tunnel_main_thread_end(gpointer data) +{ + TRACE_CALL(__func__); + RemminaSSHTunnel *tunnel = (RemminaSSHTunnel *)data; + + /* Ask tunnel owner to destroy tunnel object */ + if (tunnel->destroy_func) + (*tunnel->destroy_func)(tunnel, tunnel->destroy_func_callback_data); + + return FALSE; +} + static gpointer remmina_ssh_tunnel_main_thread(gpointer data) { @@ -1533,9 +1571,14 @@ remmina_ssh_tunnel_main_thread(gpointer data) if (tunnel->server_sock < 0 || tunnel->thread == 0 || !tunnel->running) break; } tunnel->thread = 0; + + /* Do after tunnel thread cleanup */ + IDLE_ADD((GSourceFunc)remmina_ssh_notify_tunnel_main_thread_end, (gpointer)tunnel); + return NULL; } + void remmina_ssh_tunnel_cancel_accept(RemminaSSHTunnel *tunnel) { @@ -1663,6 +1706,8 @@ remmina_ssh_tunnel_free(RemminaSSHTunnel *tunnel) TRACE_CALL(__func__); pthread_t thread; + g_debug("[SSH] %s tunnel->thread = %lX\n", __func__, tunnel->thread); + thread = tunnel->thread; if (thread != 0) { tunnel->running = FALSE; @@ -1682,6 +1727,7 @@ remmina_ssh_tunnel_free(RemminaSSHTunnel *tunnel) close(tunnel->server_sock); tunnel->server_sock = -1; } + remmina_ssh_tunnel_close_all_channels(tunnel); g_free(tunnel->buffer); @@ -1689,7 +1735,8 @@ remmina_ssh_tunnel_free(RemminaSSHTunnel *tunnel) g_free(tunnel->dest); g_free(tunnel->localdisplay); - remmina_ssh_free(REMMINA_SSH(tunnel)); + remmina_ssh_free((RemminaSSH *)tunnel); + } /*-----------------------------------------------------------------------------* diff --git a/src/remmina_ssh.h b/src/remmina_ssh.h index 463d347b8..024cef411 100644 --- a/src/remmina_ssh.h +++ b/src/remmina_ssh.h @@ -83,8 +83,9 @@ typedef struct _RemminaSSH { gchar * passphrase; gboolean is_tunnel; - gchar * tunnel_host; - gint tunnel_port; + gchar * tunnel_entrance_host; + gint tunnel_entrance_port; + } RemminaSSH; gchar *remmina_ssh_identity_path(const gchar *id); @@ -96,7 +97,7 @@ gchar *remmina_ssh_find_identity(void); gboolean remmina_ssh_init_from_file(RemminaSSH *ssh, RemminaFile *remminafile, gboolean is_tunnel); /* Initialize the SSH session */ -gboolean remmina_ssh_init_session(RemminaSSH *ssh, gboolean is_tunnel); +gboolean remmina_ssh_init_session(RemminaSSH *ssh); /* Authenticate SSH session */ @@ -172,6 +173,10 @@ struct _RemminaSSHTunnel { RemminaSSHTunnelCallback connect_func; RemminaSSHTunnelCallback disconnect_func; gpointer callback_data; + + RemminaSSHTunnelCallback destroy_func; + gpointer destroy_func_callback_data; + }; /* Create a new SSH Tunnel session and connects to the SSH server */ diff --git a/src/remmina_ssh_plugin.c b/src/remmina_ssh_plugin.c index 26c378e33..a1bb5598c 100644 --- a/src/remmina_ssh_plugin.c +++ b/src/remmina_ssh_plugin.c @@ -227,68 +227,57 @@ remmina_plugin_ssh_main_thread(gpointer data) RemminaSSHShell *shell = NULL; gboolean cont = FALSE; gchar *hostport; - gchar *tunnel_host; - int tunnel_port; gint ret; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); CANCEL_ASYNC - gpdata = GET_PLUGIN_DATA(gp); - - /** - * remmina_plugin_service->protocol_plugin_start_direct_tunnel start the - * SSH Tunnel and return the server + port string - * - **/ + gpdata = GET_PLUGIN_DATA(gp); remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); - // Optionally start the SSH tunnel + /* we may need to open a new tunnel */ hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 22, FALSE); if (hostport == NULL) { remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); return NULL; } - remmina_plugin_service->get_server_port(hostport, 22, &tunnel_host, &tunnel_port); - g_free(hostport); - ssh = g_object_get_data(G_OBJECT(gp), "user-data"); if (ssh) { /* Create SSH shell connection based on existing SSH session */ shell = remmina_ssh_shell_new_from_ssh(ssh); - if (shell->ssh.tunnel_host) - g_free(shell->ssh.tunnel_host); - shell->ssh.tunnel_host = tunnel_host; - shell->ssh.tunnel_port = tunnel_port; - if (remmina_ssh_init_session(REMMINA_SSH(shell), FALSE) && - remmina_ssh_auth(REMMINA_SSH(shell), NULL, gp, remminafile) > 0 && + remmina_plugin_service->get_server_port(hostport, 22, &ssh->tunnel_entrance_host, &ssh->tunnel_entrance_port); + + if (remmina_ssh_init_session(REMMINA_SSH(shell)) && + remmina_ssh_auth(REMMINA_SSH(shell), NULL, gp, remminafile) == REMMINA_SSH_AUTH_SUCCESS && remmina_ssh_shell_open(shell, (RemminaSSHExitFunc) remmina_plugin_service->protocol_plugin_signal_connection_closed, gp)) cont = TRUE; } else { + /* New SSH Shell connection */ shell = remmina_ssh_shell_new_from_file(remminafile); - shell->ssh.tunnel_host = tunnel_host; - shell->ssh.tunnel_port = tunnel_port; + ssh = REMMINA_SSH(shell); + remmina_plugin_service->get_server_port(hostport, 22, &ssh->tunnel_entrance_host, &ssh->tunnel_entrance_port); + while (1) { - if (!remmina_ssh_init_session(REMMINA_SSH(shell), FALSE)) { - g_debug("[SSH] init session error: %s\n", REMMINA_SSH(shell)->error); - remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(shell)->error); + if (!remmina_ssh_init_session(ssh)) { + g_debug("[SSH] init session error: %s\n", ssh->error); + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", ssh->error); break; } - ret = remmina_ssh_auth_gui(REMMINA_SSH(shell), gp, remminafile); + ret = remmina_ssh_auth_gui(ssh, gp, remminafile); if (ret != REMMINA_SSH_AUTH_SUCCESS) { if (ret != REMMINA_SSH_AUTH_USERCANCEL) - remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(shell)->error); + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", ssh->error); break; } if (!remmina_ssh_shell_open(shell, (RemminaSSHExitFunc) remmina_plugin_service->protocol_plugin_signal_connection_closed, gp)) { - remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(shell)->error); + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", ssh->error); break; } @@ -296,6 +285,9 @@ remmina_plugin_ssh_main_thread(gpointer data) break; } } + + g_free(hostport); + if (!cont) { if (shell) remmina_ssh_shell_free(shell); remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); |