Merge staging/1.1.0 changes back to master.
diff --git a/Dockerfile b/Dockerfile
index a109edd..83bce0f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -75,7 +75,7 @@
         > ${PREFIX_DIR}/DEPENDENCIES
 
 # Use same Debian as the base for the runtime image
-FROM debian:${DEBIAN_VERSION}
+FROM debian:${DEBIAN_VERSION}-slim
 
 # Base directory for installed build artifacts.
 # Due to limitations of the Docker image build process, this value is
diff --git a/configure.ac b/configure.ac
index 24c1588..ea98b8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -528,6 +528,33 @@
 fi
 
 #
+# TLS Locking Support within libVNCServer
+#
+
+if test "x${have_libvncserver}" = "xyes"
+then
+
+    have_vnc_tls_locking=yes
+    AC_CHECK_MEMBERS([rfbClient.LockWriteToTLS, rfbClient.UnlockWriteToTLS],
+                     [], [have_vnc_tls_locking=no],
+                     [[#include <rfb/rfbclient.h>]])
+
+    if test "x${have_vnc_tls_locking}" = "xno"
+    then
+        AC_MSG_WARN([
+      --------------------------------------------
+       This version of libvncclient lacks support
+       for TLS locking.  VNC connections that use
+       TLS may experience instability as documented
+       in GUACAMOLE-414])
+    else
+        AC_DEFINE([ENABLE_VNC_TLS_LOCKING],,
+                  [Whether support for TLS locking within VNC is enabled.])
+    fi
+
+fi
+
+#
 # FreeRDP 2 (libfreerdp2, libfreerdp-client2, and libwinpr2)
 #
 
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index bd84f6c..7158a98 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -239,7 +239,7 @@
 
     /* Create terminal */
     kubernetes_client->term = guac_terminal_create(client,
-            kubernetes_client->clipboard,
+            kubernetes_client->clipboard, settings->disable_copy,
             settings->max_scrollback, settings->font_name, settings->font_size,
             settings->resolution, settings->width, settings->height,
             settings->color_scheme, settings->backspace);
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 0ae3dc2..4ed5f51 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -50,6 +50,8 @@
     "read-only",
     "backspace",
     "scrollback",
+    "disable-copy",
+    "disable-paste",
     NULL
 };
 
@@ -216,6 +218,20 @@
      */
     IDX_SCROLLBACK,
 
+    /**
+     * Whether outbound clipboard access should be blocked. If set to "true",
+     * it will not be possible to copy data from the terminal to the client
+     * using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_COPY,
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set to "true", it
+     * will not be possible to paste data from the client to the terminal using
+     * the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_PASTE,
+
     KUBERNETES_ARGS_COUNT
 };
 
@@ -364,6 +380,16 @@
         guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                 IDX_BACKSPACE, 127);
 
+    /* Parse clipboard copy disable flag */
+    settings->disable_copy =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_DISABLE_COPY, false);
+
+    /* Parse clipboard paste disable flag */
+    settings->disable_paste =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_DISABLE_PASTE, false);
+
     /* Parsing was successful */
     return settings;
 
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index 6267a18..eef4973 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -171,6 +171,20 @@
     int resolution;
 
     /**
+     * Whether outbound clipboard access should be blocked. If set, it will not
+     * be possible to copy data from the terminal to the client using the
+     * clipboard.
+     */
+    bool disable_copy;
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set, it will not
+     * be possible to paste data from the client to the terminal using the
+     * clipboard.
+     */
+    bool disable_paste;
+
+    /**
      * The path in which the typescript should be saved, if enabled. If no
      * typescript should be saved, this will be NULL.
      */
diff --git a/src/protocols/kubernetes/user.c b/src/protocols/kubernetes/user.c
index e7f6d8f..d1fcd5d 100644
--- a/src/protocols/kubernetes/user.c
+++ b/src/protocols/kubernetes/user.c
@@ -81,10 +81,13 @@
     /* Only handle events if not read-only */
     if (!settings->read_only) {
 
-        /* General mouse/keyboard/clipboard events */
-        user->key_handler       = guac_kubernetes_user_key_handler;
-        user->mouse_handler     = guac_kubernetes_user_mouse_handler;
-        user->clipboard_handler = guac_kubernetes_clipboard_handler;
+        /* General mouse/keyboard events */
+        user->key_handler = guac_kubernetes_user_key_handler;
+        user->mouse_handler = guac_kubernetes_user_mouse_handler;
+
+        /* Inbound (client to server) clipboard transfer */
+        if (!settings->disable_paste)
+            user->clipboard_handler = guac_kubernetes_clipboard_handler;
 
         /* STDIN redirection */
         user->pipe_handler = guac_kubernetes_pipe_handler;
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index ff2ff8d..7bc7e6e 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -227,8 +227,10 @@
     $(srcdir)/keymaps/en_gb_qwerty.keymap \
     $(srcdir)/keymaps/en_us_qwerty.keymap \
     $(srcdir)/keymaps/es_es_qwerty.keymap \
-    $(srcdir)/keymaps/fr_fr_azerty.keymap \
+    $(srcdir)/keymaps/fr_be_azerty.keymap \
     $(srcdir)/keymaps/fr_ch_qwertz.keymap \
+    $(srcdir)/keymaps/fr_fr_azerty.keymap \
+    $(srcdir)/keymaps/hu_hu_qwertz.keymap \
     $(srcdir)/keymaps/it_it_qwerty.keymap \
     $(srcdir)/keymaps/ja_jp_qwerty.keymap \
     $(srcdir)/keymaps/pt_br_qwerty.keymap \
diff --git a/src/protocols/rdp/fs.c b/src/protocols/rdp/fs.c
index 66bb8e9..5223b5a 100644
--- a/src/protocols/rdp/fs.c
+++ b/src/protocols/rdp/fs.c
@@ -403,7 +403,7 @@
 
 }
 
