Commit 3420d6eb authored by llyzs's avatar llyzs Committed by llyzs

XDMCP: Now support running a startup program from SSH alternatively, without...

XDMCP: Now support running a startup program from SSH alternatively, without launching the XDMCP login window

git-svn-id: https://remmina.svn.sourceforge.net/svnroot/remmina/trunk@98 b6cfa94a-2857-405c-b0d6-536ef9fc39e1
parent 14d55a00
......@@ -29,6 +29,8 @@ typedef struct _RemminaPluginXdmcpData
GPid pid;
gint output_fd;
gint error_fd;
gint display;
gboolean ready;
#ifdef HAVE_PTHREAD
pthread_t thread;
......@@ -42,7 +44,12 @@ static RemminaPluginService *remmina_plugin_service = NULL;
static void
remmina_plugin_xdmcp_on_plug_added (GtkSocket *socket, RemminaProtocolWidget *gp)
{
RemminaPluginXdmcpData *gpdata;
gpdata = (RemminaPluginXdmcpData*) g_object_get_data (G_OBJECT (gp), "plugin-data");
remmina_plugin_service->protocol_plugin_emit_signal (gp, "connect");
gpdata->ready = TRUE;
}
static void
......@@ -52,23 +59,13 @@ remmina_plugin_xdmcp_on_plug_removed (GtkSocket *socket, RemminaProtocolWidget *
}
static gboolean
remmina_plugin_xdmcp_tunnel_init_callback (RemminaProtocolWidget *gp,
gint remotedisplay, const gchar *server, gint port)
{
return remmina_plugin_service->protocol_plugin_ssh_exec (gp,
"xqproxy -display %i -host %s -port %i -query -manage",
remotedisplay, server, port);
}
static gboolean
remmina_plugin_xdmcp_main (RemminaProtocolWidget *gp)
remmina_plugin_xdmcp_start_xephyr (RemminaProtocolWidget *gp)
{
RemminaPluginXdmcpData *gpdata;
RemminaFile *remminafile;
gchar *argv[50];
gint argc;
gchar *p1, *p2;
gint display;
gint i;
GError *error = NULL;
gboolean ret;
......@@ -76,18 +73,17 @@ remmina_plugin_xdmcp_main (RemminaProtocolWidget *gp)
gpdata = (RemminaPluginXdmcpData*) g_object_get_data (G_OBJECT (gp), "plugin-data");
remminafile = remmina_plugin_service->protocol_plugin_get_file (gp);
display = remmina_get_available_xdisplay ();
if (display == 0)
gpdata->display = remmina_get_available_xdisplay ();
if (gpdata->display == 0)
{
remmina_plugin_service->protocol_plugin_set_error (gp, "Run out of available local X display number.");
gpdata->thread = 0;
return FALSE;
}
argc = 0;
argv[argc++] = g_strdup ("Xephyr");
argv[argc++] = g_strdup_printf (":%i", display);
argv[argc++] = g_strdup_printf (":%i", gpdata->display);
argv[argc++] = g_strdup ("-parent");
argv[argc++] = g_strdup_printf ("%i", gpdata->socket_id);
......@@ -152,19 +148,66 @@ remmina_plugin_xdmcp_main (RemminaProtocolWidget *gp)
if (!ret)
{
remmina_plugin_service->protocol_plugin_set_error (gp, "%s", error->message);
gpdata->thread = 0;
return FALSE;
}
return TRUE;
}
static gboolean
remmina_plugin_xdmcp_tunnel_init_callback (RemminaProtocolWidget *gp,
gint remotedisplay, const gchar *server, gint port)
{
RemminaPluginXdmcpData *gpdata;
RemminaFile *remminafile;
gpdata = (RemminaPluginXdmcpData*) g_object_get_data (G_OBJECT (gp), "plugin-data");
remminafile = remmina_plugin_service->protocol_plugin_get_file (gp);
if (!remmina_plugin_xdmcp_start_xephyr (gp)) return FALSE;
while (!gpdata->ready) sleep (1);
remmina_plugin_service->protocol_plugin_set_display (gp, gpdata->display);
if (remminafile->exec && remminafile->exec[0])
{
return remmina_plugin_service->protocol_plugin_ssh_exec (gp, FALSE,
"DISPLAY=localhost:%i.0 %s", remotedisplay, remminafile->exec);
}
else
{
return remmina_plugin_service->protocol_plugin_ssh_exec (gp, TRUE,
"xqproxy -display %i -host %s -port %i -query -manage",
remotedisplay, server, port);
}
}
static gboolean
remmina_plugin_xdmcp_main (RemminaProtocolWidget *gp)
{
RemminaPluginXdmcpData *gpdata;
RemminaFile *remminafile;
gpdata = (RemminaPluginXdmcpData*) g_object_get_data (G_OBJECT (gp), "plugin-data");
remminafile = remmina_plugin_service->protocol_plugin_get_file (gp);
if (remminafile->ssh_enabled)
{
if (!remmina_plugin_service->protocol_plugin_start_xport_tunnel (gp, display,
if (!remmina_plugin_service->protocol_plugin_start_xport_tunnel (gp,
remmina_plugin_xdmcp_tunnel_init_callback))
{
gpdata->thread = 0;
return FALSE;
}
}
else
{
if (!remmina_plugin_xdmcp_start_xephyr (gp))
{
gpdata->thread = 0;
return FALSE;
}
}
gpdata->thread = 0;
return TRUE;
......@@ -288,6 +331,7 @@ static const RemminaProtocolSetting remmina_plugin_xdmcp_basic_settings[] =
REMMINA_PROTOCOL_SETTING_SERVER,
REMMINA_PROTOCOL_SETTING_RESOLUTION_FIXED,
REMMINA_PROTOCOL_SETTING_COLORDEPTH2,
REMMINA_PROTOCOL_SETTING_EXEC,
REMMINA_PROTOCOL_SETTING_SHOWCURSOR_LOCAL,
REMMINA_PROTOCOL_SETTING_ONCE,
REMMINA_PROTOCOL_SETTING_CTL_END
......
......@@ -66,7 +66,8 @@ typedef struct _RemminaPluginService
void (* protocol_plugin_emit_signal) (RemminaProtocolWidget *gp, const gchar *signal_name);
void (* protocol_plugin_register_hostkey) (RemminaProtocolWidget *gp, GtkWidget *widget);
gchar* (* protocol_plugin_start_direct_tunnel) (RemminaProtocolWidget *gp, gint default_port, gboolean port_plus);
gboolean (* protocol_plugin_start_xport_tunnel) (RemminaProtocolWidget *gp, gint display, RemminaXPortTunnelInitFunc init_func);
gboolean (* protocol_plugin_start_xport_tunnel) (RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func);
void (* protocol_plugin_set_display) (RemminaProtocolWidget *gp, gint display);
gboolean (* protocol_plugin_close_connection) (RemminaProtocolWidget *gp);
gint (* protocol_plugin_init_authpwd) (RemminaProtocolWidget *gp, RemminaAuthpwdType authpwd_type);
gint (* protocol_plugin_init_authuserpwd) (RemminaProtocolWidget *gp);
......@@ -80,7 +81,7 @@ typedef struct _RemminaPluginService
void (* protocol_plugin_init_save_cred) (RemminaProtocolWidget *gp);
void (* protocol_plugin_init_show_listen) (RemminaProtocolWidget *gp, gint port);
void (* protocol_plugin_init_show_retry) (RemminaProtocolWidget *gp);
gboolean (* protocol_plugin_ssh_exec) (RemminaProtocolWidget *gp, const gchar *fmt, ...);
gboolean (* protocol_plugin_ssh_exec) (RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...);
void (* protocol_plugin_chat_open) (RemminaProtocolWidget *gp, const gchar *name,
void(*on_send)(RemminaProtocolWidget *gp, const gchar *text),
void(*on_destroy)(RemminaProtocolWidget *gp));
......
......@@ -109,6 +109,7 @@ typedef enum
typedef struct _RemminaProtocolWidgetClass RemminaProtocolWidgetClass;
typedef struct _RemminaProtocolWidget RemminaProtocolWidget;
typedef gpointer RemminaTunnelInitFunc;
typedef gboolean (*RemminaXPortTunnelInitFunc) (RemminaProtocolWidget *gp,
gint remotedisplay, const gchar *server, gint port);
......
......@@ -58,6 +58,7 @@ RemminaPluginService remmina_plugin_manager_service =
remmina_protocol_widget_register_hostkey,
remmina_protocol_widget_start_direct_tunnel,
remmina_protocol_widget_start_xport_tunnel,
remmina_protocol_widget_set_display,
remmina_protocol_widget_close_connection,
remmina_protocol_widget_init_authpwd,
remmina_protocol_widget_init_authuserpwd,
......
......@@ -45,7 +45,7 @@ struct _RemminaProtocolWidgetPriv
gboolean has_error;
gchar *error_message;
RemminaSSHTunnel *ssh_tunnel;
RemminaXPortTunnelInitFunc init_func;
RemminaTunnelInitFunc init_func;
GtkWidget *chat_window;
......@@ -493,7 +493,7 @@ remmina_protocol_widget_start_direct_tunnel (RemminaProtocolWidget *gp, gint def
}
gboolean
remmina_protocol_widget_ssh_exec (RemminaProtocolWidget *gp, const gchar *fmt, ...)
remmina_protocol_widget_ssh_exec (RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...)
{
#ifdef HAVE_LIBSSH
RemminaSSHTunnel *tunnel = gp->priv->ssh_tunnel;
......@@ -515,27 +515,38 @@ remmina_protocol_widget_ssh_exec (RemminaProtocolWidget *gp, const gchar *fmt, .
if (channel_open_session (channel) == SSH_OK &&
channel_request_exec (channel, cmd) == SSH_OK)
{
channel_send_eof (channel);
status = channel_get_exit_status (channel);
ptr = strchr (cmd, ' ');
if (ptr) *ptr = '\0';
switch (status)
if (wait)
{
channel_send_eof (channel);
status = channel_get_exit_status (channel);
ptr = strchr (cmd, ' ');
if (ptr) *ptr = '\0';
switch (status)
{
case 0:
ret = TRUE;
break;
case 127:
remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
_("Command %s not found on SSH server"), cmd);
break;
default:
remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
_("Command %s failed on SSH server (status = %i)."), cmd, status);
break;
}
}
else
{
case 0:
ret = TRUE;
break;
case 127:
remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
_("Command %s not found on SSH server"), cmd);
break;
default:
remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
_("Command %s failed on SSH server (status = %i)."), cmd, status);
break;
}
}
else
{
remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to execute command: %s"));
}
g_free (cmd);
channel_close (channel);
if (wait) channel_close (channel);
channel_free (channel);
return ret;
......@@ -557,7 +568,8 @@ remmina_protocol_widget_tunnel_init_callback (RemminaSSHTunnel *tunnel, gpointer
gboolean ret;
remmina_public_get_server_port (gp->priv->remmina_file->server, 177, &server, &port);
ret = gp->priv->init_func (gp, tunnel->remotedisplay, (tunnel->bindlocalhost ? "localhost" : server), port);
ret = ((RemminaXPortTunnelInitFunc) gp->priv->init_func) (gp,
tunnel->remotedisplay, (tunnel->bindlocalhost ? "localhost" : server), port);
g_free (server);
return ret;
......@@ -584,8 +596,7 @@ remmina_protocol_widget_tunnel_disconnect_callback (RemminaSSHTunnel *tunnel, gp
#endif
gboolean
remmina_protocol_widget_start_xport_tunnel (RemminaProtocolWidget *gp, gint display,
RemminaXPortTunnelInitFunc init_func)
remmina_protocol_widget_start_xport_tunnel (RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
{
#ifdef HAVE_LIBSSH
gboolean bindlocalhost;
......@@ -603,7 +614,7 @@ remmina_protocol_widget_start_xport_tunnel (RemminaProtocolWidget *gp, gint disp
bindlocalhost = (g_strcmp0 (REMMINA_SSH (gp->priv->ssh_tunnel)->server, server) == 0);
g_free (server);
if (!remmina_ssh_tunnel_xport (gp->priv->ssh_tunnel, display, bindlocalhost))
if (!remmina_ssh_tunnel_xport (gp->priv->ssh_tunnel, bindlocalhost))
{
remmina_protocol_widget_set_error (gp, "Failed to open channel : %s",
ssh_get_error (REMMINA_SSH (gp->priv->ssh_tunnel)->session));
......@@ -617,6 +628,13 @@ remmina_protocol_widget_start_xport_tunnel (RemminaProtocolWidget *gp, gint disp
#endif
}
void
remmina_protocol_widget_set_display (RemminaProtocolWidget *gp, gint display)
{
if (gp->priv->ssh_tunnel->localdisplay) g_free (gp->priv->ssh_tunnel->localdisplay);
gp->priv->ssh_tunnel->localdisplay = g_strdup_printf ("unix:%i", display);
}
GtkWidget*
remmina_protocol_widget_get_init_dialog (RemminaProtocolWidget *gp)
{
......
......@@ -86,7 +86,7 @@ void remmina_protocol_widget_register_hostkey (RemminaProtocolWidget *gp, GtkWid
typedef gboolean (*RemminaHostkeyFunc) (RemminaProtocolWidget *gp, guint keyval, gpointer data);
void remmina_protocol_widget_set_hostkey_func (RemminaProtocolWidget *gp, RemminaHostkeyFunc func, gpointer data);
gboolean remmina_protocol_widget_ssh_exec (RemminaProtocolWidget *gp, const gchar *fmt, ...);
gboolean remmina_protocol_widget_ssh_exec (RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...);
/* Start a SSH tunnel if it's enabled. Returns a newly allocated string indicating:
* 1. The actual destination (host:port) if SSH tunnel is disable
......@@ -94,8 +94,8 @@ gboolean remmina_protocol_widget_ssh_exec (RemminaProtocolWidget *gp, const gcha
*/
gchar* remmina_protocol_widget_start_direct_tunnel (RemminaProtocolWidget *gp, gint default_port, gboolean port_plus);
gboolean remmina_protocol_widget_start_xport_tunnel (RemminaProtocolWidget *gp, gint display,
RemminaXPortTunnelInitFunc init_func);
gboolean remmina_protocol_widget_start_xport_tunnel (RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func);
void remmina_protocol_widget_set_display (RemminaProtocolWidget *gp, gint display);
gint remmina_protocol_widget_init_authpwd (RemminaProtocolWidget *gp, RemminaAuthpwdType authpwd_type);
gint remmina_protocol_widget_init_authuserpwd (RemminaProtocolWidget *gp);
......
......@@ -314,6 +314,8 @@ remmina_public_get_xauth_cookie (const gchar *display, gchar **msg)
GError *error = NULL;
gboolean ret;
if (!display) display = gdk_get_display ();
g_snprintf (buf, sizeof (buf), "xauth list %s", display);
ret = g_spawn_command_line_sync (buf, &out, NULL, NULL, &error);
if (ret)
......
......@@ -469,6 +469,7 @@ remmina_ssh_tunnel_new_from_file (RemminaFile *remminafile)
tunnel->socketbuffers = NULL;
tunnel->num_channels = 0;
tunnel->max_channels = 0;
tunnel->x11_channel = NULL;
tunnel->thread = 0;
tunnel->running = FALSE;
tunnel->server_sock = -1;
......@@ -509,6 +510,13 @@ remmina_ssh_tunnel_close_all_channels (RemminaSSHTunnel *tunnel)
tunnel->num_channels = 0;
tunnel->max_channels = 0;
if (tunnel->x11_channel)
{
channel_close (tunnel->x11_channel);
channel_free (tunnel->x11_channel);
tunnel->x11_channel = NULL;
}
}
static void
......@@ -567,7 +575,6 @@ remmina_ssh_tunnel_main_thread (gpointer data)
GTimeVal t1, t2;
glong diff;
ssh_channel channel = NULL;
ssh_channel schannel = NULL;
gboolean first = TRUE;
gboolean disconnected;
gint sock;
......@@ -614,65 +621,55 @@ remmina_ssh_tunnel_main_thread (gpointer data)
break;
case REMMINA_SSH_TUNNEL_X11:
if ((schannel = channel_new (tunnel->ssh.session)) == NULL)
if ((tunnel->x11_channel = channel_new (tunnel->ssh.session)) == NULL)
{
remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to create channel : %s");
tunnel->thread = 0;
return NULL;
}
if (!remmina_public_get_xauth_cookie (gdk_get_display (), &ptr))
if (!remmina_public_get_xauth_cookie (tunnel->localdisplay, &ptr))
{
remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "%s", ptr);
g_free (ptr);
channel_close (schannel);
channel_free (schannel);
tunnel->thread = 0;
return NULL;
}
if (channel_open_session (schannel) ||
channel_request_x11 (schannel, TRUE, NULL, ptr,
if (channel_open_session (tunnel->x11_channel) ||
channel_request_x11 (tunnel->x11_channel, TRUE, NULL, ptr,
gdk_screen_get_number (gdk_screen_get_default ())))
{
g_free (ptr);
channel_close (schannel);
channel_free (schannel);
remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to open channel : %s");
tunnel->thread = 0;
return NULL;
}
g_free (ptr);
if (channel_request_exec (schannel, tunnel->dest))
if (channel_request_exec (tunnel->x11_channel, tunnel->dest))
{
channel_close (schannel);
channel_free (schannel);
ptr = g_strdup_printf (_("Failed to execute %s on SSH server : %%s"), tunnel->dest);
remmina_ssh_set_error (REMMINA_SSH (tunnel), ptr);
g_free (ptr);
tunnel->thread = 0;
return NULL;
}
channel = channel_accept_x11 (schannel, 15000);
channel_close (schannel);
channel_free (schannel);
if (channel == NULL)
{
remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to accept X11 channel : %s");
tunnel->thread = 0;
return NULL;
}
sock = remmina_public_open_xdisplay (gdk_get_display ());
if (sock < 0)
if (tunnel->init_func &&
! (*tunnel->init_func) (tunnel, tunnel->callback_data))
{
if (tunnel->disconnect_func)
{
(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
}
tunnel->thread = 0;
return NULL;
}
remmina_ssh_tunnel_add_channel (tunnel, channel, sock);
ssh_set_blocking (REMMINA_SSH (tunnel)->session, FALSE);
break;
case REMMINA_SSH_TUNNEL_XPORT:
/* Detect the next available port starting from 6001 on the server */
for (i = 1; i <= MAX_X_DISPLAY_NUMBER; i++)
/* Detect the next available port starting from 6010 on the server */
for (i = 10; i <= MAX_X_DISPLAY_NUMBER; i++)
{
if (channel_forward_listen (REMMINA_SSH (tunnel)->session,
(tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL))
......@@ -717,13 +714,20 @@ remmina_ssh_tunnel_main_thread (gpointer data)
/* Start the tunnel data transmittion */
while (tunnel->running)
{
if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT)
if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT || tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
{
if (first)
{
first = FALSE;
/* Wait for a period of time for the first incoming connection */
channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 15000);
if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
{
channel = channel_accept_x11 (tunnel->x11_channel, 15000);
}
else
{
channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 15000);
}
if (!channel)
{
remmina_ssh_set_application_error (REMMINA_SSH (tunnel), _("No response from the server."));
......@@ -747,7 +751,14 @@ remmina_ssh_tunnel_main_thread (gpointer data)
diff = (t1.tv_sec - t2.tv_sec) * 10 + (t1.tv_usec - t2.tv_usec) / 100000;
if (diff > 1)
{
channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 0);
if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
{
channel = channel_accept_x11 (tunnel->x11_channel, 0);
}
else
{
channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 0);
}
if (channel == NULL)
{
t2 = t1;
......@@ -968,10 +979,9 @@ remmina_ssh_tunnel_x11 (RemminaSSHTunnel *tunnel, const gchar *cmd)
}
gboolean
remmina_ssh_tunnel_xport (RemminaSSHTunnel *tunnel, gint display, gboolean bindlocalhost)
remmina_ssh_tunnel_xport (RemminaSSHTunnel *tunnel, gboolean bindlocalhost)
{
tunnel->tunnel_type = REMMINA_SSH_TUNNEL_XPORT;
tunnel->localdisplay = g_strdup_printf ("unix:%i", display);
tunnel->bindlocalhost = bindlocalhost;
tunnel->running = TRUE;
......
......@@ -111,6 +111,8 @@ struct _RemminaSSHTunnel
gint num_channels;
gint max_channels;
ssh_channel x11_channel;
pthread_t thread;
gboolean running;
......@@ -147,7 +149,7 @@ gboolean remmina_ssh_tunnel_open (RemminaSSHTunnel *tunnel, const gchar *dest, g
gboolean remmina_ssh_tunnel_x11 (RemminaSSHTunnel *tunnel, const gchar *cmd);
/* start X Port Forwarding */
gboolean remmina_ssh_tunnel_xport (RemminaSSHTunnel *tunnel, gint display, gboolean bindlocalhost);
gboolean remmina_ssh_tunnel_xport (RemminaSSHTunnel *tunnel, gboolean bindlocalhost);
/* Tells if the tunnel is terminated after start */
gboolean remmina_ssh_tunnel_terminated (RemminaSSHTunnel *tunnel);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment