From be9c56f9a3b835a906dd5fdd887f3c6af67d94a6 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 21 Jul 2014 11:15:55 -0700 Subject: [PATCH] GUAC-779: Synchronize access to shared libssh2 handles. --- src/protocols/ssh/client.h | 5 +++++ src/protocols/ssh/guac_handlers.c | 5 ++++- src/protocols/ssh/ssh_client.c | 21 +++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/protocols/ssh/client.h b/src/protocols/ssh/client.h index 9675860c..202bff66 100644 --- a/src/protocols/ssh/client.h +++ b/src/protocols/ssh/client.h @@ -137,6 +137,11 @@ typedef struct ssh_guac_client_data { */ LIBSSH2_CHANNEL* term_channel; + /** + * Lock dictating access to the SSH terminal channel. + */ + pthread_mutex_t term_channel_lock; + /** * The terminal which will render all output from the SSH client. */ diff --git a/src/protocols/ssh/guac_handlers.c b/src/protocols/ssh/guac_handlers.c index efe74e17..28e86213 100644 --- a/src/protocols/ssh/guac_handlers.c +++ b/src/protocols/ssh/guac_handlers.c @@ -74,9 +74,12 @@ int ssh_guac_client_size_handler(guac_client* client, int width, int height) { guac_terminal_resize(terminal, width, height); /* Update SSH pty size if connected */ - if (guac_client_data->term_channel != NULL) + if (guac_client_data->term_channel != NULL) { + pthread_mutex_lock(&(guac_client_data->term_channel_lock)); libssh2_channel_request_pty_size(guac_client_data->term_channel, terminal->term_width, terminal->term_height); + pthread_mutex_unlock(&(guac_client_data->term_channel_lock)); + } return 0; } diff --git a/src/protocols/ssh/ssh_client.c b/src/protocols/ssh/ssh_client.c index 946069ab..9f082e7d 100644 --- a/src/protocols/ssh/ssh_client.c +++ b/src/protocols/ssh/ssh_client.c @@ -64,8 +64,11 @@ void* ssh_input_thread(void* data) { int bytes_read; /* Write all data read */ - while ((bytes_read = guac_terminal_read_stdin(client_data->term, buffer, sizeof(buffer))) > 0) + while ((bytes_read = guac_terminal_read_stdin(client_data->term, buffer, sizeof(buffer))) > 0) { + pthread_mutex_lock(&(client_data->term_channel_lock)); libssh2_channel_write(client_data->term_channel, buffer, bytes_read); + pthread_mutex_unlock(&(client_data->term_channel_lock)); + } return NULL; @@ -474,6 +477,8 @@ void* ssh_client_thread(void* data) { /* Logged in */ guac_client_log_info(client, "SSH connection successful."); + pthread_mutex_init(&client_data->term_channel_lock, NULL); + /* Start input thread */ if (pthread_create(&(input_thread), NULL, ssh_input_thread, (void*) client)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread"); @@ -485,15 +490,25 @@ void* ssh_client_thread(void* data) { /* While data available, write to terminal */ bytes_read = 0; - while (!libssh2_channel_eof(client_data->term_channel)) { + for (;;) { /* Track total amount of data read */ int total_read = 0; + pthread_mutex_lock(&(client_data->term_channel_lock)); + + /* Stop reading at EOF */ + if (libssh2_channel_eof(client_data->term_channel)) { + pthread_mutex_unlock(&(client_data->term_channel_lock)); + break; + } + /* Read terminal data */ bytes_read = libssh2_channel_read(client_data->term_channel, buffer, sizeof(buffer)); + pthread_mutex_unlock(&(client_data->term_channel_lock)); + /* Attempt to write data received. Exit on failure. */ if (bytes_read > 0) { int written = guac_terminal_write_stdout(client_data->term, buffer, bytes_read); @@ -540,6 +555,8 @@ void* ssh_client_thread(void* data) { pthread_join(input_thread, NULL); __openssl_free_locks(CRYPTO_num_locks()); + pthread_mutex_destroy(&client_data->term_channel_lock); + guac_client_log_info(client, "SSH connection ended."); return NULL;