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:
authorGiovanni Panozzo <giovanni@panozzo.it>2020-03-24 23:24:52 +0300
committerGiovanni Panozzo <giovanni@panozzo.it>2020-03-24 23:24:52 +0300
commitf5eac78f19997d13349c6ee29b2091a48ae1f570 (patch)
treec79e7dc0ee5638b023d46ab31e7c8dd032bbc1a1
parentc2c60226d502c6cddcab2f9273be214f0d3de6f2 (diff)
SFTP with tunnel fixes
-rw-r--r--data/reports/postats.html8
-rw-r--r--src/remmina_protocol_widget.c184
-rw-r--r--src/remmina_sftp_client.c43
-rw-r--r--src/remmina_sftp_client.h4
-rw-r--r--src/remmina_sftp_plugin.c74
-rw-r--r--src/remmina_sftp_plugin.h1
-rw-r--r--src/remmina_ssh.c73
-rw-r--r--src/remmina_ssh.h11
-rw-r--r--src/remmina_ssh_plugin.c46
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);