~ubuntu-branches/ubuntu/raring/remmina/raring

« back to all changes in this revision

Viewing changes to src/remminassh.c

  • Committer: Package Import Robot
  • Author(s): Luca Falavigna
  • Date: 2012-02-11 17:28:48 UTC
  • mfrom: (1.2.8)
  • Revision ID: package-import@ubuntu.com-20120211172848-rh3ffi7075qyobuq
Tags: 1.0.0-1
* New upstream release.
  - Compatible with FreeRDP 1.0 (Closes: #658363).
  - Ported to GTK3, this also fixes an incompatibility with
    GTK2 and recent Avahi with GTK3 support, which lead to
    crashes when scanning network services (Closes: #626499).
* debian/patches/libvncserver.patch:
  - Do not use convenience copy of libvncserver.
* debian/patches/g_thread_init.patch:
  - Do not use deprecated g_thread_init function.
* debian/patches/REMMINA_COMMAND_NONE.patch:
  - Removed, obsoleted by GApplication port.
* debian/clean:
  - Remove spurious files created at build-time.
* debian/compat:
  - Bump compatibility level to 9.
* debian/control:
  - Refresh build-dependencies to match new structure.
  - Drop remmina-dev package, no longer used.
  - Build packages once provided by remmina-plugins.
  - Provide remmina-common package.
  - Provide remmina-plugin-gnome package.
* debian/copyright:
  - Refresh copyright information.
* debian/docs:
  - Documentation is no longer accurate, do not ship it anymore.
* debian/remmina-dev.install:
  - Drop remmina-dev package, no longer used.
* debian/remmina-plugin-telepathy.install:
  - Adjust location for Remmina.client.
  - Disable D-BUS support for now.
* debian/rules:
  - Compile with -DWITH_APPINDICATOR=OFF.
  - Do not treat plugins as shared libraries.
* debian/watch:
  - Adjust watch file to match new download location.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Remmina - The GTK+ Remote Desktop Client
3
 
 * Copyright (C) 2009-2010 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 "config.h"
22
 
 
23
 
#ifdef HAVE_LIBSSH
24
 
 
25
 
/* Define this before stdlib.h to have posix_openpt */
26
 
#define _XOPEN_SOURCE 600
27
 
 
28
 
#include <gtk/gtk.h>
29
 
#include <glib/gi18n.h>
30
 
#include <stdlib.h>
31
 
#include <unistd.h>
32
 
#include <signal.h>
33
 
#include <time.h>
34
 
#include <sys/types.h>
35
 
#include <pthread.h>
36
 
#ifdef HAVE_NETDB_H
37
 
#include <netdb.h>
38
 
#endif
39
 
#ifdef HAVE_ARPA_INET_H
40
 
#include <arpa/inet.h>
41
 
#endif
42
 
#ifdef HAVE_NETINET_IN_H
43
 
#include <netinet/in.h>
44
 
#endif
45
 
#ifdef HAVE_SYS_SOCKET_H
46
 
#include <sys/socket.h>
47
 
#endif
48
 
#ifdef HAVE_FCNTL_H
49
 
#include <fcntl.h>
50
 
#endif
51
 
#ifdef HAVE_ERRNO_H
52
 
#include <errno.h>
53
 
#endif
54
 
#ifdef HAVE_TERMIOS_H
55
 
#include <termios.h>
56
 
#endif
57
 
#include "remminapublic.h"
58
 
#include "remminalog.h"
59
 
#include "remminassh.h"
60
 
 
61
 
/*************************** SSH Base *********************************/
62
 
 
63
 
#define LOCK_SSH(ssh) pthread_mutex_lock (&REMMINA_SSH (ssh)->ssh_mutex);
64
 
#define UNLOCK_SSH(ssh) pthread_mutex_unlock (&REMMINA_SSH (ssh)->ssh_mutex);
65
 
 
66
 
static const gchar *common_identities[] = {
67
 
    ".ssh/id_rsa",
68
 
    ".ssh/id_dsa",
69
 
    ".ssh/identity",
70
 
    NULL
71
 
};
72
 
 
73
 
gchar*
74
 
remmina_ssh_identity_path (const gchar *id)
75
 
{
76
 
    if (id == NULL) return NULL;
77
 
    if (id[0] == '/') return g_strdup (id);
78
 
    return g_strdup_printf ("%s/%s", g_get_home_dir (), id);
79
 
}
80
 
 
81
 
gchar*
82
 
remmina_ssh_find_identity (void)
83
 
{
84
 
    gchar *path;
85
 
    gint i;
86
 
 
87
 
    for (i = 0; common_identities[i]; i++)
88
 
    {
89
 
        path = remmina_ssh_identity_path (common_identities[i]);
90
 
        if (g_file_test (path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))
91
 
        {
92
 
            return path;
93
 
        }
94
 
        g_free (path);
95
 
    }
96
 
    return NULL;
97
 
}
98
 
 
99
 
void
100
 
remmina_ssh_set_error (RemminaSSH *ssh, const gchar *fmt)
101
 
{
102
 
    const gchar *err;
103
 
 
104
 
    err = ssh_get_error (ssh->session);
105
 
    ssh->error = g_strdup_printf (fmt, err);
106
 
}
107
 
 
108
 
void
109
 
remmina_ssh_set_application_error (RemminaSSH *ssh, const gchar *fmt, ...)
110
 
{
111
 
    va_list args;
112
 
 
113
 
    va_start (args, fmt);
114
 
    ssh->error = g_strdup_vprintf (fmt, args);
115
 
    va_end (args);
116
 
}
117
 
 
118
 
static gint
119
 
remmina_ssh_auth_password (RemminaSSH *ssh)
120
 
{
121
 
    gint ret;
122
 
 
123
 
    if (ssh->authenticated) return 1;
124
 
    if (ssh->password == NULL) return -1;
125
 
 
126
 
    ret = ssh_userauth_password (ssh->session, NULL, ssh->password);
127
 
    if (ret != SSH_AUTH_SUCCESS)
128
 
    {
129
 
        remmina_ssh_set_error (ssh, _("SSH password authentication failed: %s"));
130
 
        return 0;
131
 
    }
132
 
 
133
 
    ssh->authenticated = TRUE;
134
 
    return 1;
135
 
}
136
 
 
137
 
static gint
138
 
remmina_ssh_auth_pubkey (RemminaSSH *ssh)
139
 
{
140
 
    gint ret;
141
 
    ssh_string pubkey;
142
 
    ssh_private_key privkey;
143
 
    gint keytype;
144
 
 
145
 
    if (ssh->authenticated) return 1;
146
 
 
147
 
    if (ssh->pubkeyfile == NULL || ssh->privkeyfile == NULL)
148
 
    {
149
 
        ssh->error = g_strdup_printf (_("SSH public key authentication failed: %s"),
150
 
            _("SSH Key file not yet set."));
151
 
        return 0;
152
 
    }
153
 
 
154
 
    pubkey = publickey_from_file (ssh->session, ssh->pubkeyfile, &keytype);
155
 
    if (pubkey == NULL)
156
 
    {
157
 
        remmina_ssh_set_error (ssh, _("SSH public key authentication failed: %s"));
158
 
        return 0;
159
 
    }
160
 
 
161
 
    privkey = privatekey_from_file (ssh->session, ssh->privkeyfile, keytype, _
162
 
        (ssh->password ? ssh->password : ""));
163
 
    if (privkey == NULL)
164
 
    {
165
 
        string_free (pubkey);
166
 
        if (ssh->password == NULL || ssh->password[0] == '\0') return -1;
167
 
 
168
 
        remmina_ssh_set_error (ssh, _("SSH public key authentication failed: %s"));
169
 
        return 0;
170
 
    }
171
 
 
172
 
    ret = ssh_userauth_pubkey (ssh->session, NULL, pubkey, privkey);
173
 
    string_free (pubkey);
174
 
    privatekey_free (privkey);
175
 
 
176
 
    if (ret != SSH_AUTH_SUCCESS)
177
 
    {
178
 
        remmina_ssh_set_error (ssh, _("SSH public key authentication failed: %s"));
179
 
        return 0;
180
 
    }
181
 
 
182
 
    ssh->authenticated = TRUE;
183
 
    return 1;
184
 
}
185
 
 
186
 
static gint
187
 
remmina_ssh_auth_auto_pubkey (RemminaSSH* ssh)
188
 
{
189
 
    gint ret;
190
 
        ret = ssh_userauth_autopubkey (ssh->session, "");
191
 
 
192
 
    if (ret != SSH_AUTH_SUCCESS)
193
 
    {
194
 
        remmina_ssh_set_error (ssh, _("SSH automatic public key authentication failed: %s"));
195
 
        return 0;
196
 
    }
197
 
 
198
 
    ssh->authenticated = TRUE;
199
 
    return 1;
200
 
}
201
 
 
202
 
gint
203
 
remmina_ssh_auth (RemminaSSH *ssh, const gchar *password)
204
 
{
205
 
    if (password)
206
 
    {
207
 
        g_free (ssh->password);
208
 
        ssh->password = g_strdup (password);
209
 
    }
210
 
 
211
 
    switch (ssh->auth)
212
 
    {
213
 
 
214
 
    case SSH_AUTH_PASSWORD:
215
 
        return remmina_ssh_auth_password (ssh);
216
 
 
217
 
    case SSH_AUTH_PUBLICKEY:
218
 
        return remmina_ssh_auth_pubkey (ssh);
219
 
 
220
 
    case SSH_AUTH_AUTO_PUBLICKEY:
221
 
        return remmina_ssh_auth_auto_pubkey (ssh);
222
 
 
223
 
    default:
224
 
        return 0;
225
 
    }
226
 
}
227
 
 
228
 
gint
229
 
remmina_ssh_auth_gui (RemminaSSH *ssh, RemminaInitDialog *dialog, gboolean threaded)
230
 
{
231
 
    gchar *tips;
232
 
    gchar *keyname;
233
 
    gint ret;
234
 
 
235
 
    /* Try empty password or existing password first */
236
 
    ret = remmina_ssh_auth (ssh, NULL);
237
 
    if (ret > 0) return 1;
238
 
 
239
 
    /* Requested for a non-empty password */
240
 
    if (ret < 0)
241
 
    {
242
 
        if (!dialog) return -1;
243
 
 
244
 
        switch (ssh->auth)
245
 
        {
246
 
        case SSH_AUTH_PASSWORD:
247
 
            tips = _("Authenticating %s's password to SSH server %s...");
248
 
            keyname = _("SSH password");
249
 
            break;
250
 
        case SSH_AUTH_PUBLICKEY:
251
 
            tips = _("Authenticating %s's identity to SSH server %s...");
252
 
            keyname = _("SSH private key passphrase");
253
 
            break;
254
 
        default:
255
 
            return FALSE;
256
 
        }
257
 
 
258
 
        if (ssh->auth != SSH_AUTH_AUTO_PUBLICKEY)
259
 
        {
260
 
            if (threaded) gdk_threads_enter();
261
 
            remmina_init_dialog_set_status (dialog, tips, ssh->user, ssh->server);
262
 
 
263
 
            ret = remmina_init_dialog_authpwd (dialog, keyname, FALSE);
264
 
            if (threaded) {gdk_flush();gdk_threads_leave();}
265
 
 
266
 
            if (ret != GTK_RESPONSE_OK) return -1;
267
 
        }
268
 
        ret = remmina_ssh_auth (ssh, dialog->password);
269
 
    }
270
 
 
271
 
    if (ret <= 0)
272
 
    {
273
 
        return 0;
274
 
    }
275
 
 
276
 
    return 1;
277
 
}
278
 
 
279
 
void
280
 
remmina_ssh_log_callback (ssh_session session, int priority, const char *message, void *userdata)
281
 
{
282
 
    remmina_log_printf ("[SSH] %s\n", message);
283
 
}
284
 
 
285
 
gboolean
286
 
remmina_ssh_init_session (RemminaSSH *ssh)
287
 
{
288
 
    gint verbosity;
289
 
 
290
 
    ssh->callback = g_new0 (struct ssh_callbacks_struct, 1);
291
 
    ssh->callback->userdata = ssh;
292
 
 
293
 
    /* Init & startup the SSH session */    
294
 
    ssh->session = ssh_new ();
295
 
    ssh_options_set (ssh->session, SSH_OPTIONS_HOST, ssh->server);
296
 
    ssh_options_set (ssh->session, SSH_OPTIONS_PORT, &ssh->port);
297
 
    ssh_options_set (ssh->session, SSH_OPTIONS_USER, ssh->user);
298
 
    if (remmina_log_running ())
299
 
    {
300
 
        verbosity = SSH_LOG_RARE;
301
 
        ssh_options_set (ssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
302
 
        ssh->callback->log_function = remmina_ssh_log_callback;
303
 
    }
304
 
    ssh_callbacks_init (ssh->callback);
305
 
    ssh_set_callbacks(ssh->session, ssh->callback);
306
 
    
307
 
    if (ssh_connect (ssh->session))
308
 
    {
309
 
        remmina_ssh_set_error (ssh, _("Failed to startup SSH session: %s"));
310
 
        return FALSE;
311
 
    }
312
 
 
313
 
    /* Try the "none" authentication */
314
 
    if (ssh_userauth_none (ssh->session, NULL) == SSH_AUTH_SUCCESS)
315
 
    {
316
 
        ssh->authenticated = TRUE;
317
 
    }
318
 
    return TRUE;
319
 
}
320
 
 
321
 
gboolean
322
 
remmina_ssh_init_from_file (RemminaSSH *ssh, RemminaFile *remminafile)
323
 
{
324
 
    const gchar *ssh_server;
325
 
    const gchar *ssh_username;
326
 
    const gchar *ssh_privatekey;
327
 
    const gchar *server;
328
 
    gchar *s;
329
 
 
330
 
    ssh->session = NULL;
331
 
    ssh->callback = NULL;
332
 
    ssh->authenticated = FALSE;
333
 
    ssh->error = NULL;
334
 
    pthread_mutex_init (&ssh->ssh_mutex, NULL);
335
 
 
336
 
    /* Parse the address and port */
337
 
    ssh_server = remmina_file_get_string (remminafile, "ssh_server");
338
 
    ssh_username = remmina_file_get_string (remminafile, "ssh_username");
339
 
    ssh_privatekey = remmina_file_get_string (remminafile, "ssh_privatekey");
340
 
    server = remmina_file_get_string (remminafile, "server");
341
 
    if (ssh_server)
342
 
    {
343
 
        remmina_public_get_server_port (ssh_server, 22, &ssh->server, &ssh->port);
344
 
        if (ssh->server[0] == '\0')
345
 
        {
346
 
            g_free (ssh->server);
347
 
            remmina_public_get_server_port (server, 0, &ssh->server, NULL);
348
 
        }
349
 
    }
350
 
    else if (server == NULL)
351
 
    {
352
 
        return FALSE;
353
 
    }
354
 
    else
355
 
    {
356
 
        remmina_public_get_server_port (server, 0, &ssh->server, NULL);
357
 
        ssh->port = 22;
358
 
    }
359
 
 
360
 
    ssh->user = g_strdup (ssh_username ? ssh_username : g_get_user_name ());
361
 
    ssh->password = NULL;
362
 
    ssh->auth = remmina_file_get_int (remminafile, "ssh_auth", 0);
363
 
    ssh->charset = g_strdup (remmina_file_get_string (remminafile, "ssh_charset"));
364
 
 
365
 
    /* Public/Private keys */
366
 
    s = (ssh_privatekey ? g_strdup (ssh_privatekey) : remmina_ssh_find_identity ());
367
 
    if (s)
368
 
    {
369
 
        ssh->privkeyfile = remmina_ssh_identity_path (s);
370
 
        ssh->pubkeyfile = g_strdup_printf ("%s.pub", ssh->privkeyfile);
371
 
        g_free (s);
372
 
    }
373
 
    else
374
 
    {
375
 
        ssh->privkeyfile = NULL;
376
 
        ssh->pubkeyfile = NULL;
377
 
    }
378
 
 
379
 
    return TRUE;
380
 
}
381
 
 
382
 
static gboolean
383
 
remmina_ssh_init_from_ssh (RemminaSSH *ssh, const RemminaSSH *ssh_src)
384
 
{
385
 
    ssh->session = NULL;
386
 
    ssh->authenticated = FALSE;
387
 
    ssh->error = NULL;
388
 
    pthread_mutex_init (&ssh->ssh_mutex, NULL);
389
 
 
390
 
    ssh->server = g_strdup (ssh_src->server);
391
 
    ssh->port = ssh_src->port;
392
 
    ssh->user = g_strdup (ssh_src->user);
393
 
    ssh->auth = ssh_src->auth;
394
 
    ssh->password = g_strdup (ssh_src->password);
395
 
    ssh->pubkeyfile = g_strdup (ssh_src->pubkeyfile);
396
 
    ssh->privkeyfile = g_strdup (ssh_src->privkeyfile);
397
 
    ssh->charset = g_strdup (ssh_src->charset);
398
 
 
399
 
    return TRUE;
400
 
}
401
 
 
402
 
gchar*
403
 
remmina_ssh_convert (RemminaSSH *ssh, const gchar *from)
404
 
{
405
 
    gchar *to = NULL;
406
 
 
407
 
    if (ssh->charset && from)
408
 
    {
409
 
        to = g_convert (from, -1, "UTF-8", ssh->charset, NULL, NULL, NULL);
410
 
    }
411
 
    if (!to) to = g_strdup (from);
412
 
    return to;
413
 
}
414
 
 
415
 
gchar*
416
 
remmina_ssh_unconvert (RemminaSSH *ssh, const gchar *from)
417
 
{
418
 
    gchar *to = NULL;
419
 
 
420
 
    if (ssh->charset && from)
421
 
    {
422
 
        to = g_convert (from, -1, ssh->charset, "UTF-8", NULL, NULL, NULL);
423
 
    }
424
 
    if (!to) to = g_strdup (from);
425
 
    return to;
426
 
}
427
 
 
428
 
void
429
 
remmina_ssh_free (RemminaSSH *ssh)
430
 
{
431
 
    if (ssh->session)
432
 
    {
433
 
        ssh_free (ssh->session);
434
 
        ssh->session = NULL;
435
 
    }
436
 
    g_free (ssh->callback);
437
 
    g_free (ssh->server);
438
 
    g_free (ssh->user);
439
 
    g_free (ssh->password);
440
 
    g_free (ssh->pubkeyfile);
441
 
    g_free (ssh->privkeyfile);
442
 
    g_free (ssh->charset);
443
 
    g_free (ssh->error);
444
 
    pthread_mutex_destroy (&ssh->ssh_mutex);
445
 
    g_free (ssh);
446
 
}
447
 
 
448
 
/*************************** SSH Tunnel *********************************/
449
 
struct _RemminaSSHTunnelBuffer
450
 
{
451
 
    gchar *data;
452
 
    gchar *ptr;
453
 
    ssize_t len;
454
 
};
455
 
 
456
 
static RemminaSSHTunnelBuffer*
457
 
remmina_ssh_tunnel_buffer_new (ssize_t len)
458
 
{
459
 
    RemminaSSHTunnelBuffer *buffer;
460
 
 
461
 
    buffer = g_new (RemminaSSHTunnelBuffer, 1);
462
 
    buffer->data = (gchar*) g_malloc (len);
463
 
    buffer->ptr = buffer->data;
464
 
    buffer->len = len;
465
 
    return buffer;
466
 
}
467
 
 
468
 
static void
469
 
remmina_ssh_tunnel_buffer_free (RemminaSSHTunnelBuffer *buffer)
470
 
{
471
 
    if (buffer)
472
 
    {
473
 
        g_free (buffer->data);
474
 
        g_free (buffer);
475
 
    }
476
 
}
477
 
 
478
 
RemminaSSHTunnel*
479
 
remmina_ssh_tunnel_new_from_file (RemminaFile *remminafile)
480
 
{
481
 
    RemminaSSHTunnel *tunnel;
482
 
 
483
 
    tunnel = g_new (RemminaSSHTunnel, 1);
484
 
 
485
 
    remmina_ssh_init_from_file (REMMINA_SSH (tunnel), remminafile);
486
 
 
487
 
    tunnel->tunnel_type = -1;
488
 
    tunnel->channels = NULL;
489
 
    tunnel->sockets = NULL;
490
 
    tunnel->socketbuffers = NULL;
491
 
    tunnel->num_channels = 0;
492
 
    tunnel->max_channels = 0;
493
 
    tunnel->x11_channel = NULL;
494
 
    tunnel->thread = 0;
495
 
    tunnel->running = FALSE;
496
 
    tunnel->server_sock = -1;
497
 
    tunnel->dest = NULL;
498
 
    tunnel->port = 0;
499
 
    tunnel->buffer = NULL;
500
 
    tunnel->buffer_len = 0;
501
 
    tunnel->channels_out = NULL;
502
 
    tunnel->remotedisplay = 0;
503
 
    tunnel->localdisplay = NULL;
504
 
    tunnel->init_func = NULL;
505
 
    tunnel->connect_func = NULL;
506
 
    tunnel->disconnect_func = NULL;
507
 
    tunnel->callback_data = NULL;
508
 
 
509
 
    return tunnel;
510
 
}
511
 
 
512
 
static void
513
 
remmina_ssh_tunnel_close_all_channels (RemminaSSHTunnel *tunnel)
514
 
{
515
 
    int i;
516
 
 
517
 
    for (i = 0; i < tunnel->num_channels; i++)
518
 
    {
519
 
        close (tunnel->sockets[i]);
520
 
        remmina_ssh_tunnel_buffer_free (tunnel->socketbuffers[i]);
521
 
        channel_close (tunnel->channels[i]);
522
 
        channel_free (tunnel->channels[i]);
523
 
    }
524
 
 
525
 
    g_free (tunnel->channels);
526
 
    tunnel->channels = NULL;
527
 
    g_free (tunnel->sockets);
528
 
    tunnel->sockets = NULL;
529
 
    g_free (tunnel->socketbuffers);
530
 
    tunnel->socketbuffers = NULL;
531
 
 
532
 
    tunnel->num_channels = 0;
533
 
    tunnel->max_channels = 0;
534
 
 
535
 
    if (tunnel->x11_channel)
536
 
    {
537
 
        channel_close (tunnel->x11_channel);
538
 
        channel_free (tunnel->x11_channel);
539
 
        tunnel->x11_channel = NULL;
540
 
    }
541
 
}
542
 
 
543
 
static void
544
 
remmina_ssh_tunnel_remove_channel (RemminaSSHTunnel *tunnel, gint n)
545
 
{
546
 
    channel_close (tunnel->channels[n]);
547
 
    channel_free (tunnel->channels[n]);
548
 
    close (tunnel->sockets[n]);
549
 
    remmina_ssh_tunnel_buffer_free (tunnel->socketbuffers[n]);
550
 
    tunnel->num_channels--;
551
 
    tunnel->channels[n] = tunnel->channels[tunnel->num_channels];
552
 
    tunnel->channels[tunnel->num_channels] = NULL;
553
 
    tunnel->sockets[n] = tunnel->sockets[tunnel->num_channels];
554
 
    tunnel->socketbuffers[n] = tunnel->socketbuffers[tunnel->num_channels];
555
 
}
556
 
 
557
 
/* Register the new channel/socket pair */
558
 
static void
559
 
remmina_ssh_tunnel_add_channel (RemminaSSHTunnel *tunnel, ssh_channel channel, gint sock)
560
 
{
561
 
    gint flags;
562
 
    gint i;
563
 
 
564
 
    i = tunnel->num_channels++;
565
 
    if (tunnel->num_channels > tunnel->max_channels)
566
 
    {
567
 
        /* Allocate an extra NULL pointer in channels for ssh_select */
568
 
        tunnel->channels = (ssh_channel*) g_realloc (tunnel->channels,
569
 
            sizeof (ssh_channel) * (tunnel->num_channels + 1));
570
 
        tunnel->sockets = (gint*) g_realloc (tunnel->sockets,
571
 
            sizeof (gint) * tunnel->num_channels);
572
 
        tunnel->socketbuffers = (RemminaSSHTunnelBuffer**) g_realloc (tunnel->socketbuffers,
573
 
            sizeof (RemminaSSHTunnelBuffer*) * tunnel->num_channels);
574
 
        tunnel->max_channels = tunnel->num_channels;
575
 
 
576
 
        tunnel->channels_out = (ssh_channel*) g_realloc (tunnel->channels_out,
577
 
            sizeof (ssh_channel) * (tunnel->num_channels + 1));
578
 
    }
579
 
    tunnel->channels[i] = channel;
580
 
    tunnel->channels[i + 1] = NULL;
581
 
    tunnel->sockets[i] = sock;
582
 
    tunnel->socketbuffers[i] = NULL;
583
 
 
584
 
    flags = fcntl (sock, F_GETFL, 0);
585
 
    fcntl (sock, F_SETFL, flags | O_NONBLOCK);
586
 
}
587
 
 
588
 
static gpointer
589
 
remmina_ssh_tunnel_main_thread_proc (gpointer data)
590
 
{
591
 
    RemminaSSHTunnel *tunnel = (RemminaSSHTunnel*) data;
592
 
    gchar *ptr;
593
 
    ssize_t len = 0, lenw = 0;
594
 
    fd_set set;
595
 
    struct timeval timeout;
596
 
    GTimeVal t1, t2;
597
 
    glong diff;
598
 
    ssh_channel channel = NULL;
599
 
    gboolean first = TRUE;
600
 
    gboolean disconnected;
601
 
    gint sock;
602
 
    gint maxfd;
603
 
    gint i;
604
 
    gint ret;
605
 
    struct sockaddr_in sin;
606
 
 
607
 
    g_get_current_time (&t1);
608
 
    t2 = t1;
609
 
 
610
 
    switch (tunnel->tunnel_type)
611
 
    {
612
 
    case REMMINA_SSH_TUNNEL_OPEN:
613
 
        /* Accept a local connection */
614
 
        sock = accept (tunnel->server_sock, NULL, NULL);
615
 
        if (sock < 0)
616
 
        {
617
 
            REMMINA_SSH (tunnel)->error = g_strdup ("Failed to accept local socket");
618
 
            tunnel->thread = 0;
619
 
            return NULL;
620
 
        }
621
 
 
622
 
        if ((channel = channel_new (tunnel->ssh.session)) == NULL)
623
 
        {
624
 
            close (sock);
625
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to createt channel : %s");
626
 
            tunnel->thread = 0;
627
 
            return NULL;
628
 
        }
629
 
        /* Request the SSH server to connect to the destination */
630
 
        if (channel_open_forward (channel, tunnel->dest, tunnel->port, "127.0.0.1", 0) != SSH_OK)
631
 
        {
632
 
            close (sock);
633
 
            channel_close (channel);
634
 
            channel_free (channel);
635
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to connect to the SSH tunnel destination: %s"));
636
 
            tunnel->thread = 0;
637
 
            return NULL;
638
 
        }
639
 
        remmina_ssh_tunnel_add_channel (tunnel, channel, sock);
640
 
        break;
641
 
 
642
 
    case REMMINA_SSH_TUNNEL_X11:
643
 
        if ((tunnel->x11_channel = channel_new (tunnel->ssh.session)) == NULL)
644
 
        {
645
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to create channel : %s");
646
 
            tunnel->thread = 0;
647
 
            return NULL;
648
 
        }
649
 
        if (!remmina_public_get_xauth_cookie (tunnel->localdisplay, &ptr))
650
 
        {
651
 
            remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "%s", ptr);
652
 
            g_free (ptr);
653
 
            tunnel->thread = 0;
654
 
            return NULL;
655
 
        }
656
 
        if (channel_open_session (tunnel->x11_channel) ||
657
 
            channel_request_x11 (tunnel->x11_channel, TRUE, NULL, ptr,
658
 
                gdk_screen_get_number (gdk_screen_get_default ())))
659
 
        {
660
 
            g_free (ptr);
661
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to open channel : %s");
662
 
            tunnel->thread = 0;
663
 
            return NULL;
664
 
        }
665
 
        g_free (ptr);
666
 
        if (channel_request_exec (tunnel->x11_channel, tunnel->dest))
667
 
        {
668
 
            ptr = g_strdup_printf (_("Failed to execute %s on SSH server : %%s"), tunnel->dest);
669
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), ptr);
670
 
            g_free (ptr);
671
 
            tunnel->thread = 0;
672
 
            return NULL;
673
 
        }
674
 
 
675
 
        if (tunnel->init_func &&
676
 
            ! (*tunnel->init_func) (tunnel, tunnel->callback_data))
677
 
        {
678
 
            if (tunnel->disconnect_func)
679
 
            {
680
 
                (*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
681
 
            }
682
 
            tunnel->thread = 0;
683
 
            return NULL;
684
 
        }
685
 
 
686
 
        break;
687
 
 
688
 
    case REMMINA_SSH_TUNNEL_XPORT:
689
 
        /* Detect the next available port starting from 6010 on the server */
690
 
        for (i = 10; i <= MAX_X_DISPLAY_NUMBER; i++)
691
 
        {
692
 
            if (channel_forward_listen (REMMINA_SSH (tunnel)->session,
693
 
                (tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL))
694
 
            {
695
 
                continue;
696
 
            }
697
 
            else
698
 
            {
699
 
                tunnel->remotedisplay = i;
700
 
                break;
701
 
            }
702
 
        }
703
 
        if (tunnel->remotedisplay < 1)
704
 
        {
705
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s"));
706
 
            if (tunnel->disconnect_func)
707
 
            {
708
 
                (*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
709
 
            }
710
 
            tunnel->thread = 0;
711
 
            return NULL;
712
 
        }
713
 
 
714
 
        if (tunnel->init_func &&
715
 
            ! (*tunnel->init_func) (tunnel, tunnel->callback_data))
716
 
        {
717
 
            if (tunnel->disconnect_func)
718
 
            {
719
 
                (*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
720
 
            }
721
 
            tunnel->thread = 0;
722
 
            return NULL;
723
 
        }
724
 
 
725
 
        break;
726
 
 
727
 
    case REMMINA_SSH_TUNNEL_REVERSE:
728
 
        if (channel_forward_listen (REMMINA_SSH (tunnel)->session, NULL, tunnel->port, NULL))
729
 
        {
730
 
            remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s"));
731
 
            if (tunnel->disconnect_func)
732
 
            {
733
 
                (*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
734
 
            }
735
 
            tunnel->thread = 0;
736
 
            return NULL;
737
 
        }
738
 
 
739
 
        if (tunnel->init_func &&
740
 
            ! (*tunnel->init_func) (tunnel, tunnel->callback_data))
741
 
        {
742
 
            if (tunnel->disconnect_func)
743
 
            {
744
 
                (*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
745
 
            }
746
 
            tunnel->thread = 0;
747
 
            return NULL;
748
 
        }
749
 
 
750
 
        break;
751
 
    }
752
 
 
753
 
    tunnel->buffer_len = 10240;
754
 
    tunnel->buffer = g_malloc (tunnel->buffer_len);
755
 
 
756
 
    /* Start the tunnel data transmittion */
757
 
    while (tunnel->running)
758
 
    {
759
 
        if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT ||
760
 
            tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11 ||
761
 
            tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE)
762
 
        {
763
 
            if (first)
764
 
            {
765
 
                first = FALSE;
766
 
                /* Wait for a period of time for the first incoming connection */
767
 
                if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
768
 
                {
769
 
                    channel = channel_accept_x11 (tunnel->x11_channel, 15000);
770
 
                }
771
 
                else
772
 
                {
773
 
                    channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 15000);
774
 
                }
775
 
                if (!channel)
776
 
                {
777
 
                    remmina_ssh_set_application_error (REMMINA_SSH (tunnel), _("No response from the server."));
778
 
                    if (tunnel->disconnect_func)
779
 
                    {
780
 
                        (*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
781
 
                    }
782
 
                    tunnel->thread = 0;
783
 
                    return NULL;
784
 
                }
785
 
                if (tunnel->connect_func)
786
 
                {
787
 
                    (*tunnel->connect_func) (tunnel, tunnel->callback_data);
788
 
                }
789
 
                if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE)
790
 
                {
791
 
                    /* For reverse tunnel, we only need one connection. */
792
 
                    channel_forward_cancel (REMMINA_SSH (tunnel)->session, NULL, tunnel->port);
793
 
                }
794
 
            }
795
 
            else if (tunnel->tunnel_type != REMMINA_SSH_TUNNEL_REVERSE)
796
 
            {
797
 
                /* Poll once per some period of time if no incoming connections.
798
 
                 * Don't try to poll continuously as it will significantly slow down the loop */
799
 
                g_get_current_time (&t1);
800
 
                diff = (t1.tv_sec - t2.tv_sec) * 10 + (t1.tv_usec - t2.tv_usec) / 100000;
801
 
                if (diff > 1)
802
 
                {
803
 
                    if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
804
 
                    {
805
 
                        channel = channel_accept_x11 (tunnel->x11_channel, 0);
806
 
                    }
807
 
                    else
808
 
                    {
809
 
                        channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 0);
810
 
                    }
811
 
                    if (channel == NULL)
812
 
                    {
813
 
                        t2 = t1;
814
 
                    }
815
 
                }
816
 
            }
817
 
 
818
 
            if (channel)
819
 
            {
820
 
                if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE)
821
 
                {
822
 
                    sin.sin_family = AF_INET;
823
 
                    sin.sin_port = htons (tunnel->localport);
824
 
                    sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
825
 
                    sock = socket (AF_INET, SOCK_STREAM, 0);
826
 
                    if (connect (sock, (struct sockaddr *) &sin, sizeof (sin)) < 0)
827
 
                    {
828
 
                        remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
829
 
                            "Cannot connect to local port %i.", tunnel->localport);
830
 
                        close (sock);
831
 
                        sock = -1;
832
 
                    }
833
 
                }
834
 
                else
835
 
                {
836
 
                    sock = remmina_public_open_xdisplay (tunnel->localdisplay);
837
 
                }
838
 
                if (sock >= 0)
839
 
                {
840
 
                    remmina_ssh_tunnel_add_channel (tunnel, channel, sock);
841
 
                }
842
 
                else
843
 
                {
844
 
                    /* Failed to create unix socket. Will this happen? */
845
 
                    channel_close (channel);
846
 
                    channel_free (channel);
847
 
                }
848
 
                channel = NULL;
849
 
            }
850
 
        }
851
 
 
852
 
        if (tunnel->num_channels <= 0)
853
 
        {
854
 
            /* No more connections. We should quit */
855
 
            break;
856
 
        }
857
 
 
858
 
        timeout.tv_sec = 0;
859
 
        timeout.tv_usec = 200000;
860
 
 
861
 
        FD_ZERO (&set);
862
 
        maxfd = 0;
863
 
        for (i = 0; i < tunnel->num_channels; i++)
864
 
        {
865
 
            if (tunnel->sockets[i] > maxfd)
866
 
            {
867
 
                maxfd = tunnel->sockets[i];
868
 
            }
869
 
            FD_SET (tunnel->sockets[i], &set);
870
 
        }
871
 
 
872
 
        ret = ssh_select (tunnel->channels, tunnel->channels_out, maxfd + 1, &set, &timeout);
873
 
        if (!tunnel->running) break;
874
 
        if (ret == SSH_EINTR) continue;
875
 
        if (ret == -1) break;
876
 
 
877
 
        i = 0;
878
 
        while (tunnel->running && i < tunnel->num_channels)
879
 
        {
880
 
            disconnected = FALSE;
881
 
            if (FD_ISSET (tunnel->sockets[i], &set))
882
 
            {
883
 
                while (!disconnected &&
884
 
                    (len = read (tunnel->sockets[i], tunnel->buffer, tunnel->buffer_len)) > 0)
885
 
                {
886
 
                    for (ptr = tunnel->buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw)
887
 
                    {
888
 
                        lenw = channel_write (tunnel->channels[i], (char*) ptr, len);
889
 
                        if (lenw <= 0)
890
 
                        {
891
 
                            disconnected = TRUE;
892
 
                            break;
893
 
                        }
894
 
                    }
895
 
                }
896
 
                if (len == 0) disconnected = TRUE;
897
 
            }
898
 
            if (disconnected)
899
 
            {
900
 
                remmina_ssh_tunnel_remove_channel (tunnel, i);
901
 
                continue;
902
 
            }
903
 
            i++;
904
 
        }
905
 
        if (!tunnel->running) break;
906
 
 
907
 
        i = 0;
908
 
        while (tunnel->running && i < tunnel->num_channels)
909
 
        {
910
 
            disconnected = FALSE;
911
 
 
912
 
            if (!tunnel->socketbuffers[i])
913
 
            {
914
 
                len = channel_poll (tunnel->channels[i], 0);
915
 
                if (len == SSH_ERROR || len == SSH_EOF)
916
 
                {
917
 
                    disconnected = TRUE;
918
 
                }
919
 
                else if (len > 0)
920
 
                {
921
 
                    tunnel->socketbuffers[i] = remmina_ssh_tunnel_buffer_new (len);
922
 
                    len = channel_read_nonblocking (tunnel->channels[i], tunnel->socketbuffers[i]->data, len, 0);
923
 
                    if (len <= 0)
924
 
                    {
925
 
                        disconnected = TRUE;
926
 
                    }
927
 
                    else
928
 
                    {
929
 
                        tunnel->socketbuffers[i]->len = len;
930
 
                    }
931
 
                }
932
 
            }
933
 
 
934
 
            if (!disconnected && tunnel->socketbuffers[i])
935
 
            {
936
 
                for (lenw = 0; tunnel->socketbuffers[i]->len > 0;
937
 
                    tunnel->socketbuffers[i]->len -= lenw, tunnel->socketbuffers[i]->ptr += lenw)
938
 
                {
939
 
                    lenw = write (tunnel->sockets[i], tunnel->socketbuffers[i]->ptr, tunnel->socketbuffers[i]->len);
940
 
                    if (lenw == -1 && errno == EAGAIN && tunnel->running)
941
 
                    {
942
 
                        /* Sometimes we cannot write to a socket (always EAGAIN), probably because it's internal
943
 
                         * buffer is full. We need read the pending bytes from the socket first. so here we simply
944
 
                         * break, leave the buffer there, and continue with other data */
945
 
                        break;
946
 
                    }
947
 
                    if (lenw <= 0)
948
 
                    {
949
 
                        disconnected = TRUE;
950
 
                        break;
951
 
                    }
952
 
                }
953
 
                if (tunnel->socketbuffers[i]->len <= 0)
954
 
                {
955
 
                    remmina_ssh_tunnel_buffer_free (tunnel->socketbuffers[i]);
956
 
                    tunnel->socketbuffers[i] = NULL;
957
 
                }
958
 
            }
959
 
 
960
 
            if (disconnected)
961
 
            {
962
 
                remmina_ssh_tunnel_remove_channel (tunnel, i);
963
 
                continue;
964
 
            }
965
 
            i++;
966
 
        }
967
 
    }
968
 
 
969
 
    remmina_ssh_tunnel_close_all_channels (tunnel);
970
 
 
971
 
    return NULL;
972
 
}
973
 
 
974
 
static gpointer
975
 
remmina_ssh_tunnel_main_thread (gpointer data)
976
 
{
977
 
    RemminaSSHTunnel *tunnel = (RemminaSSHTunnel*) data;
978
 
 
979
 
    pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
980
 
 
981
 
    while (TRUE)
982
 
    {
983
 
        remmina_ssh_tunnel_main_thread_proc (data);
984
 
        if (tunnel->server_sock < 0 || tunnel->thread == 0 || !tunnel->running) break;
985
 
    }
986
 
    tunnel->thread = 0;
987
 
    return NULL;
988
 
}
989
 
 
990
 
void
991
 
remmina_ssh_tunnel_cancel_accept (RemminaSSHTunnel *tunnel)
992
 
{
993
 
    if (tunnel->server_sock >= 0)
994
 
    {
995
 
        close (tunnel->server_sock);
996
 
        tunnel->server_sock = -1;
997
 
    }
998
 
}
999
 
 
1000
 
gboolean
1001
 
remmina_ssh_tunnel_open (RemminaSSHTunnel* tunnel, const gchar *host, gint port, gint local_port)
1002
 
{
1003
 
    gint sock;
1004
 
    gint sockopt = 1;
1005
 
    struct sockaddr_in sin;
1006
 
 
1007
 
    tunnel->tunnel_type = REMMINA_SSH_TUNNEL_OPEN;
1008
 
    tunnel->dest = g_strdup (host);
1009
 
    tunnel->port = port;
1010
 
    if (tunnel->port == 0)
1011
 
    {
1012
 
        REMMINA_SSH (tunnel)->error = g_strdup ("Destination port has not been assigned");
1013
 
        return FALSE;
1014
 
    }
1015
 
 
1016
 
    /* Create the server socket that listens on the local port */
1017
 
    sock = socket (AF_INET, SOCK_STREAM, 0);
1018
 
    if (sock < 0)
1019
 
    {
1020
 
        REMMINA_SSH (tunnel)->error = g_strdup ("Failed to create socket.");
1021
 
        return FALSE;
1022
 
    }
1023
 
    setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof (sockopt));
1024
 
 
1025
 
    sin.sin_family = AF_INET;
1026
 
    sin.sin_port = htons (local_port);
1027
 
    sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
1028
 
 
1029
 
    if (bind (sock, (struct sockaddr *) &sin, sizeof(sin)))
1030
 
    {
1031
 
        REMMINA_SSH (tunnel)->error = g_strdup ("Failed to bind on local port.");
1032
 
        close (sock);
1033
 
        return FALSE;
1034
 
    }
1035
 
 
1036
 
    if (listen (sock, 1))
1037
 
    {
1038
 
        REMMINA_SSH (tunnel)->error = g_strdup ("Failed to listen on local port.");
1039
 
        close (sock);
1040
 
        return FALSE;
1041
 
    }
1042
 
 
1043
 
    tunnel->server_sock = sock;
1044
 
    tunnel->running = TRUE;
1045
 
 
1046
 
    if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel))
