diff --git a/src/common/clipboard.c b/src/common/clipboard.c index 69233138f..178e6e939 100644 --- a/src/common/clipboard.c +++ b/src/common/clipboard.c @@ -30,14 +30,14 @@ #include #include -guac_common_clipboard* guac_common_clipboard_alloc() { +guac_common_clipboard* guac_common_clipboard_alloc(int buffer_size) { guac_common_clipboard* clipboard = guac_mem_alloc(sizeof(guac_common_clipboard)); /* Init clipboard */ clipboard->mimetype[0] = '\0'; - clipboard->buffer = guac_mem_alloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH); - clipboard->available = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; + clipboard->buffer = guac_mem_alloc(buffer_size); + clipboard->available = buffer_size; clipboard->length = 0; pthread_mutex_init(&(clipboard->lock), NULL); diff --git a/src/common/common/clipboard.h b/src/common/common/clipboard.h index 308c66744..88071bab8 100644 --- a/src/common/common/clipboard.h +++ b/src/common/common/clipboard.h @@ -32,9 +32,16 @@ #define GUAC_COMMON_CLIPBOARD_BLOCK_SIZE 4096 /** - * The maximum number of bytes to allow within the clipboard. + * The minimum clipboard buffer size in bytes. + * This is the original hardcoded clipboard buffer size. */ -#define GUAC_COMMON_CLIPBOARD_MAX_LENGTH 262144 +#define GUAC_COMMON_CLIPBOARD_MIN_LENGTH 262144 + +/** + * The maximum clipboard buffer size in bytes. + * This should be enough for a raw 4K picture and even more. + */ +#define GUAC_COMMON_CLIPBOARD_MAX_LENGTH 52428800 /** * Generic clipboard structure. @@ -72,13 +79,17 @@ typedef struct guac_common_clipboard { /** * Creates a new clipboard. + * + * @param buffer_size + * The buffer size in bytes. */ -guac_common_clipboard* guac_common_clipboard_alloc(); +guac_common_clipboard* guac_common_clipboard_alloc(int buffer_size); /** * Frees the given clipboard. * - * @param clipboard The clipboard to free. + * @param clipboard + * The clipboard to free. */ void guac_common_clipboard_free(guac_common_clipboard* clipboard); @@ -86,16 +97,22 @@ void guac_common_clipboard_free(guac_common_clipboard* clipboard); * Sends the contents of the clipboard along the given client, splitting * the contents as necessary. * - * @param clipboard The clipboard whose contents should be sent. - * @param client The client to send the clipboard contents on. + * @param clipboard + * The clipboard whose contents should be sent. + * + * @param client + * The client to send the clipboard contents on. */ void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client); /** * Clears the clipboard contents and assigns a new mimetype for future data. * - * @param clipboard The clipboard to reset. - * @param mimetype The mimetype of future data. + * @param clipboard + * The clipboard to reset. + * + * @param mimetype + * The mimetype of future data. */ void guac_common_clipboard_reset(guac_common_clipboard* clipboard, const char* mimetype); @@ -104,9 +121,14 @@ void guac_common_clipboard_reset(guac_common_clipboard* clipboard, const char* m * match the mimetype chosen for the clipboard data by * guac_common_clipboard_reset(). * - * @param clipboard The clipboard to append data to. - * @param data The data to append. - * @param length The number of bytes to append from the data given. + * @param clipboard + * The clipboard to append data to. + * + * @param data + * The data to append. + * + * @param length + * The number of bytes to append from the data given. */ void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char* data, int length); diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c index a4ce74a0e..7eef33b16 100644 --- a/src/protocols/kubernetes/kubernetes.c +++ b/src/protocols/kubernetes/kubernetes.c @@ -246,6 +246,7 @@ void* guac_kubernetes_client_thread(void* data) { settings->width, settings->height, settings->resolution); /* Set optional parameters */ + options->clipboard_buffer_size = settings->clipboard_buffer_size; options->disable_copy = settings->disable_copy; options->max_scrollback = settings->max_scrollback; options->font_name = settings->font_name; diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c index 698fcc1ed..cc5cf446f 100644 --- a/src/protocols/kubernetes/settings.c +++ b/src/protocols/kubernetes/settings.c @@ -56,6 +56,7 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = { "read-only", "backspace", "scrollback", + "clipboard-buffer-size", "disable-copy", "disable-paste", NULL @@ -241,6 +242,11 @@ enum KUBERNETES_ARGS_IDX { */ IDX_SCROLLBACK, + /** + * The maximum number of bytes to allow within the clipboard. + */ + IDX_CLIPBOARD_BUFFER_SIZE, + /** * Whether outbound clipboard access should be blocked. If set to "true", * it will not be possible to copy data from the terminal to the client @@ -418,6 +424,27 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user, guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv, IDX_BACKSPACE, GUAC_TERMINAL_DEFAULT_BACKSPACE); + /* Set the maximum number of bytes to allow within the clipboard. */ + settings->clipboard_buffer_size = + guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv, + IDX_CLIPBOARD_BUFFER_SIZE, 0); + + /* Use default clipboard buffer size if given one is invalid. */ + if (settings->clipboard_buffer_size < GUAC_COMMON_CLIPBOARD_MIN_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MIN_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default minimum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + else if (settings->clipboard_buffer_size > GUAC_COMMON_CLIPBOARD_MAX_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default maximum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + /* Parse clipboard copy disable flag */ settings->disable_copy = guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv, diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h index 468029c93..2222c0a1d 100644 --- a/src/protocols/kubernetes/settings.h +++ b/src/protocols/kubernetes/settings.h @@ -160,6 +160,11 @@ typedef struct guac_kubernetes_settings { */ int resolution; + /** + * The maximum number of bytes to allow within the clipboard. + */ + int clipboard_buffer_size; + /** * Whether outbound clipboard access should be blocked. If set, it will not * be possible to copy data from the terminal to the client using the diff --git a/src/protocols/rdp/channels/cliprdr.c b/src/protocols/rdp/channels/cliprdr.c index 34bacf3ba..a93bf8c15 100644 --- a/src/protocols/rdp/channels/cliprdr.c +++ b/src/protocols/rdp/channels/cliprdr.c @@ -371,7 +371,9 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, guac_iconv_write* remote_writer; const char* input = clipboard->clipboard->buffer; - char* output = guac_mem_alloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH); + + int output_buf_size = clipboard->clipboard->available; + char* output = guac_mem_alloc(output_buf_size); /* Map requested clipboard format to a guac_iconv writer */ switch (format_data_request->requestedFormatId) { @@ -402,7 +404,7 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, BYTE* start = (BYTE*) output; guac_iconv_read* local_reader = settings->normalize_clipboard ? GUAC_READ_UTF8_NORMALIZED : GUAC_READ_UTF8; guac_iconv(local_reader, &input, clipboard->clipboard->length, - remote_writer, &output, GUAC_COMMON_CLIPBOARD_MAX_LENGTH); + remote_writer, &output, output_buf_size); CLIPRDR_FORMAT_DATA_RESPONSE data_response = { .requestedFormatData = (BYTE*) start, @@ -470,7 +472,8 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr, return CHANNEL_RC_OK; } - char received_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH]; + int output_buf_size = clipboard->clipboard->available; + char* received_data = guac_mem_alloc(output_buf_size); guac_iconv_read* remote_reader; const char* input = (char*) format_data_response->requestedFormatData; @@ -498,6 +501,7 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr, default: guac_client_log(client, GUAC_LOG_DEBUG, "Requested clipboard data " "in unsupported format (0x%X).", clipboard->requested_format); + guac_mem_free(received_data); return CHANNEL_RC_OK; } @@ -512,13 +516,15 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr, /* Convert, store, and forward the clipboard data received from RDP * server */ if (guac_iconv(remote_reader, &input, data_len, - GUAC_WRITE_UTF8, &output, sizeof(received_data))) { - int length = strnlen(received_data, sizeof(received_data)); + GUAC_WRITE_UTF8, &output, output_buf_size)) { + int length = strnlen(received_data, output_buf_size); guac_common_clipboard_reset(clipboard->clipboard, "text/plain"); guac_common_clipboard_append(clipboard->clipboard, received_data, length); guac_common_clipboard_send(clipboard->clipboard, client); } + guac_mem_free(received_data); + return CHANNEL_RC_OK; } @@ -618,12 +624,12 @@ static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context, } -guac_rdp_clipboard* guac_rdp_clipboard_alloc(guac_client* client) { +guac_rdp_clipboard* guac_rdp_clipboard_alloc(guac_client* client, int buffer_size) { /* Allocate clipboard and underlying storage */ guac_rdp_clipboard* clipboard = guac_mem_zalloc(sizeof(guac_rdp_clipboard)); clipboard->client = client; - clipboard->clipboard = guac_common_clipboard_alloc(); + clipboard->clipboard = guac_common_clipboard_alloc(buffer_size); clipboard->requested_format = CF_TEXT; return clipboard; diff --git a/src/protocols/rdp/channels/cliprdr.h b/src/protocols/rdp/channels/cliprdr.h index 4c920bfbf..d2d4e26f2 100644 --- a/src/protocols/rdp/channels/cliprdr.h +++ b/src/protocols/rdp/channels/cliprdr.h @@ -71,11 +71,14 @@ typedef struct guac_rdp_clipboard { * The guac_client associated with the Guacamole side of the RDP * connection. * + * @param buffer_size + * The buffer size in bytes. + * * @return * A newly-allocated instance of guac_rdp_clipboard which has been * initialized for processing Guacamole clipboard data. */ -guac_rdp_clipboard* guac_rdp_clipboard_alloc(guac_client* client); +guac_rdp_clipboard* guac_rdp_clipboard_alloc(guac_client* client, int buffer_size); /** * Initializes clipboard support for RDP and handling of the CLIPRDR channel. diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index 263ab8d20..f521cca54 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -205,9 +205,6 @@ int guac_client_init(guac_client* client, int argc, char** argv) { guac_rdp_client* rdp_client = guac_mem_zalloc(sizeof(guac_rdp_client)); client->data = rdp_client; - /* Init clipboard */ - rdp_client->clipboard = guac_rdp_clipboard_alloc(client); - /* Init display update module */ rdp_client->disp = guac_rdp_disp_alloc(client); diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index f47b1cff8..fcb3ec2fc 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -140,6 +140,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "load-balance-info", + "clipboard-buffer-size", "disable-copy", "disable-paste", @@ -658,6 +659,11 @@ enum RDP_ARGS_IDX { * the connection broker, if a connection broker is being used. */ IDX_LOAD_BALANCE_INFO, + + /** + * The maximum number of bytes to allow within the clipboard. + */ + IDX_CLIPBOARD_BUFFER_SIZE, /** * Whether outbound clipboard access should be blocked. If set to "true", @@ -1284,6 +1290,27 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_LOAD_BALANCE_INFO, NULL); + /* Set the maximum number of bytes to allow within the clipboard. */ + settings->clipboard_buffer_size = + guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_CLIPBOARD_BUFFER_SIZE, 0); + + /* Use default clipboard buffer size if given one is invalid. */ + if (settings->clipboard_buffer_size < GUAC_COMMON_CLIPBOARD_MIN_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MIN_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default minimum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + else if (settings->clipboard_buffer_size > GUAC_COMMON_CLIPBOARD_MAX_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default maximum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + /* Parse clipboard copy disable flag */ settings->disable_copy = guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h index 253b7628b..5f01a1adf 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -341,6 +341,11 @@ typedef struct guac_rdp_settings { */ char** svc_names; + /** + * The maximum number of bytes to allow within the clipboard. + */ + int clipboard_buffer_size; + /** * Whether outbound clipboard access should be blocked. If set, it will not * be possible to copy data from the remote desktop to the client using the diff --git a/src/protocols/rdp/user.c b/src/protocols/rdp/user.c index 5e115ebfd..3a1c84be5 100644 --- a/src/protocols/rdp/user.c +++ b/src/protocols/rdp/user.c @@ -67,6 +67,10 @@ int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) { /* Store owner's settings at client level */ rdp_client->settings = settings; + /* Init clipboard */ + rdp_client->clipboard = + guac_rdp_clipboard_alloc(user->client, settings->clipboard_buffer_size); + /* Start client thread */ if (pthread_create(&rdp_client->client_thread, NULL, guac_rdp_client_thread, user->client)) { diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 48e7383bd..22a5dced6 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -22,6 +22,7 @@ #include "argv.h" #include "client.h" #include "common/defaults.h" +#include "common/clipboard.h" #include "settings.h" #include "terminal/terminal.h" @@ -73,6 +74,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { "scrollback", "locale", "timezone", + "clipboard-buffer-size", "disable-copy", "disable-paste", "wol-send-packet", @@ -310,6 +312,11 @@ enum SSH_ARGS_IDX { */ IDX_TIMEZONE, + /** + * The maximum number of bytes to allow within the clipboard. + */ + IDX_CLIPBOARD_BUFFER_SIZE, + /** * Whether outbound clipboard access should be blocked. If set to "true", * it will not be possible to copy data from the terminal to the client @@ -555,6 +562,27 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, IDX_TIMEZONE, user->info.timezone); + /* Set the maximum number of bytes to allow within the clipboard. */ + settings->clipboard_buffer_size = + guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_CLIPBOARD_BUFFER_SIZE, 0); + + /* Use default clipboard buffer size if given one is invalid. */ + if (settings->clipboard_buffer_size < GUAC_COMMON_CLIPBOARD_MIN_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MIN_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default minimum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + else if (settings->clipboard_buffer_size > GUAC_COMMON_CLIPBOARD_MAX_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default maximum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + /* Parse clipboard copy disable flag */ settings->disable_copy = guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, diff --git a/src/protocols/ssh/settings.h b/src/protocols/ssh/settings.h index 654046183..c67c292f5 100644 --- a/src/protocols/ssh/settings.h +++ b/src/protocols/ssh/settings.h @@ -157,6 +157,11 @@ typedef struct guac_ssh_settings { */ int resolution; + /** + * The maximum number of bytes to allow within the clipboard. + */ + int clipboard_buffer_size; + /** * Whether outbound clipboard access should be blocked. If set, it will not * be possible to copy data from the terminal to the client using the diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 199064de6..1c5ba76f5 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -294,6 +294,7 @@ void* ssh_client_thread(void* data) { settings->width, settings->height, settings->resolution); /* Set optional parameters */ + options->clipboard_buffer_size = settings->clipboard_buffer_size; options->disable_copy = settings->disable_copy; options->max_scrollback = settings->max_scrollback; options->font_name = settings->font_name; diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index e55356948..beeaf224c 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -21,6 +21,7 @@ #include "argv.h" #include "common/defaults.h" +#include "common/clipboard.h" #include "settings.h" #include "terminal/terminal.h" @@ -63,6 +64,7 @@ const char* GUAC_TELNET_CLIENT_ARGS[] = { "scrollback", "login-success-regex", "login-failure-regex", + "clipboard-buffer-size", "disable-copy", "disable-paste", "wol-send-packet", @@ -248,6 +250,11 @@ enum TELNET_ARGS_IDX { */ IDX_LOGIN_FAILURE_REGEX, + /** + * The maximum number of bytes to allow within the clipboard. + */ + IDX_CLIPBOARD_BUFFER_SIZE, + /** * Whether outbound clipboard access should be blocked. If set to "true", * it will not be possible to copy data from the terminal to the client @@ -520,6 +527,27 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, IDX_TERMINAL_TYPE, "linux"); + /* Set the maximum number of bytes to allow within the clipboard. */ + settings->clipboard_buffer_size = + guac_user_parse_args_int(user, GUAC_TELNET_CLIENT_ARGS, argv, + IDX_CLIPBOARD_BUFFER_SIZE, 0); + + /* Use default clipboard buffer size if given one is invalid. */ + if (settings->clipboard_buffer_size < GUAC_COMMON_CLIPBOARD_MIN_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MIN_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default minimum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + else if (settings->clipboard_buffer_size > GUAC_COMMON_CLIPBOARD_MAX_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default maximum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + /* Parse clipboard copy disable flag */ settings->disable_copy = guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, diff --git a/src/protocols/telnet/settings.h b/src/protocols/telnet/settings.h index a28e440fe..5eb8f2fb8 100644 --- a/src/protocols/telnet/settings.h +++ b/src/protocols/telnet/settings.h @@ -165,6 +165,11 @@ typedef struct guac_telnet_settings { */ int resolution; + /** + * The maximum number of bytes to allow within the clipboard. + */ + int clipboard_buffer_size; + /** * Whether outbound clipboard access should be blocked. If set, it will not * be possible to copy data from the terminal to the client using the diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 0ddcd9fc8..37e68e077 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -545,6 +545,7 @@ void* guac_telnet_client_thread(void* data) { settings->width, settings->height, settings->resolution); /* Set optional parameters */ + options->clipboard_buffer_size = settings->clipboard_buffer_size; options->disable_copy = settings->disable_copy; options->max_scrollback = settings->max_scrollback; options->font_name = settings->font_name; diff --git a/src/protocols/vnc/client.c b/src/protocols/vnc/client.c index 206dad894..ad4bf19a0 100644 --- a/src/protocols/vnc/client.c +++ b/src/protocols/vnc/client.c @@ -115,9 +115,6 @@ int guac_client_init(guac_client* client) { /* Initialize the message lock. */ pthread_mutex_init(&(vnc_client->message_lock), NULL); - /* Init clipboard */ - vnc_client->clipboard = guac_common_clipboard_alloc(); - /* Set handlers */ client->join_handler = guac_vnc_user_join_handler; client->join_pending_handler = guac_vnc_join_pending_handler; diff --git a/src/protocols/vnc/clipboard.c b/src/protocols/vnc/clipboard.c index 319ca95f6..aea0bcd22 100644 --- a/src/protocols/vnc/clipboard.c +++ b/src/protocols/vnc/clipboard.c @@ -77,9 +77,16 @@ int guac_vnc_set_clipboard_encoding(guac_client* client, int guac_vnc_clipboard_handler(guac_user* user, guac_stream* stream, char* mimetype) { - /* Clear clipboard and prepare for new data */ guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data; - guac_common_clipboard_reset(vnc_client->clipboard, mimetype); + + /* Ignore stream creation if no clipboard structure is available to handle + * received data */ + guac_common_clipboard* clipboard = vnc_client->clipboard; + if (clipboard == NULL) + return 0; + + /* Clear clipboard and prepare for new data */ + guac_common_clipboard_reset(clipboard, mimetype); /* Set handlers for clipboard stream */ stream->blob_handler = guac_vnc_clipboard_blob_handler; @@ -90,10 +97,17 @@ int guac_vnc_clipboard_handler(guac_user* user, guac_stream* stream, int guac_vnc_clipboard_blob_handler(guac_user* user, guac_stream* stream, void* data, int length) { + + guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data; + + /* Ignore received data if no clipboard structure is available to handle + * that data */ + guac_common_clipboard* clipboard = vnc_client->clipboard; + if (clipboard == NULL) + return 0; /* Append new data */ - guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data; - guac_common_clipboard_append(vnc_client->clipboard, (char*) data, length); + guac_common_clipboard_append(clipboard, (char*) data, length); return 0; } @@ -101,22 +115,32 @@ int guac_vnc_clipboard_blob_handler(guac_user* user, guac_stream* stream, int guac_vnc_clipboard_end_handler(guac_user* user, guac_stream* stream) { guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data; + + /* Ignore end of stream if no clipboard structure is available to handle + * the data that was received */ + guac_common_clipboard* clipboard = vnc_client->clipboard; + if (clipboard == NULL) + return 0; + rfbClient* rfb_client = vnc_client->rfb_client; - char output_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH]; + int output_buf_size = clipboard->available; + char* output_data = guac_mem_alloc(output_buf_size); - const char* input = vnc_client->clipboard->buffer; + const char* input = clipboard->buffer; char* output = output_data; guac_iconv_write* writer = vnc_client->clipboard_writer; /* Convert clipboard contents */ - guac_iconv(GUAC_READ_UTF8, &input, vnc_client->clipboard->length, - writer, &output, sizeof(output_data)); + guac_iconv(GUAC_READ_UTF8, &input, clipboard->length, + writer, &output, output_buf_size); /* Send via VNC only if finished connecting */ if (rfb_client != NULL) SendClientCutText(rfb_client, output_data, output - output_data); + guac_mem_free(output_data); + return 0; } @@ -129,7 +153,8 @@ void guac_vnc_cut_text(rfbClient* client, const char* text, int textlen) { if (vnc_client->settings->disable_copy) return; - char received_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH]; + int output_buf_size = vnc_client->clipboard->available; + char* received_data = guac_mem_alloc(output_buf_size); const char* input = text; char* output = received_data; @@ -137,12 +162,13 @@ void guac_vnc_cut_text(rfbClient* client, const char* text, int textlen) { /* Convert clipboard contents */ guac_iconv(reader, &input, textlen, - GUAC_WRITE_UTF8, &output, sizeof(received_data)); + GUAC_WRITE_UTF8, &output, output_buf_size); /* Send converted data */ guac_common_clipboard_reset(vnc_client->clipboard, "text/plain"); guac_common_clipboard_append(vnc_client->clipboard, received_data, output - received_data); guac_common_clipboard_send(vnc_client->clipboard, gc); + guac_mem_free(received_data); } diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index 5b7df0bac..1b6f63ef3 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -22,6 +22,7 @@ #include "argv.h" #include "client.h" #include "common/defaults.h" +#include "common/clipboard.h" #include "settings.h" #include @@ -88,6 +89,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { "recording-include-keys", "create-recording-path", "recording-write-existing", + "clipboard-buffer-size", "disable-copy", "disable-paste", "disable-server-input", @@ -363,6 +365,11 @@ enum VNC_ARGS_IDX { */ IDX_RECORDING_WRITE_EXISTING, + /** + * The maximum number of bytes to allow within the clipboard. + */ + IDX_CLIPBOARD_BUFFER_SIZE, + /** * Whether outbound clipboard access should be blocked. If set to "true", * it will not be possible to copy data from the remote desktop to the @@ -684,6 +691,27 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, IDX_DISABLE_COPY, false); + /* Set the maximum number of bytes to allow within the clipboard. */ + settings->clipboard_buffer_size = + guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_CLIPBOARD_BUFFER_SIZE, 0); + + /* Use default clipboard buffer size if given one is invalid. */ + if (settings->clipboard_buffer_size < GUAC_COMMON_CLIPBOARD_MIN_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MIN_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default minimum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + else if (settings->clipboard_buffer_size > GUAC_COMMON_CLIPBOARD_MAX_LENGTH) { + settings->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MAX_LENGTH; + guac_user_log(user, GUAC_LOG_ERROR, "Invalid clipboard buffer " + "size: \"%s\". Using the default maximum size: %i.", + argv[IDX_CLIPBOARD_BUFFER_SIZE], + settings->clipboard_buffer_size); + } + /* Parse clipboard paste disable flag */ settings->disable_paste = guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, diff --git a/src/protocols/vnc/settings.h b/src/protocols/vnc/settings.h index f433df9bf..a23585f0d 100644 --- a/src/protocols/vnc/settings.h +++ b/src/protocols/vnc/settings.h @@ -157,6 +157,11 @@ typedef struct guac_vnc_settings { * to use the encoding required by the VNC standard. */ char* clipboard_encoding; + + /** + * The maximum number of bytes to allow within the clipboard. + */ + int clipboard_buffer_size; /** * Whether outbound clipboard access should be blocked. If set, it will not diff --git a/src/protocols/vnc/user.c b/src/protocols/vnc/user.c index 8605f0714..c28dd83e2 100644 --- a/src/protocols/vnc/user.c +++ b/src/protocols/vnc/user.c @@ -64,6 +64,10 @@ int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) { /* Store owner's settings at client level */ vnc_client->settings = settings; + /* Init clipboard. */ + vnc_client->clipboard = + guac_common_clipboard_alloc(settings->clipboard_buffer_size); + /* Start client thread */ if (pthread_create(&vnc_client->client_thread, NULL, guac_vnc_client_thread, user->client)) { guac_user_log(user, GUAC_LOG_ERROR, "Unable to start VNC client thread."); diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 466baa555..746977ec5 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -242,6 +242,7 @@ guac_terminal_options* guac_terminal_options_create( options->dpi = dpi; /* Set default values for all other parameters */ + options->clipboard_buffer_size = GUAC_COMMON_CLIPBOARD_MIN_LENGTH; options->disable_copy = GUAC_TERMINAL_DEFAULT_DISABLE_COPY; options->max_scrollback = GUAC_TERMINAL_DEFAULT_MAX_SCROLLBACK; options->font_name = GUAC_TERMINAL_DEFAULT_FONT_NAME; @@ -419,7 +420,7 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Init terminal state */ term->current_attributes = default_char.attributes; term->default_char = default_char; - term->clipboard = guac_common_clipboard_alloc(); + term->clipboard = guac_common_clipboard_alloc(options->clipboard_buffer_size); term->disable_copy = options->disable_copy; /* Calculate available text display area by character size */ @@ -2202,14 +2203,17 @@ void guac_terminal_clipboard_append(guac_terminal* terminal, const char* data, int length) { /* Allocate and clear space for the converted data */ - char output_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH]; + int output_buf_size = terminal->clipboard->available; + char* output_data = guac_mem_alloc(output_buf_size); char* output = output_data; /* Convert clipboard contents */ guac_iconv(GUAC_READ_UTF8_NORMALIZED, &data, length, - GUAC_WRITE_UTF8, &output, GUAC_COMMON_CLIPBOARD_MAX_LENGTH); + GUAC_WRITE_UTF8, &output, output_buf_size); guac_common_clipboard_append(terminal->clipboard, output_data, output - output_data); + + guac_mem_free(output_data); } void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user) { diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h index 11c8fb5a3..d7651cec6 100644 --- a/src/terminal/terminal/terminal.h +++ b/src/terminal/terminal/terminal.h @@ -180,6 +180,11 @@ typedef guac_stream* guac_terminal_file_download_handler(guac_client* client, ch */ typedef struct guac_terminal_options { + /** + * The maximum number of bytes to allow within the clipboard. + */ + int clipboard_buffer_size; + /** * Whether copying from the terminal clipboard should be blocked. If set, * the contents of the terminal can still be copied, but will be usable