This is an automated email from the ASF dual-hosted git repository.

aleitner pushed a commit to branch RDP-3
in repository https://gitbox.apache.org/repos/asf/guacamole-server.git

commit 5ccdace943b85b3e2f54260869ac0f3203742b17
Author: Alex Leitner <[email protected]>
AuthorDate: Thu May 9 11:01:13 2024 +0900

    RDP-3.
---
 Dockerfile                                         |   5 +-
 configure.ac                                       | 214 ++++++++++++++--
 src/libguac/guacamole/string.h                     |  33 ++-
 src/libguac/string.c                               |  25 +-
 src/protocols/rdp/Makefile.am                      |   3 +-
 src/protocols/rdp/bitmap.c                         |   4 +-
 src/protocols/rdp/channels/cliprdr.c               |  32 ++-
 .../rdp/channels/rdpsnd/rdpsnd-messages.c          |   3 +-
 src/protocols/rdp/color.c                          |  15 +-
 src/protocols/rdp/gdi.c                            |  10 +-
 src/protocols/rdp/glyph.c                          |   3 +-
 src/protocols/rdp/glyph.h                          |   8 +-
 src/protocols/rdp/input.c                          |  15 +-
 src/protocols/rdp/keyboard.c                       |   9 +-
 src/protocols/rdp/plugins/channels.c               |   7 +-
 src/protocols/rdp/plugins/guacai/guacai.c          |   6 +-
 src/protocols/rdp/pointer.c                        |   7 +-
 src/protocols/rdp/pointer.h                        |   8 +-
 src/protocols/rdp/rdp.c                            |  56 ++--
 src/protocols/rdp/rdp.h                            |  14 +
 src/protocols/rdp/settings.c                       | 285 ++++++++++++++++++++-
 21 files changed, 646 insertions(+), 116 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 5f1e824c..7ff1856e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -64,7 +64,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='3(\.\d+)+'
 ARG WITH_LIBSSH2='libssh2-\d+(\.\d+)+'
 ARG WITH_LIBTELNET='\d+(\.\d+)+'
 ARG WITH_LIBVNCCLIENT='LibVNCServer-\d+(\.\d+)+'
@@ -145,7 +145,7 @@ RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh
 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   \
+        ${PREFIX_DIR}/lib/freerdp3/*guac*.so   \
         > ${PREFIX_DIR}/DEPENDENCIES
 
 # Use same Alpine version as the base for the runtime image
@@ -202,4 +202,3 @@ EXPOSE 4822
 # PREFIX_DIR build argument.
 #
 CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
-
diff --git a/configure.ac b/configure.ac
index c0394ac8..a6faddb7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
+    freerdp_version=3
+    have_freerdp=yes
+    PKG_CHECK_MODULES([RDP], [freerdp3 freerdp-client3 winpr3],
+                      [CPPFLAGS="${RDP_CFLAGS} -Werror $CPPFLAGS"]
+                      [AS_IF([test "x${FREERDP_PLUGIN_DIR}" = "x"],
+                             [FREERDP_PLUGIN_DIR="`$PKG_CONFIG 
--variable=libdir freerdp3`/freerdp3"])],
+                      [AC_MSG_WARN([
+  --------------------------------------------
+   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${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 freerdp2`/freerdp2"])],
                       [AC_MSG_WARN([
   --------------------------------------------
-   Unable to find FreeRDP (libfreerdp2 / libfreerdp-client2 / libwinpr2)
+   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,164 @@ 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
+    # Check if winpr prefixed aligned functions are declared in FreeRDP 3.x
+    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
+    # Check for the presence of a common CLIPRDR_HEADER in CLIPRDR structs in 
FreeRDP 3.x
+    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
+    # Check if the newer color functions FreeRDPReadColor and 
FreeRDPWriteColor are declared in FreeRDP 3.x
+    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
+    # Check if FreeRDP 3.x moved context-related pointers to a context 
structure in the freerdp instance
+    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
+    # Check if 'freerdp_shall_disconnect_context' is present in FreeRDP
+    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>
+        
+        /* Mock function with expected signature to avoid direct dependency */
+        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 guac_rdp_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>
+        
+        /* Mock function with expected signature to confirm compatibility */
+        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 +1402,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 +1415,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 +1445,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.
 "
-
diff --git a/src/libguac/guacamole/string.h b/src/libguac/guacamole/string.h
index a94d53c2..bec28115 100644
--- a/src/libguac/guacamole/string.h
+++ b/src/libguac/guacamole/string.h
@@ -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
-
diff --git a/src/libguac/string.c b/src/libguac/string.c
index 2a7ec2cd..0fbf0bc4 100644
--- a/src/libguac/string.c
+++ b/src/libguac/string.c
@@ -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;
 
 }