1047
 
    {
1048
 
        remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread.");
1049
 
        tunnel->thread = 0;
1050
 
        return FALSE;
1051
 
    }
1052
 
    return TRUE;
1053
 
}
1054
 
 
1055
 
gboolean
1056
 
remmina_ssh_tunnel_x11 (RemminaSSHTunnel *tunnel, const gchar *cmd)
1057
 
{
1058
 
    tunnel->tunnel_type = REMMINA_SSH_TUNNEL_X11;
1059
 
    tunnel->dest = g_strdup (cmd);
1060
 
    tunnel->running = TRUE;
1061
 
 
1062
 
    if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel))
1063
 
    {
1064
 
        remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread.");
1065
 
        tunnel->thread = 0;
1066
 
        return FALSE;
1067
 
    }
1068
 
    return TRUE;
1069
 
}
1070
 
 
1071
 
gboolean
1072
 
remmina_ssh_tunnel_xport (RemminaSSHTunnel *tunnel, gboolean bindlocalhost)
1073
 
{
1074
 
    tunnel->tunnel_type = REMMINA_SSH_TUNNEL_XPORT;
1075
 
    tunnel->bindlocalhost = bindlocalhost;
1076
 
    tunnel->running = TRUE;
1077
 
 
1078
 
    if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel))
