~vanvugt/+junk/remmina-ppa

« back to all changes in this revision

Viewing changes to src/remminaplug_xdmcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2010-07-11 23:40:47 UTC
  • mfrom: (1.2.1 upstream) (8.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100711234047-id2bdu1gb59e34n4
* New upstream release.
* debian/control:
  - Bump Standards-Version to 3.9.0, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Remmina - The GTK+ Remote Desktop Client
3
 
 * Copyright (C) 2009 - Vic Lee 
4
 
 *
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.
9
 
 *
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.
14
 
 *
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.
19
 
 */
20
 
 
21
 
#include <gtk/gtk.h>
22
 
#include <glib/gi18n.h>
23
 
#include <unistd.h>
24
 
#include <signal.h>
25
 
#include "config.h"
26
 
#ifdef HAVE_PTHREAD
27
 
#include <pthread.h>
28
 
#endif
29
 
#include "remminapublic.h"
30
 
#include "remminafile.h"
31
 
#include "remminaplug.h"
32
 
#include "remminassh.h"
33
 
#include "remminaplug_xdmcp.h"
34
 
 
35
 
G_DEFINE_TYPE (RemminaPlugXdmcp, remmina_plug_xdmcp, REMMINA_TYPE_PLUG)
36
 
 
37
 
static void
38
 
remmina_plug_xdmcp_plug_added (GtkSocket *socket, RemminaPlugXdmcp *gp_xdmcp)
39
 
{
40
 
    remmina_plug_emit_signal (REMMINA_PLUG (gp_xdmcp), "connect");
41
 
    gp_xdmcp->ready = TRUE;
42
 
}
43
 
 
44
 
static void
45
 
remmina_plug_xdmcp_plug_removed (GtkSocket *socket, RemminaPlugXdmcp *gp_xdmcp)
46
 
{
47
 
    remmina_plug_close_connection (REMMINA_PLUG (gp_xdmcp));
48
 
}
49
 
 
50
 
static gboolean
51
 
remmina_plug_xdmcp_start_xephyr (RemminaPlugXdmcp *gp_xdmcp)
52
 
{
53
 
    RemminaPlug *gp = REMMINA_PLUG (gp_xdmcp);
54
 
    RemminaFile *remminafile = gp->remmina_file;
55
 
    gchar *argv[50];
56
 
    gint argc;
57
 
    gchar *p1, *p2;
58
 
    gint i;
59
 
    GError *error = NULL;
60
 
    gboolean ret;
61
 
 
62
 
    gp_xdmcp->display = remmina_public_get_available_xdisplay ();
63
 
    if (gp_xdmcp->display == 0)
64
 
    {
65
 
        g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", "Run out of available local X display number.");
66
 
        gp->has_error = TRUE;
67
 
        gp_xdmcp->thread = 0;
68
 
        return FALSE;
69
 
    }
70
 
 
71
 
    argc = 0;
72
 
    argv[argc++] = g_strdup ("Xephyr");
73
 
 
74
 
    argv[argc++] = g_strdup_printf (":%i", gp_xdmcp->display);
75
 
 
76
 
    argv[argc++] = g_strdup ("-parent");
77
 
    argv[argc++] = g_strdup_printf ("%i", gp_xdmcp->socket_id);
78
 
 
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.    
83
 
     */
84
 
    if (remminafile->colordepth >= 8)
85
 
    {
86
 
        argv[argc++] = g_strdup ("-screen");
87
 
        argv[argc++] = g_strdup_printf ("%ix%ix%i",
88
 
            remminafile->resolution_width, remminafile->resolution_height, remminafile->colordepth);
89
 
    }
90
 
 
91
 
    if (remminafile->colordepth == 2)
92
 
    {
93
 
        argv[argc++] = g_strdup ("-grayscale");
94
 
    }
95
 
 
96
 
    if (remminafile->showcursor)
97
 
    {
98
 
        argv[argc++] = g_strdup ("-host-cursor");
99
 
    }
100
 
    if (remminafile->once)
101
 
    {
102
 
        argv[argc++] = g_strdup ("-once");
103
 
    }
104
 
 
105
 
    if (!remminafile->ssh_enabled)
106
 
    {
107
 
        argv[argc++] = g_strdup ("-query");
108
 
        p1 = g_strdup (remminafile->server);
109
 
        argv[argc++] = p1;
110
 
        p2 = g_strrstr (p1, ":");
111
 
        if (p2)
112
 
        {
113
 
            *p2++ = '\0';
114
 
            argv[argc++] = g_strdup ("-port");
115
 
            argv[argc++] = g_strdup (p2);
116
 
        }
117
 
    }
118
 
    else
119
 
    {
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");
124
 
 
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");
128
 
    }
129
 
 
130
 
    argv[argc++] = NULL;
131
 
 
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]);
135
 
 
136
 
    if (!ret)
