static void remmina_nx_session_send_command(RemminaNXSession *nx, const gchar *cmdfmt, ...) { va_list args; gchar *cmd; va_start (args, cmdfmt); cmd = g_strdup_vprintf (cmdfmt, args); channel_write (nx->channel, cmd, strlen (cmd)); g_free(cmd); ssh_set_fd_towrite (nx->session); channel_write (nx->channel, "\n", 1); }
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; }
/** * @internal * * @brief A function to be called each time a step has been done in the * connection. */ static void ssh_client_connection_callback(ssh_session session){ int ssh1,ssh2; switch(session->session_state){ case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_CONNECTING: break; case SSH_SESSION_STATE_SOCKET_CONNECTED: /* If SSHv1 is disabled, we can send the banner immedietly */ if (session->opts.ssh1 == 0) { ssh_set_fd_towrite(session); ssh_send_banner(session, 0); } break; case SSH_SESSION_STATE_BANNER_RECEIVED: if (session->serverbanner == NULL) { goto error; } set_status(session, 0.4f); SSH_LOG(SSH_LOG_RARE, "SSH server banner: %s", session->serverbanner); /* Here we analyze the different protocols the server allows. */ if (ssh_analyze_banner(session, 0, &ssh1, &ssh2) < 0) { goto error; } /* Here we decide which version of the protocol to use. */ if (ssh2 && session->opts.ssh2) { session->version = 2; #ifdef WITH_SSH1 } else if(ssh1 && session->opts.ssh1) { session->version = 1; #endif } else if(ssh1 && !session->opts.ssh1){ #ifdef WITH_SSH1 ssh_set_error(session, SSH_FATAL, "SSH-1 protocol not available (configure session to allow SSH-1)"); goto error; #else ssh_set_error(session, SSH_FATAL, "SSH-1 protocol not available (libssh compiled without SSH-1 support)"); goto error; #endif } else { ssh_set_error(session, SSH_FATAL, "No version of SSH protocol usable (banner: %s)", session->serverbanner); goto error; } /* from now, the packet layer is handling incoming packets */ if (session->version == 2) { ssh_packet_register_socket_callback(session, session->socket); } #ifdef WITH_SSH1 else session->socket_callbacks.data=ssh_packet_socket_callback1; #endif ssh_packet_set_default_callbacks(session); session->session_state=SSH_SESSION_STATE_INITIAL_KEX; if (session->opts.ssh1 == 1) { ssh_send_banner(session, 0); } set_status(session, 0.5f); break; case SSH_SESSION_STATE_INITIAL_KEX: /* TODO: This state should disappear in favor of get_key handle */ #ifdef WITH_SSH1 if(session->version==1){ if (ssh_get_kex1(session) < 0) goto error; set_status(session,0.6f); session->connected = 1; break; } #endif break; case SSH_SESSION_STATE_KEXINIT_RECEIVED: set_status(session,0.6f); ssh_list_kex(&session->next_crypto->server_kex); if (ssh_set_client_kex(session) < 0) { goto error; } if (ssh_kex_select_methods(session) == SSH_ERROR) goto error; if (ssh_send_kex(session, 0) < 0) { goto error; } set_status(session,0.8f); session->session_state=SSH_SESSION_STATE_DH; if (dh_handshake(session) == SSH_ERROR) { goto error; } /* FALL THROUGH */ case SSH_SESSION_STATE_DH: if(session->dh_handshake_state==DH_STATE_FINISHED){ set_status(session,1.0f); session->connected = 1; if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) session->session_state = SSH_SESSION_STATE_AUTHENTICATED; else session->session_state=SSH_SESSION_STATE_AUTHENTICATING; } break; case SSH_SESSION_STATE_AUTHENTICATING: break; case SSH_SESSION_STATE_ERROR: goto error; default: ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); } return; error: ssh_socket_close(session->socket); session->alive = 0; session->session_state=SSH_SESSION_STATE_ERROR; }
/** * @internal * * @brief A function to be called each time a step has been done in the * connection. */ static void ssh_client_connection_callback(ssh_session session) { int rc; switch(session->session_state) { case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_CONNECTING: break; case SSH_SESSION_STATE_SOCKET_CONNECTED: ssh_set_fd_towrite(session); ssh_send_banner(session, 0); break; case SSH_SESSION_STATE_BANNER_RECEIVED: if (session->serverbanner == NULL) { goto error; } set_status(session, 0.4f); SSH_LOG(SSH_LOG_RARE, "SSH server banner: %s", session->serverbanner); /* Here we analyze the different protocols the server allows. */ rc = ssh_analyze_banner(session, 0); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "No version of SSH protocol usable (banner: %s)", session->serverbanner); goto error; } ssh_packet_register_socket_callback(session, session->socket); ssh_packet_set_default_callbacks(session); session->session_state = SSH_SESSION_STATE_INITIAL_KEX; rc = ssh_set_client_kex(session); if (rc != SSH_OK) { goto error; } rc = ssh_send_kex(session, 0); if (rc < 0) { goto error; } set_status(session, 0.5f); break; case SSH_SESSION_STATE_INITIAL_KEX: /* TODO: This state should disappear in favor of get_key handle */ break; case SSH_SESSION_STATE_KEXINIT_RECEIVED: set_status(session,0.6f); ssh_list_kex(&session->next_crypto->server_kex); if (session->next_crypto->client_kex.methods[0] == NULL) { /* in rekeying state if next_crypto client_kex is empty */ rc = ssh_set_client_kex(session); if (rc != SSH_OK) { goto error; } rc = ssh_send_kex(session, 0); if (rc < 0) { goto error; } } if (ssh_kex_select_methods(session) == SSH_ERROR) goto error; set_status(session,0.8f); session->session_state=SSH_SESSION_STATE_DH; if (dh_handshake(session) == SSH_ERROR) { goto error; } /* FALL THROUGH */ case SSH_SESSION_STATE_DH: if(session->dh_handshake_state==DH_STATE_FINISHED){ set_status(session,1.0f); session->connected = 1; if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) session->session_state = SSH_SESSION_STATE_AUTHENTICATED; else session->session_state=SSH_SESSION_STATE_AUTHENTICATING; } break; case SSH_SESSION_STATE_AUTHENTICATING: break; case SSH_SESSION_STATE_ERROR: goto error; default: ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); } return; error: ssh_socket_close(session->socket); session->alive = 0; session->session_state=SSH_SESSION_STATE_ERROR; }