1079
 
    {
1080
 
        remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread.");
1081
 
        tunnel->thread = 0;
1082
 
        return FALSE;
1083
 
    }
1084
 
    return TRUE;
1085
 
}
1086
 
 
1087
 
gboolean
1088
 
remmina_ssh_tunnel_reverse (RemminaSSHTunnel *tunnel, gint port, gint local_port)
1089
 
{
1090
 
    tunnel->tunnel_type = REMMINA_SSH_TUNNEL_REVERSE;
1091
 
    tunnel->port = port;
1092
 
    tunnel->localport = local_port;
1093
 
    tunnel->running = TRUE;
1094
 
 
1095
 
    if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel))
1096
 
    {
1097
 
        remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread.");
1098
 
        tunnel->thread = 0;
1099
 
        return FALSE;
1100
 
    }
1101
 
    return TRUE;
1102
 
}
1103
 
 
1104
 
gboolean
1105
 
remmina_ssh_tunnel_terminated (RemminaSSHTunnel* tunnel)
1106
 
{
1107
 
    return (tunnel->thread == 0);
1108
 
}
1109
 
 
1110
 
void
1111
 
remmina_ssh_tunnel_free (RemminaSSHTunnel* tunnel)
1112
 
{
1113
 
    pthread_t thread;
1114
 
 
1115
 
    thread = tunnel->thread;
1116
 
    if (thread != 0)
1117
 
    {
1118
 
        tunnel->running = FALSE;
1119
 
        pthread_cancel (thread);
1120
 
        pthread_join (thread, NULL);
1121
 
        tunnel->thread = 0;
1122
 
    }
1123
 
 
1124
 
    if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT && tunnel->remotedisplay > 0)
