2
* Remmina - The GTK+ Remote Desktop Client
3
* Copyright (C) 2009 - Vic Lee
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330,
18
* Boston, MA 02111-1307, USA.
22
#include <glib/gi18n.h>
29
#include "remminapublic.h"
30
#include "remminafile.h"
31
#include "remminaplug.h"
32
#include "remminassh.h"
33
#include "remminaplug_xdmcp.h"
35
G_DEFINE_TYPE (RemminaPlugXdmcp, remmina_plug_xdmcp, REMMINA_TYPE_PLUG)
38
remmina_plug_xdmcp_plug_added (GtkSocket *socket, RemminaPlugXdmcp *gp_xdmcp)
40
remmina_plug_emit_signal (REMMINA_PLUG (gp_xdmcp), "connect");
41
gp_xdmcp->ready = TRUE;
45
remmina_plug_xdmcp_plug_removed (GtkSocket *socket, RemminaPlugXdmcp *gp_xdmcp)
47
remmina_plug_close_connection (REMMINA_PLUG (gp_xdmcp));
51
remmina_plug_xdmcp_start_xephyr (RemminaPlugXdmcp *gp_xdmcp)
53
RemminaPlug *gp = REMMINA_PLUG (gp_xdmcp);
54
RemminaFile *remminafile = gp->remmina_file;
62
gp_xdmcp->display = remmina_public_get_available_xdisplay ();
63
if (gp_xdmcp->display == 0)
65
g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", "Run out of available local X display number.");
72
argv[argc++] = g_strdup ("Xephyr");
74
argv[argc++] = g_strdup_printf (":%i", gp_xdmcp->display);
76
argv[argc++] = g_strdup ("-parent");
77
argv[argc++] = g_strdup_printf ("%i", gp_xdmcp->socket_id);
79
/* All Xephyr version between 1.5.0 and 1.6.4 will break when -screen argument is specified with -parent.
80
* It's not possible to support color depth if you have those Xephyr version. Please see this bug
81
* http://bugs.freedesktop.org/show_bug.cgi?id=24144
82
* As a workaround, a "Default" color depth will not add the -screen argument.
84
if (remminafile->colordepth >= 8)
86
argv[argc++] = g_strdup ("-screen");
87
argv[argc++] = g_strdup_printf ("%ix%ix%i",
88
remminafile->resolution_width, remminafile->resolution_height, remminafile->colordepth);
91
if (remminafile->colordepth == 2)
93
argv[argc++] = g_strdup ("-grayscale");
96
if (remminafile->showcursor)
98
argv[argc++] = g_strdup ("-host-cursor");
100
if (remminafile->once)
102
argv[argc++] = g_strdup ("-once");
105
if (!remminafile->ssh_enabled)
107
argv[argc++] = g_strdup ("-query");
108
p1 = g_strdup (remminafile->server);
110
p2 = g_strrstr (p1, ":");
114
argv[argc++] = g_strdup ("-port");
115
argv[argc++] = g_strdup (p2);
120
/* When the connection is through an SSH tunnel, it connects back to local unix socket,
121
* so for security we can disable tcp listening */
122
argv[argc++] = g_strdup ("-nolisten");
123
argv[argc++] = g_strdup ("tcp");
125
/* FIXME: It's better to get the magic cookie back from xqproxy, then call xauth,
126
* instead of disable access control */
127
argv[argc++] = g_strdup ("-ac");
132
ret = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
133
NULL, NULL, &gp_xdmcp->pid, &error);
134
for (i = 0; i < argc; i++) g_free (argv[i]);
138
g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", error->message);
139
gp->has_error = TRUE;
140
gp_xdmcp->thread = 0;
149
remmina_plug_xdmcp_tunnel_init_callback (RemminaSSHTunnel *tunnel, gpointer data)
151
RemminaPlug *gp = REMMINA_PLUG (data);
152
RemminaPlugXdmcp *gp_xdmcp = REMMINA_PLUG_XDMCP (data);
158
gboolean ret = FALSE;
160
if (!remmina_plug_xdmcp_start_xephyr (gp_xdmcp)) return FALSE;
161
while (!gp_xdmcp->ready) sleep (1);
163
remmina_plug_set_display (gp, gp_xdmcp->display);
165
if ((channel = channel_new (REMMINA_SSH (tunnel)->session)) == NULL)
170
remmina_public_get_server_port (gp->remmina_file->server, 177, &server, &port);
171
cmd = g_strdup_printf ("xqproxy -display %i -host %s -port %i -query -manage",
172
tunnel->remotedisplay, (tunnel->bindlocalhost ? "localhost" : server), port);
174
if (channel_open_session (channel) == SSH_OK &&
175
channel_request_exec (channel, cmd) == SSH_OK)
177
channel_send_eof (channel);
178
status = channel_get_exit_status (channel);
185
remmina_ssh_set_application_error (tunnel,
186
_("Please install xqproxy on SSH server in order to run XDMCP over SSH"));
189
((RemminaSSH*)tunnel)->error = g_strdup_printf ("Error executing xqproxy on SSH server (status = %i).", status);
194
channel_close (channel);
195
channel_free (channel);
200
remmina_plug_xdmcp_tunnel_connect_callback (RemminaSSHTunnel *tunnel, gpointer data)
206
remmina_plug_xdmcp_tunnel_disconnect_callback (RemminaSSHTunnel *tunnel, gpointer data)
208
RemminaPlug *gp = REMMINA_PLUG (data);
210
if (REMMINA_SSH (tunnel)->error)
212
g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", REMMINA_SSH (tunnel)->error);
213
gp->has_error = TRUE;
215
IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, gp);
221
remmina_plug_xdmcp_main (RemminaPlugXdmcp *gp_xdmcp)
223
RemminaPlug *gp = REMMINA_PLUG (gp_xdmcp);
224
RemminaFile *remminafile = gp->remmina_file;
227
if (remminafile->ssh_enabled)
229
if (!remmina_plug_start_xport_tunnel (gp,
230
remmina_plug_xdmcp_tunnel_init_callback,
231
remmina_plug_xdmcp_tunnel_connect_callback,
232
remmina_plug_xdmcp_tunnel_disconnect_callback,
235
gp_xdmcp->thread = 0;
242
if (!remmina_plug_xdmcp_start_xephyr (gp_xdmcp))
244
gp_xdmcp->thread = 0;
249
gp_xdmcp->thread = 0;
255
remmina_plug_xdmcp_main_thread (gpointer data)
257
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
260
if (!remmina_plug_xdmcp_main (REMMINA_PLUG_XDMCP (data)))
262
IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, data);
269
remmina_plug_xdmcp_open_connection (RemminaPlug *gp)
271
RemminaPlugXdmcp *gp_xdmcp = REMMINA_PLUG_XDMCP (gp);
272
RemminaFile *remminafile = gp->remmina_file;
274
gp->width = remminafile->resolution_width;
275
gp->height = remminafile->resolution_height;
276
gtk_widget_set_size_request (GTK_WIDGET (gp), remminafile->resolution_width, remminafile->resolution_height);
277
gp_xdmcp->socket_id = gtk_socket_get_id (GTK_SOCKET (gp_xdmcp->socket));
281
if (remminafile->ssh_enabled)
283
if (pthread_create (&gp_xdmcp->thread, NULL, remmina_plug_xdmcp_main_thread, gp))
285
g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s",
286
"Failed to initialize pthread. Falling back to non-thread mode...");
287
gp->has_error = TRUE;
288
gp_xdmcp->thread = 0;
298
return remmina_plug_xdmcp_main (gp_xdmcp);
303
return remmina_plug_xdmcp_main (gp_xdmcp);
309
remmina_plug_xdmcp_close_connection (RemminaPlug *gp)
311
RemminaPlugXdmcp *gp_xdmcp = REMMINA_PLUG_XDMCP (gp);
314
if (gp_xdmcp->thread)
316
pthread_cancel (gp_xdmcp->thread);
317
if (gp_xdmcp->thread) pthread_join (gp_xdmcp->thread, NULL);
323
kill (gp_xdmcp->pid, SIGTERM);
324
g_spawn_close_pid (gp_xdmcp->pid);
328
remmina_plug_emit_signal (gp, "disconnect");
334
remmina_plug_xdmcp_query_feature (RemminaPlug *gp, RemminaPlugFeature feature)
340
remmina_plug_xdmcp_call_feature (RemminaPlug *gp, RemminaPlugFeature feature, const gpointer data)
345
remmina_plug_xdmcp_class_init (RemminaPlugXdmcpClass *klass)
347
klass->parent_class.open_connection = remmina_plug_xdmcp_open_connection;
348
klass->parent_class.close_connection = remmina_plug_xdmcp_close_connection;
349
klass->parent_class.query_feature = remmina_plug_xdmcp_query_feature;
350
klass->parent_class.call_feature = remmina_plug_xdmcp_call_feature;
354
remmina_plug_xdmcp_destroy (GtkWidget *widget, gpointer data)
359
remmina_plug_xdmcp_init (RemminaPlugXdmcp *gp_xdmcp)
361
gp_xdmcp->socket = gtk_socket_new ();
362
gtk_widget_show (gp_xdmcp->socket);
363
g_signal_connect (G_OBJECT (gp_xdmcp->socket), "plug-added",
364
G_CALLBACK (remmina_plug_xdmcp_plug_added), gp_xdmcp);
365
g_signal_connect (G_OBJECT (gp_xdmcp->socket), "plug-removed",
366
G_CALLBACK (remmina_plug_xdmcp_plug_removed), gp_xdmcp);
367
gtk_container_add (GTK_CONTAINER (gp_xdmcp), gp_xdmcp->socket);
369
g_signal_connect (G_OBJECT (gp_xdmcp), "destroy", G_CALLBACK (remmina_plug_xdmcp_destroy), NULL);
371
gp_xdmcp->socket_id = 0;
373
gp_xdmcp->output_fd = 0;
374
gp_xdmcp->error_fd = 0;
375
gp_xdmcp->thread = 0;
376
gp_xdmcp->display = 0;
377
gp_xdmcp->ready = FALSE;
381
remmina_plug_xdmcp_new (void)
383
return GTK_WIDGET (g_object_new (REMMINA_TYPE_PLUG_XDMCP, NULL));