Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 93 additions & 2 deletions src/libguac/guacamole/recording.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
*/
#define GUAC_COMMON_RECORDING_MAX_NAME_LENGTH 2048

/**
* The block size to use when sending clipboard data in a recording.
*/
#define GUAC_RECORDING_CLIPBOARD_BLOCK_SIZE 4096

/**
* An in-progress session recording, attached to a guac_client instance such
* that output Guacamole instructions may be dynamically intercepted and
Expand All @@ -61,6 +66,12 @@ typedef struct guac_recording {
*/
guac_socket* socket;

/**
* The stream used for recording clipboard data. This stream is allocated
* once during recording creation and reused for all clipboard events.
*/
guac_stream* clipboard_stream;

/**
* Non-zero if output which is broadcast to each connected client
* (graphics, streams, etc.) should be included in the session recording,
Expand Down Expand Up @@ -95,6 +106,15 @@ typedef struct guac_recording {
*/
int include_keys;

/**
* Non-zero if clipboard paste data should be included in the session
* recording, zero otherwise. Including clipboard data within the recording may
* be necessary in certain auditing contexts, but should only be done with
* caution. Clipboard can easily contain sensitive information, such as
* passwords, credit card numbers, etc.
*/
int include_clipboard;

} guac_recording;

/**
Expand Down Expand Up @@ -152,6 +172,13 @@ typedef struct guac_recording {
* Non-zero if writing to an existing file should be allowed, or zero
* otherwise.
*
* @param include_clipboard
* Non-zero if clipboard paste data should be included in the session
* recording, zero otherwise. Including clipboard data within the recording may
* be necessary in certain auditing contexts, but should only be done with
* caution. Clipboard can easily contain sensitive information, such as
* passwords, credit card numbers, etc.
*
* @return
* A new guac_recording structure representing the in-progress
* recording if the recording file has been successfully created and a
Expand All @@ -160,7 +187,7 @@ typedef struct guac_recording {
guac_recording* guac_recording_create(guac_client* client,
const char* path, const char* name, int create_path,
int include_output, int include_mouse, int include_touch,
int include_keys, int allow_write_existing);
int include_keys, int allow_write_existing, int include_clipboard);

/**
* Frees the resources associated with the given in-progress recording. Note
Expand Down Expand Up @@ -256,5 +283,69 @@ void guac_recording_report_touch(guac_recording* recording,
void guac_recording_report_key(guac_recording* recording,
int keysym, int pressed);

#endif
/**
* Reports a clipboard paste instruction within the recording.
* The full structure consists of clipboard instruction, one or more
* blob instructions and end instruction.
*
* @param recording
* The guac_recording associated with the clipboard instruction.
*
* @param stream
* The guac_stream allocated for the clipboard paste instruction.
*
* @param mimetype
* The clipboard data mimetype
*/
void guac_recording_report_clipboard_begin(guac_recording* recording,
guac_stream* stream, char* mimetype);

/**
* Report a clipboard paste blob within the recording.
*
* @param recording
* The guac_recording associated with the clipboard instruction.
*
* @param stream
* The guac_stream associated with the clipboard instruction.
*
* @param data
* The clipboard blob data.
*
* @param length
* Length of the blob data.
*/
void guac_recording_report_clipboard_blob(guac_recording* recording,
guac_stream* stream, void* data, int length);

/**
* Report a clipboard paste end instruction within the recording.
*
* @param recording
* The guac_recording associated with the clipboard instruction.
*
* @param stream
* The guac_stream associated with the clipboard instruction.
*/
void guac_recording_report_clipboard_end(guac_recording* recording,
guac_stream* stream);

/**
* Reports clipboard data within the recording.
*
* @param recording
* The guac_recording to write clipboard data to.
*
* @param mimetype
* The mimetype of the clipboard data (e.g., "text/plain").
*
* @param data
* The clipboard data buffer.
*
* @param length
* The length of the clipboard data in bytes.
*/
void guac_recording_report_clipboard(guac_recording* recording,
const char* mimetype, const char* data, int length);