1125
 
    {
1126
 
        channel_forward_cancel (REMMINA_SSH (tunnel)->session,
1127
 
            NULL, 6000 + tunnel->remotedisplay);
1128
 
    }
1129
 
    if (tunnel->server_sock >= 0)
1130
 
    {
1131
 
        close (tunnel->server_sock);
1132
 
        tunnel->server_sock = -1;
1133
 
    }
1134
 
    remmina_ssh_tunnel_close_all_channels (tunnel);
1135
 
 
1136
 
    g_free (tunnel->buffer);
1137
 
    g_free (tunnel->channels_out);
1138
 
    g_free (tunnel->dest);
1139
 
    g_free (tunnel->localdisplay);
1140
 
 
1141
 
    remmina_ssh_free (REMMINA_SSH (tunnel));
1142
 
}
1143
 
 
1144
 
/*************************** SFTP *********************************/
1145
 
 
1146
 
RemminaSFTP*
1147
 
remmina_sftp_new_from_file (RemminaFile *remminafile)
1148
 
{
1149
 
    RemminaSFTP *sftp;
1150
 
 
1151
 
    sftp = g_new (RemminaSFTP, 1);
1152
 
 
1153
 
    remmina_ssh_init_from_file (REMMINA_SSH (sftp), remminafile);
1154
 
 
1155
 
    sftp->sftp_sess = NULL;
1156
 
 
1157
 
    return sftp;
1158
 
}
1159
 
 
1160
 
