GUACAMOLE-1026: Add support for FreeRDP3.

This commit is contained in:
Alex Leitner 2024-05-09 13:49:31 +09:00 committed by Alex Leitner
parent 3ad3b041f2
commit 97ca969e3f
No known key found for this signature in database
GPG Key ID: C8AF47D3CD30770E
23 changed files with 656 additions and 125 deletions

View File

@ -27,16 +27,21 @@
ARG ALPINE_BASE_IMAGE=3.18
FROM alpine:${ALPINE_BASE_IMAGE} AS builder
# FreeRDP version (default to version 3)
ARG FREERDP_VERSION=3
# Install build dependencies
RUN apk add --no-cache \
autoconf \
automake \
build-base \
cairo-dev \
cjson-dev \
cmake \
cunit-dev \
git \
grep \
krb5-dev \
libjpeg-turbo-dev \
libpng-dev \
libtool \
@ -45,7 +50,10 @@ RUN apk add --no-cache \
openssl1.1-compat-dev \
pango-dev \
pulseaudio-dev \
util-linux-dev
sdl2-dev \
sdl2_ttf-dev \
util-linux-dev \
webkit2gtk-dev
# Copy source to container for sake of build
ARG BUILD_DIR=/tmp/guacamole-server
@ -64,7 +72,7 @@ ARG PREFIX_DIR=/opt/guacamole
# library (these can be overridden at build time if a specific version is
# needed)
#
ARG WITH_FREERDP='2(\.\d+)+'
ARG WITH_FREERDP="${FREERDP_VERSION}(\.\d+)+"
ARG WITH_LIBSSH2='libssh2-\d+(\.\d+)+'
ARG WITH_LIBTELNET='\d+(\.\d+)+'
ARG WITH_LIBVNCCLIENT='LibVNCServer-\d+(\.\d+)+'
@ -77,6 +85,7 @@ ARG WITH_LIBWEBSOCKETS='v\d+(\.\d+)+'
#
ARG FREERDP_OPTS="\
-DALLOW_IN_SOURCE_BUILD=ON \
-DBUILTIN_CHANNELS=OFF \
-DCHANNEL_URBDRC=OFF \
-DWITH_ALSA=OFF \
@ -86,22 +95,26 @@ ARG FREERDP_OPTS="\
-DWITH_CUPS=OFF \
-DWITH_DIRECTFB=OFF \
-DWITH_FFMPEG=OFF \
-DWITH_FUSE=OFF \
-DWITH_GSM=OFF \
-DWITH_GSSAPI=OFF \
-DWITH_IPP=OFF \
-DWITH_JPEG=ON \
-DWITH_KRB5=ON \
-DWITH_LIBSYSTEMD=OFF \
-DWITH_MANPAGES=OFF \
-DWITH_OPENH264=OFF \
-DWITH_OPENSSL=ON \
-DWITH_OSS=OFF \
-DWITH_PCSC=OFF \
-DWITH_PKCS11=OFF \
-DWITH_PULSE=OFF \
-DWITH_SERVER=OFF \
-DWITH_SERVER_INTERFACE=OFF \
-DWITH_SHADOW_MAC=OFF \
-DWITH_SHADOW_X11=OFF \
-DWITH_SSE2=ON \
-DWITH_SWSCALE=OFF \
-DWITH_WAYLAND=OFF \
-DWITH_X11=OFF \
-DWITH_X264=OFF \
@ -141,11 +154,14 @@ ARG LIBWEBSOCKETS_OPTS="\
# Build guacamole-server and its core protocol library dependencies
RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh
# Determine location of the FREERDP library based on the version.
ARG FREERDP_LIB_PATH=${PREFIX_DIR}/lib/freerdp${FREERDP_VERSION}
# Record the packages of all runtime library dependencies
RUN ${BUILD_DIR}/src/guacd-docker/bin/list-dependencies.sh \
${PREFIX_DIR}/sbin/guacd \
${PREFIX_DIR}/lib/libguac-client-*.so \
${PREFIX_DIR}/lib/freerdp2/*guac*.so \
${FREERDP_LIB_PATH}/*guac*.so \
> ${PREFIX_DIR}/DEPENDENCIES
# Use same Alpine version as the base for the runtime image
@ -202,4 +218,3 @@ EXPOSE 4822
# PREFIX_DIR build argument.
#
CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f

View File

@ -648,11 +648,12 @@ then
fi
#
# FreeRDP 2 (libfreerdp2, libfreerdp-client2, and libwinpr2)
# FreeRDP (libfreerdpX, libfreerdp-clientX, and libwinprX)
#
have_freerdp2=disabled
FREERDP2_PLUGIN_DIR=
freerdp_version=
have_freerdp=
FREERDP_PLUGIN_DIR=
AC_ARG_WITH([rdp],
[AS_HELP_STRING([--with-rdp],
@ -664,7 +665,7 @@ AC_ARG_WITH([rdp],
AC_ARG_WITH(freerdp_plugin_dir,
[AS_HELP_STRING([--with-freerdp-plugin-dir=<path>],
[install FreeRDP plugins to the given directory @<:@default=check@:>@])
],FREERDP2_PLUGIN_DIR=$withval)
],FREERDP_PLUGIN_DIR=$withval)
# Preserve CPPFLAGS so it can be restored later, following the addition of
# options specific to FreeRDP tests
@ -672,21 +673,38 @@ OLDCPPFLAGS="$CPPFLAGS"
if test "x$with_rdp" != "xno"
then
have_freerdp2=yes
PKG_CHECK_MODULES([RDP], [freerdp2 freerdp-client2 winpr2],
freerdp_version=3
have_freerdp=yes
PKG_CHECK_MODULES([RDP], [freerdp3 freerdp-client3 winpr3],
[CPPFLAGS="${RDP_CFLAGS} -Werror $CPPFLAGS"]
[AS_IF([test "x${FREERDP2_PLUGIN_DIR}" = "x"],
[FREERDP2_PLUGIN_DIR="`$PKG_CONFIG --variable=libdir freerdp2`/freerdp2"])],
[AS_IF([test "x${FREERDP_PLUGIN_DIR}" = "x"],
[FREERDP_PLUGIN_DIR="`$PKG_CONFIG --variable=libdir freerdp3`/freerdp3"])],
[AC_MSG_WARN([
--------------------------------------------
Unable to find FreeRDP (libfreerdp2 / libfreerdp-client2 / libwinpr2)
Unable to find FreeRDP3 (libfreerdp3 / libfreerdp-client3 / libwinpr3).
Checking for FreeRDP2.
--------------------------------------------])
have_freerdp=no])
fi
if test "x$with_rdp" != "xno" -a "x${have_freerdp}" = "xno"
then
freerdp_version=2
have_freerdp=yes
PKG_CHECK_MODULES([RDP], [freerdp2 freerdp-client2 winpr2],
[CPPFLAGS="${RDP_CFLAGS} -Werror $CPPFLAGS"]
[AS_IF([test "x${FREERDP_PLUGIN_DIR}" = "x"],
[FREERDP_PLUGIN_DIR="`$PKG_CONFIG --variable=libdir freerdp2`/freerdp2"])],
[AC_MSG_WARN([
--------------------------------------------
Unable to find FreeRDP2 (libfreerdp2 / libfreerdp-client2 / libwinpr2)
RDP will be disabled.
--------------------------------------------])
have_freerdp2=no])
have_freerdp=no])
fi
# Available color conversion functions
if test "x$have_freerdp2" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
# FreeRDP 2.0.0-rc3 and older referred to FreeRDPConvertColor() as
@ -708,7 +726,7 @@ AC_ARG_ENABLE(allow_freerdp_snapshots,
[allow building against unknown development snapshots of FreeRDP])
],allow_freerdp_snapshots=yes)
if test "x${have_freerdp2}" = "xyes" -a "x${allow_freerdp_snapshots}" != "xyes"
if test "x${have_freerdp}" = "xyes" -a "x${allow_freerdp_snapshots}" != "xyes"
then
AC_MSG_CHECKING([whether FreeRDP appears to be a development version])
@ -736,7 +754,7 @@ then
fi
# Variation in memory internal allocation/free behavior for bitmaps
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
# FreeRDP 2.0.0-rc0 and older automatically free rdpBitmap and its
@ -760,7 +778,7 @@ then
fi
# Variation in memory internal allocation/free behavior for channel streams
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
# FreeRDP 2.0.0-rc3 through 2.0.0-rc4 automatically free the wStream
@ -782,7 +800,7 @@ then
fi
# Glyph callback variants
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
# FreeRDP 2.0.0-rc3 and older used UINT32 for integer parameters to all
@ -815,7 +833,7 @@ then
fi
# CLIPRDR callback variants
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
# FreeRDP 2.0.0-rc3 and older did not use const for CLIPRDR callbacks
@ -845,7 +863,7 @@ then
fi
# RAIL callback variants
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
# FreeRDP 2.0.0-rc3 and older did not use const for RAIL callbacks
@ -875,7 +893,7 @@ then
fi
# Support for receiving unannounced orders from the RDP server
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
AC_CHECK_MEMBERS([rdpSettings.AllowUnanouncedOrdersFromServer],,
[AC_MSG_WARN([
@ -891,17 +909,151 @@ fi
# Updated certificate verification callback (introduced with 2.0.0, not present
# in 2.0.0-rc4 or earlier)
if test "x${have_freerdp2}" = "xyes"
if test "x${have_freerdp}" = "xyes"
then
AC_CHECK_MEMBERS([freerdp.VerifyCertificateEx],,,
[[#include <freerdp/freerdp.h>]])
[[#include <freerdp/freerdp.h>]])
fi
if test "x${have_freerdp}" = "xyes"
then
AC_CHECK_DECLS([winpr_aligned_free],
[AC_DEFINE([HAVE_WINPR_ALIGNED],,
[Defined if winpr_aligned_free() and winpr_aligned_malloc() are available])],,
[#include <winpr/crt.h>])
fi
if test "x${have_freerdp}" = "xyes"
then
AC_MSG_CHECKING([whether CLIPRDR structs have a common CLIPRDR_HEADER])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <freerdp/client/cliprdr.h>
int main() {
CLIPRDR_FORMAT_LIST list;
list.common.msgType = 0;
return 0;
}
]])],
[AC_MSG_RESULT([yes])]
[AC_DEFINE([HAVE_CLIPRDR_HEADER],,
[Defined if CLIPRDR structs have a common CLIPRDR_HEADER])],
[AC_MSG_RESULT([no])])
fi
if test "x${have_freerdp}" = "xyes"
then
AC_CHECK_DECLS([FreeRDPReadColor],
[AC_DEFINE([USE_UPDATED_RW_COLOR_FUNCS],,
[Defined if FreeRDPReadColor() and FreeRDPWriteColor() are available])],,
[#include <freerdp/codec/color.h>])
fi
if test "x${have_freerdp}" = "xyes"
then
AC_CHECK_DECLS([freerdp_settings_set_pointer],
[AC_DEFINE([HAVE_SETTERS_GETTERS],,
[Defined if freerdp_settings_set_pointer is available])],,
[#include <freerdp/settings.h>])
fi
if test "x${have_freerdp}" = "xyes"
then
AC_MSG_CHECKING([whether freerdp structs have a context])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <freerdp/freerdp.h>
int main() {
freerdp* instance = freerdp_new();
/* We cast to void to prevent unused variable warnings */
(void)instance->context->input;
(void)instance->context->settings;
freerdp_free(instance);
return 0;
}
]])],
[AC_MSG_RESULT([yes])]
[AC_DEFINE([FREERDP_HAS_CONTEXT],,
[FreeRDP structs have a context])],
[AC_MSG_RESULT([no])])
fi
if test "x${have_freerdp}" = "xyes"
then
AC_CHECK_DECL([freerdp_shall_disconnect_context],
[AC_DEFINE([HAVE_DISCONNECT_CONTEXT],,
[Defined if 'freerdp_shall_disconnect_context' is available in FreeRDP])],,
[#include <freerdp/freerdp.h>])
fi
if test "x${have_freerdp}" = "xyes"
then
# Check whether FreeRDP 3.x requires const for GetPluginData
AC_MSG_CHECKING([whether GetPluginData requires const for the returned args])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <freerdp/dvc.h>
int main() {
IDRDYNVC_ENTRY_POINTS test_entry_points;
const ADDIN_ARGV* args = test_entry_points.GetPluginData(&test_entry_points);
(void)args;
return 0;
}
]])],
[AC_MSG_RESULT([yes])]
[AC_DEFINE([PLUGIN_DATA_CONST],,
[Defined if GetPluginData returns a pointer to a const ADDIN_ARGV])],
[AC_MSG_RESULT([no])])
fi
if test "x${have_freerdp}" = "xyes"
then
# Check whether glyph.New expects a const rdpGlyph* parameter
AC_MSG_CHECKING([whether glyph.New expects a const rdpGlyph* parameter])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <freerdp/graphics.h>
BOOL mock_glyph_new(rdpContext* context, const rdpGlyph* glyph) {
return TRUE;
}
int main() {
rdpGlyph* glyph = (rdpGlyph*) malloc(sizeof(rdpGlyph));
glyph->New = mock_glyph_new;
free(glyph);
return 0;
}
]])],
[AC_MSG_RESULT([yes])]
[AC_DEFINE([RDP_GLYPH_NEW_REQUIRES_CONST],,
[Defined if glyph.New expects a const rdpGlyph* parameter])],
[AC_MSG_RESULT([no])])
fi
if test "x${have_freerdp}" = "xyes"
then
# Check whether pointer.Set expects a const rdpPointer* parameter
AC_MSG_CHECKING([whether pointer.Set expects a const rdpPointer* parameter])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <freerdp/graphics.h>
BOOL mock_pointer_set(rdpContext* context, const rdpPointer* pointer) {
return TRUE;
}
int main() {
rdpPointer* pointer = (rdpPointer*) malloc(sizeof(rdpPointer));
pointer->Set = mock_pointer_set;
free(pointer);
return 0;
}
]])],
[AC_MSG_RESULT([yes])]
[AC_DEFINE([RDP_POINTER_SET_REQUIRES_CONST],,
[Defined if pointer.Set expects a const rdpPointer* parameter])],
[AC_MSG_RESULT([no])])
fi
# Restore CPPFLAGS, removing FreeRDP-specific options needed for testing
CPPFLAGS="$OLDCPPFLAGS"
AC_SUBST(FREERDP2_PLUGIN_DIR)
AM_CONDITIONAL([ENABLE_RDP], [test "x${have_freerdp2}" = "xyes"])
AC_SUBST(FREERDP_PLUGIN_DIR)
AM_CONDITIONAL([ENABLE_RDP], [test "x${have_freerdp}" = "xyes"])
#
# libssh2
@ -1237,7 +1389,7 @@ AM_COND_IF([ENABLE_SYSTEMD], [build_systemd="${systemd_dir}"], [build_systemd=no
# FreeRDP plugins
#
AM_COND_IF([ENABLE_RDP], [build_rdp_plugins="${FREERDP2_PLUGIN_DIR}"], [build_rdp_plugins=no])
AM_COND_IF([ENABLE_RDP], [build_rdp_plugins="${FREERDP_PLUGIN_DIR}"], [build_rdp_plugins=no])
#
# Display summary
@ -1250,7 +1402,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
Library status:
freerdp2 ............ ${have_freerdp2}
freerdp${freerdp_version} ............ ${have_freerdp}
pango ............... ${have_pango}
libavcodec .......... ${have_libavcodec}
libavformat ......... ${have_libavformat}
@ -1280,10 +1432,9 @@ $PACKAGE_NAME version $PACKAGE_VERSION
guacenc .... ${build_guacenc}
guaclog .... ${build_guaclog}
FreeRDP plugins: ${build_rdp_plugins}
FreeRDP${freerdp_version} plugins: ${build_rdp_plugins}
Init scripts: ${build_init}
Systemd units: ${build_systemd}
Type \"make\" to compile $PACKAGE_NAME.
"

View File

@ -128,4 +128,3 @@ install_from_git "https://github.com/warmcat/libwebsockets" "$WITH_LIBWEBSOCKETS
cd "$BUILD_DIR"
autoreconf -fi && ./configure --prefix="$PREFIX_DIR" $GUACAMOLE_SERVER_OPTS
make && make check && make install

View File

@ -131,6 +131,38 @@ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n);
*/
char* guac_strnstr(const char *haystack, const char *needle, size_t len);
/**
* Duplicates up to the given number of characters from the provided string,
* returning a newly-allocated string containing the copied contents. The
* provided string must be null-terminated, and only the first 'n' characters
* will be considered for duplication, or the full string length if it is
* shorter than 'n'. The memory block for the newly-allocated string will
* include enough space for these characters, as well as for the null
* terminator.
*
* The pointer returned by guac_strndup() SHOULD be freed with a subsequent call
* to guac_mem_free(), but MAY instead be freed with a subsequent call to free().
*
* This function behaves similarly to the POSIX strndup() function, except that
* NULL will be returned if the provided string is NULL or if memory allocation
* fails. Also, the length of the string to be duplicated will be checked to
* prevent overflow if adding space for the null terminator.
*
* @param str
* The string of which up to the first 'n' characters should be duplicated
* as a newly-allocated string. If 'n' exceeds the length of the string,
* the entire string is duplicated.
*
* @param n
* The maximum number of characters to duplicate from the given string.
*
* @return
* A newly-allocated string containing up to the first 'n' characters from
* the given string, including a terminating null byte, or NULL if the
* provided string was NULL or if memory allocation fails.
*/
char* guac_strndup(const char* str, size_t n);
/**
* Duplicates the given string, returning a newly-allocated string containing
* the same contents. The provided string must be null-terminated. The size of
@ -202,4 +234,3 @@ size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
int nmemb, const char* restrict delim, size_t n);
#endif

View File

@ -115,7 +115,7 @@ char* guac_strnstr(const char *haystack, const char *needle, size_t len) {
}
char* guac_strdup(const char* str) {
char* guac_strndup(const char* str, size_t n) {
/* Return NULL if no string provided */
if (str == NULL)
@ -124,18 +124,30 @@ char* guac_strdup(const char* str) {
/* Do not attempt to duplicate if the length is somehow magically so
* obscenely large that it will not be possible to add a null terminator */
size_t length;
if (guac_mem_ckd_add(&length, strlen(str), 1))
size_t length_to_copy = strnlen(str, n);
if (guac_mem_ckd_add(&length, length_to_copy, 1))
return NULL;
/* Otherwise just copy to a new string in same manner as strdup() */
void* new_str = guac_mem_alloc(length);
if (new_str != NULL)
memcpy(new_str, str, length);
/* Otherwise just copy to a new string in same manner as strndup() */
char* new_str = (char*)guac_mem_alloc(length);
if (new_str != NULL) {
memcpy(new_str, str, length_to_copy);
new_str[length_to_copy] = '\0';
}
return new_str;
}
char* guac_strdup(const char* str) {
/* Return NULL if no string provided */
if (str == NULL)
return NULL;
return guac_strndup(str, strlen(str));
}
size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
int nmemb, const char* restrict delim, size_t n) {
@ -159,4 +171,3 @@ size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
return length;
}

