diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 35d40134..9881c304 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -193,7 +193,8 @@ void* ssh_client_thread(void* data) { } /* Initialize a ttymode array */ - guac_ssh_ttymodes* ssh_ttymodes = guac_ssh_ttymodes_init(1); + const int num_tty_opcodes = 1; + char ssh_ttymodes[(GUAC_SSH_TTY_OPCODE_SIZE * num_tty_opcodes) + 1]; /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { @@ -212,9 +213,6 @@ 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 */ - guac_ssh_ttymodes_add(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, @@ -303,22 +301,19 @@ void* ssh_client_thread(void* data) { } - /* Get char pointer array for TTY Mode Encoding */ - int ttymode_size = guac_ssh_ttymodes_size(ssh_ttymodes); - char* ttymode_array = guac_ssh_ttymodes_to_array(ssh_ttymodes, ttymode_size); + /* Set up the ttymode array prior to requesting the PTY */ + if (guac_ssh_ttymodes_init(ssh_ttymodes, sizeof(ssh_ttymodes), + num_tty_opcodes, (guac_ssh_ttymode){ GUAC_SSH_TTY_OP_VERASE, settings->backspace})) + guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error configuring TTY mode encoding."); /* Request PTY */ if (libssh2_channel_request_pty_ex(ssh_client->term_channel, "linux", sizeof("linux")-1, - ttymode_array, ttymode_size, ssh_client->term->term_width, + ssh_ttymodes, sizeof(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; } - /* We're done with TTY Mode Encoding, so free structures. */ - free(ttymode_array); - free(ssh_ttymodes); - /* If a command is specified, run that instead of a shell */ if (settings->command != NULL) { if (libssh2_channel_exec(ssh_client->term_channel, settings->command)) { diff --git a/src/protocols/ssh/ttymode.c b/src/protocols/ssh/ttymode.c index 1541da68..4c6091e5 100644 --- a/src/protocols/ssh/ttymode.c +++ b/src/protocols/ssh/ttymode.c @@ -20,58 +20,40 @@ #include "config.h" #include "ttymode.h" +#include #include #include -guac_ssh_ttymodes* guac_ssh_ttymodes_init(int max_opcodes) { - /* Allocate enough space for the max opcodes */ - guac_ssh_ttymode* ttymode_array = malloc(sizeof(guac_ssh_ttymode) * max_opcodes); - - /* Set up the initial data structure. */ - guac_ssh_ttymodes* empty_modes = malloc(sizeof(guac_ssh_ttymodes)); - empty_modes->ttymode_array = ttymode_array; - empty_modes->num_opcodes = 0; +int guac_ssh_ttymodes_init(char opcode_array[], const int array_size, + const int num_opcodes, ...) { - return empty_modes; -} + /* Initialize the variable argument list. */ + va_list args; + va_start(args, num_opcodes); -void guac_ssh_ttymodes_add(guac_ssh_ttymodes *tty_modes, char opcode, uint32_t value) { - /* Increment number of opcodes */ - tty_modes->num_opcodes++; + /* Check to make sure the array has enough space. + We need one extra byte at the end for the ending opcode. */ + if ((num_opcodes * GUAC_SSH_TTY_OPCODE_SIZE) >= (array_size)) + return 1; - /* Add new values */ - tty_modes->ttymode_array[tty_modes->num_opcodes - 1].opcode = opcode; - tty_modes->ttymode_array[tty_modes->num_opcodes - 1].value = value; -} + for (int i = 0; i < num_opcodes; i++) { + /* Calculate offset in array */ + int offset = i * GUAC_SSH_TTY_OPCODE_SIZE; -int guac_ssh_ttymodes_size(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; -} + /* Get the next argument to this function */ + guac_ssh_ttymode ttymode = va_arg(args, guac_ssh_ttymode); -char* guac_ssh_ttymodes_to_array(guac_ssh_ttymodes *tty_modes, int data_size) { - - 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; + /* Place opcode and value in array */ + opcode_array[offset] = ttymode.opcode; + opcode_array[offset + 1] = (ttymode.value >> 24) & 0xFF; + opcode_array[offset + 2] = (ttymode.value >> 16) & 0xFF; + opcode_array[offset + 3] = (ttymode.value >> 8) & 0xFF; + opcode_array[offset + 4] = ttymode.value & 0xFF; } - - /* Add the ending opcode */ - temp[data_size - 1] = GUAC_SSH_TTY_OP_END; - return temp; + /* Put the end opcode in the last opcode space */ + opcode_array[num_opcodes * GUAC_SSH_TTY_OPCODE_SIZE] = GUAC_SSH_TTY_OP_END; + + return 0; + } diff --git a/src/protocols/ssh/ttymode.h b/src/protocols/ssh/ttymode.h index 30f36e61..be40b84c 100644 --- a/src/protocols/ssh/ttymode.h +++ b/src/protocols/ssh/ttymode.h @@ -24,6 +24,14 @@ #include +/** + * The size of a TTY mode encoding opcode and + * value pair. As defined in the SSH RFC, this + * is 5 bytes - a single byte for the opcode, and + * 4 bytes for the value. + */ +#define GUAC_SSH_TTY_OPCODE_SIZE 5 + /** * The SSH TTY mode encoding opcode that terminates * the list of TTY modes. @@ -31,15 +39,15 @@ #define GUAC_SSH_TTY_OP_END 0 /** - * The SSH tty mode encoding opcode that configures + * The SSH TTY mode encoding opcode that configures * the TTY erase code to configure the server * backspace key. */ #define GUAC_SSH_TTY_OP_VERASE 3 /** - * A data type which holds a single opcode - * and the value for that opcode. + * Simple structure that defines a opcode and + * value pair. */ typedef struct guac_ssh_ttymode { char opcode; @@ -47,82 +55,26 @@ typedef struct guac_ssh_ttymode { } guac_ssh_ttymode; /** - * 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. - */ -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. + * Initialize an array with the specified opcode/value + * pairs, and return the size, in bytes, of the array. * - * @param max_opcodes - * The maximum number of opcodes that will be allocated. + * @param opcode_array + * Pointer to the opcode array. + * + * @param array_size + * Size, in bytes, of the array. + * + * @param num_opcodes + * Number of opcodes to expect. + * + * @params ... + * A variable number of guac_ssh_ttymodes + * to place in the array. * * @return - * The pointer array for the gauc_ssh_ttymodes data - * structure generated by the function. + * The size, in bytes, of the array. */ -guac_ssh_ttymodes* guac_ssh_ttymodes_init(int max_opcodes); - -/** - * 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. - * - * @param tty_modes - * The pointer to the guac_ssh_ttymodes data structure - * to add the opcode to. - * - * @param opcode - * The single byte opcode as documented in section 8 - * of the SSH RFC. - * - * @param value - * The four byte value of the opcodeto add to the - * guac_ssh_ttymodes data structure. - */ -void guac_ssh_ttymodes_add(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. - * - * @param tty_modes - * The pointer to the guac_ssh_ttymodes structure - * whose size we are curious about. - * - * @return - * The number of bytes of the opcodes and value paris - * in the data structure. - */ -int guac_ssh_ttymodes_size(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. - * - * @param tty_modes - * The pointer to the guac_ssh_ttymodes structure - * that contains the opcode and value pairs - * we want to convert to a character pointer array. - * - * @param data_size - * The size of the resulting character pointer - * array. - * - * @return - * The character pointer array of opcode and - * value pairs to be passed to a SSH session. - */ -char* guac_ssh_ttymodes_to_array(guac_ssh_ttymodes *tty_modes, int data_size); +int guac_ssh_ttymodes_init(char opcode_array[], const int array_size, + const int num_opcodes, ...); #endif