void remmina_ssh_tunnel_free (RemminaSSHTunnel* tunnel) { pthread_t thread; thread = tunnel->thread; if (thread != 0) { tunnel->running = FALSE; pthread_cancel (thread); pthread_join (thread, NULL); tunnel->thread = 0; } if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT && tunnel->remotedisplay > 0) { channel_forward_cancel (REMMINA_SSH (tunnel)->session, NULL, 6000 + tunnel->remotedisplay); } if (tunnel->server_sock >= 0) { close (tunnel->server_sock); tunnel->server_sock = -1; } remmina_ssh_tunnel_close_all_channels (tunnel); g_free(tunnel->buffer); g_free(tunnel->channels_out); g_free(tunnel->dest); g_free(tunnel->localdisplay); remmina_ssh_free (REMMINA_SSH (tunnel)); }
gboolean remmina_ssh_tunnel_open (RemminaSSHTunnel* tunnel, const gchar *host, gint port, gint local_port) { gint sock; gint sockopt = 1; struct sockaddr_in sin; tunnel->tunnel_type = REMMINA_SSH_TUNNEL_OPEN; tunnel->dest = g_strdup (host); tunnel->port = port; if (tunnel->port == 0) { REMMINA_SSH (tunnel)->error = g_strdup ("Destination port has not been assigned"); return FALSE; } /* Create the server socket that listens on the local port */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { REMMINA_SSH (tunnel)->error = g_strdup ("Failed to create socket."); return FALSE; } setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof (sockopt)); sin.sin_family = AF_INET; sin.sin_port = htons (local_port); sin.sin_addr.s_addr = inet_addr ("127.0.0.1"); if (bind (sock, (struct sockaddr *) &sin, sizeof(sin))) { REMMINA_SSH (tunnel)->error = g_strdup ("Failed to bind on local port."); close (sock); return FALSE; } if (listen (sock, 1)) { REMMINA_SSH (tunnel)->error = g_strdup ("Failed to listen on local port."); close (sock); return FALSE; } tunnel->server_sock = sock; tunnel->running = TRUE; if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread."); tunnel->thread = 0; return FALSE; } return TRUE; }
RemminaSSHTunnel* remmina_ssh_tunnel_new_from_file (RemminaFile *remminafile) { RemminaSSHTunnel *tunnel; tunnel = g_new (RemminaSSHTunnel, 1); remmina_ssh_init_from_file (REMMINA_SSH (tunnel), remminafile); tunnel->tunnel_type = -1; tunnel->channels = NULL; tunnel->sockets = NULL; 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; tunnel->dest = NULL; tunnel->port = 0; tunnel->buffer = NULL; tunnel->buffer_len = 0; tunnel->channels_out = NULL; tunnel->remotedisplay = 0; tunnel->localdisplay = NULL; tunnel->init_func = NULL; tunnel->connect_func = NULL; tunnel->disconnect_func = NULL; tunnel->callback_data = NULL; return tunnel; }
gboolean remmina_sftp_open (RemminaSFTP *sftp) { sftp->sftp_sess = sftp_new (sftp->ssh.session); if (!sftp->sftp_sess) { remmina_ssh_set_error (REMMINA_SSH (sftp), _("Failed to create sftp session: %s")); return FALSE; } if (sftp_init (sftp->sftp_sess)) { remmina_ssh_set_error (REMMINA_SSH (sftp), _("Failed to initialize sftp session: %s")); return FALSE; } return TRUE; }
void remmina_sftp_free (RemminaSFTP *sftp) { if (sftp->sftp_sess) { sftp_free (sftp->sftp_sess); sftp->sftp_sess = NULL; } remmina_ssh_free (REMMINA_SSH (sftp)); }
RemminaSFTP* remmina_sftp_new_from_ssh (RemminaSSH *ssh) { RemminaSFTP *sftp; sftp = g_new (RemminaSFTP, 1); remmina_ssh_init_from_ssh (REMMINA_SSH (sftp), ssh); sftp->sftp_sess = NULL; return sftp; }
RemminaSFTP* remmina_sftp_new_from_file (RemminaFile *remminafile) { RemminaSFTP *sftp; sftp = g_new (RemminaSFTP, 1); remmina_ssh_init_from_file (REMMINA_SSH (sftp), remminafile); sftp->sftp_sess = NULL; return sftp; }
RemminaSSHShell* remmina_ssh_shell_new_from_ssh (RemminaSSH *ssh) { RemminaSSHShell *shell; shell = g_new0 (RemminaSSHShell, 1); remmina_ssh_init_from_ssh (REMMINA_SSH (shell), ssh); shell->master = -1; shell->slave = -1; return shell; }
RemminaSSHShell* remmina_ssh_shell_new_from_file (RemminaFile *remminafile) { RemminaSSHShell *shell; shell = g_new0 (RemminaSSHShell, 1); remmina_ssh_init_from_file (REMMINA_SSH (shell), remminafile); shell->master = -1; shell->slave = -1; shell->exec = g_strdup (remmina_file_get_string (remminafile, "exec")); return shell; }
gboolean remmina_ssh_tunnel_xport (RemminaSSHTunnel *tunnel, gboolean bindlocalhost) { tunnel->tunnel_type = REMMINA_SSH_TUNNEL_XPORT; tunnel->bindlocalhost = bindlocalhost; tunnel->running = TRUE; if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread."); tunnel->thread = 0; return FALSE; } return TRUE; }
gboolean remmina_ssh_tunnel_x11 (RemminaSSHTunnel *tunnel, const gchar *cmd) { tunnel->tunnel_type = REMMINA_SSH_TUNNEL_X11; tunnel->dest = g_strdup (cmd); tunnel->running = TRUE; if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread."); tunnel->thread = 0; return FALSE; } return TRUE; }
gboolean remmina_ssh_tunnel_reverse (RemminaSSHTunnel *tunnel, gint port, gint local_port) { tunnel->tunnel_type = REMMINA_SSH_TUNNEL_REVERSE; tunnel->port = port; tunnel->localport = local_port; tunnel->running = TRUE; if (pthread_create (&tunnel->thread, NULL, remmina_ssh_tunnel_main_thread, tunnel)) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Failed to initialize pthread."); tunnel->thread = 0; return FALSE; } return TRUE; }
static gpointer remmina_ssh_tunnel_main_thread_proc (gpointer data) { RemminaSSHTunnel *tunnel = (RemminaSSHTunnel*) data; gchar *ptr; ssize_t len = 0, lenw = 0; fd_set set; struct timeval timeout; GTimeVal t1, t2; glong diff; ssh_channel channel = NULL; gboolean first = TRUE; gboolean disconnected; gint sock; gint maxfd; gint i; gint ret; struct sockaddr_in sin; g_get_current_time (&t1); t2 = t1; switch (tunnel->tunnel_type) { case REMMINA_SSH_TUNNEL_OPEN: /* Accept a local connection */ sock = accept (tunnel->server_sock, NULL, NULL); if (sock < 0) { REMMINA_SSH (tunnel)->error = g_strdup ("Failed to accept local socket"); tunnel->thread = 0; return NULL; } if ((channel = channel_new (tunnel->ssh.session)) == NULL) { close (sock); remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to createt channel : %s"); tunnel->thread = 0; return NULL; } /* Request the SSH server to connect to the destination */ if (channel_open_forward (channel, tunnel->dest, tunnel->port, "127.0.0.1", 0) != SSH_OK) { close (sock); channel_close (channel); channel_free (channel); remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to connect to the SSH tunnel destination: %s")); tunnel->thread = 0; return NULL; } remmina_ssh_tunnel_add_channel (tunnel, channel, sock); break; case REMMINA_SSH_TUNNEL_X11: 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 (tunnel->localdisplay, &ptr)) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "%s", ptr); g_free(ptr); tunnel->thread = 0; return NULL; } 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); remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to open channel : %s"); tunnel->thread = 0; return NULL; } g_free(ptr); if (channel_request_exec (tunnel->x11_channel, tunnel->dest)) { 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; } 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; } break; case REMMINA_SSH_TUNNEL_XPORT: /* 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)) { continue; } else { tunnel->remotedisplay = i; break; } } if (tunnel->remotedisplay < 1) { remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s")); if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } 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; } break; case REMMINA_SSH_TUNNEL_REVERSE: if (channel_forward_listen (REMMINA_SSH (tunnel)->session, NULL, tunnel->port, NULL)) { remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s")); if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } 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; } break; } tunnel->buffer_len = 10240; tunnel->buffer = g_malloc (tunnel->buffer_len); /* Start the tunnel data transmittion */ while (tunnel->running) { if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT || tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11 || tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) { if (first) { first = FALSE; /* Wait for a period of time for the first incoming connection */ 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.")); if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } if (tunnel->connect_func) { (*tunnel->connect_func) (tunnel, tunnel->callback_data); } if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) { /* For reverse tunnel, we only need one connection. */ channel_forward_cancel (REMMINA_SSH (tunnel)->session, NULL, tunnel->port); } } else if (tunnel->tunnel_type != REMMINA_SSH_TUNNEL_REVERSE) { /* Poll once per some period of time if no incoming connections. * Don't try to poll continuously as it will significantly slow down the loop */ g_get_current_time (&t1); diff = (t1.tv_sec - t2.tv_sec) * 10 + (t1.tv_usec - t2.tv_usec) / 100000; if (diff > 1) { 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; } } } if (channel) { if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) { sin.sin_family = AF_INET; sin.sin_port = htons (tunnel->localport); sin.sin_addr.s_addr = inet_addr ("127.0.0.1"); sock = socket (AF_INET, SOCK_STREAM, 0); if (connect (sock, (struct sockaddr *) &sin, sizeof (sin)) < 0) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Cannot connect to local port %i.", tunnel->localport); close (sock); sock = -1; } } else { sock = remmina_public_open_xdisplay (tunnel->localdisplay); } if (sock >= 0) { remmina_ssh_tunnel_add_channel (tunnel, channel, sock); } else { /* Failed to create unix socket. Will this happen? */ channel_close (channel); channel_free (channel); } channel = NULL; } } if (tunnel->num_channels <= 0) { /* No more connections. We should quit */ break; } timeout.tv_sec = 0; timeout.tv_usec = 200000; FD_ZERO (&set); maxfd = 0; for (i = 0; i < tunnel->num_channels; i++) { if (tunnel->sockets[i] > maxfd) { maxfd = tunnel->sockets[i]; } FD_SET (tunnel->sockets[i], &set); } ret = ssh_select (tunnel->channels, tunnel->channels_out, maxfd + 1, &set, &timeout); if (!tunnel->running) break; if (ret == SSH_EINTR) continue; if (ret == -1) break; i = 0; while (tunnel->running && i < tunnel->num_channels) { disconnected = FALSE; if (FD_ISSET (tunnel->sockets[i], &set)) { while (!disconnected && (len = read (tunnel->sockets[i], tunnel->buffer, tunnel->buffer_len)) > 0) { for (ptr = tunnel->buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw) { lenw = channel_write (tunnel->channels[i], (char*) ptr, len); if (lenw <= 0) { disconnected = TRUE; break; } } } if (len == 0) disconnected = TRUE; } if (disconnected) { remmina_ssh_tunnel_remove_channel (tunnel, i); continue; } i++; } if (!tunnel->running) break; i = 0; while (tunnel->running && i < tunnel->num_channels) { disconnected = FALSE; if (!tunnel->socketbuffers[i]) { len = channel_poll (tunnel->channels[i], 0); if (len == SSH_ERROR || len == SSH_EOF) { disconnected = TRUE; } else if (len > 0) { tunnel->socketbuffers[i] = remmina_ssh_tunnel_buffer_new (len); len = channel_read_nonblocking (tunnel->channels[i], tunnel->socketbuffers[i]->data, len, 0); if (len <= 0) { disconnected = TRUE; } else { tunnel->socketbuffers[i]->len = len; } } } if (!disconnected && tunnel->socketbuffers[i]) { for (lenw = 0; tunnel->socketbuffers[i]->len > 0; tunnel->socketbuffers[i]->len -= lenw, tunnel->socketbuffers[i]->ptr += lenw) { lenw = write (tunnel->sockets[i], tunnel->socketbuffers[i]->ptr, tunnel->socketbuffers[i]->len); if (lenw == -1 && errno == EAGAIN && tunnel->running) { /* Sometimes we cannot write to a socket (always EAGAIN), probably because it's internal * buffer is full. We need read the pending bytes from the socket first. so here we simply * break, leave the buffer there, and continue with other data */ break; } if (lenw <= 0) { disconnected = TRUE; break; } } if (tunnel->socketbuffers[i]->len <= 0) { remmina_ssh_tunnel_buffer_free (tunnel->socketbuffers[i]); tunnel->socketbuffers[i] = NULL; } } if (disconnected) { remmina_ssh_tunnel_remove_channel (tunnel, i); continue; } i++; } } remmina_ssh_tunnel_close_all_channels (tunnel); return NULL; }
static gpointer remmina_ssh_shell_thread (gpointer data) { RemminaSSHShell *shell = (RemminaSSHShell*) data; fd_set fds; struct timeval timeout; ssh_channel channel = NULL; ssh_channel ch[2], chout[2]; gchar *buf = NULL; gint buf_len; gint len; gint i, ret; LOCK_SSH (shell) if ((channel = channel_new (REMMINA_SSH (shell)->session)) == NULL || channel_open_session (channel)) { UNLOCK_SSH (shell) remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to open channel : %s"); if (channel) channel_free (channel); shell->thread = 0; return NULL; } channel_request_pty (channel); if (shell->exec && shell->exec[0]) { ret = channel_request_exec (channel, shell->exec); } else { ret = channel_request_shell (channel); } if (ret) { UNLOCK_SSH (shell) remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to request shell : %s"); channel_close (channel); channel_free (channel); shell->thread = 0; return NULL; } shell->channel = channel; UNLOCK_SSH (shell) buf_len = 1000; buf = g_malloc (buf_len + 1); ch[0] = channel; ch[1] = NULL; while (!shell->closed) { timeout.tv_sec = 1; timeout.tv_usec = 0; FD_ZERO (&fds); FD_SET (shell->master, &fds); ret = ssh_select (ch, chout, shell->master + 1, &fds, &timeout); if (ret == SSH_EINTR) continue; if (ret == -1) break; if (FD_ISSET (shell->master, &fds)) { len = read (shell->master, buf, buf_len); if (len <= 0) break; LOCK_SSH (shell) channel_write (channel, buf, len); UNLOCK_SSH (shell) } for (i = 0; i < 2; i++) { LOCK_SSH (shell) len = channel_poll (channel, i); UNLOCK_SSH (shell) if (len == SSH_ERROR || len == SSH_EOF) { shell->closed = TRUE; break; } if (len <= 0) continue; if (len > buf_len) { buf_len = len; buf = (gchar*) g_realloc (buf, buf_len + 1); } LOCK_SSH (shell) len = channel_read_nonblocking (channel, buf, len, i); UNLOCK_SSH (shell) if (len <= 0) { shell->closed = TRUE; break; } while (len > 0) { ret = write (shell->master, buf, len); if (ret <= 0) break; len -= ret; } } }
fclose (local_file); local_file = g_fopen (local_path, "wb"); if (!local_file) { remmina_sftp_client_thread_set_error (client, task, _("Error creating file %s."), local_path); return FALSE; } size = 0; break; case GTK_RESPONSE_APPLY: break; } } tmp = remmina_ssh_unconvert (REMMINA_SSH (sftp), remote_path); remote_file = sftp_open (sftp->sftp_sess, tmp, O_RDONLY, 0); g_free(tmp); if (!remote_file) { fclose (local_file); remmina_sftp_client_thread_set_error (client, task, _("Error opening file %s on server. %s"), remote_path, ssh_get_error (REMMINA_SSH (client->sftp)->session)); return FALSE; } if (size > 0) { if (sftp_seek64 (remote_file, size) < 0) {
static gpointer remmina_plugin_sftp_main_thread (gpointer data) { RemminaProtocolWidget *gp = (RemminaProtocolWidget*) data; RemminaPluginSftpData *gpdata; RemminaFile *remminafile; RemminaSSH *ssh; RemminaSFTP *sftp = NULL; gboolean cont = FALSE; gint ret; const gchar *cs; pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); CANCEL_ASYNC gpdata = (RemminaPluginSftpData*) g_object_get_data (G_OBJECT(gp), "plugin-data"); 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)) && remmina_ssh_auth (REMMINA_SSH (sftp), NULL) > 0 && remmina_sftp_open (sftp)) { cont = TRUE; } } else { /* New SFTP connection */ remminafile = remmina_plugin_service->protocol_plugin_get_file (gp); remmina_plugin_service->file_set_string (remminafile, "ssh_server", remmina_plugin_service->file_get_string (remminafile, "server")); sftp = remmina_sftp_new_from_file (remminafile); while (1) { if (!remmina_ssh_init_session (REMMINA_SSH (sftp))) { remmina_plugin_service->protocol_plugin_set_error (gp, "%s", REMMINA_SSH (sftp)->error); break; } ret = remmina_ssh_auth_gui (REMMINA_SSH (sftp), REMMINA_INIT_DIALOG (remmina_protocol_widget_get_init_dialog (gp)), TRUE); if (ret == 0) { remmina_plugin_service->protocol_plugin_set_error (gp, "%s", REMMINA_SSH (sftp)->error); } if (ret <= 0) break; if (!remmina_sftp_open (sftp)) { remmina_plugin_service->protocol_plugin_set_error (gp, "%s", REMMINA_SSH (sftp)->error); break; } cs = remmina_plugin_service->file_get_string (remminafile, "execpath"); if (cs && cs[0]) { remmina_ftp_client_set_dir (REMMINA_FTP_CLIENT (gpdata->client), cs); } cont = TRUE; break; } } if (!cont) { if (sftp) remmina_sftp_free (sftp); IDLE_ADD ((GSourceFunc) remmina_plugin_service->protocol_plugin_close_connection, gp); return NULL; } remmina_sftp_client_open (REMMINA_SFTP_CLIENT (gpdata->client), sftp); /* RemminaSFTPClient owns the object, we just take the reference */ gpdata->sftp = sftp; remmina_plugin_service->protocol_plugin_emit_signal (gp, "connect"); gpdata->thread = 0; return NULL; }