-int guac_rdp_fs_read(guac_rdp_fs* fs, int file_id, int offset,
+int guac_rdp_fs_read(guac_rdp_fs* fs, int file_id, uint64_t offset,
         void* buffer, int length) {
 
     int bytes_read;
@@ -427,7 +427,7 @@
 
 }
 
-int guac_rdp_fs_write(guac_rdp_fs* fs, int file_id, int offset,
+int guac_rdp_fs_write(guac_rdp_fs* fs, int file_id, uint64_t offset,
         void* buffer, int length) {
 
     int bytes_written;
diff --git a/src/protocols/rdp/fs.h b/src/protocols/rdp/fs.h
index b95af55..83a0b3b 100644
--- a/src/protocols/rdp/fs.h
+++ b/src/protocols/rdp/fs.h
@@ -120,7 +120,7 @@
  * Converts a UNIX timestamp (seconds since Jan 1, 1970 UTC) to Windows
  * timestamp (100 nanosecond intervals since Jan 1, 1601 UTC).
  */
-#define WINDOWS_TIME(t) ((t - ((uint64_t) 11644473600)) * 10000000)
+#define WINDOWS_TIME(t) ((t + ((uint64_t) 11644473600)) * 10000000)
 
 /**
  * An arbitrary file on the virtual filesystem of the Guacamole drive.
@@ -424,7 +424,7 @@
  *     error occurs. All error codes are negative values and correspond to
  *     GUAC_RDP_FS constants, such as GUAC_RDP_FS_ENOENT.
  */
-int guac_rdp_fs_read(guac_rdp_fs* fs, int file_id, int offset,
+int guac_rdp_fs_read(guac_rdp_fs* fs, int file_id, uint64_t offset,
         void* buffer, int length);
 
 /**
@@ -452,7 +452,7 @@
  *     occurs. All error codes are negative values and correspond to
  *     GUAC_RDP_FS constants, such as GUAC_RDP_FS_ENOENT.
  */
-int guac_rdp_fs_write(guac_rdp_fs* fs, int file_id, int offset,
+int guac_rdp_fs_write(guac_rdp_fs* fs, int file_id, uint64_t offset,
         void* buffer, int length);
 
 /**
diff --git a/src/protocols/rdp/keymaps/base.keymap b/src/protocols/rdp/keymaps/base.keymap
index c55a37f..d02c5ea 100644
--- a/src/protocols/rdp/keymaps/base.keymap
+++ b/src/protocols/rdp/keymaps/base.keymap
@@ -42,7 +42,7 @@
 # Locks
 map      0x45 ~ 0xff7f # Num_Lock
 map      0x46 ~ 0xff14 # Scroll_Lock
-map +ext 0x3A ~ 0xffe5 # Caps_Lock
+map      0x3A ~ 0xffe5 # Caps_Lock
 
 # Keypad numerals
 map -shift +num 0x52 ~ 0xffb0 # KP_0
diff --git a/src/protocols/rdp/keymaps/fr_be_azerty.keymap b/src/protocols/rdp/keymaps/fr_be_azerty.keymap
new file mode 100644
index 0000000..cf2def6
--- /dev/null
+++ b/src/protocols/rdp/keymaps/fr_be_azerty.keymap
@@ -0,0 +1,58 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+parent  "base"
+name    "fr-be-azerty"
+freerdp "KBD_BELGIAN_FRENCH"
+
+#
+# Basic keys
+#
+
+map -altgr -shift 0x29 0x02..0x0D      ~ "²&é"'(§è!çà)_"
+map -altgr -shift      0x10..0x19 0x1B ~ "azertyuiop$"
+map -altgr -shift      0x1E..0x28 0x2B ~ "qsdfghjklmùµ"
+map -altgr -shift 0x56 0x2C..0x35      ~ "<wxcvbn,;:="
+
+map -altgr +shift 0x29 0x02..0x0D      ~ "³1234567890°-"
+map -altgr +shift      0x10..0x19 0x1B ~ "AZERTYUIOP£"
+map -altgr +shift      0x1E..0x28 0x2B ~ "QSDFGHJKLM%£"
+map -altgr +shift 0x56 0x2C..0x35      ~ ">WXCVBN?./+"
+
+#
+# Keys requiring AltGr
+#
+
+map +altgr -shift 0x02..0x04 ~ "|@#"
+map +altgr -shift 0x0A..0x0B ~ "{}"
+map +altgr -shift 0x1A..0x1B ~ "[]"
+
+map +altgr -shift 0x12 ~ "€"
+map +altgr -shift 0x56 ~ "\"
+map +altgr -shift 0x07 ~ "^"
+
+#
+# Dead keys
+#
+
+map -altgr -shift 0x1A ~ 0xFE52 # Dead circumflex
+map -altgr +shift 0x1A ~ 0xFE57 # Dead umlaut
+map +altgr -shift 0x35 ~ 0xFE53 # Dead tilde
+map +altgr -shift 0x28 ~ 0xFE51 # Dead acute
+map +altgr -shift 0x2B ~ 0xFE50 # Dead grave
diff --git a/src/protocols/rdp/keymaps/hu_hu_qwertz.keymap b/src/protocols/rdp/keymaps/hu_hu_qwertz.keymap
new file mode 100644
index 0000000..bcb6a67
--- /dev/null
+++ b/src/protocols/rdp/keymaps/hu_hu_qwertz.keymap
@@ -0,0 +1,100 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+parent  "base"
+name    "hu-hu-qwertz"
+freerdp "KBD_HUNGARIAN"
+
+#
+# Basic keys
+#
+
+map -altgr -shift 0x29 0x02..0x0D      ~ "0123456789öüó"
+map -altgr -shift      0x10..0x1B      ~ "qwertzuıopőú"
+map -altgr -shift      0x1E..0x28 0x2B ~ "asdfghjkléáű"
+map -altgr -shift 0x56 0x2C..0x35      ~ "íyxcvbnm,.-"
+
+map -altgr +shift 0x29 0x02..0x0D      ~ "§'"+!%/=()ÖÜÓ"
+map -altgr +shift      0x10..0x1B      ~ "QWERTZUIOPŐÚ"
+map -altgr +shift      0x1E..0x28 0x2B ~ "ASDFGHJKLÉÁŰ"
+map -altgr +shift 0x56 0x2C..0x35      ~ "ÍYXCVBNM?:_"
+
+
+#
+# Keys requiring AltGr
+#
+
+map +altgr -shift 0x02 ~ "~"
+map +altgr -shift 0x08 ~ "`"
+
+map +altgr -shift 0x10 ~ "\"
+map +altgr -shift 0x11 ~ "|"
+map +altgr -shift 0x12 ~ "Ä"
+map +altgr -shift 0x16 ~ "€"
+map +altgr -shift 0x17 ~ "Í"
+map +altgr -shift 0x1A ~ "÷"
+map +altgr -shift 0x1B ~ "×"
+
+map +altgr -shift 0x1E ~ "ä"
+map +altgr -shift 0x1F ~ "đ"
+map +altgr -shift 0x20 ~ "Đ"
+map +altgr -shift 0x21 ~ "["
+map +altgr -shift 0x22 ~ "]"
+map +altgr -shift 0x24 ~ "í"
+map +altgr -shift 0x25 ~ "ł"
+map +altgr -shift 0x26 ~ "Ł"
+map +altgr -shift 0x27 ~ "$"
+map +altgr -shift 0x28 ~ "ß"
+map +altgr -shift 0x2B ~ "¤"
+
+map +altgr -shift 0x56 ~ "<"
+map +altgr -shift 0x2C ~ ">"
+map +altgr -shift 0x2D ~ "#"
+map +altgr -shift 0x2E ~ "&"
+map +altgr -shift 0x2F ~ "@"
+map +altgr -shift 0x30 ~ "{"
+map +altgr -shift 0x31 ~ "}"
+map +altgr -shift 0x32 ~ "<"
+map +altgr -shift 0x33 ~ ";"
+map +altgr -shift 0x34 ~ ">"
+map +altgr -shift 0x35 ~ "*"
+
+
+#
+# Keys requiring AltGr & Shift
+#
+
+
+#
+# Dead keys
+#
+
+map +altgr -shift 0x03 ~ 0xFE5A # Dead caron
+map +altgr -shift 0x04 ~ 0xFE52 # Dead circumflex
+map +altgr -shift 0x05 ~ 0xFE55 # Dead breve
+map +altgr -shift 0x06 ~ 0xFE58 # Dead abovering
+map +altgr -shift 0x07 ~ 0xFE5C # Dead ogonek
+map +altgr -shift 0x09 ~ 0xFE56 # Dead abovedot
+map +altgr -shift 0x0A ~ 0xFE51 # Dead acute
+map +altgr -shift 0x0B ~ 0xFE59 # Dead doubleacute
+map +altgr -shift 0x0C ~ 0xFE57 # Dead diaeresis
+map +altgr -shift 0x0D ~ 0xFE5B # Dead cedilla
+
+
+# END
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index 7e6b3e8..8330c7e 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -100,8 +100,9 @@
         guac_rdp_audio_load_plugin(instance->context);
     }
 
-    /* Load "cliprdr" plugin for clipboard support */
-    guac_rdp_clipboard_load_plugin(rdp_client->clipboard, context);
+    /* Load "cliprdr" service if not disabled */
+    if (!(settings->disable_copy && settings->disable_paste))
+        guac_rdp_clipboard_load_plugin(rdp_client->clipboard, context);
 
     /* If RDPSND/RDPDR required, load them */
     if (settings->printing_enabled
diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c
index bac74ff..fe2cf67 100644
--- a/src/protocols/rdp/settings.c
+++ b/src/protocols/rdp/settings.c
@@ -111,6 +111,8 @@
 
     "load-balance-info",
 
+    "disable-copy",
+    "disable-paste",
     NULL
 };
 
@@ -535,6 +537,20 @@
      */
     IDX_LOAD_BALANCE_INFO,
 
+    /**
+     * Whether outbound clipboard access should be blocked. If set to "true",
+     * it will not be possible to copy data from the remote desktop to the
+     * client using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_COPY,
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set to "true", it
+     * will not be possible to paste data from the client to the remote desktop
+     * using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_PASTE,
+
     RDP_ARGS_COUNT
 };
 
@@ -997,6 +1013,16 @@
         guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                 IDX_LOAD_BALANCE_INFO, NULL);
 
+    /* Parse clipboard copy disable flag */
+    settings->disable_copy =
+        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
+                IDX_DISABLE_COPY, 0);
+
+    /* Parse clipboard paste disable flag */
+    settings->disable_paste =
+        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
+                IDX_DISABLE_PASTE, 0);
+
     /* Success */
     return settings;
 
diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h
index 2e0dd3b..e4c579e 100644
--- a/src/protocols/rdp/settings.h
+++ b/src/protocols/rdp/settings.h
@@ -284,6 +284,20 @@
     char** svc_names;
 
     /**
+     * Whether outbound clipboard access should be blocked. If set, it will not
+     * be possible to copy data from the remote desktop to the client using the
+     * clipboard.
+     */
+    int disable_copy;
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set, it will not
+     * be possible to paste data from the client to the remote desktop using
+     * the clipboard.
+     */
+    int disable_paste;
+
+    /**
      * Whether the desktop wallpaper should be visible. If unset, the desktop
      * wallpaper will be hidden, reducing the amount of bandwidth required.
      */
diff --git a/src/protocols/rdp/user.c b/src/protocols/rdp/user.c
index 38f2623..c2b487f 100644
--- a/src/protocols/rdp/user.c
+++ b/src/protocols/rdp/user.c
@@ -100,10 +100,13 @@
     /* Only handle events if not read-only */
     if (!settings->read_only) {
 
-        /* General mouse/keyboard/clipboard events */
-        user->mouse_handler     = guac_rdp_user_mouse_handler;
-        user->key_handler       = guac_rdp_user_key_handler;
-        user->clipboard_handler = guac_rdp_clipboard_handler;
+        /* General mouse/keyboard events */
+        user->mouse_handler = guac_rdp_user_mouse_handler;
+        user->key_handler = guac_rdp_user_key_handler;
+
+        /* Inbound (client to server) clipboard transfer */
+        if (!settings->disable_paste)
+            user->clipboard_handler = guac_rdp_clipboard_handler;
 
         /* Display size change events */
         user->size_handler = guac_rdp_user_size_handler;
diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c
index a0af9f9..7dab321 100644
--- a/src/protocols/ssh/settings.c
+++ b/src/protocols/ssh/settings.c
@@ -62,6 +62,8 @@
     "scrollback",
     "locale",
     "timezone",
+    "disable-copy",
+    "disable-paste",
     NULL
 };
 
@@ -258,6 +260,20 @@
      */
     IDX_TIMEZONE,
 
+    /**
+     * Whether outbound clipboard access should be blocked. If set to "true",
+     * it will not be possible to copy data from the terminal to the client
+     * using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_COPY,
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set to "true", it
+     * will not be possible to paste data from the client to the terminal using
+     * the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_PASTE,
+
     SSH_ARGS_COUNT
 };
 
@@ -426,6 +442,16 @@
         guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                 IDX_TIMEZONE, user->info.timezone);
 
+    /* Parse clipboard copy disable flag */
+    settings->disable_copy =
+        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
+                IDX_DISABLE_COPY, false);
+
+    /* Parse clipboard paste disable flag */
+    settings->disable_paste =
+        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
+                IDX_DISABLE_PASTE, false);
+
     /* Parsing was successful */
     return settings;
 
diff --git a/src/protocols/ssh/settings.h b/src/protocols/ssh/settings.h
index baa634a..bab21bd 100644
--- a/src/protocols/ssh/settings.h
+++ b/src/protocols/ssh/settings.h
@@ -156,6 +156,20 @@
     int resolution;
 
     /**
+     * Whether outbound clipboard access should be blocked. If set, it will not
+     * be possible to copy data from the terminal to the client using the
+     * clipboard.
+     */
+    bool disable_copy;
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set, it will not
+     * be possible to paste data from the client to the terminal using the
+     * clipboard.
+     */
+    bool disable_paste;
+
+    /**
      * Whether SFTP is enabled.
      */
     bool enable_sftp;
diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c
index 456c214..8957205 100644
--- a/src/protocols/ssh/ssh.c
+++ b/src/protocols/ssh/ssh.c
@@ -223,9 +223,10 @@
 
     /* Create terminal */
     ssh_client->term = guac_terminal_create(client, ssh_client->clipboard,
-            settings->max_scrollback, settings->font_name, settings->font_size,
-            settings->resolution, settings->width, settings->height,
-            settings->color_scheme, settings->backspace);
+            settings->disable_copy, settings->max_scrollback,
+            settings->font_name, settings->font_size, settings->resolution,
+            settings->width, settings->height, settings->color_scheme,
+            settings->backspace);
 
     /* Fail if terminal init failed */
     if (ssh_client->term == NULL) {
diff --git a/src/protocols/ssh/user.c b/src/protocols/ssh/user.c
index ccf2447..8ea30a4 100644
--- a/src/protocols/ssh/user.c
+++ b/src/protocols/ssh/user.c
@@ -81,10 +81,13 @@
     /* Only handle events if not read-only */
     if (!settings->read_only) {
 
-        /* General mouse/keyboard/clipboard events */
-        user->key_handler       = guac_ssh_user_key_handler;
-        user->mouse_handler     = guac_ssh_user_mouse_handler;
-        user->clipboard_handler = guac_ssh_clipboard_handler;
+        /* General mouse/keyboard events */
+        user->key_handler = guac_ssh_user_key_handler;
+        user->mouse_handler = guac_ssh_user_mouse_handler;
+
+        /* Inbound (client to server) clipboard transfer */
+        if (!settings->disable_paste)
+            user->clipboard_handler = guac_ssh_clipboard_handler;
 
         /* STDIN redirection */
         user->pipe_handler = guac_ssh_pipe_handler;
diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c
index 85b4fb8..e72359c 100644
--- a/src/protocols/telnet/settings.c
+++ b/src/protocols/telnet/settings.c
@@ -55,6 +55,8 @@
     "scrollback",
     "login-success-regex",
     "login-failure-regex",
+    "disable-copy",
+    "disable-paste",
     NULL
 };
 
@@ -216,6 +218,20 @@
      */
     IDX_LOGIN_FAILURE_REGEX,
 
+    /**
+     * Whether outbound clipboard access should be blocked. If set to "true",
+     * it will not be possible to copy data from the terminal to the client
+     * using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_COPY,
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set to "true", it
+     * will not be possible to paste data from the client to the terminal using
+     * the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_PASTE,
+
     TELNET_ARGS_COUNT
 };
 
@@ -428,6 +444,16 @@
         guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv,
                 IDX_TERMINAL_TYPE, "linux");
 
+    /* Parse clipboard copy disable flag */
+    settings->disable_copy =
+        guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv,
+                IDX_DISABLE_COPY, false);
+
+    /* Parse clipboard paste disable flag */
+    settings->disable_paste =
+        guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv,
+                IDX_DISABLE_PASTE, false);
+
     /* Parsing was successful */
     return settings;
 