137
 
    {
138
 
        g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", error->message);
139
 
        gp->has_error = TRUE;
140
 
        gp_xdmcp->thread = 0;
141
 
        return FALSE;
142
 
    }
143
 
 
144
 
    return TRUE;
145
 
}
146
 
 
147
 
#ifdef HAVE_LIBSSH
148
 
static gboolean
149
 
remmina_plug_xdmcp_tunnel_init_callback (RemminaSSHTunnel *tunnel, gpointer data)
150
 
{
151
 
    RemminaPlug *gp = REMMINA_PLUG (data);
152
 
    RemminaPlugXdmcp *gp_xdmcp = REMMINA_PLUG_XDMCP (data);
153
 
    ssh_channel channel;
154
 
    gchar *server;
155
 
    gint port;
156
 
    gchar *cmd;
157
 
    gint status;
158
 
    gboolean ret = FALSE;
159
 
 
160
 
    if (!remmina_plug_xdmcp_start_xephyr (gp_xdmcp)) return FALSE;
161
 
    while (!gp_xdmcp->ready) sleep (1);
162
 
 
163
 
    remmina_plug_set_display (gp, gp_xdmcp->display);
164
 
 
165
 
    if ((channel = channel_new (REMMINA_SSH (tunnel)->session)) == NULL)
166
 
    {
167
 
        return FALSE;
168
 
    }
169
 
 
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);
173
 
    g_free (server);
174
 
    if (channel_open_session (channel) == SSH_OK &&
175
 
        channel_request_exec (channel, cmd) == SSH_OK)
176
 
    {
177
 
        channel_send_eof (channel);
178
 
        status = channel_get_exit_status (channel);
179
 
        switch (status)
180
 
        {
181
 
        case 0:
182
 
            ret = TRUE;
183
 
            break;
184
 
        case 127:
185
 
            remmina_ssh_set_application_error (tunnel,
186
 
                _("Please install xqproxy on SSH server in order to run XDMCP over SSH"));
187
 
            break;
188
 
        default:
189
 
            ((RemminaSSH*)tunnel)->error = g_strdup_printf ("Error executing xqproxy on SSH server (status = %i).", status);
190
 
            break;
191
 
        }
192
 
    }
193
 
    g_free (cmd);
194
 
    channel_close (channel);
195
 
    channel_free (channel);
196
 
    return ret;
197
 
}
198
 
 
199
 
static gboolean
200
 
remmina_plug_xdmcp_tunnel_connect_callback (RemminaSSHTunnel *tunnel, gpointer data)
201
 
{
202
 
    return TRUE;
203
 
}
204
 
 
205
 
static gboolean
206
 
remmina_plug_xdmcp_tunnel_disconnect_callback (RemminaSSHTunnel *tunnel, gpointer data)
207
 
{
208
 
    RemminaPlug *gp = REMMINA_PLUG (data);
209
 
 
210
 
    if (REMMINA_SSH (tunnel)->error)
211
 
    {
212
 
        g_snprintf (gp->error_message, MAX_ERROR_LENGTH, "%s", REMMINA_SSH (tunnel)->error);
213
 
        gp->has_error = TRUE;
214
 
    }
215
 
    IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, gp);
216
 
    return TRUE;
217
 
}
218
 
#endif
219
 
 
220
 
static gboolean
221
 
remmina_plug_xdmcp_main (RemminaPlugXdmcp *gp_xdmcp)
222
 
{
223
 
    RemminaPlug *gp = REMMINA_PLUG (gp_xdmcp);
224
 
    RemminaFile *remminafile = gp->remmina_file;
225
 
 
226
 
#ifdef HAVE_LIBSSH
227
 
    if (remminafile->ssh_enabled)
228
 
    {
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,
233
 
            gp_xdmcp))
234
 
        {
235
 
            gp_xdmcp->thread = 0;
236
 
            return FALSE;
237
 
        }
238
 
    }
239
 
    else
240
 
#endif
241
 
    {
242
 
        if (!remmina_plug_xdmcp_start_xephyr (gp_xdmcp))
243
 
        {
244
 
            gp_xdmcp->thread = 0;
245
 
            return FALSE;
246
 
        }
247
 
    }