#endif
57 changes: 56 additions & 1 deletion src/libguac/recording.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
guac_recording* guac_recording_create(guac_client* client,
const char* path, const char* name, int create_path,
int include_output, int include_mouse, int include_touch,
int include_keys, int allow_write_existing) {
int include_keys, int allow_write_existing, int include_clipboard) {

char filename[GUAC_COMMON_RECORDING_MAX_NAME_LENGTH];

Expand Down Expand Up @@ -76,6 +76,12 @@ guac_recording* guac_recording_create(guac_client* client,
recording->include_mouse = include_mouse;
recording->include_touch = include_touch;
recording->include_keys = include_keys;
recording->include_clipboard = include_clipboard;

if (include_clipboard)
recording->clipboard_stream = guac_client_alloc_stream(client);
else
recording->clipboard_stream = NULL;

/* Replace client socket with wrapped recording socket only if including
* output within the recording */
Expand Down Expand Up @@ -133,3 +139,52 @@ void guac_recording_report_key(guac_recording* recording,

}

void guac_recording_report_clipboard_begin(guac_recording* recording, guac_stream* stream, char* mimetype) {
/* Report clipboard only if recording should contain it */
if (recording->include_clipboard)
guac_protocol_send_clipboard(recording->socket, stream, mimetype);
}

void guac_recording_report_clipboard_blob(guac_recording* recording, guac_stream* stream, void* data, int length) {
/* Report clipboard only if recording should contain it */
if (recording->include_clipboard)
guac_protocol_send_blob(recording->socket, stream, data, length);
}

void guac_recording_report_clipboard_end(guac_recording* recording, guac_stream* stream) {
/* Report clipboard only if recording should contain it */
if (recording->include_clipboard)
guac_protocol_send_end(recording->socket, stream);
}

void guac_recording_report_clipboard(guac_recording* recording,
const char* mimetype, const char* data, int length) {

/* Report clipboard only if recording should contain clipboard changes */
if (!recording->include_clipboard || !recording->clipboard_stream)
return;

guac_socket* socket = recording->socket;
guac_stream* stream = recording->clipboard_stream;

const char* current = data;
int remaining = length;

guac_protocol_send_clipboard(socket, stream, mimetype);

while (remaining > 0) {

int block_size = GUAC_RECORDING_CLIPBOARD_BLOCK_SIZE;
if (remaining < block_size)
block_size = remaining;

guac_protocol_send_blob(socket, stream, current, block_size);

remaining -= block_size;
current += block_size;

}

guac_protocol_send_end(socket, stream);

}
17 changes: 16 additions & 1 deletion src/protocols/kubernetes/clipboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ int guac_kubernetes_clipboard_handler(guac_user* user, guac_stream* stream,
stream->blob_handler = guac_kubernetes_clipboard_blob_handler;
stream->end_handler = guac_kubernetes_clipboard_end_handler;

/* Report clipboard within recording */
if (kubernetes_client->recording != NULL)
guac_recording_report_clipboard_begin(kubernetes_client->recording, stream, mimetype);

return 0;
}

Expand All @@ -49,6 +53,10 @@ int guac_kubernetes_clipboard_blob_handler(guac_user* user,
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;

/* Report clipboard blob within recording */
if (kubernetes_client->recording != NULL)
guac_recording_report_clipboard_blob(kubernetes_client->recording, stream, data, length);

/* Append new data */
guac_terminal_clipboard_append(kubernetes_client->term, data, length);

Expand All @@ -58,8 +66,15 @@ int guac_kubernetes_clipboard_blob_handler(guac_user* user,
int guac_kubernetes_clipboard_end_handler(guac_user* user,
guac_stream* stream) {

guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;

/* Report clipboard blob within recording */
if (kubernetes_client->recording != NULL)
guac_recording_report_clipboard_end(kubernetes_client->recording, stream);

/* Nothing to do - clipboard is implemented within client */

return 0;
}

3 changes: 2 additions & 1 deletion src/protocols/kubernetes/kubernetes.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ void* guac_kubernetes_client_thread(void* data) {
!settings->recording_exclude_mouse,
0, /* Touch events not supported */
settings->recording_include_keys,
settings->recording_write_existing);
settings->recording_write_existing,
settings->recording_include_clipboard);
}

/* Create terminal options with required parameters */
Expand Down
16 changes: 16 additions & 0 deletions src/protocols/kubernetes/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
"recording-exclude-output",
"recording-exclude-mouse",
"recording-include-keys",
"recording-include-clipboard",
"create-recording-path",
"recording-write-existing",
"read-only",
Expand Down Expand Up @@ -213,6 +214,16 @@ enum KUBERNETES_ARGS_IDX {
*/
IDX_RECORDING_INCLUDE_KEYS,

/**
* Whether clipboard paste data should be included in the session recording.
* Clipboard data is NOT included by default within the recording,
* as doing so has privacy and security implications. Including clipboard data
* may be necessary in certain auditing contexts, but should only be done
* with caution. Clipboard data can easily contain sensitive information, such
* as passwords, credit card numbers, etc.
*/
IDX_RECORDING_INCLUDE_CLIPBOARD,

/**
* Whether the specified screen recording path should automatically be
* created if it does not yet exist.
Expand Down Expand Up @@ -409,6 +420,11 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_INCLUDE_KEYS, false);

/* Parse clipboard inclusion flag */
settings->recording_include_clipboard =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_INCLUDE_CLIPBOARD, false);

/* Parse path creation flag */
settings->create_recording_path =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
Expand Down
10 changes: 10 additions & 0 deletions src/protocols/kubernetes/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,16 @@ typedef struct guac_kubernetes_settings {
*/
bool recording_include_keys;

/**
* Whether clipboard paste data should be included in the session recording.
* Clipboard data is NOT included by default within the recording,
* as doing so has privacy and security implications. Including clipboard data
* may be necessary in certain auditing contexts, but should only be done
* with caution. Clipboard data can easily contain sensitive information, such
* as passwords, credit card numbers, etc.
*/
bool recording_include_clipboard;

/**
* Whether existing files should be appended to when creating a new recording.
* Disabled by default.
Expand Down
21 changes: 21 additions & 0 deletions src/protocols/rdp/channels/cliprdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,13 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
guac_common_clipboard_reset(clipboard->clipboard, "text/plain");
guac_common_clipboard_append(clipboard->clipboard, received_data, length);
guac_common_clipboard_send(clipboard->clipboard, client);

/* Record clipboard if recording is active */
if (rdp_client->recording != NULL)
guac_recording_report_clipboard(rdp_client->recording,
clipboard->clipboard->mimetype,
clipboard->clipboard->buffer,
clipboard->clipboard->length);
}

guac_mem_free(received_data);
Expand Down Expand Up @@ -695,6 +702,12 @@ int guac_rdp_clipboard_handler(guac_user* user, guac_stream* stream,
/* Clear any current contents, assigning the mimetype the data which will
* be received */
guac_common_clipboard_reset(clipboard->clipboard, mimetype);

/* Report clipboard within recording */
if (rdp_client->recording != NULL)
guac_recording_report_clipboard_begin(rdp_client->recording, stream,
mimetype);

return 0;

}
Expand All @@ -711,6 +724,10 @@ int guac_rdp_clipboard_blob_handler(guac_user* user, guac_stream* stream,
if (clipboard == NULL)
return 0;

/* Report clipboard blob within recording */
if (rdp_client->recording != NULL)
guac_recording_report_clipboard_blob(rdp_client->recording, stream, data, length);

/* Append received data to current clipboard contents */
guac_common_clipboard_append(clipboard->clipboard, (char*) data, length);
return 0;
Expand All @@ -728,6 +745,10 @@ int guac_rdp_clipboard_end_handler(guac_user* user, guac_stream* stream) {
if (clipboard == NULL)
return 0;

/* Report clipboard stream end within recording */
if (rdp_client->recording != NULL)
guac_recording_report_clipboard_end(rdp_client->recording, stream);

/* Terminate clipboard data with NULL */
guac_common_clipboard_append(clipboard->clipboard, "", 1);

Expand Down
3 changes: 2 additions & 1 deletion src/protocols/rdp/rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,8 @@ void* guac_rdp_client_thread(void* data) {
!settings->recording_exclude_mouse,
!settings->recording_exclude_touch,
settings->recording_include_keys,
settings->recording_write_existing);
settings->recording_write_existing,
settings->recording_include_clipboard);
}

/* Continue handling connections until error or client disconnect */
Expand Down
Loading