View File

@ -158,7 +158,7 @@ freerdp_LTLIBRARIES = \
libguac-common-svc-client.la \
libguacai-client.la
freerdpdir = @FREERDP2_PLUGIN_DIR@
freerdpdir = @FREERDP_PLUGIN_DIR@
#
# Common SVC plugin (shared by RDPDR, RDPSND, etc.)
@ -264,4 +264,3 @@ EXTRA_DIST = \
$(rdp_keymaps) \
keymaps/generate.pl \
plugins/generate-entry-wrappers.pl

View File

@ -132,8 +132,7 @@ void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap) {
/* NOTE: Except in FreeRDP 2.0.0-rc0 and earlier, FreeRDP-allocated memory
* for the rdpBitmap will NOT be automatically released after this free
* handler is invoked, thus we must do so manually here */
_aligned_free(bitmap->data);
GUAC_ALIGNED_FREE(bitmap->data);
free(bitmap);
#endif
@ -167,4 +166,3 @@ BOOL guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL pri
return TRUE;
}

View File

@ -82,7 +82,13 @@ static UINT guac_rdp_cliprdr_send_format_list(CliprdrClientContext* cliprdr) {
/* We support CP-1252 and UTF-16 text */
CLIPRDR_FORMAT_LIST format_list = {
#ifdef HAVE_CLIPRDR_HEADER
.common = {
.msgType = CB_FORMAT_LIST
},
#else
.msgType = CB_FORMAT_LIST,
#endif
.formats = (CLIPRDR_FORMAT[]) {
{ .formatId = CF_TEXT },
{ .formatId = CF_UNICODETEXT }
@ -298,9 +304,15 @@ static UINT guac_rdp_cliprdr_format_list(CliprdrClientContext* cliprdr,
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Received format list.");
CLIPRDR_FORMAT_LIST_RESPONSE format_list_response = {
#ifdef HAVE_CLIPRDR_HEADER
.common = {
.msgType = CB_FORMAT_LIST_RESPONSE,
.msgFlags = CB_RESPONSE_OK
}
#else
.msgFlags = CB_RESPONSE_OK
#endif
};
/* Report successful processing of format list */
pthread_mutex_lock(&(rdp_client->message_lock));
cliprdr->ClientFormatListResponse(cliprdr, &format_list_response);
@ -394,8 +406,16 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr,
CLIPRDR_FORMAT_DATA_RESPONSE data_response = {
.requestedFormatData = (BYTE*) start,
#ifdef HAVE_CLIPRDR_HEADER
.common = {
.msgType = CB_FORMAT_DATA_RESPONSE,
.msgFlags = CB_RESPONSE_OK,
.dataLen = ((BYTE*) output) - start,
}
#else
.dataLen = ((BYTE*) output) - start,
.msgFlags = CB_RESPONSE_OK
#endif
};
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Sending format data response.");
@ -482,9 +502,16 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
}
int data_len;
#ifdef HAVE_CLIPRDR_HEADER
data_len = format_data_response->common.dataLen;
#else
data_len = format_data_response->dataLen;
#endif
/* Convert, store, and forward the clipboard data received from RDP
* server */
if (guac_iconv(remote_reader, &input, format_data_response->dataLen,
if (guac_iconv(remote_reader, &input, data_len,
GUAC_WRITE_UTF8, &output, sizeof(received_data))) {
int length = strnlen(received_data, sizeof(received_data));
guac_common_clipboard_reset(clipboard->clipboard, "text/plain");
@ -712,4 +739,3 @@ int guac_rdp_clipboard_end_handler(guac_user* user, guac_stream* stream) {
return 0;
}

View File

@ -204,7 +204,7 @@ void guac_rdpsnd_formats_handler(guac_rdp_common_svc* svc,
Stream_Write_UINT16(output_stream, rdpsnd->format_count);
/* Reposition cursor at end (necessary for message send) */
Stream_SetPointer(output_stream, output_stream_end);
Stream_SetPosition(output_stream, output_stream_end - Stream_Buffer(output_stream));
/* Send accepted formats */
guac_rdp_common_svc_write(svc, output_stream);
@ -366,4 +366,3 @@ void guac_rdpsnd_close_handler(guac_rdp_common_svc* svc,
/* Do nothing */
}

View File

@ -56,7 +56,12 @@ UINT32 guac_rdp_convert_color(rdpContext* context, UINT32 color) {
/* Convert provided color into the intermediate representation expected by
* FreeRDPConvertColor() */
UINT32 intermed = ReadColor((BYTE*) &color, src_format);
UINT32 intermed;
#ifdef USE_UPDATED_RW_COLOR_FUNCS
intermed = FreeRDPReadColor((BYTE*) &color, src_format);
#else
intermed = ReadColor((BYTE*) &color, src_format);
#endif
/* Convert color from RDP source format to the native format used by Cairo,
* still maintaining intermediate representation */
@ -69,8 +74,12 @@ UINT32 guac_rdp_convert_color(rdpContext* context, UINT32 color) {
/* Convert color from intermediate representation to the actual desired
* format */
WriteColor((BYTE*) &color, dst_format, intermed);
#ifdef USE_UPDATED_RW_COLOR_FUNCS
intermed = FreeRDPWriteColor((BYTE*) &color, dst_format, intermed);
#else
intermed = WriteColor((BYTE*) &color, dst_format, intermed);
#endif
return color;
}

View File

@ -412,7 +412,14 @@ BOOL guac_rdp_gdi_surface_frame_marker(rdpContext* context, const SURFACE_FRAME_
guac_rdp_gdi_mark_frame(context, surface_frame_marker->frameAction != SURFACECMD_FRAMEACTION_END);
if (context->settings->FrameAcknowledge > 0)
int frame_acknowledge;
#ifdef HAVE_SETTERS_GETTERS
frame_acknowledge = freerdp_settings_get_uint32(context->settings, FreeRDP_FrameAcknowledge);
#else
frame_acknowledge = context->settings->FrameAcknowledge;
#endif
if (frame_acknowledge > 0)
IFCALL(context->update->SurfaceFrameAcknowledge, context,
surface_frame_marker->frameId);
@ -496,4 +503,3 @@ BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) {
guac_rdp_get_height(context->instance));
}

View File

@ -36,7 +36,7 @@
#define cairo_format_stride_for_width(format, width) (width*4)
#endif
BOOL guac_rdp_glyph_new(rdpContext* context, const rdpGlyph* glyph) {
BOOL guac_rdp_glyph_new(rdpContext* context, GLYPH_NEW_CONST rdpGlyph* glyph) {
int x, y, i;
int stride;
@ -168,4 +168,3 @@ BOOL guac_rdp_glyph_enddraw(rdpContext* context,
/* IGNORE */
return TRUE;
}

View File

@ -41,6 +41,12 @@
#define GLYPH_CALLBACK_INT32 UINT32
#endif
#ifdef RDP_GLYPH_NEW_REQUIRES_CONST
#define GLYPH_NEW_CONST const
#else
#define GLYPH_NEW_CONST
#endif
/**
* Guacamole-specific rdpGlyph data.
*/
@ -71,7 +77,7 @@ typedef struct guac_rdp_glyph {
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_glyph_new(rdpContext* context, const rdpGlyph* glyph);
BOOL guac_rdp_glyph_new(rdpContext* context, GLYPH_NEW_CONST rdpGlyph* glyph);
/**
* Draws a previously-cached glyph at the given coordinates within the current

View File

@ -57,7 +57,8 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
/* If button mask unchanged, just send move event */
if (mask == rdp_client->mouse_button_mask) {
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_MOVE, x, y);
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_MOVE, x, y);
pthread_mutex_unlock(&(rdp_client->message_lock));
}
@ -80,7 +81,8 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
if (released_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->MouseEvent(rdp_inst->input, flags, x, y);
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, flags, x, y);
pthread_mutex_unlock(&(rdp_client->message_lock));
}
@ -98,7 +100,8 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
/* Send event */
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->MouseEvent(rdp_inst->input, flags, x, y);
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, flags, x, y);
pthread_mutex_unlock(&(rdp_client->message_lock));
}
@ -109,14 +112,16 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
/* Down */
if (pressed_mask & 0x08) {
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_WHEEL | 0x78, x, y);
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_WHEEL | 0x78, x, y);
pthread_mutex_unlock(&(rdp_client->message_lock));
}
/* Up */
if (pressed_mask & 0x10) {
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88, x, y);
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88, x, y);
pthread_mutex_unlock(&(rdp_client->message_lock));
}

View File

@ -107,7 +107,8 @@ static void guac_rdp_send_key_event(guac_rdp_client* rdp_client,
/* Send actual key */
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->KeyboardEvent(rdp_inst->input, flags | pressed_flags, scancode);
GUAC_RDP_CONTEXT(rdp_inst)->input->KeyboardEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, flags | pressed_flags, scancode);
pthread_mutex_unlock(&(rdp_client->message_lock));
}
@ -136,7 +137,8 @@ static void guac_rdp_send_unicode_event(guac_rdp_client* rdp_client,
/* Send Unicode event */
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->UnicodeKeyboardEvent(rdp_inst->input, 0, codepoint);
GUAC_RDP_CONTEXT(rdp_inst)->input->UnicodeKeyboardEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, 0, codepoint);
pthread_mutex_unlock(&(rdp_client->message_lock));
}
@ -165,7 +167,8 @@ static void guac_rdp_send_synchronize_event(guac_rdp_client* rdp_client,
/* Synchronize lock key states */
pthread_mutex_lock(&(rdp_client->message_lock));
rdp_inst->input->SynchronizeEvent(rdp_inst->input, flags);
GUAC_RDP_CONTEXT(rdp_inst)->input->SynchronizeEvent(
GUAC_RDP_CONTEXT(rdp_inst)->input, flags);
pthread_mutex_unlock(&(rdp_client->message_lock));
}

