Skip to content

Commit

Permalink
GUACAMOLE-2002: Allow connection clipboard limits to be configured.
Browse files Browse the repository at this point in the history
  • Loading branch information
eugen-keeper committed Jan 23, 2025
1 parent 32dbdfa commit 5b070e5
Show file tree
Hide file tree
Showing 24 changed files with 272 additions and 41 deletions.
6 changes: 3 additions & 3 deletions src/common/clipboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
#include <string.h>
#include <stdlib.h>

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);
Expand Down
44 changes: 33 additions & 11 deletions src/common/common/clipboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -72,30 +79,40 @@ 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);

/**
* 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);

Expand All @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/protocols/kubernetes/kubernetes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions src/protocols/kubernetes/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
"read-only",
"backspace",
"scrollback",
"clipboard-buffer-size",
"disable-copy",
"disable-paste",
NULL
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/protocols/kubernetes/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 13 additions & 7 deletions src/protocols/rdp/channels/cliprdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

}
Expand All @@ -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;

}
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/protocols/rdp/channels/cliprdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ typedef struct guac_rdp_clipboard {
* 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.
Expand Down
3 changes: 0 additions & 3 deletions src/protocols/rdp/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
27 changes: 27 additions & 0 deletions src/protocols/rdp/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {

"load-balance-info",

"clipboard-buffer-size",
"disable-copy",
"disable-paste",

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/protocols/rdp/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/protocols/rdp/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
28 changes: 28 additions & 0 deletions src/protocols/ssh/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -73,6 +74,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
"scrollback",
"locale",
"timezone",
"clipboard-buffer-size",
"disable-copy",
"disable-paste",
"wol-send-packet",
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/protocols/ssh/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 5b070e5

Please sign in to comment.