diff --git a/src/protocols/telnet/settings.h b/src/protocols/telnet/settings.h
index 86302b7..691669c 100644
--- a/src/protocols/telnet/settings.h
+++ b/src/protocols/telnet/settings.h
@@ -172,6 +172,20 @@
     int resolution;
 
     /**
+     * Whether outbound clipboard access should be blocked. If set, it will not
+     * be possible to copy data from the terminal to the client using the
+     * clipboard.
+     */
+    bool disable_copy;
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set, it will not
+     * be possible to paste data from the client to the terminal using the
+     * clipboard.
+     */
+    bool disable_paste;
+
+    /**
      * The path in which the typescript should be saved, if enabled. If no
      * typescript should be saved, this will be NULL.
      */
diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c
index e100fae..5a5ca30 100644
--- a/src/protocols/telnet/telnet.c
+++ b/src/protocols/telnet/telnet.c
@@ -570,7 +570,7 @@
 
     /* Create terminal */
     telnet_client->term = guac_terminal_create(client,
-            telnet_client->clipboard,
+            telnet_client->clipboard, settings->disable_copy,
             settings->max_scrollback, settings->font_name, settings->font_size,
             settings->resolution, settings->width, settings->height,
             settings->color_scheme, settings->backspace);
diff --git a/src/protocols/telnet/user.c b/src/protocols/telnet/user.c
index 08cfc6f..63408cc 100644
--- a/src/protocols/telnet/user.c
+++ b/src/protocols/telnet/user.c
@@ -80,10 +80,13 @@
     /* Only handle events if not read-only */
     if (!settings->read_only) {
 
-        /* General mouse/keyboard/clipboard events */
-        user->key_handler       = guac_telnet_user_key_handler;
-        user->mouse_handler     = guac_telnet_user_mouse_handler;
-        user->clipboard_handler = guac_telnet_clipboard_handler;
+        /* General mouse/keyboard events */
+        user->key_handler = guac_telnet_user_key_handler;
+        user->mouse_handler = guac_telnet_user_mouse_handler;
+
+        /* Inbound (client to server) clipboard transfer */
+        if (!settings->disable_paste)
+            user->clipboard_handler = guac_telnet_clipboard_handler;
 
         /* STDIN redirection */
         user->pipe_handler = guac_telnet_pipe_handler;
diff --git a/src/protocols/vnc/auth.c b/src/protocols/vnc/auth.c
index e93dbc6..8cc6b1d 100644
--- a/src/protocols/vnc/auth.c
+++ b/src/protocols/vnc/auth.c
@@ -31,3 +31,22 @@
     return ((guac_vnc_client*) gc->data)->settings->password;
 }
 
+rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType) {
+    guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
+    guac_vnc_settings* settings = ((guac_vnc_client*) gc->data)->settings;
+    
+    if (credentialType == rfbCredentialTypeUser) {
+        rfbCredential *creds = malloc(sizeof(rfbCredential));
+        creds->userCredential.username = settings->username;
+        creds->userCredential.password = settings->password;
+        return creds;
+    }
+
+    guac_client_abort(gc, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+            "Unsupported credential type requested.");
+    guac_client_log(gc, GUAC_LOG_DEBUG,
+            "Unable to provide requested type of credential: %d.",
+            credentialType);
+    return NULL;
+    
+}
diff --git a/src/protocols/vnc/auth.h b/src/protocols/vnc/auth.h
index 615d80a..155a48d 100644
--- a/src/protocols/vnc/auth.h
+++ b/src/protocols/vnc/auth.h
@@ -27,7 +27,7 @@
 
 /**
  * Callback which is invoked by libVNCServer when it needs to read the user's
- * VNC password. As ths user's password, if any, will be stored in the
+ * VNC password. As this user's password, if any, will be stored in the
  * connection settings, this function does nothing more than return that value.
  *
  * @param client
@@ -38,5 +38,23 @@
  */
 char* guac_vnc_get_password(rfbClient* client);
 