View File

@ -136,8 +136,11 @@ void guac_freerdp_dynamic_channel_collection_add(rdpSettings* settings,
va_end(args);
/* Register plugin with FreeRDP */
#ifdef HAVE_SETTERS_GETTERS
freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicChannels, TRUE);
#else
settings->SupportDynamicChannels = TRUE;
#endif
freerdp_dynamic_channel_collection_add(settings, freerdp_args);
}

View File

@ -61,8 +61,8 @@
* The name of the plugin to load. If the plugin is not statically built
* into FreeRDP, this name will determine the filename of the library to be
* loaded dynamically. For a plugin named "NAME", the library called
* "libNAME-client" will be loaded from the "freerdp2" subdirectory of the
* main directory containing the FreeRDP libraries.
* "libNAME-client" will be loaded from the "freerdp2" or "freerdp3"
* subdirectory of the main directory containing the FreeRDP libraries.
*
* @param data
* Arbitrary data to be passed to the plugin entry point. For most plugins
@ -105,8 +105,8 @@ int guac_freerdp_channels_load_plugin(rdpContext* context,
* The name of the plugin to load. If the plugin is not statically built
* into FreeRDP, this name will determine the filename of the library to be
* loaded dynamically. For a plugin named "NAME", the library called
* "libNAME-client" will be loaded from the "freerdp2" subdirectory of the
* main directory containing the FreeRDP libraries.
* "libNAME-client" will be loaded from the "freerdp2" or "freerdp3"
* subdirectory of the main directory containing the FreeRDP libraries.
*
* @param ...
* Arbitrary arguments to be passed to the plugin entry point. For most
@ -204,4 +204,3 @@ PVIRTUALCHANNELENTRY guac_rdp_plugin_wrap_entry(guac_client* client,
PVIRTUALCHANNELENTRY entry);
#endif

View File

@ -283,7 +283,12 @@ static UINT guac_rdp_ai_terminated(IWTSPlugin* plugin) {
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
/* Pull guac_client from arguments */
#ifdef PLUGIN_DATA_CONST
const ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
#else
ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
#endif
guac_client* client = (guac_client*) guac_rdp_string_to_ptr(args->argv[1]);
/* Pull previously-allocated plugin */
@ -309,4 +314,3 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
return CHANNEL_RC_OK;
}

View File

@ -42,7 +42,7 @@ BOOL guac_rdp_pointer_new(rdpContext* context, rdpPointer* pointer) {
rdp_client->display, pointer->width, pointer->height);
/* Allocate data for image */
unsigned char* data = _aligned_malloc(pointer->width * pointer->height * 4, 16);
unsigned char* data = GUAC_ALIGNED_MALLOC(pointer->width * pointer->height * 4, 16);
cairo_surface_t* surface;
@ -64,7 +64,7 @@ BOOL guac_rdp_pointer_new(rdpContext* context, rdpPointer* pointer) {
/* Free surface */
cairo_surface_destroy(surface);
_aligned_free(data);
GUAC_ALIGNED_FREE(data);
/* Remember buffer */
((guac_rdp_pointer*) pointer)->layer = buffer;
@ -73,7 +73,7 @@ BOOL guac_rdp_pointer_new(rdpContext* context, rdpPointer* pointer) {
}
BOOL guac_rdp_pointer_set(rdpContext* context, const rdpPointer* pointer) {
BOOL guac_rdp_pointer_set(rdpContext* context, POINTER_SET_CONST rdpPointer* pointer) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
@ -156,4 +156,3 @@ BOOL guac_rdp_pointer_set_default(rdpContext* context) {
return TRUE;
}

View File

@ -26,6 +26,12 @@
#include <freerdp/graphics.h>
#include <winpr/wtypes.h>
#ifdef RDP_POINTER_SET_REQUIRES_CONST
#define POINTER_SET_CONST const
#else
#define POINTER_SET_CONST
#endif
/**
* Guacamole-specific rdpPointer data.
*/
@ -71,7 +77,7 @@ BOOL guac_rdp_pointer_new(rdpContext* context, rdpPointer* pointer);
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_pointer_set(rdpContext* context, const rdpPointer* pointer);
BOOL guac_rdp_pointer_set(rdpContext* context, POINTER_SET_CONST rdpPointer* pointer);
/**
* Frees all Guacamole-related data associated with the given pointer, allowing

View File

@ -53,12 +53,6 @@
#endif
#include <freerdp/addin.h>
#include <freerdp/cache/bitmap.h>
#include <freerdp/cache/brush.h>
#include <freerdp/cache/glyph.h>
#include <freerdp/cache/offscreen.h>
#include <freerdp/cache/palette.h>
#include <freerdp/cache/pointer.h>
#include <freerdp/channels/channels.h>
#include <freerdp/client/channels.h>
#include <freerdp/freerdp.h>
@ -86,7 +80,7 @@
BOOL rdp_freerdp_pre_connect(freerdp* instance) {
rdpContext* context = instance->context;
rdpContext* context = GUAC_RDP_CONTEXT(instance);
rdpGraphics* graphics = context->graphics;
guac_client* client = ((rdp_freerdp_context*) context)->client;
@ -112,7 +106,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
/* Upgrade the lock to write temporarily for setting the newly allocated audio buffer */
guac_rwlock_acquire_write_lock(&(rdp_client->lock));
rdp_client->audio_input = guac_rdp_audio_buffer_alloc(client);
guac_rdp_audio_load_plugin(instance->context);
guac_rdp_audio_load_plugin(GUAC_RDP_CONTEXT(instance));
/* Downgrade the lock to allow for concurrent read access */
guac_rwlock_release_lock(&(rdp_client->lock));
@ -178,42 +172,35 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
graphics_register_pointer(graphics, &pointer);
/* Beep on receipt of Play Sound PDU */
instance->update->PlaySound = guac_rdp_beep_play_sound;
GUAC_RDP_CONTEXT(instance)->update->PlaySound = guac_rdp_beep_play_sound;
/* Automatically synchronize keyboard locks when changed server-side */
instance->update->SetKeyboardIndicators = guac_rdp_keyboard_set_indicators;
GUAC_RDP_CONTEXT(instance)->update->SetKeyboardIndicators = guac_rdp_keyboard_set_indicators;
/* Set up GDI */
instance->update->DesktopResize = guac_rdp_gdi_desktop_resize;
instance->update->BeginPaint = guac_rdp_gdi_begin_paint;
instance->update->EndPaint = guac_rdp_gdi_end_paint;
instance->update->SetBounds = guac_rdp_gdi_set_bounds;
GUAC_RDP_CONTEXT(instance)->update->DesktopResize = guac_rdp_gdi_desktop_resize;
GUAC_RDP_CONTEXT(instance)->update->BeginPaint = guac_rdp_gdi_begin_paint;
GUAC_RDP_CONTEXT(instance)->update->EndPaint = guac_rdp_gdi_end_paint;
GUAC_RDP_CONTEXT(instance)->update->SetBounds = guac_rdp_gdi_set_bounds;
instance->update->SurfaceFrameMarker = guac_rdp_gdi_surface_frame_marker;
instance->update->altsec->FrameMarker = guac_rdp_gdi_frame_marker;
GUAC_RDP_CONTEXT(instance)->update->SurfaceFrameMarker = guac_rdp_gdi_surface_frame_marker;
GUAC_RDP_CONTEXT(instance)->update->altsec->FrameMarker = guac_rdp_gdi_frame_marker;
rdpPrimaryUpdate* primary = instance->update->primary;
rdpPrimaryUpdate* primary = GUAC_RDP_CONTEXT(instance)->update->primary;
primary->DstBlt = guac_rdp_gdi_dstblt;
primary->PatBlt = guac_rdp_gdi_patblt;
primary->ScrBlt = guac_rdp_gdi_scrblt;
primary->MemBlt = guac_rdp_gdi_memblt;
primary->OpaqueRect = guac_rdp_gdi_opaquerect;
pointer_cache_register_callbacks(instance->update);
glyph_cache_register_callbacks(instance->update);
brush_cache_register_callbacks(instance->update);
bitmap_cache_register_callbacks(instance->update);
offscreen_cache_register_callbacks(instance->update);
palette_cache_register_callbacks(instance->update);
/* Load "rdpgfx" plugin for Graphics Pipeline Extension */
if (settings->enable_gfx)
guac_rdp_rdpgfx_load_plugin(context);
/* Load plugin providing Dynamic Virtual Channel support, if required */
if (instance->settings->SupportDynamicChannels &&
if (freerdp_settings_get_bool(GUAC_RDP_CONTEXT(instance)->settings, FreeRDP_SupportDynamicChannels) &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
instance->settings)) {
GUAC_RDP_CONTEXT(instance)->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
@ -254,7 +241,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username,
char** password, char** domain) {
rdpContext* context = instance->context;
rdpContext* context = GUAC_RDP_CONTEXT(instance);
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;
@ -396,7 +383,7 @@ static DWORD rdp_freerdp_verify_certificate(freerdp* instance,
const char* fingerprint, BOOL host_mismatch) {
#endif
rdpContext* context = instance->context;
rdpContext* context = GUAC_RDP_CONTEXT(instance);
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client =
(guac_rdp_client*) client->data;
@ -432,7 +419,7 @@ static int rdp_guac_client_wait_for_messages(guac_client* client,
freerdp* rdp_inst = rdp_client->rdp_inst;
HANDLE handles[GUAC_RDP_MAX_FILE_DESCRIPTORS];
int num_handles = freerdp_get_event_handles(rdp_inst->context, handles,
int num_handles = freerdp_get_event_handles(GUAC_RDP_CONTEXT(rdp_inst), handles,
GUAC_RDP_MAX_FILE_DESCRIPTORS);
/* Wait for data and construct a reasonable frame */
@ -521,7 +508,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
goto fail;
}
((rdp_freerdp_context*) rdp_inst->context)->client = client;
((rdp_freerdp_context*) GUAC_RDP_CONTEXT(rdp_inst))->client = client;
/* Load keymap into client */
rdp_client->keyboard = guac_rdp_keyboard_alloc(client,
@ -579,7 +566,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
/* Handle any queued FreeRDP events (this may result in RDP
* messages being sent) */
pthread_mutex_lock(&(rdp_client->message_lock));
int event_result = freerdp_check_event_handles(rdp_inst->context);
int event_result = freerdp_check_event_handles(GUAC_RDP_CONTEXT(rdp_inst));
pthread_mutex_unlock(&(rdp_client->message_lock));
/* Abort if FreeRDP event handling fails */
@ -622,7 +609,12 @@ static int guac_rdp_handle_connection(guac_client* client) {
}
/* Test whether the RDP server is closing the connection */
int connection_closing = freerdp_shall_disconnect(rdp_inst);
int connection_closing;
#ifdef HAVE_DISCONNECT_CONTEXT
connection_closing = freerdp_shall_disconnect_context(rdp_inst->context);
#else
connection_closing = freerdp_shall_disconnect(rdp_inst);
#endif
/* Close connection cleanly if server is disconnecting */
if (connection_closing)

View File

@ -51,6 +51,20 @@
#include <pthread.h>
#include <stdint.h>
#ifdef HAVE_WINPR_ALIGNED
#define GUAC_ALIGNED_FREE winpr_aligned_free
#define GUAC_ALIGNED_MALLOC winpr_aligned_malloc
#else
#define GUAC_ALIGNED_FREE _aligned_free
#define GUAC_ALIGNED_MALLOC _aligned_malloc
#endif
#ifdef FREERDP_HAS_CONTEXT
#define GUAC_RDP_CONTEXT(rdp_instance) ((rdp_instance)->context)
#else
#define GUAC_RDP_CONTEXT(rdp_instance) ((rdp_instance))
#endif
/**
* RDP-specific client data.
*/

View File

@ -21,6 +21,7 @@
#include "common/defaults.h"
#include "common/string.h"
#include "config.h"
#include "rdp.h"
#include "resolution.h"
#include "settings.h"
@ -1394,18 +1395,6 @@ void guac_rdp_settings_free(guac_rdp_settings* settings) {
}
int guac_rdp_get_width(freerdp* rdp) {
return rdp->settings->DesktopWidth;
}
int guac_rdp_get_height(freerdp* rdp) {
return rdp->settings->DesktopHeight;
}
int guac_rdp_get_depth(freerdp* rdp) {
return rdp->settings->ColorDepth;
}
/**
* Given the settings structure of the Guacamole RDP client, calculates the
* standard performance flag value to send to the RDP server. The value of
@ -1451,11 +1440,279 @@ static int guac_rdp_get_performance_flags(guac_rdp_settings* guac_settings) {
}
int guac_rdp_get_width(freerdp* rdp) {
#ifdef HAVE_SETTERS_GETTERS
return freerdp_settings_get_uint32(rdp->context->settings, FreeRDP_DesktopWidth);
#else
return rdp->settings->DesktopWidth;
#endif
}
int guac_rdp_get_height(freerdp* rdp) {
#ifdef HAVE_SETTERS_GETTERS
return freerdp_settings_get_uint32(rdp->context->settings, FreeRDP_DesktopHeight);
#else
return rdp->settings->DesktopHeight;
#endif
}
int guac_rdp_get_depth(freerdp* rdp) {
#ifdef HAVE_SETTERS_GETTERS
return freerdp_settings_get_uint32(rdp->context->settings, FreeRDP_ColorDepth);
#else
return rdp->settings->ColorDepth;
#endif
}
void guac_rdp_push_settings(guac_client* client,
guac_rdp_settings* guac_settings, freerdp* rdp) {
rdpSettings* rdp_settings = rdp->settings;
rdpSettings* rdp_settings = GUAC_RDP_CONTEXT(rdp)->settings;
#ifdef HAVE_SETTERS_GETTERS
/* Authentication */
freerdp_settings_set_string(rdp_settings, FreeRDP_Domain, guac_strdup(guac_settings->domain));
freerdp_settings_set_string(rdp_settings, FreeRDP_Username, guac_strdup(guac_settings->username));
freerdp_settings_set_string(rdp_settings, FreeRDP_Password, guac_strdup(guac_settings->password));
/* Connection */
freerdp_settings_set_string(rdp_settings, FreeRDP_ServerHostname, guac_strdup(guac_settings->hostname));
freerdp_settings_set_uint32(rdp_settings, FreeRDP_ServerPort, guac_settings->port);
/* Session */
freerdp_settings_set_uint32(rdp_settings, FreeRDP_DesktopWidth, guac_settings->width);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_DesktopHeight, guac_settings->height);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_ColorDepth, guac_settings->color_depth);
freerdp_settings_set_string(rdp_settings, FreeRDP_AlternateShell, guac_strdup(guac_settings->initial_program));
freerdp_settings_set_uint32(rdp_settings, FreeRDP_KeyboardLayout, guac_settings->server_layout->freerdp_keyboard_layout);
/* Performance flags */
/* Explicitly set flag value */
freerdp_settings_set_uint32(rdp_settings, FreeRDP_PerformanceFlags, guac_rdp_get_performance_flags(guac_settings));
/* Always request frame markers */
freerdp_settings_set_bool(rdp_settings, FreeRDP_FrameMarkerCommandEnabled, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE);
/* Enable RemoteFX / Graphics Pipeline */
if (guac_settings->enable_gfx) {
freerdp_settings_set_bool(rdp_settings, FreeRDP_SupportGraphicsPipeline, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_RemoteFxCodec, TRUE);
if (freerdp_settings_get_uint32(rdp_settings, FreeRDP_ColorDepth) != RDP_GFX_REQUIRED_DEPTH) {
guac_client_log(client, GUAC_LOG_WARNING, "Ignoring requested "
"color depth of %i bpp, as the RDP Graphics Pipeline "
"requires %i bpp.", freerdp_settings_get_uint32(rdp_settings, FreeRDP_ColorDepth), RDP_GFX_REQUIRED_DEPTH);
}
/* Required for RemoteFX / Graphics Pipeline */
freerdp_settings_set_bool(rdp_settings, FreeRDP_FastPathOutput, TRUE);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_ColorDepth, RDP_GFX_REQUIRED_DEPTH);
freerdp_settings_set_bool(rdp_settings, FreeRDP_SoftwareGdi, TRUE);
}
/* Set individual flags - some FreeRDP versions overwrite flags set by guac_rdp_get_performance_flags() above */
freerdp_settings_set_bool(rdp_settings, FreeRDP_AllowFontSmoothing, guac_settings->font_smoothing_enabled);
freerdp_settings_set_bool(rdp_settings, FreeRDP_DisableWallpaper, guac_settings->wallpaper_enabled);
freerdp_settings_set_bool(rdp_settings, FreeRDP_DisableFullWindowDrag, guac_settings->full_window_drag_enabled);
freerdp_settings_set_bool(rdp_settings, FreeRDP_DisableMenuAnims, guac_settings->menu_animations_enabled);
freerdp_settings_set_bool(rdp_settings, FreeRDP_DisableThemes, guac_settings->theming_enabled);
freerdp_settings_set_bool(rdp_settings, FreeRDP_AllowDesktopComposition, guac_settings->desktop_composition_enabled);
/* Client name */
if (guac_settings->client_name != NULL) {
freerdp_settings_set_string(rdp_settings, FreeRDP_ClientHostname,
guac_strndup(guac_settings->client_name, RDP_CLIENT_HOSTNAME_SIZE));
}
/* Console */
freerdp_settings_set_bool(rdp_settings, FreeRDP_ConsoleSession, guac_settings->console);
freerdp_settings_set_bool(rdp_settings, FreeRDP_RemoteConsoleAudio, guac_settings->console_audio);
/* Audio */
freerdp_settings_set_bool(rdp_settings, FreeRDP_AudioPlayback, guac_settings->audio_enabled);
/* Audio capture */
freerdp_settings_set_bool(rdp_settings, FreeRDP_AudioCapture, guac_settings->enable_audio_input);
/* Display Update channel */
freerdp_settings_set_bool(rdp_settings, FreeRDP_SupportDisplayControl,
(guac_settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE));
/* Timezone redirection */
if (guac_settings->timezone) {
if (setenv("TZ", guac_settings->timezone, 1)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Unable to forward timezone: TZ environment variable "
"could not be set: %s", strerror(errno));
}
}
/* Device redirection */
freerdp_settings_set_bool(rdp_settings, FreeRDP_DeviceRedirection,
(guac_settings->audio_enabled || guac_settings->drive_enabled || guac_settings->printing_enabled));
/* Security */
switch (guac_settings->security_mode) {
/* Legacy RDP encryption */
case GUAC_SECURITY_RDP:
freerdp_settings_set_bool(rdp_settings, FreeRDP_RdpSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_TlsSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_ExtSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_UseRdpSecurityLayer, TRUE);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_EncryptionLevel,
ENCRYPTION_LEVEL_CLIENT_COMPATIBLE);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_EncryptionMethods,
ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS);
break;
/* TLS encryption */
case GUAC_SECURITY_TLS:
freerdp_settings_set_bool(rdp_settings, FreeRDP_RdpSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_TlsSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_ExtSecurity, FALSE);
break;
/* Network level authentication */
case GUAC_SECURITY_NLA:
freerdp_settings_set_bool(rdp_settings, FreeRDP_RdpSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_TlsSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_ExtSecurity, FALSE);
break;
/* Extended network level authentication */
case GUAC_SECURITY_EXTENDED_NLA:
freerdp_settings_set_bool(rdp_settings, FreeRDP_RdpSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_TlsSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_ExtSecurity, TRUE);
break;
/* Hyper-V "VMConnect" negotiation mode */
case GUAC_SECURITY_VMCONNECT:
freerdp_settings_set_bool(rdp_settings, FreeRDP_RdpSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_TlsSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_ExtSecurity, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_VmConnectMode, TRUE);
break;
/* All security types */
case GUAC_SECURITY_ANY:
freerdp_settings_set_bool(rdp_settings, FreeRDP_RdpSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_TlsSecurity, TRUE);
/* Explicitly disable NLA if FIPS mode is enabled - it won't work */
if (guac_fips_enabled()) {
guac_client_log(client, GUAC_LOG_INFO,
"FIPS mode is enabled. Excluding NLA security mode from security negotiation "
"(see: https://github.com/FreeRDP/FreeRDP/issues/3412).");
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, FALSE);
}
/* NLA mode is allowed if FIPS is not enabled */
else
freerdp_settings_set_bool(rdp_settings, FreeRDP_NlaSecurity, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_ExtSecurity, FALSE);
break;
}
/* Security */
freerdp_settings_set_bool(rdp_settings, FreeRDP_Authentication, !guac_settings->disable_authentication);
freerdp_settings_set_bool(rdp_settings, FreeRDP_IgnoreCertificate, guac_settings->ignore_certificate);
freerdp_settings_set_bool(rdp_settings, FreeRDP_AutoAcceptCertificate, guac_settings->certificate_tofu);
if (guac_settings->certificate_fingerprints != NULL)
freerdp_settings_set_string(rdp_settings, FreeRDP_CertificateAcceptedFingerprints,
guac_strdup(guac_settings->certificate_fingerprints));
/* RemoteApp */
if (guac_settings->remote_app != NULL) {
freerdp_settings_set_bool(rdp_settings, FreeRDP_Workarea, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_RemoteApplicationMode, TRUE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_RemoteAppLanguageBarSupported, TRUE);
freerdp_settings_set_string(rdp_settings, FreeRDP_RemoteApplicationProgram, guac_strdup(guac_settings->remote_app));
freerdp_settings_set_string(rdp_settings, FreeRDP_ShellWorkingDirectory, guac_strdup(guac_settings->remote_app_dir));
freerdp_settings_set_string(rdp_settings, FreeRDP_RemoteApplicationCmdLine, guac_strdup(guac_settings->remote_app_args));
}
/* Preconnection ID */
if (guac_settings->preconnection_id != -1) {
freerdp_settings_set_bool(rdp_settings, FreeRDP_NegotiateSecurityLayer, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_SendPreconnectionPdu, TRUE);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_PreconnectionId, guac_settings->preconnection_id);
}
/* Preconnection BLOB */
if (guac_settings->preconnection_blob != NULL) {
freerdp_settings_set_bool(rdp_settings, FreeRDP_NegotiateSecurityLayer, FALSE);
freerdp_settings_set_bool(rdp_settings, FreeRDP_SendPreconnectionPdu, TRUE);
freerdp_settings_set_string(rdp_settings, FreeRDP_PreconnectionBlob, guac_strdup(guac_settings->preconnection_blob));
}
/* Enable use of RD gateway if a gateway hostname is provided */
if (guac_settings->gateway_hostname != NULL) {
/* Enable RD gateway */
freerdp_settings_set_bool(rdp_settings, FreeRDP_GatewayEnabled, TRUE);
/* RD gateway connection details */
freerdp_settings_set_string(rdp_settings, FreeRDP_GatewayHostname, guac_strdup(guac_settings->gateway_hostname));
freerdp_settings_set_uint32(rdp_settings, FreeRDP_GatewayPort, guac_settings->gateway_port);
/* RD gateway credentials */
freerdp_settings_set_bool(rdp_settings, FreeRDP_GatewayUseSameCredentials, FALSE);
freerdp_settings_set_string(rdp_settings, FreeRDP_GatewayDomain, guac_strdup(guac_settings->gateway_domain));
freerdp_settings_set_string(rdp_settings, FreeRDP_GatewayUsername, guac_strdup(guac_settings->gateway_username));
freerdp_settings_set_string(rdp_settings, FreeRDP_GatewayPassword, guac_strdup(guac_settings->gateway_password));
}
/* Store load balance info (and calculate length) if provided */
if (guac_settings->load_balance_info != NULL) {
freerdp_settings_set_pointer(rdp_settings, FreeRDP_LoadBalanceInfo, (BYTE*) guac_strdup(guac_settings->load_balance_info));
freerdp_settings_set_uint32(rdp_settings, FreeRDP_LoadBalanceInfoLength, strlen(guac_settings->load_balance_info));
}
freerdp_settings_set_bool(rdp_settings, FreeRDP_BitmapCacheEnabled, !guac_settings->disable_bitmap_caching);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_OffscreenSupportLevel, !guac_settings->disable_offscreen_caching);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_GlyphSupportLevel,
(!guac_settings->disable_glyph_caching ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE));
freerdp_settings_set_uint32(rdp_settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNSPECIFIED);
freerdp_settings_set_uint32(rdp_settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED);
freerdp_settings_set_bool(rdp_settings, FreeRDP_DesktopResize, TRUE);
/* Claim support only for specific updates, independent of FreeRDP defaults */
BYTE* order_support = freerdp_settings_get_pointer_writable(rdp_settings, FreeRDP_OrderSupport);
if (order_support) {
ZeroMemory(order_support, GUAC_RDP_ORDER_SUPPORT_LENGTH);
order_support[NEG_DSTBLT_INDEX] = TRUE;
order_support[NEG_SCRBLT_INDEX] = TRUE;
order_support[NEG_MEMBLT_INDEX] = !guac_settings->disable_bitmap_caching;
order_support[NEG_MEMBLT_V2_INDEX] = !guac_settings->disable_bitmap_caching;
order_support[NEG_GLYPH_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
order_support[NEG_FAST_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
order_support[NEG_FAST_GLYPH_INDEX] = !guac_settings->disable_glyph_caching;
}
#ifdef HAVE_RDPSETTINGS_ALLOWUNANOUNCEDORDERSFROMSERVER
/* Do not consider server use of unannounced orders to be a fatal error */
freerdp_settings_set_bool(rdp_settings, FreeRDP_AllowUnanouncedOrdersFromServer, TRUE);
#endif
#else
/* Authentication */
rdp_settings->Domain = guac_strdup(guac_settings->domain);
rdp_settings->Username = guac_strdup(guac_settings->username);
@ -1499,7 +1756,7 @@ void guac_rdp_push_settings(guac_client* client,
}
/* Set individual flags - some FreeRDP versions overwrite the above */
/* Set individual flags - some FreeRDP versions overwrite flags set by guac_rdp_get_performance_flags() above */
rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled;
rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled;
rdp_settings->DisableFullWindowDrag = !guac_settings->full_window_drag_enabled;
@ -1692,5 +1949,5 @@ void guac_rdp_push_settings(guac_client* client,
rdp_settings->AllowUnanouncedOrdersFromServer = TRUE;
#endif
#endif
}