RemminaSFTP*
1161
 
remmina_sftp_new_from_ssh (RemminaSSH *ssh)
1162
 
{
1163
 
    RemminaSFTP *sftp;
1164
 
 
1165
 
    sftp = g_new (RemminaSFTP, 1);
1166
 
 
1167
 
    remmina_ssh_init_from_ssh (REMMINA_SSH (sftp), ssh);
1168
 
 
1169
 
    sftp->sftp_sess = NULL;
1170
 
 
1171
 
    return sftp;
1172
 
}
1173
 
 
1174
 
gboolean
1175
 
remmina_sftp_open (RemminaSFTP *sftp)
1176
 
{
1177
 
    sftp->sftp_sess = sftp_new (sftp->ssh.session);
1178
 
    if (!sftp->sftp_sess)
1179
 
    {
1180
 
        remmina_ssh_set_error (REMMINA_SSH (sftp), _("Failed to create sftp session: %s"));
1181
 
        return FALSE;
1182
 
    }
1183
 
    if (sftp_init (sftp->sftp_sess))
1184
 
    {
1185
 
        remmina_ssh_set_error (REMMINA_SSH (sftp), _("Failed to initialize sftp session: %s"));
1186
 
        return FALSE;
1187
 
    }
1188
 
    return TRUE;
1189
 
}
1190
 
 
1191
 