+/**
+ * Callback which is invoked by libVNCServer when it needs to read the user's
+ * VNC credentials.  The credentials are stored in the connection settings,
+ * so they will be retrieved from that.
+ * 
+ * @param client
+ *     The rfbClient associated with the VNC connection requiring the
+ *     authentication.
+ * 
+ * @param credentialType
+ *     The credential type being requested, as defined by the libVNCclient
+ *     code in the rfbclient.h header.
+ * 
+ * @return
+ *     The rfbCredential object that contains the required credentials.
+ */
+rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType);
+
 #endif
 
diff --git a/src/protocols/vnc/client.c b/src/protocols/vnc/client.c
index 9cc85a1..cee1d4d 100644
--- a/src/protocols/vnc/client.c
+++ b/src/protocols/vnc/client.c
@@ -36,6 +36,7 @@
 
 #include <guacamole/client.h>
 
+#include <pthread.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -48,6 +49,11 @@
     guac_vnc_client* vnc_client = calloc(1, sizeof(guac_vnc_client));
     client->data = vnc_client;
 
+#ifdef ENABLE_VNC_TLS_LOCKING
+    /* Initialize the write lock */
+    pthread_mutex_init(&(vnc_client->tls_lock), NULL);
+#endif
+
     /* Init clipboard */
     vnc_client->clipboard = guac_common_clipboard_alloc(GUAC_VNC_CLIPBOARD_MAX_LENGTH);
 
@@ -125,6 +131,11 @@
     if (settings != NULL)
         guac_vnc_settings_free(settings);
 