-
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index 1c393c30..57204f2a 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -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
-
diff --git a/src/protocols/rdp/bitmap.c b/src/protocols/rdp/bitmap.c
index 05f9e214..6faa151f 100644
--- a/src/protocols/rdp/bitmap.c
+++ b/src/protocols/rdp/bitmap.c
@@ -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;
 
 }
-
diff --git a/src/protocols/rdp/channels/cliprdr.c 
b/src/protocols/rdp/channels/cliprdr.c
index 4b37d58a..34bacf3b 100644
--- a/src/protocols/rdp/channels/cliprdr.c
+++ b/src/protocols/rdp/channels/cliprdr.c
@@ -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;
 
 }
-
diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c 
b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
index 1aeb8df9..7c57bc5c 100644
--- a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
+++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
@@ -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 */
 
 }
-
diff --git a/src/protocols/rdp/color.c b/src/protocols/rdp/color.c
index 964310af..7733b2c4 100644
--- a/src/protocols/rdp/color.c
+++ b/src/protocols/rdp/color.c
@@ -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;
 
 }
-
diff --git a/src/protocols/rdp/gdi.c b/src/protocols/rdp/gdi.c
index 6fc311bf..a379bc73 100644
--- a/src/protocols/rdp/gdi.c
+++ b/src/protocols/rdp/gdi.c
@@ -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));
 
 }
-
diff --git a/src/protocols/rdp/glyph.c b/src/protocols/rdp/glyph.c
index 7241a385..e0907956 100644
--- a/src/protocols/rdp/glyph.c
+++ b/src/protocols/rdp/glyph.c
@@ -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;
 }
-
diff --git a/src/protocols/rdp/glyph.h b/src/protocols/rdp/glyph.h
index b217de02..36b8f3a3 100644
--- a/src/protocols/rdp/glyph.h
+++ b/src/protocols/rdp/glyph.h
@@ -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
diff --git a/src/protocols/rdp/input.c b/src/protocols/rdp/input.c
index 458c12e7..8a8d0c6e 100644
--- a/src/protocols/rdp/input.c
+++ b/src/protocols/rdp/input.c
@@ -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));
             }
 
diff --git a/src/protocols/rdp/keyboard.c b/src/protocols/rdp/keyboard.c
index fa93c20e..3e749bc7 100644
--- a/src/protocols/rdp/keyboard.c
+++ b/src/protocols/rdp/keyboard.c
@@ -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));
 
 }
diff --git a/src/protocols/rdp/plugins/channels.c 
b/src/protocols/rdp/plugins/channels.c
index 342ca33b..3ae3a855 100644
--- a/src/protocols/rdp/plugins/channels.c
+++ b/src/protocols/rdp/plugins/channels.c
@@ -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;
-    freerdp_dynamic_channel_collection_add(settings, freerdp_args);
+#endif
 
+    freerdp_dynamic_channel_collection_add(settings, freerdp_args);
 }
-
diff --git a/src/protocols/rdp/plugins/guacai/guacai.c 
b/src/protocols/rdp/plugins/guacai/guacai.c
index 6ab633c0..2abae652 100644
--- a/src/protocols/rdp/plugins/guacai/guacai.c
+++ b/src/protocols/rdp/plugins/guacai/guacai.c
@@ -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;
 
 }
-
diff --git a/src/protocols/rdp/pointer.c b/src/protocols/rdp/pointer.c
index 8c024b71..1d4a4e89 100644
--- a/src/protocols/rdp/pointer.c
+++ b/src/protocols/rdp/pointer.c
@@ -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;
 }
-
diff --git a/src/protocols/rdp/pointer.h b/src/protocols/rdp/pointer.h
index b5fa6a23..03df2f91 100644
--- a/src/protocols/rdp/pointer.h
+++ b/src/protocols/rdp/pointer.h
@@ -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
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index dff536ef..119f117d 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -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)
diff --git a/src/protocols/rdp/rdp.h b/src/protocols/rdp/rdp.h
index 70668f42..4cda2c85 100644
--- a/src/protocols/rdp/rdp.h
+++ b/src/protocols/rdp/rdp.h
@@ -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.
  */
diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c
index 4b02b3eb..62d01930 100644
--- a/src/protocols/rdp/settings.c
+++ b/src/protocols/rdp/settings.c
@@ -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 the 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);
@@ -1692,5 +1949,5 @@ void guac_rdp_push_settings(guac_client* client,
     rdp_settings->AllowUnanouncedOrdersFromServer = TRUE;
 #endif
 
+#endif
 }
-

Reply via email to