GUACAMOLE-221: Merge server-side support for parameter prompting.
This commit is contained in:
commit
aa870debad
@ -340,6 +340,9 @@ static void guacd_exec_proc(guacd_proc* proc, const char* protocol) {
|
||||
owner = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Enable keep alive on the broadcast socket */
|
||||
guac_socket_require_keep_alive(client->socket);
|
||||
|
||||
cleanup_client:
|
||||
|
||||
|
@ -478,6 +478,44 @@ int guac_client_load_plugin(guac_client* client, const char* protocol) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback function which is invoked by guac_client_owner_send_required() to
|
||||
* send the required parameters to the specified user, who is the owner of the
|
||||
* client session.
|
||||
*
|
||||
* @param user
|
||||
* The guac_user that will receive the required parameters, who is the owner
|
||||
* of the client.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to a NULL-terminated array of required parameters that will be
|
||||
* passed on to the owner to continue the connection.
|
||||
*
|
||||
* @return
|
||||
* 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. */
|
||||
if (user != NULL)
|
||||
return (void*) ((intptr_t) guac_protocol_send_required(user->socket, required));
|
||||
|
||||
return (void*) ((intptr_t) -1);
|
||||
|
||||
}
|
||||
|
||||
int guac_client_owner_send_required(guac_client* client, const char** required) {
|
||||
|
||||
/* Don't send required instruction if client does not support it. */
|
||||
if (!guac_client_owner_supports_required(client))
|
||||
return -1;
|
||||
|
||||
return (int) ((intptr_t) guac_client_for_owner(client, guac_client_owner_send_required_callback, required));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the provided approximate processing lag, taking into account the
|
||||
* processing lag of the given user.
|
||||
@ -633,6 +671,36 @@ static void* __webp_support_callback(guac_user* user, void* data) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A callback function which is invoked by guac_client_owner_supports_required()
|
||||
* to determine if the owner of a client supports the "required" instruction,
|
||||
* 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
|
||||
* Data provided to the callback. This value is never used within this
|
||||
* callback.
|
||||
*
|
||||
* @return
|
||||
* 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) {
|
||||
|
||||
return (void*) ((intptr_t) guac_user_supports_required(user));
|
||||
|
||||
}
|
||||
|
||||
int guac_client_owner_supports_required(guac_client* client) {
|
||||
|
||||
return (int) ((intptr_t) guac_client_for_owner(client, guac_owner_supports_required_callback, NULL));
|
||||
|
||||
}
|
||||
|
||||
int guac_client_supports_webp(guac_client* client) {
|
||||
|
||||
#ifdef ENABLE_WEBP
|
||||
|
@ -549,6 +549,22 @@ int guac_client_load_plugin(guac_client* client, const char* protocol);
|
||||
*/
|
||||
int guac_client_get_processing_lag(guac_client* client);
|
||||
|
||||
/**
|
||||
* Sends a request to the owner of the given guac_client for parameters required
|
||||
* to continue the connection started by the client. The function returns zero
|
||||
* on success or non-zero on failure.
|
||||
*
|
||||
* @param client
|
||||
* The client where additional connection parameters are required.
|
||||
*
|
||||
* @param required
|
||||
* The NULL-terminated array of required parameters.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int guac_client_owner_send_required(guac_client* client, const char** required);
|
||||
|
||||
/**
|
||||
* Streams the given connection parameter value over an argument value stream
|
||||
* ("argv" instruction), exposing the current value of the named connection
|
||||
@ -692,6 +708,21 @@ void guac_client_stream_webp(guac_client* client, guac_socket* socket,
|
||||
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
||||
cairo_surface_t* surface, int quality, int lossless);
|
||||
|
||||
/**
|
||||
* Returns whether the owner of the given client supports the "required"
|
||||
* instruction, returning non-zero if the client owner does support the
|
||||
* instruction, or zero if the owner does not.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole client whose owner should be checked for supporting
|
||||
* the "required" instruction.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the owner of the given client supports the "required"
|
||||
* instruction, zero otherwise.
|
||||
*/
|
||||
int guac_client_owner_supports_required(guac_client* client);
|
||||
|
||||
/**
|
||||
* Returns whether all users of the given client support WebP. If any user does
|
||||
* not support WebP, or the server cannot encode WebP images, zero is returned.
|
||||
|
@ -38,7 +38,7 @@
|
||||
* 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"
|
||||
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_3_0"
|
||||
|
||||
/**
|
||||
* The maximum number of bytes that should be sent in any one blob instruction
|
||||
|
@ -276,5 +276,39 @@ typedef enum guac_line_join_style {
|
||||
GUAC_LINE_JOIN_ROUND = 0x2
|
||||
} guac_line_join_style;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* An unknown version of the Guacamole protocol.
|
||||
*/
|
||||
GUAC_PROTOCOL_VERSION_UNKNOWN = 0x000000,
|
||||
|
||||
/**
|
||||
* Original protocol version 1.0.0, which lacks support for negotiating
|
||||
* parameters and protocol version, and requires that parameters in the
|
||||
* client/server handshake be delivered in order.
|
||||
*/
|
||||
GUAC_PROTOCOL_VERSION_1_0_0 = 0x010000,
|
||||
|
||||
/**
|
||||
* Protocol version 1.1.0, which includes support for parameter and version
|
||||
* negotiation and for sending timezone information from the client
|
||||
* to the server.
|
||||
*/
|
||||
GUAC_PROTOCOL_VERSION_1_1_0 = 0x010100,
|
||||
|
||||
/**
|
||||
* Protocol version 1.3.0, which supports the "required" instruction,
|
||||
* allowing connections in guacd to request information from the client and
|
||||
* await a response.
|
||||
*/
|
||||
GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300
|
||||
|
||||
} guac_protocol_version;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -794,6 +794,22 @@ int guac_protocol_send_push(guac_socket* socket, const guac_layer* layer);
|
||||
int guac_protocol_send_rect(guac_socket* socket, const guac_layer* layer,
|
||||
int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* Sends a "required" instruction over the given guac_socket connection. This
|
||||
* instruction indicates to the client that one or more additional parameters
|
||||
* are needed to continue the connection.
|
||||
*
|
||||
* @param socket
|
||||
* The guac_socket connection to which to send the instruction.
|
||||
*
|
||||
* @param required
|
||||
* A NULL-terminated array of required parameters.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_protocol_send_required(guac_socket* socket, const char** required);
|
||||
|
||||
/**
|
||||
* Sends a reset instruction over the given guac_socket connection.
|
||||
*
|
||||
@ -1007,5 +1023,32 @@ 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, 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 the provided version is not known.
|
||||
*/
|
||||
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
|
||||
* representation of the version, or NULL if the version is unknown.
|
||||
*
|
||||
* @param version
|
||||
* The enum value of the protocol version.
|
||||
*
|
||||
* @return
|
||||
* A pointer to the string representation of the protocol version, or NULL
|
||||
* if the version is unknown.
|
||||
*/
|
||||
const char* guac_protocol_version_to_string(guac_protocol_version version);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -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
|
||||
|
@ -95,6 +95,12 @@ struct guac_user_info {
|
||||
* is the standard tzdata naming convention.
|
||||
*/
|
||||
const char* timezone;
|
||||
|
||||
/**
|
||||
* The Guacamole protocol version that the remote system supports, allowing
|
||||
* for feature support to be negotiated between client and server.
|
||||
*/
|
||||
guac_protocol_version protocol_version;
|
||||
|
||||
};
|
||||
|
||||
@ -823,6 +829,17 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket,
|
||||
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
||||
cairo_surface_t* surface, int quality, int lossless);
|
||||
|
||||
/**
|
||||
* Returns whether the given user supports the "required" instruction.
|
||||
*
|
||||
* @param user
|
||||
* The Guacamole user to check for support of the "required" instruction.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the user supports the "required" instruction, otherwise zero.
|
||||
*/
|
||||
int guac_user_supports_required(guac_user* user);
|
||||
|
||||
/**
|
||||
* Returns whether the given user supports WebP. If the user does not
|
||||
* support WebP, or the server cannot encode WebP images, zero is returned.
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "guacamole/layer.h"
|
||||
#include "guacamole/object.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/protocol-types.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "guacamole/unicode.h"
|
||||
@ -39,6 +40,34 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* A structure mapping the enum value of a Guacamole protocol version to the
|
||||
* string representation of the version.
|
||||
*/
|
||||
typedef struct guac_protocol_version_mapping {
|
||||
|
||||
/**
|
||||
* The enum value of the protocol version.
|
||||
*/
|
||||
guac_protocol_version version;
|
||||
|
||||
/**
|
||||
* The string value representing the protocol version.
|
||||
*/
|
||||
char* version_string;
|
||||
|
||||
} guac_protocol_version_mapping;
|
||||
|
||||
/**
|
||||
* The map of known protocol versions to the corresponding string value.
|
||||
*/
|
||||
guac_protocol_version_mapping guac_protocol_version_table[] = {
|
||||
{ GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_1_1_0, "VERSION_1_1_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_1_3_0, "VERSION_1_3_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_UNKNOWN, NULL }
|
||||
};
|
||||
|
||||
/* Output formatting functions */
|
||||
|
||||
ssize_t __guac_socket_write_length_string(guac_socket* socket, const char* str) {
|
||||
@ -66,6 +95,38 @@ ssize_t __guac_socket_write_length_double(guac_socket* socket, double d) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through the provided NULL-terminated array, writing the values in the
|
||||
* array to the given socket. Values are written as a series of Guacamole
|
||||
* protocol elements, including the leading comma and the value length in
|
||||
* addition to the value itself. Returns zero on success, non-zero on error.
|
||||
*
|
||||
* @param socket
|
||||
* The socket to which the data should be written.
|
||||
*
|
||||
* @param array
|
||||
* The NULL-terminated array of values to write.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
static int guac_socket_write_array(guac_socket* socket, const char** array) {
|
||||
|
||||
/* Loop through array, writing provided values to the socket. */
|
||||
for (int i=0; array[i] != NULL; i++) {
|
||||
|
||||
if (guac_socket_write_string(socket, ","))
|
||||
return -1;
|
||||
|
||||
if (__guac_socket_write_length_string(socket, array[i]))
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Protocol functions */
|
||||
|
||||
int guac_protocol_send_ack(guac_socket* socket, guac_stream* stream,
|
||||
@ -90,8 +151,6 @@ int guac_protocol_send_ack(guac_socket* socket, guac_stream* stream,
|
||||
|
||||
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 ahead of other args. */
|
||||
@ -99,15 +158,8 @@ static int __guac_protocol_send_args(guac_socket* socket, const char** args) {
|
||||
|| __guac_socket_write_length_string(socket, GUACAMOLE_PROTOCOL_VERSION))
|
||||
return -1;
|
||||
|
||||
for (i=0; args[i] != NULL; i++) {
|
||||
|
||||
if (guac_socket_write_string(socket, ","))
|
||||
return -1;
|
||||
|
||||
if (__guac_socket_write_length_string(socket, args[i]))
|
||||
return -1;
|
||||
|
||||
}
|
||||
if (guac_socket_write_array(socket, args))
|
||||
return -1;
|
||||
|
||||
return guac_socket_write_string(socket, ";");
|
||||
|
||||
@ -308,19 +360,11 @@ int guac_protocol_send_close(guac_socket* socket, const guac_layer* layer) {
|
||||
|
||||
static int __guac_protocol_send_connect(guac_socket* socket, const char** args) {
|
||||
|
||||
int i;
|
||||
if (guac_socket_write_string(socket, "7.connect"))
|
||||
return -1;
|
||||
|
||||
if (guac_socket_write_string(socket, "7.connect")) return -1;
|
||||
|
||||
for (i=0; args[i] != NULL; i++) {
|
||||
|
||||
if (guac_socket_write_string(socket, ","))
|
||||
return -1;
|
||||
|
||||
if (__guac_socket_write_length_string(socket, args[i]))
|
||||
return -1;
|
||||
|
||||
}
|
||||
if (guac_socket_write_array(socket, args))
|
||||
return -1;
|
||||
|
||||
return guac_socket_write_string(socket, ";");
|
||||
|
||||
@ -961,6 +1005,23 @@ int guac_protocol_send_rect(guac_socket* socket,
|
||||
|
||||
}
|
||||
|
||||
int guac_protocol_send_required(guac_socket* socket, const char** required) {
|
||||
|
||||
int ret_val;
|
||||
|
||||
guac_socket_instruction_begin(socket);
|
||||
|
||||
ret_val = guac_socket_write_string(socket, "8.required")
|
||||
|| guac_socket_write_array(socket, required)
|
||||
|| guac_socket_write_string(socket, ";")
|
||||
|| guac_socket_flush(socket);
|
||||
|
||||
guac_socket_instruction_end(socket);
|
||||
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
int guac_protocol_send_reset(guac_socket* socket, const guac_layer* layer) {
|
||||
|
||||
int ret_val;
|
||||
@ -1241,3 +1302,35 @@ int guac_protocol_decode_base64(char* base64) {
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (strcmp(current->version_string, version_string) == 0)
|
||||
return current->version;
|
||||
|
||||
current++;
|
||||
|
||||
}
|
||||
|
||||
return GUAC_PROTOCOL_VERSION_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
const char* guac_protocol_version_to_string(guac_protocol_version version) {
|
||||
|
||||
guac_protocol_version_mapping* current = guac_protocol_version_table;
|
||||
while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) {
|
||||
|
||||
if (current->version == version)
|
||||
return (const char*) current->version_string;
|
||||
|
||||
current++;
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -40,8 +40,10 @@ test_libguac_SOURCES = \
|
||||
parser/read.c \
|
||||
pool/next_free.c \
|
||||
protocol/base64_decode.c \
|
||||
protocol/guac_protocol_version.c \
|
||||
socket/fd_send_instruction.c \
|
||||
socket/nested_send_instruction.c \
|
||||
string/strdup.c \
|
||||
string/strlcat.c \
|
||||
string/strlcpy.c \
|
||||
string/strljoin.c \
|
||||
|
69
src/libguac/tests/protocol/guac_protocol_version.c
Normal file
69
src/libguac/tests/protocol/guac_protocol_version.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/protocol-types.h>
|
||||
|
||||
/**
|
||||
* Test which verifies that conversion of the guac_protocol_version enum to
|
||||
* string values succeeds and produces the expected results.
|
||||
*/
|
||||
void test_guac_protocol__version_to_string() {
|
||||
|
||||
guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_3_0;
|
||||
guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0;
|
||||
guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN;
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that the version of String representations of Guacamole
|
||||
* protocol versions are successfully converted into their matching
|
||||
* guac_protocol_version enum values, and that versions that do not match
|
||||
* any version get the correct unknown value.
|
||||
*/
|
||||
void test_guac_protocol__string_to_version() {
|
||||
|
||||
char* str_version_a = "VERSION_1_3_0";
|
||||
char* str_version_b = "VERSION_1_1_0";
|
||||
char* str_version_c = "AVACADO";
|
||||
char* str_version_d = "VERSION_31_4_1";
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that the comparisons between guac_protocol_version enum
|
||||
* values produces the expected results.
|
||||
*/
|
||||
void test_gauc_protocol__version_comparison() {
|
||||
|
||||
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);
|
||||
|
||||
}
|
49
src/libguac/tests/string/strdup.c
Normal file
49
src/libguac/tests/string/strdup.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Source test string for copying.
|
||||
*/
|
||||
const char* source_string = "Mashing avocados.";
|
||||
|
||||
/**
|
||||
* A NULL string variable for copying to insure that NULL is copied properly.
|
||||
*/
|
||||
const char* null_string = NULL;
|
||||
|
||||
/**
|
||||
* Verify guac_strdup() behavior when the string is both NULL and not NULL.
|
||||
*/
|
||||
void test_string__strdup() {
|
||||
|
||||
/* Copy the strings. */
|
||||
char* dest_string = guac_strdup(source_string);
|
||||
char* null_copy = guac_strdup(null_string);
|
||||
|
||||
/* Run the tests. */
|
||||
CU_ASSERT_STRING_EQUAL(dest_string, "Mashing avocados.");
|
||||
CU_ASSERT_PTR_NULL(null_copy);
|
||||
|
||||
}
|
@ -344,12 +344,16 @@ 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)
|
||||
if (strcmp(parser->argv[0],"") != 0) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Client is using protocol "
|
||||
"version \"%s\"", parser->argv[0]);
|
||||
else
|
||||
user->info.protocol_version = guac_protocol_string_to_version(parser->argv[0]);
|
||||
}
|
||||
else {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Client has not defined "
|
||||
"its protocol version.");
|
||||
user->info.protocol_version = GUAC_PROTOCOL_VERSION_1_0_0;
|
||||
}
|
||||
|
||||
/* Handle user I/O, wait for connection to terminate */
|
||||
guac_user_start(parser, user, usec_timeout);
|
||||
|
@ -316,6 +316,15 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket,
|
||||
|
||||
}
|
||||
|
||||
int guac_user_supports_required(guac_user* user) {
|
||||
|
||||
if (user == NULL)
|
||||
return 0;
|
||||
|
||||
return (user->info.protocol_version >= GUAC_PROTOCOL_VERSION_1_3_0);
|
||||
|
||||
}
|
||||
|
||||
int guac_user_supports_webp(guac_user* user) {
|
||||
|
||||
#ifdef ENABLE_WEBP
|
||||
|
@ -38,6 +38,7 @@ nodist_libguac_client_rdp_la_SOURCES = \
|
||||
_generated_keymaps.c
|
||||
|
||||
libguac_client_rdp_la_SOURCES = \
|
||||
argv.c \
|
||||
beep.c \
|
||||
bitmap.c \
|
||||
channels/audio-input/audio-buffer.c \
|
||||
@ -82,6 +83,7 @@ libguac_client_rdp_la_SOURCES = \
|
||||
user.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
argv.h \
|
||||
beep.h \
|
||||
bitmap.h \
|
||||
channels/audio-input/audio-buffer.h \
|
||||
|
60
src/protocols/rdp/argv.c
Normal file
60
src/protocols/rdp/argv.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "argv.h"
|
||||
#include "rdp.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int guac_rdp_argv_callback(guac_user* user, const char* mimetype,
|
||||
const char* name, const char* value, void* data) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
guac_rdp_settings* settings = rdp_client->settings;
|
||||
|
||||
/* Update username */
|
||||
if (strcmp(name, GUAC_RDP_ARGV_USERNAME) == 0) {
|
||||
free(settings->username);
|
||||
settings->username = strdup(value);
|
||||
}
|
||||
|
||||
/* Update password */
|
||||
else if (strcmp(name, GUAC_RDP_ARGV_PASSWORD) == 0) {
|
||||
free(settings->password);
|
||||
settings->password = strdup(value);
|
||||
}
|
||||
|
||||
/* Update domain */
|
||||
else if (strcmp(name, GUAC_RDP_ARGV_DOMAIN) == 0) {
|
||||
free(settings->domain);
|
||||
settings->domain = strdup(value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
54
src/protocols/rdp/argv.h
Normal file
54
src/protocols/rdp/argv.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_RDP_ARGV_H
|
||||
#define GUAC_RDP_ARGV_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handles a received argument value from a Guacamole "argv" instruction,
|
||||
* updating the given connection parameter.
|
||||
*/
|
||||
guac_argv_callback guac_rdp_argv_callback;
|
||||
|
||||
/**
|
||||
* The name of the parameter that specifies/updates the username that will be
|
||||
* sent to the RDP server during authentication.
|
||||
*/
|
||||
#define GUAC_RDP_ARGV_USERNAME "username"
|
||||
|
||||
/**
|
||||
* The name of the parameter that specifies/updates the password that will be
|
||||
* sent to the RDP server during authentication.
|
||||
*/
|
||||
#define GUAC_RDP_ARGV_PASSWORD "password"
|
||||
|
||||
/**
|
||||
* The name of the parameter that specifies/updates the domain name that will be
|
||||
* sent to the RDP server during authentication.
|
||||
*/
|
||||
#define GUAC_RDP_ARGV_DOMAIN "domain"
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "argv.h"
|
||||
#include "beep.h"
|
||||
#include "bitmap.h"
|
||||
#include "channels/audio-input/audio-buffer.h"
|
||||
@ -42,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"
|
||||
@ -64,10 +66,12 @@
|
||||
#include <freerdp/primary.h>
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/update.h>
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <guacamole/wol.h>
|
||||
#include <winpr/error.h>
|
||||
@ -200,10 +204,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked by FreeRDP when authentication is required but a username
|
||||
* and password has not already been given. In the case of Guacamole, this
|
||||
* function always succeeds but does not populate the usename or password. The
|
||||
* username/password must be given within the connection parameters.
|
||||
* Callback invoked by FreeRDP when authentication is required but the required
|
||||
* parameters have not been provided. In the case of Guacamole clients that
|
||||
* support the "required" instruction, this function will send any of the three
|
||||
* unpopulated RDP authentication parameters back to the client so that the
|
||||
* connection owner can provide the required information. If the values have
|
||||
* been provided in the original connection parameters the user will not be
|
||||
* prompted for updated parameters. If the version of Guacamole Client in use
|
||||
* by the connection owner does not support the "required" instruction then the
|
||||
* connection will fail. This function always returns true.
|
||||
*
|
||||
* @param instance
|
||||
* The FreeRDP instance associated with the RDP session requesting
|
||||
@ -227,10 +236,63 @@ static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username,
|
||||
|
||||
rdpContext* context = instance->context;
|
||||
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] = {NULL};
|
||||
int i = 0;
|
||||
|
||||
/* If the client does not support the "required" instruction, warn and
|
||||
* quit.
|
||||
*/
|
||||
if (!guac_client_owner_supports_required(client)) {
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "Client does not support the "
|
||||
"\"required\" instruction. No authentication parameters will "
|
||||
"be requested.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Warn if connection is likely to fail due to lack of credentials */
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Authentication requested but username or password not given");
|
||||
/* If the username is undefined, add it to the requested parameters. */
|
||||
if (settings->username == NULL) {
|
||||
guac_argv_register(GUAC_RDP_ARGV_USERNAME, guac_rdp_argv_callback, NULL, 0);
|
||||
params[i] = GUAC_RDP_ARGV_USERNAME;
|
||||
i++;
|
||||
|
||||
/* If username is undefined and domain is also undefined, request domain. */
|
||||
if (settings->domain == NULL) {
|
||||
guac_argv_register(GUAC_RDP_ARGV_DOMAIN, guac_rdp_argv_callback, NULL, 0);
|
||||
params[i] = GUAC_RDP_ARGV_DOMAIN;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If the password is undefined, add it to the requested parameters. */
|
||||
if (settings->password == NULL) {
|
||||
guac_argv_register(GUAC_RDP_ARGV_PASSWORD, guac_rdp_argv_callback, NULL, 0);
|
||||
params[i] = GUAC_RDP_ARGV_PASSWORD;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* NULL-terminate the array. */
|
||||
params[i] = NULL;
|
||||
|
||||
if (i > 0) {
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
}
|
||||
|
||||
/* Always return TRUE allowing connection to retry. */
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "argv.h"
|
||||
#include "common/defaults.h"
|
||||
#include "common/string.h"
|
||||
#include "config.h"
|
||||
@ -42,9 +43,9 @@
|
||||
const char* GUAC_RDP_CLIENT_ARGS[] = {
|
||||
"hostname",
|
||||
"port",
|
||||
"domain",
|
||||
"username",
|
||||
"password",
|
||||
GUAC_RDP_ARGV_DOMAIN,
|
||||
GUAC_RDP_ARGV_USERNAME,
|
||||
GUAC_RDP_ARGV_PASSWORD,
|
||||
"width",
|
||||
"height",
|
||||
"dpi",
|
||||
@ -1266,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 */
|
||||
@ -1424,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 */
|
||||
@ -1440,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 */
|
||||
@ -1450,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);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "sftp.h"
|
||||
#endif
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
@ -116,6 +117,10 @@ 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;
|
||||
|
||||
/* If we own it, register handler for updating parameters during connection. */
|
||||
if (user->owner)
|
||||
user->argv_handler = guac_argv_handler;
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
lib_LTLIBRARIES = libguac-client-vnc.la
|
||||
|
||||
libguac_client_vnc_la_SOURCES = \
|
||||
argv.c \
|
||||
auth.c \
|
||||
client.c \
|
||||
clipboard.c \
|
||||
@ -41,6 +42,7 @@ libguac_client_vnc_la_SOURCES = \
|
||||
vnc.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
argv.h \
|
||||
auth.h \
|
||||
client.h \
|
||||
clipboard.h \
|
||||
|
53
src/protocols/vnc/argv.c
Normal file
53
src/protocols/vnc/argv.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "argv.h"
|
||||
#include "vnc.h"
|
||||
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int guac_vnc_argv_callback(guac_user* user, const char* mimetype,
|
||||
const char* name, const char* value, void* data) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_vnc_client* vnc_client = (guac_vnc_client*) client->data;
|
||||
guac_vnc_settings* settings = vnc_client->settings;
|
||||
|
||||
/* Update username */
|
||||
if (strcmp(name, GUAC_VNC_ARGV_USERNAME) == 0) {
|
||||
free(settings->username);
|
||||
settings->username = strdup(value);
|
||||
}
|
||||
|
||||
/* Update password */
|
||||
else if (strcmp(name, GUAC_VNC_ARGV_PASSWORD) == 0) {
|
||||
free(settings->password);
|
||||
settings->password = strdup(value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
47
src/protocols/vnc/argv.h
Normal file
47
src/protocols/vnc/argv.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef ARGV_H
|
||||
#define ARGV_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handles a received argument value from a Guacamole "argv" instruction,
|
||||
* updating the given connection parameter.
|
||||
*/
|
||||
guac_argv_callback guac_vnc_argv_callback;
|
||||
|
||||
/**
|
||||
* The name of the parameter Guacamole will use to specify/update the username
|
||||
* for the VNC connection.
|
||||
*/
|
||||
#define GUAC_VNC_ARGV_USERNAME "username"
|
||||
|
||||
/**
|
||||
* The name of the parameter Guacamole will use to specify/update the password
|
||||
* for the VNC connection.
|
||||
*/
|
||||
#define GUAC_VNC_ARGV_PASSWORD "password"
|
||||
|
||||
#endif /* ARGV_H */
|
||||
|
@ -19,27 +19,94 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "argv.h"
|
||||
#include "auth.h"
|
||||
#include "vnc.h"
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
#include <rfb/rfbproto.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
char* guac_vnc_get_password(rfbClient* client) {
|
||||
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
|
||||
return ((guac_vnc_client*) gc->data)->settings->password;
|
||||
guac_vnc_client* vnc_client = ((guac_vnc_client*) gc->data);
|
||||
guac_vnc_settings* settings = vnc_client->settings;
|
||||
|
||||
/* If the client does not support the "required" instruction, just return
|
||||
the configuration data. */
|
||||
if (!guac_client_owner_supports_required(gc))
|
||||
return guac_strdup(settings->password);
|
||||
|
||||
/* If password isn't around, prompt for it. */
|
||||
if (settings->password == NULL) {
|
||||
|
||||
guac_argv_register(GUAC_VNC_ARGV_PASSWORD, guac_vnc_argv_callback, NULL, 0);
|
||||
|
||||
const char* params[] = {GUAC_VNC_ARGV_PASSWORD, NULL};
|
||||
|
||||
/* Send the request for password to the owner. */
|
||||
guac_client_owner_send_required(gc, params);
|
||||
|
||||
/* Wait for the arguments to be returned */
|
||||
guac_argv_await(params);
|
||||
|
||||
}
|
||||
|
||||
return guac_strdup(settings->password);
|
||||
|
||||
}
|
||||
|
||||
rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType) {
|
||||
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
|
||||
guac_vnc_settings* settings = ((guac_vnc_client*) gc->data)->settings;
|
||||
|
||||
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;
|
||||
|
||||
/* Handle request for Username/Password credentials */
|
||||
if (credentialType == rfbCredentialTypeUser) {
|
||||
rfbCredential *creds = malloc(sizeof(rfbCredential));
|
||||
creds->userCredential.username = settings->username;
|
||||
creds->userCredential.password = settings->password;
|
||||
|
||||
/* 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 not provided. */
|
||||
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 not provided. */
|
||||
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 and await response. */
|
||||
if (i > 0) {
|
||||
guac_client_owner_send_required(gc, (const char**) params);
|
||||
guac_argv_await((const char**) params);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the values and return the credential set. */
|
||||
creds->userCredential.username = guac_strdup(settings->username);
|
||||
creds->userCredential.password = guac_strdup(settings->password);
|
||||
return creds;
|
||||
|
||||
}
|
||||
|
||||
guac_client_abort(gc, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
|
@ -50,8 +50,8 @@ int guac_client_init(guac_client* client) {
|
||||
client->data = vnc_client;
|
||||
|
||||
#ifdef ENABLE_VNC_TLS_LOCKING
|
||||
/* Initialize the write lock */
|
||||
pthread_mutex_init(&(vnc_client->tls_lock), NULL);
|
||||
/* Initialize the TLS write lock */
|
||||
pthread_mutex_init(&vnc_client->tls_lock, NULL);
|
||||
#endif
|
||||
|
||||
/* Init clipboard */
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "argv.h"
|
||||
#include "client.h"
|
||||
#include "common/defaults.h"
|
||||
#include "settings.h"
|
||||
@ -37,8 +38,8 @@ const char* GUAC_VNC_CLIENT_ARGS[] = {
|
||||
"port",
|
||||
"read-only",
|
||||
"encodings",
|
||||
"username",
|
||||
"password",
|
||||
GUAC_VNC_ARGV_USERNAME,
|
||||
GUAC_VNC_ARGV_PASSWORD,
|
||||
"swap-red-blue",
|
||||
"color-depth",
|
||||
"cursor",
|
||||
@ -392,11 +393,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user,
|
||||
|
||||
settings->username =
|
||||
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
|
||||
IDX_USERNAME, ""); /* NOTE: freed by libvncclient */
|
||||
IDX_USERNAME, NULL);
|
||||
|
||||
settings->password =
|
||||
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
|
||||
IDX_PASSWORD, ""); /* NOTE: freed by libvncclient */
|
||||
IDX_PASSWORD, NULL);
|
||||
|
||||
/* Remote cursor */
|
||||
if (strcmp(argv[IDX_CURSOR], "remote") == 0) {
|
||||
@ -624,8 +625,10 @@ void guac_vnc_settings_free(guac_vnc_settings* settings) {
|
||||
free(settings->clipboard_encoding);
|
||||
free(settings->encodings);
|
||||
free(settings->hostname);
|
||||
free(settings->password);
|
||||
free(settings->recording_name);
|
||||
free(settings->recording_path);
|
||||
free(settings->username);
|
||||
|
||||
#ifdef ENABLE_VNC_REPEATER
|
||||
/* Free VNC repeater settings */
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "pulse/pulse.h"
|
||||
#endif
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
@ -98,6 +99,10 @@ int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) {
|
||||
/* Inbound (client to server) clipboard transfer */
|
||||
if (!settings->disable_paste)
|
||||
user->clipboard_handler = guac_vnc_clipboard_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 */
|
||||
|
@ -259,9 +259,6 @@ void* guac_vnc_client_thread(void* data) {
|
||||
"clipboard encoding: '%s'.", settings->clipboard_encoding);
|
||||
}
|
||||
|
||||
/* Ensure connection is kept alive during lengthy connects */
|
||||
guac_socket_require_keep_alive(client->socket);
|
||||
|
||||
/* Set up libvncclient logging */
|
||||
rfbClientLog = guac_vnc_client_log_info;
|
||||
rfbClientErr = guac_vnc_client_log_error;
|
||||
|
Loading…
Reference in New Issue
Block a user