From fd58d31eeae1857f33d3d679da782b465c289026 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 25 Feb 2018 08:41:14 -0500 Subject: [PATCH] GUACAMOLE-269: Use backspace config to set up tty modes. --- src/protocols/ssh/ssh.c | 10 ++++-- src/protocols/ssh/ttymode.c | 61 ++++++++++++++++++++++++++++++++++--- src/protocols/ssh/ttymode.h | 52 ++++++++++++++++++++++++++----- 3 files changed, 108 insertions(+), 15 deletions(-) diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 86ebddbc..6b90a197 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -192,6 +192,9 @@ void* ssh_client_thread(void* data) { return NULL; } + /* Initialize a ttymode array */ + guac_ssh_ttymodes ssh_ttymodes = init_ttymodes(); + /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { ssh_client->recording = guac_common_recording_create(client, @@ -209,6 +212,9 @@ void* ssh_client_thread(void* data) { settings->resolution, settings->width, settings->height, settings->color_scheme, settings->backspace); + /* Add the backspace key to the ttymode array */ + add_ttymode(&ssh_ttymodes, GUAC_SSH_TTY_OP_VERASE, settings->backspace); + /* Fail if terminal init failed */ if (ssh_client->term == NULL) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, @@ -298,8 +304,8 @@ void* ssh_client_thread(void* data) { } /* Request PTY */ - if (libssh2_channel_request_pty_ex(ssh_client->term_channel, "linux", sizeof("linux")-1, GUAC_SSH_TTY_MODES, - sizeof(GUAC_SSH_TTY_MODES), ssh_client->term->term_width, ssh_client->term->term_height, 0, 0)) { + if (libssh2_channel_request_pty_ex(ssh_client->term_channel, "linux", sizeof("linux")-1, ttymodes_to_array(&ssh_ttymodes), + sizeof_ttymodes(&ssh_ttymodes), ssh_client->term->term_width, ssh_client->term->term_height, 0, 0)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY."); return NULL; } diff --git a/src/protocols/ssh/ttymode.c b/src/protocols/ssh/ttymode.c index e5baff4f..286f124f 100644 --- a/src/protocols/ssh/ttymode.c +++ b/src/protocols/ssh/ttymode.c @@ -20,8 +20,59 @@ #include "config.h" #include "ttymode.h" -const char GUAC_SSH_TTY_MODES[6] = { - GUAC_SSH_TTY_OP_VERASE, - 0, 0, 0, GUAC_SSH_TERM_DEFAULT_BACKSPACE, - GUAC_SSH_TTY_OP_END -}; +#include +#include + +guac_ssh_ttymodes init_ttymodes() { + // Simple allocation for a placeholder + guac_ssh_ttymode* ttymode_array = malloc(1); + + // Set up the initial data structure. + guac_ssh_ttymodes empty_modes = { + ttymode_array, + 0 + }; + + return empty_modes; +} + +void add_ttymode(guac_ssh_ttymodes *tty_modes, char opcode, uint32_t value) { + tty_modes->num_opcodes++; + tty_modes->ttymode_array = realloc(tty_modes->ttymode_array, sizeof(guac_ssh_ttymode) * tty_modes->num_opcodes); + tty_modes->ttymode_array[tty_modes->num_opcodes - 1].opcode = opcode; + tty_modes->ttymode_array[tty_modes->num_opcodes - 1].value = value; + +} + +int sizeof_ttymodes(guac_ssh_ttymodes *tty_modes) { + // Each opcode pair is 5 bytes (1 opcode, 4 value) + // Add one for the ending opcode + return (tty_modes->num_opcodes * 5) + 1; +} + +char* ttymodes_to_array(guac_ssh_ttymodes *tty_modes) { + // Total data size should be number of tracked opcodes + // plus one final byte for the TTY_OP_END code. + int data_size = (tty_modes->num_opcodes * 5) + 1; + char* temp = malloc(data_size); + + // Loop through the array based on number of tracked + // opcodes and convert each one. + for (int i = 0; i < tty_modes->num_opcodes; i++) { + int idx = i * 5; + uint32_t value = tty_modes->ttymode_array[i].value; + // Opcode goes in first byte. + temp[idx] = tty_modes->ttymode_array[i].opcode; + + // Convert 32-bit int to individual bytes. + temp[idx+1] = (value >> 24) & 0xFF; + temp[idx+2] = (value >> 16) & 0xFF; + temp[idx+3] = (value >> 8) & 0xFF; + temp[idx+4] = value & 0xFF; + } + + // Add the ending opcode + temp[data_size - 1] = GUAC_SSH_TTY_OP_END; + + return temp; +} diff --git a/src/protocols/ssh/ttymode.h b/src/protocols/ssh/ttymode.h index e1a0101f..93f85bf1 100644 --- a/src/protocols/ssh/ttymode.h +++ b/src/protocols/ssh/ttymode.h @@ -22,6 +22,8 @@ #include "config.h" +#include + /** * The SSH TTY mode encoding opcode that terminates * the list of TTY modes. @@ -36,17 +38,51 @@ #define GUAC_SSH_TTY_OP_VERASE 3 /** - * The default ASCII code to send for the backspace - * key that will be sent to the SSH server. + * A data type which holds a single opcode + * and the value for that opcode. */ -#define GUAC_SSH_TERM_DEFAULT_BACKSPACE 127 +typedef struct guac_ssh_ttymode { + char opcode; + uint32_t value; +} guac_ssh_ttymode; /** - * The array of TTY mode encoding data to send to the - * SSH server. These consist of pairs of byte codes - * and uint32 (4-byte) values, with a 0 to terminate - * the list. + * A data type which holds an array of + * guac_ssh_ttymode data, along with the count of + * the number of opcodes currently in the array. */ -extern const char GUAC_SSH_TTY_MODES[6]; +typedef struct guac_ssh_ttymodes { + guac_ssh_ttymode* ttymode_array; + int num_opcodes; +} guac_ssh_ttymodes; + + +/** + * Initialize an empty guac_ssh_ttymodes data structure, + * with a null array of guac_ssh_ttymode and opcodes + * set to zero. + */ +guac_ssh_ttymodes init_ttymodes(); + +/** + * Add an item to the opcode array. This resizes the + * array, increments the number of opcodes, and adds + * the specified opcode and value pair to the data + * structure. + */ +void add_ttymode(guac_ssh_ttymodes *tty_modes, char opcode, uint32_t value); + +/** + * Retrieve the size, in bytes, of the ttymode_array + * in the given guac_ssh_ttymodes data structure. + */ +int sizeof_ttymodes(guac_ssh_ttymodes *tty_modes); + +/** + * Convert the ttymodes data structure into a char + * pointer array suitable for passing into the + * libssh2_channel_request_pty_ex() function. + */ +char* ttymodes_to_array(guac_ssh_ttymodes *tty_modes); #endif