+#ifdef ENABLE_VNC_TLS_LOCKING
+    /* Clean up TLS lock mutex. */
+    pthread_mutex_destroy(&(vnc_client->tls_lock));
+#endif
+
     /* Free generic data struct */
     free(client->data);
 
diff --git a/src/protocols/vnc/clipboard.c b/src/protocols/vnc/clipboard.c
index a49f565..c3b1bd1 100644
--- a/src/protocols/vnc/clipboard.c
+++ b/src/protocols/vnc/clipboard.c
@@ -125,6 +125,10 @@
     guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
     guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;
 
+    /* Ignore received text if outbound clipboard transfer is disabled */
+    if (vnc_client->settings->disable_copy)
+        return;
+
     char received_data[GUAC_VNC_CLIPBOARD_MAX_LENGTH];
 
     const char* input = text;
diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c
index 623e668..21f6405 100644
--- a/src/protocols/vnc/settings.c
+++ b/src/protocols/vnc/settings.c
@@ -35,6 +35,7 @@
     "port",
     "read-only",
     "encodings",
+    "username",
     "password",
     "swap-red-blue",
     "color-depth",
@@ -77,7 +78,8 @@
     "recording-exclude-mouse",
     "recording-include-keys",
     "create-recording-path",
-
+    "disable-copy",
+    "disable-paste",
     NULL
 };
 
@@ -108,6 +110,11 @@
     IDX_ENCODINGS,
 
     /**
+     * The username to send to the VNC server if authentication is requested.
+     */
+    IDX_USERNAME,
+    
+    /**
      * The password to send to the VNC server if authentication is requested.
      */
     IDX_PASSWORD,
@@ -298,6 +305,20 @@
      */
     IDX_CREATE_RECORDING_PATH,
 
+    /**
+     * Whether outbound clipboard access should be blocked. If set to "true",
+     * it will not be possible to copy data from the remote desktop to the
+     * client using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_COPY,
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set to "true", it
+     * will not be possible to paste data from the client to the remote desktop
+     * using the clipboard. By default, clipboard access is not blocked.
+     */
+    IDX_DISABLE_PASTE,
+
     VNC_ARGS_COUNT
 };
 
@@ -322,10 +343,14 @@
         guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
                 IDX_PORT, 0);
 
+    settings->username =
+        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
+                IDX_USERNAME, ""); /* NOTE: freed by libvncclient */
+    
     settings->password =
         guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                 IDX_PASSWORD, ""); /* NOTE: freed by libvncclient */
-
+    
     /* Remote cursor */
     if (strcmp(argv[IDX_CURSOR], "remote") == 0) {
         guac_user_log(user, GUAC_LOG_INFO, "Cursor rendering: remote");
@@ -493,6 +518,16 @@
         guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
                 IDX_CREATE_RECORDING_PATH, false);
 
+    /* Parse clipboard copy disable flag */
+    settings->disable_copy =
+        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
+                IDX_DISABLE_COPY, false);
+
+    /* Parse clipboard paste disable flag */
+    settings->disable_paste =
+        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
+                IDX_DISABLE_PASTE, false);
+
     return settings;
 
 }
diff --git a/src/protocols/vnc/settings.h b/src/protocols/vnc/settings.h
index 3e2ebd5..34c08ec 100644
--- a/src/protocols/vnc/settings.h
+++ b/src/protocols/vnc/settings.h
@@ -46,6 +46,11 @@
     int port;
 
     /**
+     * The username given in the arguments.
+     */
+    char* username;
+    
+    /**
      * The password given in the arguments.
      */
     char* password;
@@ -127,6 +132,20 @@
      */
     char* clipboard_encoding;
 