void
1192
 
remmina_sftp_free (RemminaSFTP *sftp)
1193
 
{
1194
 
    if (sftp->sftp_sess)
1195
 
    {
1196
 
        sftp_free (sftp->sftp_sess);
1197
 
        sftp->sftp_sess = NULL;
1198
 
    }
1199
 
    remmina_ssh_free (REMMINA_SSH (sftp));
1200
 
}
1201
 
 
1202
 
/*************************** SSH Shell *********************************/
1203
 
 
1204
 
RemminaSSHShell*
1205
 
remmina_ssh_shell_new_from_file (RemminaFile *remminafile)
1206
 
{
1207
 
    RemminaSSHShell *shell;
1208
 
 
1209
 
    shell = g_new0 (RemminaSSHShell, 1);
1210
 
 
1211
 
    remmina_ssh_init_from_file (REMMINA_SSH (shell), remminafile);
1212
 
 
1213
 
    shell->master = -1;
1214
 
    shell->slave = -1;
1215
 
    shell->exec = g_strdup (remmina_file_get_string (remminafile, "exec"));
1216
 
 
1217
 
    return shell;
1218
 
}
1219
 
 
1220
 
RemminaSSHShell*
1221
 
remmina_ssh_shell_new_from_ssh (RemminaSSH *ssh)
1222
 
