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; } } }
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_nx_session_tunnel_main_thread(gpointer data) { RemminaNXSession *nx = (RemminaNXSession*) data; gchar *ptr; ssize_t len = 0, lenw = 0; fd_set set; struct timeval timeout; ssh_channel channels[2]; ssh_channel channels_out[2]; gint sock; gint ret; gchar buffer[10240]; gchar socketbuffer[10240]; gchar *socketbuffer_ptr = NULL; gint socketbuffer_len = 0; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* Accept a local connection */ sock = accept(nx->server_sock, NULL, NULL); if (sock < 0) { remmina_nx_session_set_application_error(nx, "Failed to accept local socket"); nx->thread = 0; return NULL; } close(nx->server_sock); nx->server_sock = -1; channels[0] = nx->channel; channels[1] = NULL; /* Start the tunnel data transmittion */ while (nx->running) { timeout.tv_sec = 1; timeout.tv_usec = 0; FD_ZERO(&set); FD_SET(sock, &set); ret = ssh_select(channels, channels_out, sock + 1, &set, &timeout); if (!nx->running) break; if (ret == SSH_EINTR) continue; if (ret == -1) break; if (FD_ISSET(sock, &set)) { len = read(sock, buffer, sizeof(buffer)); if (len == 0) nx->running = FALSE; else if (len > 0) { for (ptr = buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw) { ssh_set_fd_towrite(nx->session); lenw = channel_write(channels[0], (char*) ptr, len); if (lenw <= 0) { nx->running = FALSE; break; } } } } if (!nx->running) break; if (channels_out[0] && socketbuffer_len <= 0) { len = channel_read_nonblocking(channels_out[0], socketbuffer, sizeof(socketbuffer), 0); if (len == SSH_ERROR || len == SSH_EOF) { nx->running = FALSE; break; } else if (len > 0) { socketbuffer_ptr = socketbuffer; socketbuffer_len = len; } else { /* Clean up the stderr buffer in case FreeNX send something there */ len = channel_read_nonblocking(channels_out[0], buffer, sizeof(buffer), 1); } } if (nx->running && socketbuffer_len > 0) { for (lenw = 0; socketbuffer_len > 0; socketbuffer_len -= lenw, socketbuffer_ptr += lenw) { lenw = write(sock, socketbuffer_ptr, socketbuffer_len); if (lenw == -1 && errno == EAGAIN && nx->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) { nx->running = FALSE; break; } } } } nx->thread = 0; return NULL; }