diff --git a/src/libguac/client.c b/src/libguac/client.c index 4be0d4de..9738c0c2 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -492,15 +492,17 @@ int guac_client_load_plugin(guac_client* client, const char* protocol) { * passed on to the owner to continue the connection. * * @return - * A pointer to an integer containing the return status of the send - * operation. + * Zero if the operation succeeds or non-zero on failure, cast as a void*. */ static void* guac_client_owner_send_required_callback(guac_user* user, void* data) { const char** required = (const char **) data; /* Send required parameters to owner. */ - return (void*) ((intptr_t) guac_protocol_send_required(user->socket, required)); + if (user != NULL) + return (void*) ((intptr_t) guac_protocol_send_required(user->socket, required)); + + return (void*) ((intptr_t) -1); } @@ -672,38 +674,30 @@ static void* __webp_support_callback(guac_user* user, void* data) { /** * A callback function which is invoked by guac_client_owner_supports_required() * to determine if the owner of a client supports the "required" instruction, - * updating the flag to indicate support. + * returning zero if the user does not support the instruction or non-zero if + * the user supports it. * * @param user * The guac_user that will be checked for "required" instruction support. * * @param data - * A pointer to an int containing the status for support of the "required" - * instruction. This will be 0 if the owner does not support this - * instruction, or 1 if the owner does support it. + * Data provided to the callback. This value is never used within this + * callback. * * @return - * Always NULL. + * A non-zero integer if the provided user who owns the connection supports + * the "required" instruction, or zero if the user does not. The integer + * is cast as a void*. */ static void* guac_owner_supports_required_callback(guac_user* user, void* data) { - int* required_supported = (int *) data; - - /* Check if owner supports required */ - if (*required_supported) - *required_supported = guac_user_supports_required(user); - - return NULL; + return (void*) ((intptr_t) guac_user_supports_required(user)); } int guac_client_owner_supports_required(guac_client* client) { - int required_supported = 1; - - guac_client_for_owner(client, guac_owner_supports_required_callback, &required_supported); - - return required_supported; + return (int) ((intptr_t) guac_client_for_owner(client, guac_owner_supports_required_callback, NULL)); } diff --git a/src/libguac/guacamole/protocol-types.h b/src/libguac/guacamole/protocol-types.h index d492fe7f..51652d2b 100644 --- a/src/libguac/guacamole/protocol-types.h +++ b/src/libguac/guacamole/protocol-types.h @@ -277,8 +277,8 @@ typedef enum guac_line_join_style { } guac_line_join_style; /** - * The set of protocol versions known to guacd to help negotiate features that - * may not be supported by various versions of the client. + * The set of protocol versions known to guacd to handle negotiation or feature + * support between differing versions of Guacamole clients and guacd. */ typedef enum guac_protocol_version { diff --git a/src/libguac/guacamole/protocol.h b/src/libguac/guacamole/protocol.h index c4c6f211..c6dbed29 100644 --- a/src/libguac/guacamole/protocol.h +++ b/src/libguac/guacamole/protocol.h @@ -797,7 +797,7 @@ int guac_protocol_send_rect(guac_socket* socket, const guac_layer* layer, /** * Sends a "required" instruction over the given guac_socket connection. This * instruction indicates to the client that one or more additional parameters - * is needed to continue the connection. + * are needed to continue the connection. * * @param socket * The guac_socket connection to which to send the instruction. @@ -1024,18 +1024,18 @@ int guac_protocol_send_name(guac_socket* socket, const char* name); int guac_protocol_decode_base64(char* base64); /** - * Given a string representation of a protocol version, search the mapping - * to find the matching enum version, or GUAC_PROTOCOL_VERSION_UNKNOWN if no - * match is found. + * Given a string representation of a protocol version, return the enum value of + * that protocol version, or GUAC_PROTOCOL_VERSION_UNKNOWN if the value is not a + * known version. * * @param version_string * The string representation of the protocol version. * * @return * The enum value of the protocol version, or GUAC_PROTOCOL_VERSION_UNKNOWN - * if no match is found. + * if the provided version is not known. */ -guac_protocol_version guac_protocol_string_to_version(char* version_string); +guac_protocol_version guac_protocol_string_to_version(const char* version_string); /** * Given the enum value of the protocol version, return a pointer to the string diff --git a/src/libguac/guacamole/string.h b/src/libguac/guacamole/string.h index 5e56e330..a648c0c2 100644 --- a/src/libguac/guacamole/string.h +++ b/src/libguac/guacamole/string.h @@ -109,6 +109,19 @@ size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n); */ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n); +/** + * Simple wrapper for strdup() which behaves identically to standard strdup(), + * except that NULL will be returned if the provided string is NULL. + * + * @param str + * The string to duplicate as a newly-allocated string. + * + * @return + * A newly-allocated string containing identically the same content as the + * given string, or NULL if the given string was NULL. + */ +char* guac_strdup(const char* str); + /** * Concatenates each of the given strings, separated by the given delimiter, * storing the result within a destination buffer. The number of bytes written diff --git a/src/libguac/protocol.c b/src/libguac/protocol.c index 8002c92a..59a46d5b 100644 --- a/src/libguac/protocol.c +++ b/src/libguac/protocol.c @@ -1302,7 +1302,7 @@ int guac_protocol_decode_base64(char* base64) { } -guac_protocol_version guac_protocol_string_to_version(char* version_string) { +guac_protocol_version guac_protocol_string_to_version(const char* version_string) { guac_protocol_version_mapping* current = guac_protocol_version_table; while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) { @@ -1321,11 +1321,12 @@ guac_protocol_version guac_protocol_string_to_version(char* version_string) { const char* guac_protocol_version_to_string(guac_protocol_version version) { guac_protocol_version_mapping* current = guac_protocol_version_table; - while (current->version) { + while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) { - if (current->version == version) { + if (current->version == version) return (const char*) current->version_string; - } + + current++; } diff --git a/src/libguac/string.c b/src/libguac/string.c index f05c4c06..e75f7c18 100644 --- a/src/libguac/string.c +++ b/src/libguac/string.c @@ -81,6 +81,17 @@ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n) { } +char* guac_strdup(const char* str) { + + /* Return NULL if no string provided */ + if (str == NULL) + return NULL; + + /* Otherwise just invoke strdup() */ + return strdup(str); + +} + size_t guac_strljoin(char* restrict dest, const char* restrict const* elements, int nmemb, const char* restrict delim, size_t n) { diff --git a/src/libguac/tests/protocol/guac_protocol_version.c b/src/libguac/tests/protocol/guac_protocol_version.c index 782b0aa4..37f42e0f 100644 --- a/src/libguac/tests/protocol/guac_protocol_version.c +++ b/src/libguac/tests/protocol/guac_protocol_version.c @@ -31,9 +31,9 @@ void test_guac_protocol__version_to_string() { guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0; guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN; - CU_ASSERT_STRING_EQUAL_FATAL(guac_protocol_version_to_string(version_a), "VERSION_1_3_0"); - CU_ASSERT_STRING_EQUAL_FATAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_0"); - CU_ASSERT_PTR_NULL_FATAL(guac_protocol_version_to_string(version_c)); + CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_a), "VERSION_1_3_0"); + CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_0"); + CU_ASSERT_PTR_NULL(guac_protocol_version_to_string(version_c)); } @@ -50,10 +50,10 @@ void test_guac_protocol__string_to_version() { char* str_version_c = "AVACADO"; char* str_version_d = "VERSION_31_4_1"; - CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_a), GUAC_PROTOCOL_VERSION_1_3_0); - CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_b), GUAC_PROTOCOL_VERSION_1_1_0); - CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_c), GUAC_PROTOCOL_VERSION_UNKNOWN); - CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_d), GUAC_PROTOCOL_VERSION_UNKNOWN); + CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_a), GUAC_PROTOCOL_VERSION_1_3_0); + CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_b), GUAC_PROTOCOL_VERSION_1_1_0); + CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_c), GUAC_PROTOCOL_VERSION_UNKNOWN); + CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_d), GUAC_PROTOCOL_VERSION_UNKNOWN); } @@ -63,7 +63,7 @@ void test_guac_protocol__string_to_version() { */ void test_gauc_protocol__version_comparison() { - CU_ASSERT_TRUE_FATAL(GUAC_PROTOCOL_VERSION_1_3_0 > GUAC_PROTOCOL_VERSION_1_0_0); - CU_ASSERT_TRUE_FATAL(GUAC_PROTOCOL_VERSION_UNKNOWN < GUAC_PROTOCOL_VERSION_1_1_0); + CU_ASSERT_TRUE(GUAC_PROTOCOL_VERSION_1_3_0 > GUAC_PROTOCOL_VERSION_1_0_0); + CU_ASSERT_TRUE(GUAC_PROTOCOL_VERSION_UNKNOWN < GUAC_PROTOCOL_VERSION_1_1_0); } \ No newline at end of file diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index 8bf1f22e..6c80abcd 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -43,6 +43,7 @@ #include "pointer.h" #include "print-job.h" #include "rdp.h" +#include "settings.h" #ifdef ENABLE_COMMON_SSH #include "common-ssh/sftp.h" @@ -70,6 +71,7 @@ #include #include #include +#include #include #include #include @@ -236,7 +238,7 @@ static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username, guac_client* client = ((rdp_freerdp_context*) context)->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; - char* params[4] = {}; + char* params[4] = {NULL}; int i = 0; /* If the client does not support the "required" instruction, warn and @@ -275,15 +277,17 @@ static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username, if (i > 0) { - /* Send required parameters to the owner. */ + /* Send required parameters to the owner and wait for the response. */ guac_client_owner_send_required(client, (const char**) params); - guac_argv_await((const char**) params); - /* Get new values from settings. */ - *username = settings->username; - *password = settings->password; - *domain = settings->domain; + /* Free old values and get new values from settings. */ + free(*username); + free(*password); + free(*domain); + *username = guac_strdup(settings->username); + *password = guac_strdup(settings->password); + *domain = guac_strdup(settings->domain); } diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index bac8af0b..57760d93 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -1267,47 +1267,25 @@ static int guac_rdp_get_performance_flags(guac_rdp_settings* guac_settings) { } -/** - * Simple wrapper for strdup() which behaves identically to standard strdup(), - * execpt that NULL will be returned if the provided string is NULL. - * - * @param str - * The string to duplicate as a newly-allocated string. - * - * @return - * A newly-allocated string containing identically the same content as the - * given string, or NULL if the given string was NULL. - */ -static char* guac_rdp_strdup(const char* str) { - - /* Return NULL if no string provided */ - if (str == NULL) - return NULL; - - /* Otherwise just invoke strdup() */ - return strdup(str); - -} - void guac_rdp_push_settings(guac_client* client, guac_rdp_settings* guac_settings, freerdp* rdp) { rdpSettings* rdp_settings = rdp->settings; /* Authentication */ - rdp_settings->Domain = guac_rdp_strdup(guac_settings->domain); - rdp_settings->Username = guac_rdp_strdup(guac_settings->username); - rdp_settings->Password = guac_rdp_strdup(guac_settings->password); + rdp_settings->Domain = guac_strdup(guac_settings->domain); + rdp_settings->Username = guac_strdup(guac_settings->username); + rdp_settings->Password = guac_strdup(guac_settings->password); /* Connection */ - rdp_settings->ServerHostname = guac_rdp_strdup(guac_settings->hostname); + rdp_settings->ServerHostname = guac_strdup(guac_settings->hostname); rdp_settings->ServerPort = guac_settings->port; /* Session */ rdp_settings->ColorDepth = guac_settings->color_depth; rdp_settings->DesktopWidth = guac_settings->width; rdp_settings->DesktopHeight = guac_settings->height; - rdp_settings->AlternateShell = guac_rdp_strdup(guac_settings->initial_program); + rdp_settings->AlternateShell = guac_strdup(guac_settings->initial_program); rdp_settings->KeyboardLayout = guac_settings->server_layout->freerdp_keyboard_layout; /* Performance flags */ @@ -1425,9 +1403,9 @@ void guac_rdp_push_settings(guac_client* client, rdp_settings->Workarea = TRUE; rdp_settings->RemoteApplicationMode = TRUE; rdp_settings->RemoteAppLanguageBarSupported = TRUE; - rdp_settings->RemoteApplicationProgram = guac_rdp_strdup(guac_settings->remote_app); - rdp_settings->ShellWorkingDirectory = guac_rdp_strdup(guac_settings->remote_app_dir); - rdp_settings->RemoteApplicationCmdLine = guac_rdp_strdup(guac_settings->remote_app_args); + rdp_settings->RemoteApplicationProgram = guac_strdup(guac_settings->remote_app); + rdp_settings->ShellWorkingDirectory = guac_strdup(guac_settings->remote_app_dir); + rdp_settings->RemoteApplicationCmdLine = guac_strdup(guac_settings->remote_app_args); } /* Preconnection ID */ @@ -1441,7 +1419,7 @@ void guac_rdp_push_settings(guac_client* client, if (guac_settings->preconnection_blob != NULL) { rdp_settings->NegotiateSecurityLayer = FALSE; rdp_settings->SendPreconnectionPdu = TRUE; - rdp_settings->PreconnectionBlob = guac_rdp_strdup(guac_settings->preconnection_blob); + rdp_settings->PreconnectionBlob = guac_strdup(guac_settings->preconnection_blob); } /* Enable use of RD gateway if a gateway hostname is provided */ @@ -1451,20 +1429,20 @@ void guac_rdp_push_settings(guac_client* client, rdp_settings->GatewayEnabled = TRUE; /* RD gateway connection details */ - rdp_settings->GatewayHostname = guac_rdp_strdup(guac_settings->gateway_hostname); + rdp_settings->GatewayHostname = guac_strdup(guac_settings->gateway_hostname); rdp_settings->GatewayPort = guac_settings->gateway_port; /* RD gateway credentials */ rdp_settings->GatewayUseSameCredentials = FALSE; - rdp_settings->GatewayDomain = guac_rdp_strdup(guac_settings->gateway_domain); - rdp_settings->GatewayUsername = guac_rdp_strdup(guac_settings->gateway_username); - rdp_settings->GatewayPassword = guac_rdp_strdup(guac_settings->gateway_password); + rdp_settings->GatewayDomain = guac_strdup(guac_settings->gateway_domain); + rdp_settings->GatewayUsername = guac_strdup(guac_settings->gateway_username); + rdp_settings->GatewayPassword = guac_strdup(guac_settings->gateway_password); } /* Store load balance info (and calculate length) if provided */ if (guac_settings->load_balance_info != NULL) { - rdp_settings->LoadBalanceInfo = (BYTE*) guac_rdp_strdup(guac_settings->load_balance_info); + rdp_settings->LoadBalanceInfo = (BYTE*) guac_strdup(guac_settings->load_balance_info); rdp_settings->LoadBalanceInfoLength = strlen(guac_settings->load_balance_info); } diff --git a/src/protocols/rdp/user.c b/src/protocols/rdp/user.c index e7a91d77..351c67e6 100644 --- a/src/protocols/rdp/user.c +++ b/src/protocols/rdp/user.c @@ -118,8 +118,9 @@ int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) { /* Inbound arbitrary named pipes */ user->pipe_handler = guac_rdp_pipe_svc_pipe_handler; - /* Handler for updating parameters during connection. */ - user->argv_handler = guac_argv_handler; + /* If we own it, register handler for updating parameters during connection. */ + if (user->owner) + user->argv_handler = guac_argv_handler; } diff --git a/src/protocols/vnc/auth.c b/src/protocols/vnc/auth.c index 12f8361e..b5a74b15 100644 --- a/src/protocols/vnc/auth.c +++ b/src/protocols/vnc/auth.c @@ -63,6 +63,7 @@ char* guac_vnc_get_password(rfbClient* client) { } rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType) { + guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY); guac_vnc_client* vnc_client = ((guac_vnc_client*) gc->data); guac_vnc_settings* settings = vnc_client->settings; @@ -71,43 +72,46 @@ rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType) { if (credentialType == rfbCredentialTypeUser) { rfbCredential *creds = malloc(sizeof(rfbCredential)); - /* If the client does not support the "required" instruction, just return - the parameters already configured. */ - if (!guac_client_owner_supports_required(gc)) { - creds->userCredential.username = settings->username; - creds->userCredential.password = settings->password; - return creds; + /* If the client supports the "required" instruction, prompt for and + update those. */ + if (guac_client_owner_supports_required(gc)) { + char* params[3] = {NULL}; + int i = 0; + + /* Check if username is null or empty. */ + if (settings->username == NULL) { + guac_argv_register(GUAC_VNC_ARGV_USERNAME, guac_vnc_argv_callback, NULL, 0); + params[i] = GUAC_VNC_ARGV_USERNAME; + i++; + } + + /* Check if password is null or empty. */ + if (settings->password == NULL) { + guac_argv_register(GUAC_VNC_ARGV_PASSWORD, guac_vnc_argv_callback, NULL, 0); + params[i] = GUAC_VNC_ARGV_PASSWORD; + i++; + } + + params[i] = NULL; + + /* If we have empty parameters, request them. */ + if (i > 0) { + + /* Send required parameters to owner. */ + guac_client_owner_send_required(gc, (const char**) params); + + /* Wait for the parameters to be returned. */ + guac_argv_await((const char**) params); + + return creds; + + } } - char* params[2] = {NULL}; - int i = 0; - - /* Check if username is null or empty. */ - if (settings->username == NULL) { - guac_argv_register(GUAC_VNC_ARGV_USERNAME, guac_vnc_argv_callback, NULL, 0); - params[i] = GUAC_VNC_ARGV_USERNAME; - i++; - } - - /* Check if password is null or empty. */ - if (settings->password == NULL) { - guac_argv_register(GUAC_VNC_ARGV_PASSWORD, guac_vnc_argv_callback, NULL, 0); - params[i] = GUAC_VNC_ARGV_PASSWORD; - i++; - } - - /* If we have empty parameters, request them. */ - if (i > 0) { - - /* Send required parameters to owner. */ - guac_client_owner_send_required(gc, (const char**) params); - - /* Wait for the parameters to be returned. */ - guac_argv_await((const char**) params); - - return creds; - - } + /* Copy the values and return the credential set. */ + creds->userCredential.username = strdup(settings->username); + creds->userCredential.password = strdup(settings->password); + return creds; } diff --git a/src/protocols/vnc/user.c b/src/protocols/vnc/user.c index 807cd0e8..4e6f473c 100644 --- a/src/protocols/vnc/user.c +++ b/src/protocols/vnc/user.c @@ -100,8 +100,9 @@ int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) { if (!settings->disable_paste) user->clipboard_handler = guac_vnc_clipboard_handler; - /* Updates to connection parameters */ - user->argv_handler = guac_argv_handler; + /* Updates to connection parameters if we own the connection */ + if (user->owner) + user->argv_handler = guac_argv_handler; #ifdef ENABLE_COMMON_SSH /* Set generic (non-filesystem) file upload handler */