From f70aa4939fc8c69126037317fcefa05606311b19 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 24 Mar 2019 21:36:44 -0400 Subject: [PATCH 01/18] GUACAMOLE-422: Add client timezone to handshake. --- src/libguac/guacamole/user.h | 7 +++++++ src/libguac/user-handshake.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/libguac/guacamole/user.h b/src/libguac/guacamole/user.h index 792c7421..75accdb9 100644 --- a/src/libguac/guacamole/user.h +++ b/src/libguac/guacamole/user.h @@ -88,6 +88,13 @@ struct guac_user_info { * stated resolution of the display size request is recommended. */ int optimal_resolution; + + /** + * The timezone of the remote system. If the client does not provide + * a specific timezone then this will be NULL. The format of the timezone + * is the standard tzdata naming convention. + */ + const char** timezone; }; diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 13bea51f..87354054 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -384,6 +384,31 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { /* Store image mimetypes */ char** image_mimetypes = guac_copy_mimetypes(parser->argv, parser->argc); user->info.image_mimetypes = (const char**) image_mimetypes; + + /* Get client timezone */ + if (guac_parser_expect(parser, socket, usec_timeout, "timezone")) { + + /* Log error */ + guac_user_log_handshake_failure(user); + guac_user_log_guac_error(user, GUAC_LOG_DEBUG, + "Error reading \"timezone\""); + + guac_parser_free(parser); + return 1; + + } + + /* Check number of timezone arguments */ + if (parser->argc < 1) { + guac_user_log(user, GUAC_LOG_ERROR, "Received \"timezone\" instruction " + "lacked required arguments."); + guac_parser_free(parser); + return 1; + } + + /* Store timezone */ + char** timezone = parser->argv[0]; + user->info.timezone = (const char**) timezone; /* Get args from connect instruction */ if (guac_parser_expect(parser, socket, usec_timeout, "connect")) { From 6fae0b4b23b70a98fdb91826fc20aaeda0378e4f Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 24 Mar 2019 21:55:45 -0400 Subject: [PATCH 02/18] GUACAMOLE-422: Use timezone from handshake when parameter does not exist. --- src/libguac/guacamole/user.h | 2 +- src/libguac/user-handshake.c | 11 ++++++++--- src/protocols/rdp/rdp_settings.c | 4 ++-- src/protocols/ssh/settings.c | 4 ++++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libguac/guacamole/user.h b/src/libguac/guacamole/user.h index 75accdb9..adc4c4e9 100644 --- a/src/libguac/guacamole/user.h +++ b/src/libguac/guacamole/user.h @@ -94,7 +94,7 @@ struct guac_user_info { * a specific timezone then this will be NULL. The format of the timezone * is the standard tzdata naming convention. */ - const char** timezone; + const char* timezone; }; diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 87354054..b0a9b2f3 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -406,9 +406,10 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { return 1; } - /* Store timezone */ - char** timezone = parser->argv[0]; - user->info.timezone = (const char**) timezone; + /* Store timezone, if present */ + char* timezone = parser->argv[0]; + if (timezone != NULL && !strcmp(timezone, "")) + user->info.timezone = (const char*) timezone; /* Get args from connect instruction */ if (guac_parser_expect(parser, socket, usec_timeout, "connect")) { @@ -452,6 +453,10 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_free_mimetypes(audio_mimetypes); guac_free_mimetypes(video_mimetypes); guac_free_mimetypes(image_mimetypes); + + /* Free timezone */ + if (timezone != NULL) + free(timezone); guac_parser_free(parser); diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c index d322a480..e5aa85dd 100644 --- a/src/protocols/rdp/rdp_settings.c +++ b/src/protocols/rdp/rdp_settings.c @@ -851,10 +851,10 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, if (settings->server_layout == NULL) settings->server_layout = guac_rdp_keymap_find(GUAC_DEFAULT_KEYMAP); - /* Timezone if provied by client */ + /* Timezone if provided by client, or use handshake version */ settings->timezone = guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, - IDX_TIMEZONE, NULL); + IDX_TIMEZONE, user->info.timezone); #ifdef ENABLE_COMMON_SSH /* SFTP enable/disable */ diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 962524ce..74706e0d 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -425,6 +425,10 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, settings->timezone = guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, IDX_TIMEZONE, NULL); + + /* If timezone not explicitly set, try to pull from tunnel */ + if (settings->timezone == NULL) + settings->timezone = user->info.timezone; /* Parsing was successful */ return settings; From 5caa8a25f7e3fb228356c51fe5cbca181c185134 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 25 Mar 2019 17:23:58 -0400 Subject: [PATCH 03/18] GUACAMOLE-422: SSH parameter should use handshake for default. --- src/protocols/ssh/settings.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 74706e0d..a0af9f9b 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -421,14 +421,10 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, IDX_LOCALE, NULL); - /* Read the client timezone. */ + /* Read the timezone parameter, or use client handshake. */ settings->timezone = guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, - IDX_TIMEZONE, NULL); - - /* If timezone not explicitly set, try to pull from tunnel */ - if (settings->timezone == NULL) - settings->timezone = user->info.timezone; + IDX_TIMEZONE, user->info.timezone); /* Parsing was successful */ return settings; From 5480b288e8ee08d6b2572dbbbb40883600d384cf Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 25 Mar 2019 17:26:37 -0400 Subject: [PATCH 04/18] GUACAMOLE-422: Remove NULL check for parser argv. --- src/libguac/user-handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index b0a9b2f3..e5143927 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -408,7 +408,7 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { /* Store timezone, if present */ char* timezone = parser->argv[0]; - if (timezone != NULL && !strcmp(timezone, "")) + if (!strcmp(timezone, "")) user->info.timezone = (const char*) timezone; /* Get args from connect instruction */ From 0ee47e01869d5fc6d25c059f2bd23fa5420f17ce Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Thu, 28 Mar 2019 20:09:32 -0400 Subject: [PATCH 05/18] GUACAMOLE-422: Change handshake to ignore order of opcodes. --- src/libguac/guacamole/user.h | 73 +++++++++++ src/libguac/user-handshake.c | 246 ++++++++++++++++++----------------- 2 files changed, 198 insertions(+), 121 deletions(-) diff --git a/src/libguac/guacamole/user.h b/src/libguac/guacamole/user.h index adc4c4e9..137553a7 100644 --- a/src/libguac/guacamole/user.h +++ b/src/libguac/guacamole/user.h @@ -505,6 +505,79 @@ struct guac_user { }; +/** + * Handler for Guacamole protocol opcode specific to the handshake that + * happens between client and server at the beginning of the connection. The + * handler will be invoked when the matching opcode is received during the + * handshake process. + * + * @param user + * The user that initiated the handshake. + * + * @param parser + * The parser allocated for parsing the data provided by the client. + * + * @param timeout + * The timeout, in microseconds, for parsing the value. + * + * @return + * Zero if the handshake instruction is successfully parsed; otherwise + * false. + */ +typedef int __guac_handshake_handler(guac_user* user, int argc, char** argv); + +/** + * Structure that maps opcodes received during the handshake phase of the + * connection to callback functions used when those opcodes are received. + */ +typedef struct __guac_handshake_mapping { + + /** + * The instruction opcode which maps to the handler. + */ + char* opcode; + + /** + * The handler function used when specified opcode is received. + */ + __guac_handshake_handler* handler; + +} __guac_handshake_mapping; + +/** + * Internal handler function that is called when the size instruction is + * received during the handshake process. + */ +__guac_handshake_handler __guac_handshake_size_handler; + +/** + * Internal handler function that is called when the audio instruction is + * received during the handshake process, specifying the audio mimetypes + * available to the client. + */ +__guac_handshake_handler __guac_handshake_audio_handler; + +/** + * Internal handler function that is called when the video instruction is + * received during the handshake process, specifying the video mimetypes + * available to the client. + */ +__guac_handshake_handler __guac_handshake_video_handler; + +/** + * Internal handler function that is called when the image instruction is + * received during the handshake process, specifying the image mimetypes + * available to the client. + */ +__guac_handshake_handler __guac_handshake_image_handler; + +/** + * Internal handler function that is called when the timezone instruction is + * received during the handshake process, specifying the timezone of the + * client. + */ +__guac_handshake_handler __guac_handshake_timezone_handler; + /** * Allocates a new, blank user, not associated with any specific client or * socket. diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index e5143927..a9cf003b 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -171,6 +171,80 @@ static void guac_free_mimetypes(char** mimetypes) { } +/* Guacamole handshake handler functions. */ + +int __guac_handshake_size_handler(guac_user* user, int argc, char** argv) { + + /* Validate size of instruction. */ + if (argc < 2) { + guac_user_log(user, GUAC_LOG_ERROR, "Received \"size\" " + "instruction lacked required arguments."); + return 1; + } + + /* Parse optimal screen dimensions from size instruction */ + user->info.optimal_width = atoi(argv[0]); + user->info.optimal_height = atoi(argv[1]); + + /* If DPI given, set the user resolution */ + if (argc >= 3) + user->info.optimal_resolution = atoi(argv[2]); + + /* Otherwise, use a safe default for rough backwards compatibility */ + else + user->info.optimal_resolution = 96; + + return 0; + +} + +int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { + + /* Store audio mimetypes */ + user->info.audio_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); + + return 0; + +} + +int __guac_handshake_video_handler(guac_user* user, int argc, char** argv) { + + /* Store video mimetypes */ + user->info.video_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); + + return 0; + +} + +int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) { + + /* Store image mimetypes */ + user->info.image_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); + + return 0; + +} + +int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) { + + /* Store timezone, if present */ + if (argc > 0 && strcmp(argv[0], "")) + user->info.timezone = (const char*) strdup(argv[0]); + + return 0; + +} + +/* Guacamole handshake handler mappings. */ +__guac_handshake_mapping __guac_handshake_map[] = { + {"size", __guac_handshake_size_handler}, + {"audio", __guac_handshake_audio_handler}, + {"video", __guac_handshake_video_handler}, + {"image", __guac_handshake_image_handler}, + {"timezone", __guac_handshake_timezone_handler}, + {NULL, NULL} +}; + /** * The thread which handles all user input, calling event handlers for received * instructions. @@ -305,122 +379,53 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_parser* parser = guac_parser_alloc(); - /* Get optimal screen size */ - if (guac_parser_expect(parser, socket, usec_timeout, "size")) { - - /* Log error */ - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error reading \"size\""); - - guac_parser_free(parser); - return 1; - } - - /* Validate content of size instruction */ - if (parser->argc < 2) { - guac_user_log(user, GUAC_LOG_ERROR, "Received \"size\" " - "instruction lacked required arguments."); - guac_parser_free(parser); - return 1; - } - - /* Parse optimal screen dimensions from size instruction */ - user->info.optimal_width = atoi(parser->argv[0]); - user->info.optimal_height = atoi(parser->argv[1]); - - /* If DPI given, set the user resolution */ - if (parser->argc >= 3) - user->info.optimal_resolution = atoi(parser->argv[2]); - - /* Otherwise, use a safe default for rough backwards compatibility */ - else - user->info.optimal_resolution = 96; - - /* Get supported audio formats */ - if (guac_parser_expect(parser, socket, usec_timeout, "audio")) { - - /* Log error */ - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error reading \"audio\""); - - guac_parser_free(parser); - return 1; - } - - /* Store audio mimetypes */ - char** audio_mimetypes = guac_copy_mimetypes(parser->argv, parser->argc); - user->info.audio_mimetypes = (const char**) audio_mimetypes; - - /* Get supported video formats */ - if (guac_parser_expect(parser, socket, usec_timeout, "video")) { - - /* Log error */ - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error reading \"video\""); - - guac_parser_free(parser); - return 1; - } - - /* Store video mimetypes */ - char** video_mimetypes = guac_copy_mimetypes(parser->argv, parser->argc); - user->info.video_mimetypes = (const char**) video_mimetypes; - - /* Get supported image formats */ - if (guac_parser_expect(parser, socket, usec_timeout, "image")) { - - /* Log error */ - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error reading \"image\""); - - guac_parser_free(parser); - return 1; - } - - /* Store image mimetypes */ - char** image_mimetypes = guac_copy_mimetypes(parser->argv, parser->argc); - user->info.image_mimetypes = (const char**) image_mimetypes; - - /* Get client timezone */ - if (guac_parser_expect(parser, socket, usec_timeout, "timezone")) { + /* Handle each of the opcodes. */ + while (1) { + if (guac_parser_read(parser, socket, usec_timeout)) { + guac_user_log_handshake_failure(user); + guac_user_log_guac_error(user, GUAC_LOG_DEBUG, + "Error while reading opcode instruction."); + guac_parser_free(parser); + return 1; + } - /* Log error */ - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error reading \"timezone\""); + /* If we receive the connect opcode, we're done. */ + if (strcmp(parser->opcode, "connect") == 0) + break; - guac_parser_free(parser); - return 1; - - } - - /* Check number of timezone arguments */ - if (parser->argc < 1) { - guac_user_log(user, GUAC_LOG_ERROR, "Received \"timezone\" instruction " - "lacked required arguments."); - guac_parser_free(parser); - return 1; - } - - /* Store timezone, if present */ - char* timezone = parser->argv[0]; - if (!strcmp(timezone, "")) - user->info.timezone = (const char*) timezone; + /* Loop available opcodes and run handler if/when match found. */ + __guac_handshake_mapping* current = __guac_handshake_map; + while (current->opcode != NULL) { + + /* Check if loop opcode matches parsed opcode. */ + if (strcmp(parser->opcode, current->opcode) == 0) { + + /* If calling the handler fails, log it and return. */ + if (current->handler(user, parser->argc, parser->argv)) { + + guac_user_log_handshake_failure(user); + guac_user_log_guac_error(user, GUAC_LOG_DEBUG, + "Error handling handling opcode during handshake."); + guac_user_log(user, GUAC_LOG_DEBUG, "Failed opcode: %s", + current->opcode); - /* Get args from connect instruction */ - if (guac_parser_expect(parser, socket, usec_timeout, "connect")) { + guac_parser_free(parser); + return 1; + } + + /* If calling the handler has succeeded, log it and break. */ + else { + guac_user_log(user, GUAC_LOG_DEBUG, + "Successfully processed instruction: \"%s\"", + current->opcode); + break; + } - /* Log error */ - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error reading \"connect\""); - - guac_parser_free(parser); - return 1; + } + + /* Move to next opcode. */ + current++; + } } /* Acknowledge connection availability */ @@ -448,16 +453,15 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { "users remain)", user->user_id, client->connected_users); } - - /* Free mimetype lists */ - guac_free_mimetypes(audio_mimetypes); - guac_free_mimetypes(video_mimetypes); - guac_free_mimetypes(image_mimetypes); - /* Free timezone */ - if (timezone != NULL) - free(timezone); - + /* Free mimetype character arrays. */ + guac_free_mimetypes((char **) user->info.audio_mimetypes); + guac_free_mimetypes((char **) user->info.image_mimetypes); + guac_free_mimetypes((char **) user->info.video_mimetypes); + + /* Free timezone info. */ + free((char *) user->info.timezone); + guac_parser_free(parser); /* Successful disconnect */ From 2b68925ec9cd8168950a03dc33c79a643c96c9fc Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 30 Mar 2019 13:43:01 -0400 Subject: [PATCH 06/18] GUACAMOLE-422: Add protocol version as initial item passed back in args. --- src/libguac/user-handshake.c | 10 ++++++++-- src/protocols/kubernetes/settings.c | 13 +++++++++++++ src/protocols/rdp/rdp_settings.c | 13 +++++++++++++ src/protocols/ssh/settings.c | 13 +++++++++++++ src/protocols/telnet/settings.c | 13 +++++++++++++ src/protocols/vnc/settings.c | 13 +++++++++++++ 6 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index a9cf003b..e9ccbacd 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -199,7 +199,7 @@ int __guac_handshake_size_handler(guac_user* user, int argc, char** argv) { } int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { - + /* Store audio mimetypes */ user->info.audio_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); @@ -208,7 +208,7 @@ int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { } int __guac_handshake_video_handler(guac_user* user, int argc, char** argv) { - + /* Store video mimetypes */ user->info.video_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); @@ -227,6 +227,9 @@ int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) { int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) { + /* Free any past value */ + free((char *) user->info.timezone); + /* Store timezone, if present */ if (argc > 0 && strcmp(argv[0], "")) user->info.timezone = (const char*) strdup(argv[0]); @@ -393,6 +396,9 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { if (strcmp(parser->opcode, "connect") == 0) break; + guac_user_log(user, GUAC_LOG_DEBUG, "Processing instruction: %s", + parser->opcode); + /* Loop available opcodes and run handler if/when match found. */ __guac_handshake_mapping* current = __guac_handshake_map; while (current->opcode != NULL) { diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c index 4f00a445..6e8ddd41 100644 --- a/src/protocols/kubernetes/settings.c +++ b/src/protocols/kubernetes/settings.c @@ -25,6 +25,14 @@ /* Client plugin arguments */ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = { + /** + * This first argument defines the protocol version in use so that the + * client knows how to handle talking to different versions of guacd. + * If this is omitted the client may choose not to enable certain + * features. + */ + "VERSION_1_1_0", + "hostname", "port", "namespace", @@ -55,6 +63,11 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = { enum KUBERNETES_ARGS_IDX { + /** + * The protocol version provided to the client. + */ + IDX_PROTOCOL_VERSION, + /** * The hostname to connect to. Required. */ diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c index e5aa85dd..9edcb746 100644 --- a/src/protocols/rdp/rdp_settings.c +++ b/src/protocols/rdp/rdp_settings.c @@ -42,6 +42,14 @@ /* Client plugin arguments */ const char* GUAC_RDP_CLIENT_ARGS[] = { + /** + * This first argument defines the protocol version in use so that the + * client knows how to handle talking to different versions of guacd. + * If this is omitted the client may choose not to enable certain + * features. + */ + "VERSION_1_1_0", + "hostname", "port", "domain", @@ -124,6 +132,11 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { enum RDP_ARGS_IDX { + /** + * The protocol version sent to the client. + */ + IDX_PROTOCOL_VERSION, + /** * The hostname to connect to. */ diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index a0af9f9b..a404e8ca 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -30,6 +30,14 @@ /* Client plugin arguments */ const char* GUAC_SSH_CLIENT_ARGS[] = { + /** + * This first argument defines the protocol version in use so that the + * client knows how to handle talking to different versions of guacd. + * If this is omitted the client may choose not to enable certain + * features. + */ + "VERSION_1_1_0", + "hostname", "host-key", "port", @@ -66,6 +74,11 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { }; enum SSH_ARGS_IDX { + + /** + * The protocol version + */ + IDX_PROTOCOL_VERSION, /** * The hostname to connect to. Required. diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index 890d5fec..4d2d4dd1 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -31,6 +31,14 @@ /* Client plugin arguments */ const char* GUAC_TELNET_CLIENT_ARGS[] = { + /** + * This first argument defines the protocol version in use so that the + * client knows how to handle talking to different versions of guacd. + * If this is omitted the client may choose not to enable certain + * features. + */ + "VERSION_1_1_0", + "hostname", "port", "username", @@ -60,6 +68,11 @@ const char* GUAC_TELNET_CLIENT_ARGS[] = { enum TELNET_ARGS_IDX { + /** + * The protocol version provided by the client. + */ + IDX_PROTOCOL_VERSION, + /** * The hostname to connect to. Required. */ diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index 8f65cfb2..941a2757 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -31,6 +31,14 @@ /* Client plugin arguments */ const char* GUAC_VNC_CLIENT_ARGS[] = { + /** + * This first argument defines the protocol version in use so that the + * client knows how to handle talking to different versions of guacd. + * If this is omitted the client may choose not to enable certain + * features. + */ + "VERSION_1_1_0", + "hostname", "port", "read-only", @@ -83,6 +91,11 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { enum VNC_ARGS_IDX { + /** + * The protocol version provided to the client. + */ + IDX_PROTOCOL_VERSION, + /** * The hostname of the VNC server (or repeater) to connect to. */ From 2f57564f5d2ed7e8a41179000178bcf6ec4e5487 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 2 Apr 2019 21:38:28 -0400 Subject: [PATCH 07/18] GUACAMOLE-422: Remove duplicate code and migrate handshake to user handlers. --- src/libguac/guacamole/user.h | 99 ------------------- src/libguac/user-handlers.c | 131 ++++++++++++++++++++++++++ src/libguac/user-handlers.h | 101 ++++++++++++++++++++ src/libguac/user-handshake.c | 178 +++-------------------------------- src/libguac/user.c | 18 ---- 5 files changed, 245 insertions(+), 282 deletions(-) diff --git a/src/libguac/guacamole/user.h b/src/libguac/guacamole/user.h index 137553a7..67ca7c88 100644 --- a/src/libguac/guacamole/user.h +++ b/src/libguac/guacamole/user.h @@ -505,79 +505,6 @@ struct guac_user { }; -/** - * Handler for Guacamole protocol opcode specific to the handshake that - * happens between client and server at the beginning of the connection. The - * handler will be invoked when the matching opcode is received during the - * handshake process. - * - * @param user - * The user that initiated the handshake. - * - * @param parser - * The parser allocated for parsing the data provided by the client. - * - * @param timeout - * The timeout, in microseconds, for parsing the value. - * - * @return - * Zero if the handshake instruction is successfully parsed; otherwise - * false. - */ -typedef int __guac_handshake_handler(guac_user* user, int argc, char** argv); - -/** - * Structure that maps opcodes received during the handshake phase of the - * connection to callback functions used when those opcodes are received. - */ -typedef struct __guac_handshake_mapping { - - /** - * The instruction opcode which maps to the handler. - */ - char* opcode; - - /** - * The handler function used when specified opcode is received. - */ - __guac_handshake_handler* handler; - -} __guac_handshake_mapping; - -/** - * Internal handler function that is called when the size instruction is - * received during the handshake process. - */ -__guac_handshake_handler __guac_handshake_size_handler; - -/** - * Internal handler function that is called when the audio instruction is - * received during the handshake process, specifying the audio mimetypes - * available to the client. - */ -__guac_handshake_handler __guac_handshake_audio_handler; - -/** - * Internal handler function that is called when the video instruction is - * received during the handshake process, specifying the video mimetypes - * available to the client. - */ -__guac_handshake_handler __guac_handshake_video_handler; - -/** - * Internal handler function that is called when the image instruction is - * received during the handshake process, specifying the image mimetypes - * available to the client. - */ -__guac_handshake_handler __guac_handshake_image_handler; - -/** - * Internal handler function that is called when the timezone instruction is - * received during the handshake process, specifying the timezone of the - * client. - */ -__guac_handshake_handler __guac_handshake_timezone_handler; - /** * Allocates a new, blank user, not associated with any specific client or * socket. @@ -617,32 +544,6 @@ void guac_user_free(guac_user* user); */ int guac_user_handle_connection(guac_user* user, int usec_timeout); -/** - * Call the appropriate handler defined by the given user for the given - * instruction. A comparison is made between the instruction opcode and the - * initial handler lookup table defined in user-handlers.c. The intial handlers - * will in turn call the user's handler (if defined). - * - * @param user - * The user whose handlers should be called. - * - * @param opcode - * The opcode of the instruction to pass to the user via the appropriate - * handler. - * - * @param argc - * The number of arguments which are part of the instruction. - * - * @param argv - * An array of all arguments which are part of the instruction. - * - * @return - * Non-negative if the instruction was handled successfully, or negative - * if an error occurred. - */ -int guac_user_handle_instruction(guac_user* user, const char* opcode, - int argc, char** argv); - /** * Allocates a new stream. An arbitrary index is automatically assigned * if no previously-allocated stream is available for use. diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index 6be20e2e..737e6f30 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -31,6 +31,7 @@ #include #include #include +#include /* Guacamole instruction handler map */ @@ -53,6 +54,17 @@ __guac_instruction_handler_mapping __guac_instruction_handler_map[] = { {NULL, NULL} }; +/* Guacamole handshake handler map */ + +__guac_instruction_handler_mapping __guac_handshake_handler_map[] = { + {"size", __guac_handshake_size_handler}, + {"audio", __guac_handshake_audio_handler}, + {"video", __guac_handshake_video_handler}, + {"image", __guac_handshake_image_handler}, + {"timezone", __guac_handshake_timezone_handler}, + {NULL, NULL} +}; + /** * Parses a 64-bit integer from the given string. It is assumed that the string * will contain only decimal digits, with an optional leading minus sign. @@ -581,3 +593,122 @@ int __guac_handle_disconnect(guac_user* user, int argc, char** argv) { return 0; } +/* Guacamole handshake handler functions. */ + +int __guac_handshake_size_handler(guac_user* user, int argc, char** argv) { + + /* Validate size of instruction. */ + if (argc < 2) { + guac_user_log(user, GUAC_LOG_ERROR, "Received \"size\" " + "instruction lacked required arguments."); + return 1; + } + + /* Parse optimal screen dimensions from size instruction */ + user->info.optimal_width = atoi(argv[0]); + user->info.optimal_height = atoi(argv[1]); + + /* If DPI given, set the user resolution */ + if (argc >= 3) + user->info.optimal_resolution = atoi(argv[2]); + + /* Otherwise, use a safe default for rough backwards compatibility */ + else + user->info.optimal_resolution = 96; + + return 0; + +} + +int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { + + /* Store audio mimetypes */ + user->info.audio_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); + + return 0; + +} + +int __guac_handshake_video_handler(guac_user* user, int argc, char** argv) { + + /* Store video mimetypes */ + user->info.video_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); + + return 0; + +} + +int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) { + + /* Store image mimetypes */ + user->info.image_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); + + return 0; + +} + +int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) { + + /* Free any past value */ + free((char *) user->info.timezone); + + /* Store timezone, if present */ + if (argc > 0 && strcmp(argv[0], "")) + user->info.timezone = (const char*) strdup(argv[0]); + + return 0; + +} + +char** guac_copy_mimetypes(char** mimetypes, int count) { + + int i; + + /* Allocate sufficient space for NULL-terminated array of mimetypes */ + char** mimetypes_copy = malloc(sizeof(char*) * (count+1)); + + /* Copy each provided mimetype */ + for (i = 0; i < count; i++) + mimetypes_copy[i] = strdup(mimetypes[i]); + + /* Terminate with NULL */ + mimetypes_copy[count] = NULL; + + return mimetypes_copy; + +} + +void guac_free_mimetypes(char** mimetypes) { + + char** current_mimetype = mimetypes; + + /* Free all strings within NULL-terminated mimetype array */ + while (*current_mimetype != NULL) { + free(*current_mimetype); + current_mimetype++; + } + + /* Free the array itself, now that its contents have been freed */ + free(mimetypes); + +} + +int guac_user_handle_instruction(__guac_instruction_handler_mapping* map, + guac_user* user, const char* opcode, int argc, char** argv) { + + /* For each defined instruction */ + __guac_instruction_handler_mapping* current = map; + while (current->opcode != NULL) { + + /* If recognized, call handler */ + if (strcmp(opcode, current->opcode) == 0) + return current->handler(user, argc, argv); + + current++; + } + + /* If unrecognized, ignore */ + return 0; + +} + diff --git a/src/libguac/user-handlers.h b/src/libguac/user-handlers.h index 5d7c6eae..1a6477ed 100644 --- a/src/libguac/user-handlers.h +++ b/src/libguac/user-handlers.h @@ -177,6 +177,40 @@ __guac_instruction_handler __guac_handle_size; */ __guac_instruction_handler __guac_handle_disconnect; +/** + * Internal handler function that is called when the size instruction is + * received during the handshake process. + */ +__guac_instruction_handler __guac_handshake_size_handler; + +/** + * Internal handler function that is called when the audio instruction is + * received during the handshake process, specifying the audio mimetypes + * available to the client. + */ +__guac_instruction_handler __guac_handshake_audio_handler; + +/** + * Internal handler function that is called when the video instruction is + * received during the handshake process, specifying the video mimetypes + * available to the client. + */ +__guac_instruction_handler __guac_handshake_video_handler; + +/** + * Internal handler function that is called when the image instruction is + * received during the handshake process, specifying the image mimetypes + * available to the client. + */ +__guac_instruction_handler __guac_handshake_image_handler; + +/** + * Internal handler function that is called when the timezone instruction is + * received during the handshake process, specifying the timezone of the + * client. + */ +__guac_instruction_handler __guac_handshake_timezone_handler; + /** * Instruction handler mapping table. This is a NULL-terminated array of * __guac_instruction_handler_mapping structures, each mapping an opcode @@ -186,4 +220,71 @@ __guac_instruction_handler __guac_handle_disconnect; */ extern __guac_instruction_handler_mapping __guac_instruction_handler_map[]; +/** + * Handler mapping table for instructions (opcodes) specifically for the + * handshake portion of the connection. Each + * __guac_instruction_handler_mapping structure within this NULL-terminated + * array maps an opcode to a __guac_instruction_handler. The end of the array + * must be marked with a mapping with the opcode set to NULL. + */ +extern __guac_instruction_handler_mapping __guac_handshake_handler_map[]; + +/** + * Frees the given array of mimetypes, including the space allocated to each + * mimetype string within the array. The provided array of mimetypes MUST have + * been allocated with guac_copy_mimetypes(). + * + * @param mimetypes + * The NULL-terminated array of mimetypes to free. This array MUST have + * been previously allocated with guac_copy_mimetypes(). + */ +void guac_free_mimetypes(char** mimetypes); + +/** + * Copies the given array of mimetypes (strings) into a newly-allocated NULL- + * terminated array of strings. Both the array and the strings within the array + * are newly-allocated and must be later freed via guac_free_mimetypes(). + * + * @param mimetypes + * The array of mimetypes to copy. + * + * @param count + * The number of mimetypes in the given array. + * + * @return + * A newly-allocated, NULL-terminated array containing newly-allocated + * copies of each of the mimetypes provided in the original mimetypes + * array. + */ +char** guac_copy_mimetypes(char** mimetypes, int count); + +/** + * Call the appropriate handler defined by the given user for the given + * instruction. A comparison is made between the instruction opcode and the + * initial handler lookup table defined in user-handlers.c. The intial handlers + * will in turn call the user's handler (if defined). + * + * @param map + * The array that holds the opcode to handler mappings. + * + * @param user + * The user whose handlers should be called. + * + * @param opcode + * The opcode of the instruction to pass to the user via the appropriate + * handler. + * + * @param argc + * The number of arguments which are part of the instruction. + * + * @param argv + * An array of all arguments which are part of the instruction. + * + * @return + * Non-negative if the instruction was handled successfully, or negative + * if an error occurred. + */ +int guac_user_handle_instruction(__guac_instruction_handler_mapping* map, + guac_user* user, const char* opcode, int argc, char** argv); + #endif diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index e9ccbacd..9cccec4c 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -113,141 +113,6 @@ static void guac_user_log_handshake_failure(guac_user* user) { } -/** - * Copies the given array of mimetypes (strings) into a newly-allocated NULL- - * terminated array of strings. Both the array and the strings within the array - * are newly-allocated and must be later freed via guac_free_mimetypes(). - * - * @param mimetypes - * The array of mimetypes to copy. - * - * @param count - * The number of mimetypes in the given array. - * - * @return - * A newly-allocated, NULL-terminated array containing newly-allocated - * copies of each of the mimetypes provided in the original mimetypes - * array. - */ -static char** guac_copy_mimetypes(char** mimetypes, int count) { - - int i; - - /* Allocate sufficient space for NULL-terminated array of mimetypes */ - char** mimetypes_copy = malloc(sizeof(char*) * (count+1)); - - /* Copy each provided mimetype */ - for (i = 0; i < count; i++) - mimetypes_copy[i] = strdup(mimetypes[i]); - - /* Terminate with NULL */ - mimetypes_copy[count] = NULL; - - return mimetypes_copy; - -} - -/** - * Frees the given array of mimetypes, including the space allocated to each - * mimetype string within the array. The provided array of mimetypes MUST have - * been allocated with guac_copy_mimetypes(). - * - * @param mimetypes - * The NULL-terminated array of mimetypes to free. This array MUST have - * been previously allocated with guac_copy_mimetypes(). - */ -static void guac_free_mimetypes(char** mimetypes) { - - char** current_mimetype = mimetypes; - - /* Free all strings within NULL-terminated mimetype array */ - while (*current_mimetype != NULL) { - free(*current_mimetype); - current_mimetype++; - } - - /* Free the array itself, now that its contents have been freed */ - free(mimetypes); - -} - -/* Guacamole handshake handler functions. */ - -int __guac_handshake_size_handler(guac_user* user, int argc, char** argv) { - - /* Validate size of instruction. */ - if (argc < 2) { - guac_user_log(user, GUAC_LOG_ERROR, "Received \"size\" " - "instruction lacked required arguments."); - return 1; - } - - /* Parse optimal screen dimensions from size instruction */ - user->info.optimal_width = atoi(argv[0]); - user->info.optimal_height = atoi(argv[1]); - - /* If DPI given, set the user resolution */ - if (argc >= 3) - user->info.optimal_resolution = atoi(argv[2]); - - /* Otherwise, use a safe default for rough backwards compatibility */ - else - user->info.optimal_resolution = 96; - - return 0; - -} - -int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { - - /* Store audio mimetypes */ - user->info.audio_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); - - return 0; - -} - -int __guac_handshake_video_handler(guac_user* user, int argc, char** argv) { - - /* Store video mimetypes */ - user->info.video_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); - - return 0; - -} - -int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) { - - /* Store image mimetypes */ - user->info.image_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); - - return 0; - -} - -int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) { - - /* Free any past value */ - free((char *) user->info.timezone); - - /* Store timezone, if present */ - if (argc > 0 && strcmp(argv[0], "")) - user->info.timezone = (const char*) strdup(argv[0]); - - return 0; - -} - -/* Guacamole handshake handler mappings. */ -__guac_handshake_mapping __guac_handshake_map[] = { - {"size", __guac_handshake_size_handler}, - {"audio", __guac_handshake_audio_handler}, - {"video", __guac_handshake_video_handler}, - {"image", __guac_handshake_image_handler}, - {"timezone", __guac_handshake_timezone_handler}, - {NULL, NULL} -}; - /** * The thread which handles all user input, calling event handlers for received * instructions. @@ -296,7 +161,8 @@ static void* guac_user_input_thread(void* data) { guac_error_message = NULL; /* Call handler, stop on error */ - if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) { + if (guac_user_handle_instruction(__guac_instruction_handler_map, + user, parser->opcode, parser->argc, parser->argv) < 0) { /* Log error */ guac_user_log_guac_error(user, GUAC_LOG_WARNING, @@ -399,39 +265,21 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_user_log(user, GUAC_LOG_DEBUG, "Processing instruction: %s", parser->opcode); - /* Loop available opcodes and run handler if/when match found. */ - __guac_handshake_mapping* current = __guac_handshake_map; - while (current->opcode != NULL) { + /* Run instruction handler for opcode with arguments. */ + if (guac_user_handle_instruction(__guac_handshake_handler_map, user, + parser->opcode, parser->argc, parser->argv)) { - /* Check if loop opcode matches parsed opcode. */ - if (strcmp(parser->opcode, current->opcode) == 0) { - - /* If calling the handler fails, log it and return. */ - if (current->handler(user, parser->argc, parser->argv)) { - - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error handling handling opcode during handshake."); - guac_user_log(user, GUAC_LOG_DEBUG, "Failed opcode: %s", - current->opcode); + guac_user_log_handshake_failure(user); + guac_user_log_guac_error(user, GUAC_LOG_DEBUG, + "Error handling handling opcode during handshake."); + guac_user_log(user, GUAC_LOG_DEBUG, "Failed opcode: %s", + parser->opcode); - guac_parser_free(parser); - return 1; - } - - /* If calling the handler has succeeded, log it and break. */ - else { - guac_user_log(user, GUAC_LOG_DEBUG, - "Successfully processed instruction: \"%s\"", - current->opcode); - break; - } - - } + guac_parser_free(parser); + return 1; - /* Move to next opcode. */ - current++; } + } /* Acknowledge connection availability */ diff --git a/src/libguac/user.c b/src/libguac/user.c index 16590060..64c2a763 100644 --- a/src/libguac/user.c +++ b/src/libguac/user.c @@ -167,24 +167,6 @@ void guac_user_free_object(guac_user* user, guac_object* object) { } -int guac_user_handle_instruction(guac_user* user, const char* opcode, int argc, char** argv) { - - /* For each defined instruction */ - __guac_instruction_handler_mapping* current = __guac_instruction_handler_map; - while (current->opcode != NULL) { - - /* If recognized, call handler */ - if (strcmp(opcode, current->opcode) == 0) - return current->handler(user, argc, argv); - - current++; - } - - /* If unrecognized, ignore */ - return 0; - -} - void guac_user_stop(guac_user* user) { user->active = 0; } From c750b18f6030b7925760f00da9c205dbb96336b7 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 10 Apr 2019 07:08:20 -0400 Subject: [PATCH 08/18] GUACAMOLE-422: Handle sending version internally. --- src/libguac/guacamole/protocol.h | 3 +++ src/libguac/protocol.c | 5 +++++ src/protocols/kubernetes/settings.c | 8 -------- src/protocols/rdp/rdp_settings.c | 8 -------- src/protocols/ssh/settings.c | 8 -------- src/protocols/telnet/settings.c | 8 -------- src/protocols/vnc/settings.c | 8 -------- 7 files changed, 8 insertions(+), 40 deletions(-) diff --git a/src/libguac/guacamole/protocol.h b/src/libguac/guacamole/protocol.h index d1a0420a..ff7746ff 100644 --- a/src/libguac/guacamole/protocol.h +++ b/src/libguac/guacamole/protocol.h @@ -38,6 +38,9 @@ #include #include +/* The protocol version */ +#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_1_0" + /* CONTROL INSTRUCTIONS */ /** diff --git a/src/libguac/protocol.c b/src/libguac/protocol.c index ee266e87..f58179f3 100644 --- a/src/libguac/protocol.c +++ b/src/libguac/protocol.c @@ -93,6 +93,11 @@ static int __guac_protocol_send_args(guac_socket* socket, const char** args) { int i; if (guac_socket_write_string(socket, "4.args")) return -1; + + // Send protocol version + if (guac_socket_write_string(socket, ",") + || __guac_socket_write_length_string(socket, GUACAMOLE_PROTOCOL_VERSION)) + return -1; for (i=0; args[i] != NULL; i++) { diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c index 6e8ddd41..ce7f6977 100644 --- a/src/protocols/kubernetes/settings.c +++ b/src/protocols/kubernetes/settings.c @@ -25,14 +25,6 @@ /* Client plugin arguments */ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = { - /** - * This first argument defines the protocol version in use so that the - * client knows how to handle talking to different versions of guacd. - * If this is omitted the client may choose not to enable certain - * features. - */ - "VERSION_1_1_0", - "hostname", "port", "namespace", diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c index 9edcb746..f45b3a43 100644 --- a/src/protocols/rdp/rdp_settings.c +++ b/src/protocols/rdp/rdp_settings.c @@ -42,14 +42,6 @@ /* Client plugin arguments */ const char* GUAC_RDP_CLIENT_ARGS[] = { - /** - * This first argument defines the protocol version in use so that the - * client knows how to handle talking to different versions of guacd. - * If this is omitted the client may choose not to enable certain - * features. - */ - "VERSION_1_1_0", - "hostname", "port", "domain", diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index a404e8ca..b69ddd6c 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -30,14 +30,6 @@ /* Client plugin arguments */ const char* GUAC_SSH_CLIENT_ARGS[] = { - /** - * This first argument defines the protocol version in use so that the - * client knows how to handle talking to different versions of guacd. - * If this is omitted the client may choose not to enable certain - * features. - */ - "VERSION_1_1_0", - "hostname", "host-key", "port", diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index 4d2d4dd1..9d334df2 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -31,14 +31,6 @@ /* Client plugin arguments */ const char* GUAC_TELNET_CLIENT_ARGS[] = { - /** - * This first argument defines the protocol version in use so that the - * client knows how to handle talking to different versions of guacd. - * If this is omitted the client may choose not to enable certain - * features. - */ - "VERSION_1_1_0", - "hostname", "port", "username", diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index 941a2757..c39aa730 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -31,14 +31,6 @@ /* Client plugin arguments */ const char* GUAC_VNC_CLIENT_ARGS[] = { - /** - * This first argument defines the protocol version in use so that the - * client knows how to handle talking to different versions of guacd. - * If this is omitted the client may choose not to enable certain - * features. - */ - "VERSION_1_1_0", - "hostname", "port", "read-only", From 379fce2d770608911e29fd3ca9bb1b9d9e3e1dbb Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Thu, 11 Apr 2019 17:11:41 -0400 Subject: [PATCH 09/18] GUACAMOLE-422: Rename new opcode handler function. --- src/libguac/guacamole/user.h | 26 ++++++++++++++++++++++++++ src/libguac/user-handlers.c | 2 +- src/libguac/user-handlers.h | 8 +++++--- src/libguac/user-handshake.c | 5 +++-- src/libguac/user.c | 7 +++++++ 5 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/libguac/guacamole/user.h b/src/libguac/guacamole/user.h index 67ca7c88..f920c325 100644 --- a/src/libguac/guacamole/user.h +++ b/src/libguac/guacamole/user.h @@ -544,6 +544,32 @@ void guac_user_free(guac_user* user); */ int guac_user_handle_connection(guac_user* user, int usec_timeout); +/** + * Call the appropriate handler defined by the given user for the given + * instruction. A comparison is made between the instruction opcode and the + * initial handler lookup table defined in user-handlers.c. The initial handlers + * will in turn call the user's handler (if defined). + * + * @param user + * The user whose handlers should be called. + * + * @param opcode + * The opcode of the instruction to pass to the user via the appropriate + * handler. + * + * @param argc + * The number of arguments which are part of the instruction. + * + * @param argv + * An array of all arguments which are part of the instruction. + * + * @return + * Non-negative if the instruction was handled successfully, or negative + * if an error occurred. + */ +int guac_user_handle_instruction(guac_user* user, const char* opcode, + int argc, char** argv); + /** * Allocates a new stream. An arbitrary index is automatically assigned * if no previously-allocated stream is available for use. diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index 737e6f30..92dc249a 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -693,7 +693,7 @@ void guac_free_mimetypes(char** mimetypes) { } -int guac_user_handle_instruction(__guac_instruction_handler_mapping* map, +int __guac_user_call_opcode_handler(__guac_instruction_handler_mapping* map, guac_user* user, const char* opcode, int argc, char** argv) { /* For each defined instruction */ diff --git a/src/libguac/user-handlers.h b/src/libguac/user-handlers.h index 1a6477ed..dd9f829b 100644 --- a/src/libguac/user-handlers.h +++ b/src/libguac/user-handlers.h @@ -261,8 +261,10 @@ char** guac_copy_mimetypes(char** mimetypes, int count); /** * Call the appropriate handler defined by the given user for the given * instruction. A comparison is made between the instruction opcode and the - * initial handler lookup table defined in user-handlers.c. The intial handlers - * will in turn call the user's handler (if defined). + * initial handler lookup table defined in the map that is provided to this + * function. If an entry for the instruction is found in the provided map, + * the handler defined in that map will be called and the value returned. If + * no match is found, it is silently ignored. * * @param map * The array that holds the opcode to handler mappings. @@ -284,7 +286,7 @@ char** guac_copy_mimetypes(char** mimetypes, int count); * Non-negative if the instruction was handled successfully, or negative * if an error occurred. */ -int guac_user_handle_instruction(__guac_instruction_handler_mapping* map, +int __guac_user_call_opcode_handler(__guac_instruction_handler_mapping* map, guac_user* user, const char* opcode, int argc, char** argv); #endif diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 9cccec4c..cf96d347 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -25,6 +25,7 @@ #include "guacamole/protocol.h" #include "guacamole/socket.h" #include "guacamole/user.h" +#include "user-handlers.h" #include #include @@ -161,7 +162,7 @@ static void* guac_user_input_thread(void* data) { guac_error_message = NULL; /* Call handler, stop on error */ - if (guac_user_handle_instruction(__guac_instruction_handler_map, + if (__guac_user_call_opcode_handler(__guac_instruction_handler_map, user, parser->opcode, parser->argc, parser->argv) < 0) { /* Log error */ @@ -266,7 +267,7 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { parser->opcode); /* Run instruction handler for opcode with arguments. */ - if (guac_user_handle_instruction(__guac_handshake_handler_map, user, + if (__guac_user_call_opcode_handler(__guac_handshake_handler_map, user, parser->opcode, parser->argc, parser->argv)) { guac_user_log_handshake_failure(user); diff --git a/src/libguac/user.c b/src/libguac/user.c index 64c2a763..9145b275 100644 --- a/src/libguac/user.c +++ b/src/libguac/user.c @@ -167,6 +167,13 @@ void guac_user_free_object(guac_user* user, guac_object* object) { } +int guac_user_handle_instruction(guac_user* user, const char* opcode, int argc, char** argv) { + + return __guac_user_call_opcode_handler(__guac_instruction_handler_map, + user, opcode, argc, argv); + +} + void guac_user_stop(guac_user* user) { user->active = 0; } From 340aef5362ae013ca38e3a8cbe1bfcdf53746775 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 13 Apr 2019 21:30:57 -0400 Subject: [PATCH 10/18] GUACAMOLE-422: Update to remove first argument --- src/libguac/user-handshake.c | 9 +++++---- src/protocols/kubernetes/settings.c | 5 ----- src/protocols/rdp/rdp_settings.c | 5 ----- src/protocols/ssh/settings.c | 5 ----- src/protocols/telnet/settings.c | 5 ----- src/protocols/vnc/settings.c | 5 ----- 6 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index cf96d347..a7805b21 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -234,7 +234,7 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_socket* socket = user->socket; guac_client* client = user->client; - + /* Send args */ if (guac_protocol_send_args(socket, client->args) || guac_socket_flush(socket)) { @@ -286,9 +286,10 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { /* Acknowledge connection availability */ guac_protocol_send_ready(socket, client->connection_id); guac_socket_flush(socket); - - /* Attempt join */ - if (guac_client_add_user(client, user, parser->argc, parser->argv)) + + /* Check return value from join attempt */ + if (guac_client_add_user(client, user, (parser->argc - 1), + parser->argv + 1)) guac_client_log(client, GUAC_LOG_ERROR, "User \"%s\" could NOT " "join connection \"%s\"", user->user_id, client->connection_id); diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c index ce7f6977..0ae3dc23 100644 --- a/src/protocols/kubernetes/settings.c +++ b/src/protocols/kubernetes/settings.c @@ -54,11 +54,6 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = { }; enum KUBERNETES_ARGS_IDX { - - /** - * The protocol version provided to the client. - */ - IDX_PROTOCOL_VERSION, /** * The hostname to connect to. Required. diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c index f45b3a43..51214a61 100644 --- a/src/protocols/rdp/rdp_settings.c +++ b/src/protocols/rdp/rdp_settings.c @@ -123,11 +123,6 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { }; enum RDP_ARGS_IDX { - - /** - * The protocol version sent to the client. - */ - IDX_PROTOCOL_VERSION, /** * The hostname to connect to. diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index b69ddd6c..a0af9f9b 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -66,11 +66,6 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { }; enum SSH_ARGS_IDX { - - /** - * The protocol version - */ - IDX_PROTOCOL_VERSION, /** * The hostname to connect to. Required. diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index 9d334df2..85b4fb85 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -59,11 +59,6 @@ const char* GUAC_TELNET_CLIENT_ARGS[] = { }; enum TELNET_ARGS_IDX { - - /** - * The protocol version provided by the client. - */ - IDX_PROTOCOL_VERSION, /** * The hostname to connect to. Required. diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index c39aa730..623e6688 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -82,11 +82,6 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { }; enum VNC_ARGS_IDX { - - /** - * The protocol version provided to the client. - */ - IDX_PROTOCOL_VERSION, /** * The hostname of the VNC server (or repeater) to connect to. From 54f88531d43b0eb7fd54543651844f6fc12d3df8 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 17 Apr 2019 14:56:51 -0400 Subject: [PATCH 11/18] GUACAMOLE-422: Try to avoid memory leaks with mimetypes. --- src/libguac/user-handlers.c | 9 +++++++++ src/libguac/user-handshake.c | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index 92dc249a..f1d937e3 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -622,6 +622,8 @@ int __guac_handshake_size_handler(guac_user* user, int argc, char** argv) { int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { + guac_free_mimetypes((char **) user->info.audio_mimetypes); + /* Store audio mimetypes */ user->info.audio_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); @@ -631,6 +633,8 @@ int __guac_handshake_audio_handler(guac_user* user, int argc, char** argv) { int __guac_handshake_video_handler(guac_user* user, int argc, char** argv) { + guac_free_mimetypes((char **) user->info.video_mimetypes); + /* Store video mimetypes */ user->info.video_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); @@ -640,6 +644,8 @@ int __guac_handshake_video_handler(guac_user* user, int argc, char** argv) { int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) { + guac_free_mimetypes((char **) user->info.image_mimetypes); + /* Store image mimetypes */ user->info.image_mimetypes = (const char**) guac_copy_mimetypes(argv, argc); @@ -680,6 +686,9 @@ char** guac_copy_mimetypes(char** mimetypes, int count) { void guac_free_mimetypes(char** mimetypes) { + if (mimetypes == NULL) + return; + char** current_mimetype = mimetypes; /* Free all strings within NULL-terminated mimetype array */ diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index a7805b21..8c1fd89b 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -235,6 +235,10 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_socket* socket = user->socket; guac_client* client = user->client; + user->info.audio_mimetypes = NULL; + user->info.image_mimetypes = NULL; + user->info.video_mimetypes = NULL; + /* Send args */ if (guac_protocol_send_args(socket, client->args) || guac_socket_flush(socket)) { From 75c0deac1f445fdd81f768972d5cd5340352982a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 17 Apr 2019 15:03:27 -0400 Subject: [PATCH 12/18] GUACAMOLE-422: Update comment style for consistency. --- src/libguac/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libguac/protocol.c b/src/libguac/protocol.c index f58179f3..46a9858e 100644 --- a/src/libguac/protocol.c +++ b/src/libguac/protocol.c @@ -94,7 +94,7 @@ static int __guac_protocol_send_args(guac_socket* socket, const char** args) { if (guac_socket_write_string(socket, "4.args")) return -1; - // Send protocol version + /* Send protocol version ahead of other args. */ if (guac_socket_write_string(socket, ",") || __guac_socket_write_length_string(socket, GUACAMOLE_PROTOCOL_VERSION)) return -1; From 98cb7ccf6773f9e55645ccfe542de31ab2bc136c Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 17 Apr 2019 15:12:46 -0400 Subject: [PATCH 13/18] GUACAMOLE-422: Fix comment and style. --- src/libguac/user-handshake.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 8c1fd89b..ed30c63a 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -291,9 +291,8 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_protocol_send_ready(socket, client->connection_id); guac_socket_flush(socket); - /* Check return value from join attempt */ - if (guac_client_add_user(client, user, (parser->argc - 1), - parser->argv + 1)) + /* Attempt to join user to connection. */ + if (guac_client_add_user(client, user, (parser->argc - 1), parser->argv + 1)) guac_client_log(client, GUAC_LOG_ERROR, "User \"%s\" could NOT " "join connection \"%s\"", user->user_id, client->connection_id); From ab12b2aa8e3134d42c5fd42432d95eeec9be2a77 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Fri, 19 Apr 2019 15:48:14 -0400 Subject: [PATCH 14/18] GUACAMOLE-422: More substantial comment for protocol version; NULL out timezone at beginning of handshake. --- src/libguac/guacamole/protocol.h | 13 ++++++++++++- src/libguac/user-handshake.c | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libguac/guacamole/protocol.h b/src/libguac/guacamole/protocol.h index ff7746ff..0b462b4c 100644 --- a/src/libguac/guacamole/protocol.h +++ b/src/libguac/guacamole/protocol.h @@ -38,7 +38,18 @@ #include #include -/* The protocol version */ +/** + * This defines the overall protocol version that this build of libguac + * supports. The protocol version is used to provide compatibility between + * potentially different versions of Guacamole server and clients. The + * version number is a MAJOR_MINOR_PATCH version that matches the versioning + * used throughout the components of the Guacamole project. This version + * will not necessarily increment with the other components, unless additional + * functionality is introduced that affects compatibility. + * + * This version is passed by the __guac_protocol_send_args() function from the + * server to the client during the client/server handshake. + */ #define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_1_0" /* CONTROL INSTRUCTIONS */ diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index ed30c63a..26b42a76 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -238,6 +238,7 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { user->info.audio_mimetypes = NULL; user->info.image_mimetypes = NULL; user->info.video_mimetypes = NULL; + user->info.timezone = NULL; /* Send args */ if (guac_protocol_send_args(socket, client->args) From 588e0f194a7a90cc92e900dc89e66bb566d304dd Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Fri, 19 Apr 2019 15:50:29 -0400 Subject: [PATCH 15/18] GUACAMOLE-422: Fix return documentation on opcode handler function. --- src/libguac/user-handlers.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libguac/user-handlers.h b/src/libguac/user-handlers.h index dd9f829b..17cfc0db 100644 --- a/src/libguac/user-handlers.h +++ b/src/libguac/user-handlers.h @@ -283,8 +283,7 @@ char** guac_copy_mimetypes(char** mimetypes, int count); * An array of all arguments which are part of the instruction. * * @return - * Non-negative if the instruction was handled successfully, or negative - * if an error occurred. + * Zero if the instruction was handled successfully, or non-zero otherwise. */ int __guac_user_call_opcode_handler(__guac_instruction_handler_mapping* map, guac_user* user, const char* opcode, int argc, char** argv); From 4b43de963e998e874051b1895a44436a903f0565 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 22 Apr 2019 11:49:46 -0400 Subject: [PATCH 16/18] GUACAMOLE-422: Break handshake out into separate function; NULL out timezone when not received. --- src/libguac/user-handlers.c | 3 ++ src/libguac/user-handshake.c | 94 ++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index f1d937e3..cef6c14c 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -662,6 +662,9 @@ int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) { if (argc > 0 && strcmp(argv[0], "")) user->info.timezone = (const char*) strdup(argv[0]); + else + user->info.timezone = NULL; + return 0; } diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 26b42a76..31f9d9fb 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -230,6 +230,62 @@ static int guac_user_start(guac_parser* parser, guac_user* user, } +/** + * This function loops through the received instructions during the handshake + * with the client attempting to join the connection, and runs the handlers + * for each of the opcodes, ending when the connect instruction is received. + * Returns zero if the handshake completes successfully with the connect opcode, + * or a non-zero value if an error occurs. + * + * @param user + * The guac_user attempting to join the connection. + * + * @param parser + * The parser used to examine the received data. + * + * @param usec_timeout + * The timeout, in microseconds, for reading the instructions. + * + * @return + * Zero if the handshake completes successfully with the connect opcode, + * or non-zero if an error occurs. + */ +static int __guac_user_handshake(guac_user* user, guac_parser* parser, + int usec_timeout) { + + guac_socket* socket = user->socket; + + /* Handle each of the opcodes. */ + while (guac_parser_read(parser, socket, usec_timeout) == 0) { + + /* If we receive the connect opcode, we're done. */ + if (strcmp(parser->opcode, "connect") == 0) + return 0; + + guac_user_log(user, GUAC_LOG_DEBUG, "Processing instruction: %s", + parser->opcode); + + /* Run instruction handler for opcode with arguments. */ + if (__guac_user_call_opcode_handler(__guac_handshake_handler_map, user, + parser->opcode, parser->argc, parser->argv)) { + + guac_user_log_handshake_failure(user); + guac_user_log_guac_error(user, GUAC_LOG_DEBUG, + "Error handling handling opcode during handshake."); + guac_user_log(user, GUAC_LOG_DEBUG, "Failed opcode: %s", + parser->opcode); + + guac_parser_free(parser); + return 1; + + } + + } + + /* If we get here something has gone wrong. */ + return 1; +} + int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_socket* socket = user->socket; @@ -254,38 +310,12 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_parser* parser = guac_parser_alloc(); - /* Handle each of the opcodes. */ - while (1) { - if (guac_parser_read(parser, socket, usec_timeout)) { - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error while reading opcode instruction."); - guac_parser_free(parser); - return 1; - } - - /* If we receive the connect opcode, we're done. */ - if (strcmp(parser->opcode, "connect") == 0) - break; - - guac_user_log(user, GUAC_LOG_DEBUG, "Processing instruction: %s", - parser->opcode); - - /* Run instruction handler for opcode with arguments. */ - if (__guac_user_call_opcode_handler(__guac_handshake_handler_map, user, - parser->opcode, parser->argc, parser->argv)) { - - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error handling handling opcode during handshake."); - guac_user_log(user, GUAC_LOG_DEBUG, "Failed opcode: %s", - parser->opcode); - - guac_parser_free(parser); - return 1; - - } - + /* Perform the handshake with the client. */ + if (__guac_user_handshake(user, parser, usec_timeout)) { + guac_user_log_handshake_failure(user); + guac_user_log_guac_error(user, GUAC_LOG_DEBUG, + "Error while reading opcode instruction."); + guac_parser_free(parser); } /* Acknowledge connection availability */ From 93a240b8adcaac88cbea0de9847ac058f029c53e Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 24 Apr 2019 22:21:18 -0400 Subject: [PATCH 17/18] GUACAMOLE-422: Add debugging and check argument count. --- src/libguac/user-handlers.c | 4 +++- src/libguac/user-handshake.c | 29 +++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index cef6c14c..fd8540c5 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -719,7 +719,9 @@ int __guac_user_call_opcode_handler(__guac_instruction_handler_mapping* map, current++; } - /* If unrecognized, ignore */ + /* If unrecognized, log and ignore */ + guac_user_log(user, GUAC_LOG_WARNING, "Handler not found for \"%s\"", + opcode); return 0; } diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index 31f9d9fb..a2d8ec4a 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -163,7 +163,7 @@ static void* guac_user_input_thread(void* data) { /* Call handler, stop on error */ if (__guac_user_call_opcode_handler(__guac_instruction_handler_map, - user, parser->opcode, parser->argc, parser->argv) < 0) { + user, parser->opcode, parser->argc, parser->argv)) { /* Log error */ guac_user_log_guac_error(user, GUAC_LOG_WARNING, @@ -271,7 +271,7 @@ static int __guac_user_handshake(guac_user* user, guac_parser* parser, guac_user_log_handshake_failure(user); guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error handling handling opcode during handshake."); + "Error handling instruction during handshake."); guac_user_log(user, GUAC_LOG_DEBUG, "Failed opcode: %s", parser->opcode); @@ -282,7 +282,9 @@ static int __guac_user_handshake(guac_user* user, guac_parser* parser, } - /* If we get here something has gone wrong. */ + /* If we get here it's because we never got the connect instruction. */ + guac_user_log(user, GUAC_LOG_ERROR, + "Handshake failed, \"connect\" instruction was not received."); return 1; } @@ -296,6 +298,10 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { user->info.video_mimetypes = NULL; user->info.timezone = NULL; + /* Count number of arguments. */ + int numArgs; + for (numArgs = 0; client->args[numArgs] != NULL; numArgs++); + /* Send args */ if (guac_protocol_send_args(socket, client->args) || guac_socket_flush(socket)) { @@ -312,16 +318,21 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { /* Perform the handshake with the client. */ if (__guac_user_handshake(user, parser, usec_timeout)) { - guac_user_log_handshake_failure(user); - guac_user_log_guac_error(user, GUAC_LOG_DEBUG, - "Error while reading opcode instruction."); guac_parser_free(parser); + return 1; } /* Acknowledge connection availability */ guac_protocol_send_ready(socket, client->connection_id); guac_socket_flush(socket); + /* Verify argument count. */ + if (parser->argc != (numArgs + 1)) { + guac_client_log(client, GUAC_LOG_ERROR, "Client did not return the " + "expected number of arguments."); + return 1; + } + /* Attempt to join user to connection. */ if (guac_client_add_user(client, user, (parser->argc - 1), parser->argv + 1)) guac_client_log(client, GUAC_LOG_ERROR, "User \"%s\" could NOT " @@ -333,6 +344,12 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_client_log(client, GUAC_LOG_INFO, "User \"%s\" joined connection " "\"%s\" (%i users now present)", user->user_id, client->connection_id, client->connected_users); + if (strcmp(parser->argv[0],"") != 0) + guac_client_log(client, GUAC_LOG_DEBUG, "Client is using protocol " + "version \"%s\"", parser->argv[0]); + else + guac_client_log(client, GUAC_LOG_DEBUG, "Client has not defined " + "its protocol version."); /* Handle user I/O, wait for connection to terminate */ guac_user_start(parser, user, usec_timeout); From bf741a46d6fc4de1afc3b013c6094ba9893df881 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 27 Apr 2019 21:37:26 -0400 Subject: [PATCH 18/18] GUACAMOLE-422: Minor style and debug changes. --- src/libguac/user-handlers.c | 2 +- src/libguac/user-handshake.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libguac/user-handlers.c b/src/libguac/user-handlers.c index fd8540c5..eeed9bcd 100644 --- a/src/libguac/user-handlers.c +++ b/src/libguac/user-handlers.c @@ -720,7 +720,7 @@ int __guac_user_call_opcode_handler(__guac_instruction_handler_mapping* map, } /* If unrecognized, log and ignore */ - guac_user_log(user, GUAC_LOG_WARNING, "Handler not found for \"%s\"", + guac_user_log(user, GUAC_LOG_DEBUG, "Handler not found for \"%s\"", opcode); return 0; diff --git a/src/libguac/user-handshake.c b/src/libguac/user-handshake.c index a2d8ec4a..89afccdd 100644 --- a/src/libguac/user-handshake.c +++ b/src/libguac/user-handshake.c @@ -299,8 +299,8 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { user->info.timezone = NULL; /* Count number of arguments. */ - int numArgs; - for (numArgs = 0; client->args[numArgs] != NULL; numArgs++); + int num_args; + for (num_args = 0; client->args[num_args] != NULL; num_args++); /* Send args */ if (guac_protocol_send_args(socket, client->args) @@ -327,7 +327,7 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) { guac_socket_flush(socket); /* Verify argument count. */ - if (parser->argc != (numArgs + 1)) { + if (parser->argc != (num_args + 1)) { guac_client_log(client, GUAC_LOG_ERROR, "Client did not return the " "expected number of arguments."); return 1;