Skip to content

Commit

Permalink
Merge branch 'apache:main' into configurable-clipboard-limit
Browse files Browse the repository at this point in the history
  • Loading branch information
eugen-keeper authored Jan 16, 2025
2 parents a894101 + 32dbdfa commit 544ac9f
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 77 deletions.
51 changes: 16 additions & 35 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -657,59 +657,40 @@ then
fi

#
# libVNCserver support for the rfbSetDesktopSizeMsg message, which allows the
# VNC client to send its dimensions to the server, requesting that the server
# resize itself to match. If libvnc lacks this message, remote resize will
# be completely disabled.
# libVNCserver support for the rfbSetDesktopSizeMsg message and the screen
# data structure, both of which are required in order to properly request that
# a remote server resize its screen to match the dimensions that the client
# sends. If libvnc lacks either this message or the screen data structure
# remote resize will be completely disabled.
#

if test "x${have_libvncserver}" = "xyes"
then

have_vnc_size_msg=yes
have_vnc_resize_support=yes
AC_CHECK_TYPE([rfbSetDesktopSizeMsg],
[], [have_vnc_size_msg=no],
[], [have_vnc_resize_support=no],
[[#include <rfb/rfbproto.h>]])

if test "x${have_vnc_size_msg}" = "xno"
AC_CHECK_MEMBERS([rfbClient.screen],
[], [have_vnc_resize_support=no],
[[#include <rfb/rfbclient.h>]])

if test "x${have_vnc_resize_support}" = "xno"
then
AC_MSG_WARN([
--------------------------------------------------------
No support for rfbSetDesktopSizeMsg in libvncclient.
VNC support for remote display resize will be disabled.
The libvncclient library lacks support for either the
rfbSetDesktopSizeMsg message or for extended screen
support. Resizing of remote displays will be disabled.
--------------------------------------------------------])
else
AC_DEFINE([LIBVNC_HAS_SIZE_MSG],,
AC_DEFINE([LIBVNC_HAS_RESIZE_SUPPORT],,
[Whether VNC client will support sending desktop size messages.])
fi

fi

#
# libVNCserver support for the screen structure, which allows for tracking
# multiple screens that are part of a larger frame buffer display. If this
# feature is missing, the VNC client may still attempt to send the display
# resize messages, but will assume that there is a one-to-one relationship
# between the screen size and the frame buffer size (which is currently safe
# for Guacamole, as it lacks multi-monitor/screen support).
#

if test "x${have_libvncserver}" = "xyes"
then

have_vnc_screen=yes
AC_CHECK_MEMBERS([rfbClient.screen],
[], [have_vnc_screen=no],
[[#include <rfb/rfbclient.h>]])

if test "x${have_vnc_screen}" = "xyes"
then
AC_DEFINE([LIBVNC_CLIENT_HAS_SCREEN],,
[Whether rfbClient contains the screen data structure.])
fi

fi

#
# libVNCserver support for the requestedResize member, which enables the
# client to pause frame buffer updates during a resize operation. If support
Expand Down
66 changes: 65 additions & 1 deletion src/common-ssh/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* under the License.
*/

#include "common/string.h"

#include "common-ssh/key.h"
#include "common-ssh/ssh.h"
#include "common-ssh/user.h"
Expand All @@ -41,6 +43,7 @@
#include <netinet/in.h>
#include <pthread.h>
#include <pwd.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -64,7 +67,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
/**
* A list of ciphers that are both FIPS-compliant, and OpenSSL-supported.
*/
#define FIPS_COMPLIANT_CIPHERS "aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes192-cbc,aes256-cbc"
#define FIPS_COMPLIANT_CIPHERS "aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes192-cbc,aes256-cbc"

#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
/**
Expand Down Expand Up @@ -412,6 +415,59 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)

}

/**
* Verifies if given algorithms are supported by libssh2.
* Writes log messages if an algorithm is not supported or
* could not get the list of supported algorithms from libssh2.
*
* @param client
* The Guacamole client that is using SSH.
*
* @param session
* The session associated with the user to be authenticated.
*
* @param method_type
* One of the libssh2 Method Type constants for libssh2_session_method_pref().
*
* @param algs
* A string with preferred list of algorithms, for example FIPS_COMPLIANT_CIPHERS.
*
*/
static void check_if_algs_are_supported(guac_client* client, LIBSSH2_SESSION* session,
int method_type, const char* algs) {

/* Request the list of supported algorithms/cyphers from libssh2. */
const char** supported_algs;
int supported_algs_count =
libssh2_session_supported_algs(session, method_type, &supported_algs);

if (supported_algs_count > 0) {
char** preferred_algs = guac_split(algs, ',');
for (int i = 0; preferred_algs[i]; i++) {
bool found = false;
/* Check if the algorithm is found in the libssh2 supported list. */
for (int j = 0; j < supported_algs_count; j++) {
if (strcmp(preferred_algs[i], supported_algs[j]) == 0) {
found = true;
break;
}
}
if (!found) {
guac_client_log(client, GUAC_LOG_WARNING,
"Preferred algorithm/cipher '%s' is not supported by libssh2", preferred_algs[i]);
}
}
guac_mem_free(preferred_algs);
/* should free if supported_algs_count is a positive number. */
libssh2_free(session, supported_algs);
}
else {
guac_client_log(client, GUAC_LOG_WARNING,
"libssh2 reports that no ciphers/algorithms are supported. This may be a bug in libssh2. "
"If the SSH connection fails, it may not be possible to log the cause here.");
}
}

guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user,
int timeout, int keepalive, const char* host_key,
Expand Down Expand Up @@ -445,8 +501,16 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
* https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp2906.pdf
*/
if (guac_fips_enabled()) {
/*
* The following algorithm check is only to simplify debugging.
* libssh2_session_method_pref() ignores unsupported methods.
* So they are not sent to the remote host during protocol negotiation anyways.
*/
check_if_algs_are_supported(client, session, LIBSSH2_METHOD_KEX, FIPS_COMPLIANT_KEX_ALGORITHMS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_KEX, FIPS_COMPLIANT_KEX_ALGORITHMS);
check_if_algs_are_supported(client, session, LIBSSH2_METHOD_CRYPT_CS, FIPS_COMPLIANT_CIPHERS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_CS, FIPS_COMPLIANT_CIPHERS);
check_if_algs_are_supported(client, session, LIBSSH2_METHOD_CRYPT_SC, FIPS_COMPLIANT_CIPHERS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_SC, FIPS_COMPLIANT_CIPHERS);
}

Expand Down
34 changes: 8 additions & 26 deletions src/protocols/vnc/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, in

}

#ifdef LIBVNC_HAS_SIZE_MSG
#ifdef LIBVNC_HAS_RESIZE_SUPPORT
/**
* This function does the actual work of sending the message to the RFB/VNC
* server to request the resize, and then makes sure that the client frame
Expand All @@ -173,7 +173,11 @@ static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int heig
/* Get the Guacamole client data */
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);

#ifdef LIBVNC_CLIENT_HAS_SCREEN
if (client->screen.width == 0 || client->screen.height == 0) {
guac_client_log(gc, GUAC_LOG_WARNING, "Screen data has not been initialized, yet.");
return FALSE;
}

guac_client_log(gc, GUAC_LOG_TRACE,
"Current screen size is %ix%i; setting new size %ix%i\n",
rfbClientSwap16IfLE(client->screen.width),
Expand All @@ -185,19 +189,6 @@ static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int heig
guac_client_log(gc, GUAC_LOG_WARNING, "Screen size has not changed, not sending update.");
return FALSE;
}
#else
/* Don't send an update if the screen appears to be uninitialized. */
if (client->width == 0 || client->height == 0) {
guac_client_log(gc, GUAC_LOG_WARNING, "Framebuffer has not been initialized, cannot send resize.");
return FALSE;
}

/* Don't send an update if the requested dimensions are identical to current dimensions. */
if (client->width == rfbClientSwap16IfLE(width) && client->height == rfbClientSwap16IfLE(height)) {
guac_client_log(gc, GUAC_LOG_WARNING, "Screen size has not changed, not sending update.");
return FALSE;
}
#endif

/**
* Note: The RFB protocol requires two message types to be sent during a
Expand All @@ -219,19 +210,11 @@ static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int heig
size_msg.height = rfbClientSwap16IfLE(height);
size_msg.numberOfScreens = 1;

#ifdef LIBVNC_CLIENT_HAS_SCREEN
/* Configure the screen update message. */
new_screen.id = GUAC_VNC_SCREEN_ID;
new_screen.x = client->screen.x;
new_screen.y = client->screen.y;
new_screen.flags = client->screen.flags;
#else
/* Assume screen starts at the origin. */
new_screen.id = GUAC_VNC_SCREEN_ID;
new_screen.x = 0;
new_screen.y = 0;
new_screen.flags = 0;
#endif // LIBVNC_CLIENT_HAS_SCREEN

new_screen.width = rfbClientSwap16IfLE(width);
new_screen.height = rfbClientSwap16IfLE(height);
Expand All @@ -246,11 +229,9 @@ static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int heig

}

#ifdef LIBVNC_CLIENT_HAS_SCREEN
/* Update the client frame buffer with the requested size. */
client->screen.width = rfbClientSwap16IfLE(width);
client->screen.height = rfbClientSwap16IfLE(height);
#endif // LIBVNC_CLIENT_HAS_SCREEN

#ifdef LIBVNC_CLIENT_HAS_REQUESTED_RESIZE
client->requestedResize = FALSE;
Expand All @@ -266,6 +247,7 @@ static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int heig

/* Update should be successful. */
return TRUE;

}

void* guac_vnc_display_set_owner_size(guac_user* owner, void* data) {
Expand Down Expand Up @@ -323,7 +305,7 @@ void guac_vnc_display_set_size(rfbClient* client, int requested_width, int reque
pthread_mutex_unlock(&(vnc_client->message_lock));

}
#endif // LIBVNC_HAS_SIZE_MSG
#endif // LIBVNC_HAS_RESIZE_SUPPORT

void guac_vnc_set_pixel_format(rfbClient* client, int color_depth) {
client->format.trueColour = 1;
Expand Down
4 changes: 2 additions & 2 deletions src/protocols/vnc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ int guac_vnc_user_key_handler(guac_user* user, int keysym, int pressed) {
return 0;
}

#ifdef LIBVNC_HAS_SIZE_MSG
#ifdef LIBVNC_HAS_RESIZE_SUPPORT
int guac_vnc_user_size_handler(guac_user* user, int width, int height) {

guac_user_log(user, GUAC_LOG_TRACE, "Running user size handler.");
Expand All @@ -78,4 +78,4 @@ int guac_vnc_user_size_handler(guac_user* user, int width, int height) {
return 0;

}
#endif //LIBVNC_HAS_SIZE_MSG
#endif // LIBVNC_HAS_RESIZE_SUPPORT
7 changes: 5 additions & 2 deletions src/protocols/vnc/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,14 @@ int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) {
user->file_handler = guac_vnc_sftp_file_handler;
#endif

#ifdef LIBVNC_HAS_SIZE_MSG
#ifdef LIBVNC_HAS_RESIZE_SUPPORT
/* If user is owner, set size handler. */
if (user->owner && !settings->disable_display_resize)
user->size_handler = guac_vnc_user_size_handler;
#endif // LIBVNC_HAS_SIZE_MSG
#else
guac_user_log(user, GUAC_LOG_WARNING,
"The libvncclient library does not support remote resize.");
#endif // LIBVNC_HAS_RESIZE_SUPPORT

}

Expand Down
40 changes: 33 additions & 7 deletions src/protocols/vnc/vnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,9 @@ static int guac_vnc_wait_for_messages(rfbClient* rfb_client, int msec_timeout) {
* True (non-zero) if messages were handled successfully, false (zero)
* otherwise.
*/
static rfbBool guac_vnc_handle_messages(guac_vnc_client* vnc_client) {
static rfbBool guac_vnc_handle_messages(guac_client* client) {

guac_vnc_client* vnc_client = (guac_vnc_client*) client->data;
rfbClient* rfb_client = vnc_client->rfb_client;
guac_display_layer* default_layer = guac_display_default_layer(vnc_client->display);

Expand Down Expand Up @@ -311,6 +312,31 @@ static rfbBool guac_vnc_handle_messages(guac_vnc_client* vnc_client) {
guac_display_layer_close_raw(default_layer, context);
vnc_client->current_context = NULL;

#ifdef LIBVNC_HAS_RESIZE_SUPPORT
// If screen was not previously initialized, check for it and set it.
if (!vnc_client->rfb_screen_initialized
&& rfb_client->screen.width > 0
&& rfb_client->screen.height > 0) {
vnc_client->rfb_screen_initialized = true;
guac_client_log(client, GUAC_LOG_DEBUG, "Screen is now initialized.");
}

/*
* If the screen is now or has been initialized, check to see if the initial
* dimensions have already been sent. If not, and resize is not disabled,
* send the initial size.
*/
if (vnc_client->rfb_screen_initialized) {
guac_vnc_settings* settings = vnc_client->settings;
if (!vnc_client->rfb_initial_resize && !settings->disable_display_resize) {
guac_client_log(client, GUAC_LOG_DEBUG,
"Sending initial screen size to VNC server.");
guac_client_for_owner(client, guac_vnc_display_set_owner_size, rfb_client);
vnc_client->rfb_initial_resize = true;
}
}
#endif // LIBVNC_HAS_RESIZE_SUPPORT

/* Resize the surface if VNC screen size has changed (this call
* automatically deals with invalid dimensions and is a no-op
* if the size has not changed) */
Expand Down Expand Up @@ -592,11 +618,11 @@ void* guac_vnc_client_thread(void* data) {
guac_display_set_cursor(vnc_client->display, GUAC_DISPLAY_CURSOR_POINTER);
}

#ifdef LIBVNC_HAS_SIZE_MSG
/* Update the display with the owner's screen size. */
if (!settings->disable_display_resize)
guac_client_for_owner(client, guac_vnc_display_set_owner_size, rfb_client);
#endif // LIBVNC_HAS_SIZE_MSG
#ifdef LIBVNC_HAS_RESIZE_SUPPORT
/* Set initial state of the screen and resize flags. */
vnc_client->rfb_screen_initialized = false;
vnc_client->rfb_initial_resize = false;
#endif // LIBVNC_HAS_RESIZE_SUPPORT

guac_display_end_frame(vnc_client->display);

Expand All @@ -610,7 +636,7 @@ void* guac_vnc_client_thread(void* data) {
if (wait_result > 0) {

/* Handle any message received */
if (!guac_vnc_handle_messages(vnc_client)) {
if (!guac_vnc_handle_messages(client)) {
guac_client_abort(client,
GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
"Error handling message from VNC server.");
Expand Down
13 changes: 13 additions & 0 deletions src/protocols/vnc/vnc.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ typedef struct guac_vnc_client {
*/
guac_iconv_write* clipboard_writer;

#ifdef LIBVNC_HAS_RESIZE_SUPPORT
/**
* Whether or not the server has sent the required message to initialize
* the screen data in the client.
*/
bool rfb_screen_initialized;

/**
* Whether or not the client has sent it's starting size to the server.
*/
bool rfb_initial_resize;
#endif

} guac_vnc_client;

/**
Expand Down
Loading

0 comments on commit 544ac9f

Please sign in to comment.