+    /**
+     * Whether outbound clipboard access should be blocked. If set, it will not
+     * be possible to copy data from the remote desktop to the client using the
+     * clipboard.
+     */
+    bool disable_copy;
+
+    /**
+     * Whether inbound clipboard access should be blocked. If set, it will not
+     * be possible to paste data from the client to the remote desktop using
+     * the clipboard.
+     */
+    bool disable_paste;
+
 #ifdef ENABLE_COMMON_SSH
     /**
      * Whether SFTP should be enabled for the VNC connection.
diff --git a/src/protocols/vnc/user.c b/src/protocols/vnc/user.c
index da3b843..0dee504 100644
--- a/src/protocols/vnc/user.c
+++ b/src/protocols/vnc/user.c
@@ -91,10 +91,13 @@
     /* Only handle events if not read-only */
     if (!settings->read_only) {
 
-        /* General mouse/keyboard/clipboard events */
-        user->mouse_handler     = guac_vnc_user_mouse_handler;
-        user->key_handler       = guac_vnc_user_key_handler;
-        user->clipboard_handler = guac_vnc_clipboard_handler;
+        /* General mouse/keyboard events */
+        user->mouse_handler = guac_vnc_user_mouse_handler;
+        user->key_handler = guac_vnc_user_key_handler;
+
+        /* Inbound (client to server) clipboard transfer */
+        if (!settings->disable_paste)
+            user->clipboard_handler = guac_vnc_clipboard_handler;
 
 #ifdef ENABLE_COMMON_SSH
         /* Set generic (non-filesystem) file upload handler */
diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c
index afffaac..f33b267 100644
--- a/src/protocols/vnc/vnc.c
+++ b/src/protocols/vnc/vnc.c
@@ -55,6 +55,66 @@
 
 char* GUAC_VNC_CLIENT_KEY = "GUAC_VNC";
 
+#ifdef ENABLE_VNC_TLS_LOCKING
+/**
+ * A callback function that is called by the VNC library prior to writing
+ * data to a TLS-encrypted socket.  This returns the rfbBool FALSE value
+ * if there's an error locking the mutex, or rfbBool TRUE otherwise.
+ * 
+ * @param rfb_client
+ *     The rfbClient for which to lock the TLS mutex.
+ *
+ * @returns
+ *     rfbBool FALSE if an error occurs locking the mutex, otherwise
+ *     TRUE.
+ */
+static rfbBool guac_vnc_lock_write_to_tls(rfbClient* rfb_client) {
+
+    /* Retrieve the Guacamole data structures */
+    guac_client* gc = rfbClientGetClientData(rfb_client, GUAC_VNC_CLIENT_KEY);
+    guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;
+
+    /* Lock write access */
+    int retval = pthread_mutex_lock(&(vnc_client->tls_lock));
+    if (retval) {
+        guac_client_log(gc, GUAC_LOG_ERROR, "Error locking TLS write mutex: %s",
+                strerror(retval));
+        return FALSE;
+    }
+    return TRUE;
+
+}
+
+/**
+ * A callback function for use by the VNC library that is called once
+ * the client is finished writing to a TLS-encrypted socket. A rfbBool
+ * FALSE value is returned if an error occurs unlocking the mutex,
+ * otherwise TRUE is returned.
+ *
+ * @param rfb_client
+ *     The rfbClient for which to unlock the TLS mutex.
+ *
+ * @returns
+ *     rfbBool FALSE if an error occurs unlocking the mutex, otherwise
+ *     TRUE.
+ */
+static rfbBool guac_vnc_unlock_write_to_tls(rfbClient* rfb_client) {
+
+    /* Retrieve the Guacamole data structures */
+    guac_client* gc = rfbClientGetClientData(rfb_client, GUAC_VNC_CLIENT_KEY);
+    guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;
+
+    /* Unlock write access */
+    int retval = pthread_mutex_unlock(&(vnc_client->tls_lock));
+    if (retval) {
+        guac_client_log(gc, GUAC_LOG_ERROR, "Error unlocking TLS write mutex: %s",
+                strerror(retval));
+        return FALSE;
+    }
+    return TRUE;
+}
+#endif
+
 rfbClient* guac_vnc_get_client(guac_client* client) {
 
     rfbClient* rfb_client = rfbGetClient(8, 3, 4); /* 32-bpp client */
@@ -68,6 +128,12 @@
     rfb_client->GotFrameBufferUpdate = guac_vnc_update;
     rfb_client->GotCopyRect = guac_vnc_copyrect;
 
+#ifdef ENABLE_VNC_TLS_LOCKING
+    /* TLS Locking and Unlocking */
+    rfb_client->LockWriteToTLS = guac_vnc_lock_write_to_tls;
+    rfb_client->UnlockWriteToTLS = guac_vnc_unlock_write_to_tls;
+#endif
+
     /* Do not handle clipboard and local cursor if read-only */
     if (vnc_settings->read_only == 0) {
 
@@ -87,6 +153,9 @@
 
     }
 
+    /* Authentication */
+    rfb_client->GetCredential = guac_vnc_get_credentials;
+    
     /* Password */
     rfb_client->GetPassword = guac_vnc_get_password;
 
@@ -403,4 +472,3 @@
     return NULL;
 
 }
-
diff --git a/src/protocols/vnc/vnc.h b/src/protocols/vnc/vnc.h
index ce2d20a..7c189cf 100644
--- a/src/protocols/vnc/vnc.h
+++ b/src/protocols/vnc/vnc.h
@@ -55,6 +55,13 @@
      */
     pthread_t client_thread;
 
+#ifdef ENABLE_VNC_TLS_LOCKING
+    /**
+     * The TLS mutex lock for the client.
+     */
+    pthread_mutex_t tls_lock;
+#endif
+
     /**
      * The underlying VNC client.
      */
diff --git a/src/terminal/select.c b/src/terminal/select.c
index 20fc3cd..0a075eb 100644
--- a/src/terminal/select.c
+++ b/src/terminal/select.c
@@ -375,8 +375,10 @@
     }
 
     /* Send data */
-    guac_common_clipboard_send(terminal->clipboard, client);
-    guac_socket_flush(socket);
+    if (!terminal->disable_copy) {
+        guac_common_clipboard_send(terminal->clipboard, client);
+        guac_socket_flush(socket);
+    }
 
     guac_terminal_notify(terminal);
 
diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index 05bf720..1430b05 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -202,6 +202,7 @@
     /* Reset cursor location */
     term->cursor_row = term->visible_cursor_row = term->saved_cursor_row = 0;
     term->cursor_col = term->visible_cursor_col = term->saved_cursor_col = 0;
+    term->cursor_visible = true;
 
     /* Clear scrollback, buffer, and scroll region */
     term->buffer->top = 0;