248
 
 
249
 
    gp_xdmcp->thread = 0;
250
 
    return TRUE;
251
 
}
252
 
 
253
 
#ifdef HAVE_LIBSSH
254
 
static gpointer
255
 
remmina_plug_xdmcp_main_thread (gpointer data)
256
 
{
257
 
    pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
258
 
 
259
 
    CANCEL_ASYNC
260
 
    if (!remmina_plug_xdmcp_main (REMMINA_PLUG_XDMCP (data)))
261
 
    {
262
 
        IDLE_ADD ((GSourceFunc) remmina_plug_close_connection, data);
263
 
    }
264
 
    return NULL;
265
 
}
266
 
#endif
267
 
 
268
 
static gboolean
269
 
remmina_plug_xdmcp_open_connection (RemminaPlug *gp)
270
 
{
271
 
    RemminaPlugXdmcp *gp_xdmcp = REMMINA_PLUG_XDMCP (gp);
272
 
    RemminaFile *remminafile = gp->remmina_file;
273
 
 
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));
278
 
 
279
 
#ifdef HAVE_LIBSSH
280
 
 
281
 
    if (remminafile->ssh_enabled)
282
 
    {
283
 
        if (pthread_create (&gp_xdmcp->thread, NULL, remmina_plug_xdmcp_main_thread, gp))
284
 
        {
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;
289
 
            return FALSE;
290
 
        }
291
 
        else
292
 
        {
293
 
            return TRUE;
294
 
        }
295
 
    }
296
 
    else
297
 
    {
298
 
        return remmina_plug_xdmcp_main (gp_xdmcp);
299
 
    }
300
 
 
301
 
#else
302
 
 
303
 
    return remmina_plug_xdmcp_main (gp_xdmcp);
304
 
 
305
 
#endif
306
 
}
307
 
 
308
 
static gboolean
309
 
remmina_plug_xdmcp_close_connection (RemminaPlug *gp)
310
 
{
311
 
    RemminaPlugXdmcp *gp_xdmcp = REMMINA_PLUG_XDMCP (gp);
312
 
 
313
 
#ifdef HAVE_PTHREAD
314
 
    if (gp_xdmcp->thread)
315
 
    {
316
 
        pthread_cancel (gp_xdmcp->thread);
317
 
        if (gp_xdmcp->thread) pthread_join (gp_xdmcp->thread, NULL);
318
 
    }
319
 
#endif
320
 
 
321
 
    if (gp_xdmcp->pid)
322
 
    {
323
 
        kill (gp_xdmcp->pid, SIGTERM);
324
 
        g_spawn_close_pid (gp_xdmcp->pid);
325
 
        gp_xdmcp->pid = 0;
326
 
    }
327
 
 
328
 
    remmina_plug_emit_signal (gp, "disconnect");
329
 
 
330
 
    return FALSE;
331
 
}
332
 
 
333
 
static gpointer
334
 
remmina_plug_xdmcp_query_feature (RemminaPlug *gp, RemminaPlugFeature feature)
335
 
{
336
 
    return NULL;
337
 
}
338
 
 
339
 
static void
340
 
remmina_plug_xdmcp_call_feature (RemminaPlug *gp, RemminaPlugFeature feature, const gpointer data)
341
 
{
342
 
}
343
 
 
344
 
static void
345
 
remmina_plug_xdmcp_class_init (RemminaPlugXdmcpClass *klass)
346
 
{
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;
351
 
}
352
 
 
353
 
static void
354
 
remmina_plug_xdmcp_destroy (GtkWidget *widget, gpointer data)
355
 
{
356
 
}
357
 
 
358
 
static void
359
 
remmina_plug_xdmcp_init (RemminaPlugXdmcp *gp_xdmcp)
360
 
{
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);
368
 
 
369
 
    g_signal_connect (G_OBJECT (gp_xdmcp), "destroy", G_CALLBACK (remmina_plug_xdmcp_destroy), NULL);
370
 
 
371
 
    gp_xdmcp->socket_id = 0;
372
 
    gp_xdmcp->pid = 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;
378
 
}
379
 
 
380
 
GtkWidget*
381
 
remmina_plug_xdmcp_new (void)
382
 
{
383
 
    return GTK_WIDGET (g_object_new (REMMINA_TYPE_PLUG_XDMCP, NULL));
384
 
}
385