{
1223
 
    RemminaSSHShell *shell;
1224
 
 
1225
 
    shell = g_new0 (RemminaSSHShell, 1);
1226
 
 
1227
 
    remmina_ssh_init_from_ssh (REMMINA_SSH (shell), ssh);
1228
 
 
1229
 
    shell->master = -1;
1230
 
    shell->slave = -1;
1231
 
 
1232
 
    return shell;
1233
 
}
1234
 
 
1235
 
static gpointer
1236
 
remmina_ssh_shell_thread (gpointer data)
1237
 
{
1238
 
    RemminaSSHShell *shell = (RemminaSSHShell*) data;
1239
 
    fd_set fds;
1240
 
    struct timeval timeout;
1241
 
    ssh_channel channel = NULL;
1242
 
    ssh_channel ch[2], chout[2];
1243
 
    gchar *buf = NULL;
1244
 
    gint buf_len;
1245
 
    gint len;
1246
 
    gint i, ret;
1247
 
 
1248
 
    LOCK_SSH (shell)
1249
 
 
1250
 
    if ((channel = channel_new (REMMINA_SSH (shell)->session)) == NULL ||
1251
 
        channel_open_session (channel))
1252
 
    {
1253
 
        UNLOCK_SSH (shell)
1254
 
        remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to open channel : %s");
1255
 
        if (channel) channel_free (channel);
1256
 
        shell->thread = 0;
1257
 
        return NULL;
1258
 
    }
1259
 
 
1260
 
    channel_request_pty (channel);
1261
 
    if (shell->exec && shell->exec[0])
1262
 
    {
1263
 
        ret = channel_request_exec (channel, shell->exec);
1264
 
    }
1265
 
    else
1266
 
    {
1267
 
        ret = channel_request_shell (channel);
1268
 
    }
1269
 
    if (ret)
1270
 
    {
1271
 
        UNLOCK_SSH (shell)
1272
 
        remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to request shell : %s");
1273
 
        channel_close (channel);
1274
 
        channel_free (channel);
1275
 
        shell->thread = 0;
1276
 
        return NULL;
1277
 
    }
1278
 
 
1279
 
    shell->channel = channel;
1280
 
 
1281
 
    UNLOCK_SSH (shell)
1282
 
 
1283
 
    buf_len = 1000;
1284
 
    buf = g_malloc (buf_len + 1);
1285
 
 
1286
 
    ch[0] = channel;
1287
 
    ch[1] = NULL;
1288
 
 
1289
 
    while (!shell->closed)
1290
 
    {
1291
 
        timeout.tv_sec = 1;
1292
 
        timeout.tv_usec = 0;
1293
 
 
1294
 
        FD_ZERO (&fds);
1295
 
        FD_SET (shell->master, &fds);
1296
 
 
1297
 
        ret = ssh_select (ch, chout, shell->master + 1, &fds, &timeout);
1298
 
        if (ret == SSH_EINTR) continue;
1299
 
        if (ret == -1) break;
1300
 
 
1301
 
        if (FD_ISSET (shell->master, &fds))
1302
 
        {
1303
 
            len = read (shell->master, buf, buf_len);
1304
 
            if (len <= 0) break;
1305
 
            LOCK_SSH (shell)
1306
 
            channel_write (channel, buf, len);
1307
 
            UNLOCK_SSH (shell)
1308
 
        }
1309
 
        for (i = 0; i < 2; i++)
1310
 
        {
1311
 
            LOCK_SSH (shell)
1312
 
            len = channel_poll (channel, i);
1313
 
            UNLOCK_SSH (shell)
1314
 
            if (len == SSH_ERROR || len == SSH_EOF)
1315
 
            {
1316
 
                shell->closed = TRUE;
1317
 
                break;
1318
 
            }
1319
 
            if (len <= 0) continue;
1320
 
            if (len > buf_len)
1321
 
            {
1322
 
                buf_len = len;
1323
 
                buf = (gchar*) g_realloc (buf, buf_len + 1);
1324
 
            }
1325
 
            LOCK_SSH (shell)
1326
 
            len = channel_read_nonblocking (channel, buf, len, i);
1327
 
            UNLOCK_SSH (shell)
1328
 
            if (len <= 0)
1329
 
            {
1330
 
                shell->closed = TRUE;
1331
 
                break;
1332
 
            }
1333
 
            while (len > 0)
1334
 
            {
1335
 
                ret = write (shell->master, buf, len);
1336
 
                if (ret <= 0) break;
1337
 
                len -= ret;
1338
 
            }
1339
 
        }
1340
 
    }
1341
 
 
1342
 
    LOCK_SSH (shell)
1343
 
    shell->channel = NULL;
1344
 
    channel_close (channel);
1345
 
    channel_free (channel);
1346
 
    UNLOCK_SSH (shell)
1347
 
 
1348
 
    g_free (buf);
1349
 
    shell->thread = 0;
1350
 
 
1351
 
    if (shell->exit_callback) shell->exit_callback (shell->user_data);
1352
 
    return NULL;
1353
 
}
1354
 
 
1355
 