@@ -306,8 +307,8 @@
 }
 
 guac_terminal* guac_terminal_create(guac_client* client,
-        guac_common_clipboard* clipboard, int max_scrollback,
-        const char* font_name, int font_size, int dpi,
+        guac_common_clipboard* clipboard, bool disable_copy,
+        int max_scrollback, const char* font_name, int font_size, int dpi,
         int width, int height, const char* color_scheme,
         const int backspace) {
 
@@ -392,6 +393,7 @@
     term->current_attributes = default_char.attributes;
     term->default_char = default_char;
     term->clipboard = clipboard;
+    term->disable_copy = disable_copy;
 
     /* Calculate character size */
     int rows    = height / term->display->char_height;
@@ -776,31 +778,42 @@
 
     guac_terminal_char* guac_char;
 
-    guac_terminal_buffer_row* old_row;
-    guac_terminal_buffer_row* new_row;
+    guac_terminal_buffer_row* row;
 
     /* If no change, done */
-    if (term->visible_cursor_row == term->cursor_row && term->visible_cursor_col == term->cursor_col)
+    if (term->cursor_visible && term->visible_cursor_row == term->cursor_row && term->visible_cursor_col == term->cursor_col)
         return;
 
-    /* Get old and new rows with cursor */
-    new_row = guac_terminal_buffer_get_row(term->buffer, term->cursor_row, term->cursor_col+1);
-    old_row = guac_terminal_buffer_get_row(term->buffer, term->visible_cursor_row, term->visible_cursor_col+1);
+    /* Clear cursor if it was visible */
+    if (term->visible_cursor_row != -1 && term->visible_cursor_col != -1) {
+        /* Get old row with cursor */
+        row = guac_terminal_buffer_get_row(term->buffer, term->visible_cursor_row, term->visible_cursor_col+1);
 
-    /* Clear cursor */
-    guac_char = &(old_row->characters[term->visible_cursor_col]);
-    guac_char->attributes.cursor = false;
-    guac_terminal_display_set_columns(term->display, term->visible_cursor_row + term->scroll_offset,
-            term->visible_cursor_col, term->visible_cursor_col, guac_char);
+        guac_char = &(row->characters[term->visible_cursor_col]);
+        guac_char->attributes.cursor = false;
+        guac_terminal_display_set_columns(term->display, term->visible_cursor_row + term->scroll_offset,
+                term->visible_cursor_col, term->visible_cursor_col, guac_char);
+    }
 
-    /* Set cursor */
-    guac_char = &(new_row->characters[term->cursor_col]);
-    guac_char->attributes.cursor = true;
-    guac_terminal_display_set_columns(term->display, term->cursor_row + term->scroll_offset,
-            term->cursor_col, term->cursor_col, guac_char);
+    /* Set cursor if should be visible */
+    if (term->cursor_visible) {
+        /* Get new row with cursor */
+        row = guac_terminal_buffer_get_row(term->buffer, term->cursor_row, term->cursor_col+1);
 
-    term->visible_cursor_row = term->cursor_row;
-    term->visible_cursor_col = term->cursor_col;
+        guac_char = &(row->characters[term->cursor_col]);
+        guac_char->attributes.cursor = true;
+        guac_terminal_display_set_columns(term->display, term->cursor_row + term->scroll_offset,
+                term->cursor_col, term->cursor_col, guac_char);
+
+        term->visible_cursor_row = term->cursor_row;
+        term->visible_cursor_col = term->cursor_col;
+    }
+
+    /* Otherwise set visible position to a sentinel value */
+    else {
+        term->visible_cursor_row = -1;
+        term->visible_cursor_col = -1;
+    }
 
     return;
 
@@ -1239,7 +1252,8 @@
             /* Update buffer top and cursor row based on shift */
             term->buffer->top += shift_amount;
             term->cursor_row  -= shift_amount;
-            term->visible_cursor_row  -= shift_amount;
+            if (term->visible_cursor_row != -1)
+                term->visible_cursor_row -= shift_amount;
 
             /* Redraw characters within old region */
             __guac_terminal_redraw_rect(term, height - shift_amount, 0, height-1, width-1);
@@ -1273,7 +1287,8 @@
             /* Update buffer top and cursor row based on shift */
             term->buffer->top -= shift_amount;
             term->cursor_row  += shift_amount;
-            term->visible_cursor_row  += shift_amount;
+            if (term->visible_cursor_row != -1)
+                term->visible_cursor_row += shift_amount;
 
             /* If scrolled enough, use scroll to fulfill entire resize */
             if (term->scroll_offset >= shift_amount) {
diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h
index e7746cb..2d61959 100644
--- a/src/terminal/terminal/terminal.h
+++ b/src/terminal/terminal/terminal.h
@@ -338,12 +338,19 @@
     int cursor_col;
 
     /**
+     * The desired visibility state of the cursor.
+     */
+    bool cursor_visible;
+
+    /**
      * The row of the rendered cursor.
+     * Will be set to -1 if the cursor is not visible.
      */
     int visible_cursor_row;
 
     /**
      * The column of the rendered cursor.
+     * Will be set to -1 if the cursor is not visible.
      */
     int visible_cursor_col;
 
@@ -530,6 +537,14 @@
      */
     char backspace;
 
+    /**
+     * Whether copying from the terminal clipboard should be blocked. If set,
+     * the contents of the terminal can still be copied, but will be usable
+     * only within the terminal itself. The clipboard contents will not be
+     * automatically streamed to the client.
+     */
+    bool disable_copy;
+
 };
 
 /**
@@ -552,6 +567,12 @@
  *     clipboard instructions. This clipboard will not be automatically
  *     freed when this terminal is freed.
  *
+ * @param disable_copy
+ *     Whether copying from the terminal clipboard should be blocked. If set,
+ *     the contents of the terminal can still be copied, but will be usable
+ *     only within the terminal itself. The clipboard contents will not be
+ *     automatically streamed to the client.
+ *
  * @param max_scrollback
  *     The maximum number of rows to allow within the scrollback buffer. The
  *     user may still alter the size of the scrollback buffer using terminal
@@ -591,8 +612,8 @@
  *     which renders all text to the given client.
  */
 guac_terminal* guac_terminal_create(guac_client* client,
-        guac_common_clipboard* clipboard, int max_scrollback,
-        const char* font_name, int font_size, int dpi,
+        guac_common_clipboard* clipboard, bool disable_copy,
+        int max_scrollback, const char* font_name, int font_size, int dpi,
         int width, int height, const char* color_scheme,
         const int backspace);
 
diff --git a/src/terminal/terminal_handlers.c b/src/terminal/terminal_handlers.c
index ec258ff..d406c48 100644
--- a/src/terminal/terminal_handlers.c
+++ b/src/terminal/terminal_handlers.c
@@ -432,6 +432,7 @@
     if (private_mode == '?') {
         switch (num) {
             case 1:  return &(term->application_cursor_keys); /* DECCKM */
+            case 25: return &(term->cursor_visible); /* DECTECM */
         }
     }