Merge staging/1.2.0 changes back to master.
diff --git a/src/common-ssh/sftp.c b/src/common-ssh/sftp.c
index e12fbf5..0100cc1 100644
--- a/src/common-ssh/sftp.c
+++ b/src/common-ssh/sftp.c
@@ -376,6 +376,18 @@
     char fullpath[GUAC_COMMON_SSH_SFTP_MAX_PATH];
     LIBSSH2_SFTP_HANDLE* file;
 
+    /* Ignore upload if uploads have been disabled */
+    if (filesystem->disable_upload) {
+        guac_user_log(user, GUAC_LOG_WARNING, "A upload attempt has "
+                "been blocked due to uploads being disabled, however it "
+                "should have been blocked at a higher level. This is likely "
+                "a bug.");
+        guac_protocol_send_ack(user->socket, stream, "SFTP: Upload disabled",
+                GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
+        guac_socket_flush(user->socket);
+        return 0;
+    }
+
     /* Concatenate filename with path */
     if (!guac_ssh_append_filename(fullpath, filesystem->upload_path,
                 filename)) {
@@ -516,6 +528,15 @@
     guac_stream* stream;
     LIBSSH2_SFTP_HANDLE* file;
 
+    /* Ignore download if downloads have been disabled */
+    if (filesystem->disable_download) {
+        guac_user_log(user, GUAC_LOG_WARNING, "A download attempt has "
+                "been blocked due to downloads being disabled, however it "
+                "should have been blocked at a higher level. This is likely "
+                "a bug.");
+        return NULL;
+    }
+
     /* Attempt to open file for reading */
     file = libssh2_sftp_open(filesystem->sftp_session, filename,
             LIBSSH2_FXF_READ, 0);
@@ -850,6 +871,18 @@
     guac_common_ssh_sftp_filesystem* filesystem =
         (guac_common_ssh_sftp_filesystem*) object->data;
 
+    /* Ignore upload if uploads have been disabled */
+    if (filesystem->disable_upload) {
+        guac_user_log(user, GUAC_LOG_WARNING, "A upload attempt has "
+                "been blocked due to uploads being disabled, however it "
+                "should have been blocked at a higher level. This is likely "
+                "a bug.");
+        guac_protocol_send_ack(user->socket, stream, "SFTP: Upload disabled",
+                GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
+        guac_socket_flush(user->socket);
+        return 0;
+    }
+
     LIBSSH2_SFTP* sftp = filesystem->sftp_session;
 
     /* Translate stream name into filesystem path */
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c
index 1ea6701..16a6cfb 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c
@@ -166,7 +166,8 @@
             destination_path);
 
     /* If file moving to \Download folder, start stream, do not move */
-    if (strncmp(destination_path, "\\Download\\", 10) == 0) {
+    if (strncmp(destination_path, "\\Download\\", 10) == 0
+			&& !((guac_rdp_fs*) device->data)->disable_download) {
 
         guac_rdp_fs_file* file;
 
diff --git a/src/protocols/rdp/download.c b/src/protocols/rdp/download.c
index 34a8c8a..d70b8e1 100644
--- a/src/protocols/rdp/download.c
+++ b/src/protocols/rdp/download.c
@@ -148,8 +148,8 @@
 
     }
 
-    /* Otherwise, send file contents */
-    else {
+    /* Otherwise, send file contents if downloads are allowed */
+    else if (!fs->disable_download) {
 
         /* Create stream data */
         guac_rdp_download_status* download_status = malloc(sizeof(guac_rdp_download_status));
@@ -167,6 +167,10 @@
 
     }
 
+    else
+        guac_client_log(client, GUAC_LOG_INFO, "Unable to download file "
+                "\"%s\", file downloads have been disabled.", name);
+
     guac_socket_flush(user->socket);
     return 0;
 }
@@ -185,6 +189,15 @@
     if (filesystem == NULL)
         return NULL;
 
+    /* Ignore download if downloads have been disabled */
+    if (filesystem->disable_download) {
+        guac_client_log(client, GUAC_LOG_WARNING, "A download attempt has "
+                "been blocked due to downloads being disabled, however it "
+                "should have been blocked at a higher level. This is likely "
+                "a bug.");
+        return NULL;
+    }
+
     /* Attempt to open requested file */
     char* path = (char*) data;
     int file_id = guac_rdp_fs_open(filesystem, path,
diff --git a/src/protocols/rdp/upload.c b/src/protocols/rdp/upload.c
index 5317edb..2b08b2f 100644
--- a/src/protocols/rdp/upload.c
+++ b/src/protocols/rdp/upload.c
@@ -87,6 +87,18 @@
         return 0;
     }
 
+    /* Ignore upload if uploads have been disabled */
+    if (fs->disable_upload) {
+        guac_client_log(client, GUAC_LOG_WARNING, "A upload attempt has "
+                "been blocked due to uploads being disabled, however it "
+                "should have been blocked at a higher level. This is likely "
+                "a bug.");
+        guac_protocol_send_ack(user->socket, stream, "FAIL (UPLOAD DISABLED)",
+                GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
+        guac_socket_flush(user->socket);
+        return 0;
+    }
+
     /* Translate name */
     __generate_upload_path(filename, file_path);
 
@@ -205,6 +217,18 @@
         return 0;
     }
 
+    /* Ignore upload if uploads have been disabled */
+    if (fs->disable_upload) {
+        guac_client_log(client, GUAC_LOG_WARNING, "A upload attempt has "
+                "been blocked due to uploads being disabled, however it "
+                "should have been blocked at a higher level. This is likely "
+                "a bug.");
+        guac_protocol_send_ack(user->socket, stream, "FAIL (UPLOAD DISABLED)",
+                GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
+        guac_socket_flush(user->socket);
+        return 0;
+    }
+
     /* Open file */
     int file_id = guac_rdp_fs_open(fs, name, GENERIC_WRITE, 0,
             FILE_OVERWRITE_IF, 0);