gboolean
1356
 
remmina_ssh_shell_open (RemminaSSHShell *shell, RemminaSSHExitFunc exit_callback, gpointer data)
1357
 
{
1358
 
    gchar *slavedevice;
1359
 
    struct termios stermios;
1360
 
 
1361
 
    shell->master = posix_openpt (O_RDWR | O_NOCTTY);
1362
 
    if (shell->master == -1 ||
1363
 
        grantpt (shell->master) == -1 ||
1364
 
        unlockpt (shell->master) == -1 ||
1365
 
        (slavedevice = ptsname (shell->master)) == NULL ||
1366
 
        (shell->slave = open (slavedevice, O_RDWR | O_NOCTTY)) < 0)
1367
 
    {
1368
 
        REMMINA_SSH (shell)->error = g_strdup ("Failed to create pty device.");
1369
 
        return FALSE;
1370
 
    }
1371
 
 
1372
 
    /* These settings works fine with OpenSSH... */
1373
 
    tcgetattr (shell->slave, &stermios);
1374
 
    stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
1375
 
    stermios.c_iflag &= ~(ICRNL);
1376
 
    tcsetattr (shell->slave, TCSANOW, &stermios);
1377
 
 
1378
 
    shell->exit_callback = exit_callback;
1379
 
    shell->user_data = data;
1380
 
 
1381
 
    /* Once the process started, we should always TRUE and assume the pthread will be created always */
1382
 
    pthread_create (&shell->thread, NULL, remmina_ssh_shell_thread, shell);
1383
 
 
1384
 
    return TRUE;
1385
 
}
1386
 
 
1387
 
void
1388
 
remmina_ssh_shell_set_size (RemminaSSHShell *shell, gint columns, gint rows)
1389
 
{
1390
 
    LOCK_SSH (shell)
1391
 
    if (shell->channel)
1392
 
    {
1393
 
        channel_change_pty_size (shell->channel, columns, rows);
1394
 
    }
1395
 
    UNLOCK_SSH (shell)
1396
 
}
1397
 
 
1398
 
void
1399
 
remmina_ssh_shell_free (RemminaSSHShell *shell)
1400
 
{
1401
 
    pthread_t thread = shell->thread;
1402
 
 
1403
 
    shell->exit_callback = NULL;
1404
 
    if (thread)
1405
 
    {
1406
 
        shell->closed = TRUE;
1407
 
        pthread_join (thread, NULL);
1408
 
    }
1409
 
    close (shell->master);
1410
 
    if (shell->exec)
1411
 
    {
1412
 
        g_free (shell->exec);
1413
 
        shell->exec = NULL;
1414
 
    }
1415
 
    /* It's not necessary to close shell->slave since the other end (vte) will close it */;
1416
 
    remmina_ssh_free (REMMINA_SSH (shell));
1417
 
}
1418
 
 
1419
 
#endif /* HAVE_LIBSSH */
1420