GUACAMOLE-1059: Merge changes leveraging appropriate FreeRDP checks to verify input stream length.

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 0f45303..1ea6701 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
@@ -135,11 +135,28 @@
     wStream* output_stream;
     char destination_path[GUAC_RDP_FS_MAX_PATH];
 
+    /* Check stream size prior to reading. */
+    if (Stream_GetRemainingLength(input_stream) < 6) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Set "
+                "Information Request (FileRenameInformation) PDU does not "
+                "contain the expected number of bytes.  File redirection "
+                "may not work as expected.");
+        return;
+    }
+        
     /* Read structure */
     Stream_Seek_UINT8(input_stream); /* ReplaceIfExists */
     Stream_Seek_UINT8(input_stream); /* RootDirectory */
     Stream_Read_UINT32(input_stream, filename_length); /* FileNameLength */
 
+    if (Stream_GetRemainingLength(input_stream) < filename_length) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Set "
+                "Information Request (FileRenameInformation) PDU does not "
+                "contain the expected number of bytes.  File redirection "
+                "may not work as expected.");
+        return;
+    }
+    
     /* Convert name to UTF-8 */
     guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), filename_length/2,
             destination_path, sizeof(destination_path));
@@ -192,6 +209,15 @@
     UINT64 size;
     wStream* output_stream;
 
+    /* Check to make sure the stream has at least 8 bytes (UINT64) */
+    if (Stream_GetRemainingLength(input_stream) < 8) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Set "
+                "Information Request (FileAllocationInformation) PDU does not "
+                "contain the expected number of bytes.  File redirection "
+                "may not work as expected.");
+        return;
+    }
+    
     /* Read new size */
     Stream_Read_UINT64(input_stream, size); /* AllocationSize */
 
@@ -244,6 +270,15 @@
     UINT64 size;
     wStream* output_stream;
 
+    /* Check to make sure stream contains at least 8 bytes (UINT64) */
+    if (Stream_GetRemainingLength(input_stream) < 8) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Set "
+                "Information Request (FileEndOfFileInformation) PDU does not "
+                "contain the expected number of bytes.  File redirection "
+                "may not work as expected.");
+        return;
+    }
+    
     /* Read new size */
     Stream_Read_UINT64(input_stream, size); /* AllocationSize */
 
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c
index 529eea5..facba6f 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c
@@ -48,6 +48,14 @@
     int create_disposition, create_options, path_length;
     char path[GUAC_RDP_FS_MAX_PATH];
 
+    /* Check remaining stream data prior to reading. */
+    if (Stream_GetRemainingLength(input_stream) < 32) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Create Drive "
+                "Request PDU does not contain the expected number of bytes. "
+                "Drive redirection may not work as expected.");
+        return;
+    }
+    
     /* Read "create" information */
     Stream_Read_UINT32(input_stream, desired_access);
     Stream_Seek_UINT64(input_stream); /* allocation size */
@@ -57,6 +65,14 @@
     Stream_Read_UINT32(input_stream, create_options);
     Stream_Read_UINT32(input_stream, path_length);
 
+    /* Check to make sure the stream contains path_length bytes. */
+    if(Stream_GetRemainingLength(input_stream) < path_length) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Create Drive "
+                "Request PDU does not contain the expected number of bytes. "
+                "Drive redirection may not work as expected.");
+        return;
+    }
+    
     /* Convert path to UTF-8 */
     guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path_length/2 - 1,
             path, sizeof(path));
@@ -123,6 +139,14 @@
 
     wStream* output_stream;
 
+    /* Check remaining bytes before reading stream. */
+    if (Stream_GetRemainingLength(input_stream) < 12) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Read "
+                "Request PDU does not contain the expected number of bytes. "
+                "Drive redirection may not work as expected.");
+        return;
+    }
+    
     /* Read packet */
     Stream_Read_UINT32(input_stream, length);
     Stream_Read_UINT64(input_stream, offset);
@@ -172,6 +196,14 @@
 
     wStream* output_stream;
 
+    /* Check remaining length. */
+    if (Stream_GetRemainingLength(input_stream) < 32) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Write "
+                "Request PDU does not contain the expected number of bytes. "
+                "Drive redirection may not work as expected.");
+        return;
+    }
+    
     /* Read packet */
     Stream_Read_UINT32(input_stream, length);
     Stream_Read_UINT64(input_stream, offset);
@@ -181,6 +213,14 @@
             "%s: [file_id=%i] length=%i, offset=%" PRIu64,
              __func__, iorequest->file_id, length, (uint64_t) offset);
 
+    /* Check to make sure stream contains at least length bytes */
+    if (Stream_GetRemainingLength(input_stream) < length) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Write "
+                "Request PDU does not contain the expected number of bytes. "
+                "Drive redirection may not work as expected.");
+        return;
+    }
+    
     /* Attempt write */
     bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data,
             iorequest->file_id, offset, Stream_Pointer(input_stream), length);
@@ -244,6 +284,14 @@
 
     int fs_information_class;
 
+    /* Check remaining length */
+    if (Stream_GetRemainingLength(input_stream) < 4) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
+                "Volume Information PDU does not contain the expected number "
+                "of bytes. Drive redirection may not work as expected.");
+        return;
+    }
+    
     Stream_Read_UINT32(input_stream, fs_information_class);
 
     /* Dispatch to appropriate class-specific handler */
@@ -282,6 +330,14 @@
 
     int fs_information_class;
 
+    /* Check remaining length */
+    if (Stream_GetRemainingLength(input_stream) < 4) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
+                "Information PDU does not contain the expected number of "
+                "bytes. Drive redirection may not work as expected.");
+        return;
+    }
+    
     Stream_Read_UINT32(input_stream, fs_information_class);
 
     /* Dispatch to appropriate class-specific handler */
@@ -328,6 +384,14 @@
     int fs_information_class;
     int length;
 
+    /* Check remaining length */
+    if (Stream_GetRemainingLength(input_stream) < 32) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Set "
+                "Information PDU does not contain the expected number of "
+                "bytes. Drive redirection may not work as expected.");
+        return;
+    }
+    
     Stream_Read_UINT32(input_stream, fs_information_class);
     Stream_Read_UINT32(input_stream, length); /* Length */
     Stream_Seek(input_stream, 24);            /* Padding */
@@ -406,6 +470,13 @@
     if (file == NULL)
         return;
 
+    if (Stream_GetRemainingLength(input_stream) < 9) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
+                "Directory PDU does not contain the expected number of bytes. "
+                "Drive redirection may not work as expected.");
+        return;
+    }
+    
     /* Read main header */
     Stream_Read_UINT32(input_stream, fs_information_class);
     Stream_Read_UINT8(input_stream,  initial_query);
@@ -414,8 +485,19 @@
     /* If this is the first query, the path is included after padding */
     if (initial_query) {
 
+        /*
+         * Check to make sure Stream has at least the 23 padding bytes in it
+         * prior to seeking.
+         */
+        if (Stream_GetRemainingLength(input_stream) < (23 + path_length)) {
+            guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
+                    "Directory PDU does not contain the expected number of "
+                    "bytes. Drive redirection may not work as expected.");
+            return;
+        }
+        
         Stream_Seek(input_stream, 23);       /* Padding */
-
+        
         /* Convert path to UTF-8 */
         guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path_length/2 - 1,
                 file->dir_pattern, sizeof(file->dir_pattern));
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c
index 28a27e6..5fee465 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c
@@ -212,6 +212,14 @@
 
     unsigned int major, minor, client_id;
 
+    /* Stream should contain at least 8 bytes (UINT16 + UINT16 + UINT32) */
+    if (Stream_GetRemainingLength(input_stream) < 8) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Announce "
+                "Request PDU does not contain the expected number of bytes. "
+                "Device redirection may not work as expected.");
+        return;
+    }
+    
     Stream_Read_UINT16(input_stream, major);
     Stream_Read_UINT16(input_stream, minor);
     Stream_Read_UINT32(input_stream, client_id);
@@ -243,6 +251,14 @@
     unsigned int device_id, ntstatus;
     int severity, c, n, facility, code;
 
+    /* Stream should contain at least 8 bytes (UINT32 + UINT32 ) */
+    if (Stream_GetRemainingLength(input_stream) < 8) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Device Announce"
+                "Response PDU does not contain the expected number of bytes."
+                "Device redirection may not work as expected.");
+        return;
+    }
+    
     Stream_Read_UINT32(input_stream, device_id);
     Stream_Read_UINT32(input_stream, ntstatus);
 
@@ -278,6 +294,14 @@
     guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data;
     guac_rdpdr_iorequest iorequest;
 
+    /* Check to make sure the Stream contains at least 20 bytes (5 x UINT32 ). */
+    if (Stream_GetRemainingLength(input_stream) < 20) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Device I/O Request PDU "
+                "does not contain the expected number of bytes. Device "
+                "redirection may not work as expected.");
+        return;
+    }
+    
     /* Read header */
     Stream_Read_UINT32(input_stream, iorequest.device_id);
     Stream_Read_UINT32(input_stream, iorequest.file_id);
@@ -306,6 +330,14 @@
     int count;
     int i;
 
+    /* Check to make sure the Stream has at least 4 bytes (UINT16 + 2) */
+    if (Stream_GetRemainingLength(input_stream) < 4) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Core Capability "
+                "Request PDU does not contain the expected number of bytes."
+                "Device redirection may not work as expected.");
+        return;
+    }
+    
     /* Read header */
     Stream_Read_UINT16(input_stream, count);
     Stream_Seek(input_stream, 2);
@@ -316,9 +348,27 @@
         int type;
         int length;
 
+        /* Make sure Stream has at least 4 bytes (UINT16 + UINT16) */
+        if (Stream_GetRemainingLength(input_stream) < 4) {
+            guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Core "
+                    "Capability Request PDU does not contain the expected "
+                    "number of bytes. Device redirection may not work as "
+                    "expected.");
+            break;
+        }
+        
         Stream_Read_UINT16(input_stream, type);
         Stream_Read_UINT16(input_stream, length);
 
+        /* Make sure Stream has required length remaining for Seek below. */
+        if (Stream_GetRemainingLength(input_stream) < (length - 4)) {
+            guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Core "
+                    "Capability Request PDU does not contain the expected "
+                    "number of bytes. Device redirection may not work as "
+                    "expected.");
+            break;
+        }
+        
         /* Ignore all for now */
         guac_client_log(svc->client, GUAC_LOG_DEBUG, "Ignoring server capability set type=0x%04x, length=%i", type, length);
         Stream_Seek(input_stream, length - 4);
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c
index d90116f..4ff7053 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c
@@ -67,12 +67,28 @@
     int length;
     int status;
 
+    /* Verify that Stream contains at least 32 bytes (UINT32 + 8 + 20) */
+    if (Stream_GetRemainingLength(input_stream) < 32) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Print job write stream does "
+                "not contain the expected number of bytes. Printer redirection "
+                "may not work as expected.");
+        return;
+    }
+    
     /* Read buffer of print data */
     Stream_Read_UINT32(input_stream, length);
     Stream_Seek(input_stream, 8);  /* Offset */
     Stream_Seek(input_stream, 20); /* Padding */
     buffer = Stream_Pointer(input_stream);
 
+    /* Verify the stream has at least length number of bytes remaining. */
+    if (Stream_GetRemainingLength(input_stream) < length) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Print job write stream does "
+                "not contain the expected number of bytes. Printer redirection "
+                "may not work as expected.");
+        return;
+    }
+    
     /* Write data only if job exists, translating status for RDP */
     if (job != NULL && (length = guac_rdp_print_job_write(job,
                     buffer, length)) >= 0) {
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr.c b/src/protocols/rdp/channels/rdpdr/rdpdr.c
index e04bc9d..68bb73e 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr.c
@@ -38,6 +38,17 @@
     int component;
     int packet_id;
 
+    /* 
+     * Check that device redirection stream contains at least 4 bytes
+     * (UINT16 + UINT16).
+     */
+    if (Stream_GetRemainingLength(input_stream) < 4) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Device redirection "
+                "channel PDU header does not contain the expected number of "
+                "bytes. Device redirection may not function as expected.");
+        return;
+    }
+    
     /* Read header */
     Stream_Read_UINT16(input_stream, component);
     Stream_Read_UINT16(input_stream, packet_id);
diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
index 1d69e06..c057cd1 100644
--- a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
+++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
@@ -50,6 +50,17 @@
     /* Reset own format count */
     rdpsnd->format_count = 0;
 
+    /* 
+     * Check to make sure the stream has at least 20 bytes (14 byte seek,
+     * 2 x UTF16 reads, and 2 x UTF8 seeks).
+     */
+    if (Stream_GetRemainingLength(input_stream) < 20) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Server Audio Formats and "
+                "Version PDU does not contain the expected number of bytes. "
+                "Audio redirection may not work as expected.");
+        return;
+    }
+    
     /* Format header */
     Stream_Seek(input_stream, 14);
     Stream_Read_UINT16(input_stream, server_format_count);
@@ -96,6 +107,15 @@
             /* Remember position in stream */
             Stream_GetPointer(input_stream, format_start);
 
+            /* Check to make sure Stream has at least 18 bytes. */
+            if (Stream_GetRemainingLength(input_stream) < 18) {
+                guac_client_log(client, GUAC_LOG_WARNING, "Server Audio "
+                        "Formats and Version PDU does not contain the expected "
+                        "number of bytes. Audio redirection may not work as "
+                        "expected.");
+                return;
+            }
+            
             /* Read format */
             Stream_Read_UINT16(input_stream, format_tag);
             Stream_Read_UINT16(input_stream, channels);
@@ -106,6 +126,16 @@
 
             /* Skip past extra data */
             Stream_Read_UINT16(input_stream, body_size);
+            
+            /* Check that Stream has at least body_size bytes remaining. */
+            if (Stream_GetRemainingLength(input_stream) < body_size) {
+                guac_client_log(client, GUAC_LOG_WARNING, "Server Audio "
+                        "Formats and Version PDU does not contain the expected "
+                        "number of bytes. Audio redirection may not work as "
+                        "expected.");
+                return;
+            }
+            
             Stream_Seek(input_stream, body_size);
 
             /* If PCM, accept */
@@ -205,6 +235,14 @@
 
     guac_rdpsnd* rdpsnd = (guac_rdpsnd*) svc->data;
 
+    /* Check to make sure audio stream contains a minimum number of bytes. */
+    if (Stream_GetRemainingLength(input_stream) < 4) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Audio Training PDU "
+                "does not contain the expected number of bytes. Audio "
+                "redirection may not work as expected.");
+        return;
+    }
+    
     /* Read timestamp and data size */
     Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
     Stream_Read_UINT16(input_stream, data_size);
@@ -232,6 +270,14 @@
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     guac_audio_stream* audio = rdp_client->audio;
 
+    /* Check to make sure audio stream contains a minimum number of bytes. */
+    if (Stream_GetRemainingLength(input_stream) < 12) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Audio WaveInfo PDU "
+                "does not contain the expected number of bytes. Sound may not "
+                "work as expected.");
+        return;
+    }
+    
     /* Read wave information */
     Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
     Stream_Read_UINT16(input_stream, format);
@@ -266,6 +312,14 @@
 
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     guac_audio_stream* audio = rdp_client->audio;
+    
+    /* Verify that the stream has bytes to cover the wave size plus header. */
+    if (Stream_Length(input_stream) < (rdpsnd->incoming_wave_size + 4)) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Audio Wave PDU does "
+                "not contain the expected number of bytes. Sound may not work "
+                "as expected.");
+        return;
+    }
 
     /* Wave Confirmation PDU */
     wStream* output_stream = Stream_New(NULL, 8);
diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c
index be6034d..40b5315 100644
--- a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c
+++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c
@@ -35,11 +35,19 @@
     guac_rdpsnd* rdpsnd = (guac_rdpsnd*) svc->data;
     guac_rdpsnd_pdu_header header;
 
+    /* Check that we have at least the 4 byte header (UINT8 + UINT8 + UINT16) */
+    if (Stream_GetRemainingLength(input_stream) < 4) {
+        guac_client_log(svc->client, GUAC_LOG_WARNING, "Audio Stream does not "
+                "contain the expected number of bytes. Audio redirection may "
+                "not work as expected.");
+        return;
+    }
+    
     /* Read RDPSND PDU header */
     Stream_Read_UINT8(input_stream, header.message_type);
     Stream_Seek_UINT8(input_stream);
     Stream_Read_UINT16(input_stream, header.body_size);
-
+    
     /* 
      * If next PDU is SNDWAVE (due to receiving WaveInfo PDU previously),
      * ignore the header and parse as a Wave PDU.
diff --git a/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c b/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c
index 535cb45..91dee29 100644
--- a/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c
+++ b/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c
@@ -116,6 +116,10 @@
         svc->_input_stream = Stream_New(NULL, total_length);
     }
 
+    /* leave if we don't have a stream. */
+    if (svc->_input_stream == NULL)
+        return;
+    
     /* Add chunk to buffer only if sufficient space remains */
     if (Stream_EnsureRemainingCapacity(svc->_input_stream, data_length))
         Stream_Write(svc->_input_stream, data, data_length);
@@ -137,6 +141,7 @@
             svc->_receive_handler(svc, svc->_input_stream);
 
         Stream_Free(svc->_input_stream, TRUE);
+        svc->_input_stream = NULL;
 
     }
 
diff --git a/src/protocols/rdp/plugins/guacai/guacai-messages.c b/src/protocols/rdp/plugins/guacai/guacai-messages.c
index 38f7a7c..eb9a79d 100644
--- a/src/protocols/rdp/plugins/guacai/guacai-messages.c
+++ b/src/protocols/rdp/plugins/guacai/guacai-messages.c
@@ -35,10 +35,17 @@
  *
  * @param format
  *     The structure to populate with data from the stream.
+ * 
+ * @return
+ *     Zero on success or non-zero if an error occurs processing the format.
  */
-static void guac_rdp_ai_read_format(wStream* stream,
+static int guac_rdp_ai_read_format(wStream* stream,
         guac_rdp_ai_format* format) {
 
+    /* Check that we have at least 18 bytes (5 x UINT16, 2 x UINT32) */
+    if (Stream_GetRemainingLength(stream) < 18)
+        return 1;
+    
     /* Read audio format into structure */
     Stream_Read_UINT16(stream, format->tag); /* wFormatTag */
     Stream_Read_UINT16(stream, format->channels); /* nChannels */
@@ -48,11 +55,19 @@
     Stream_Read_UINT16(stream, format->bps); /* wBitsPerSample */
     Stream_Read_UINT16(stream, format->data_size); /* cbSize */
 
-    /* Read arbitrary data block (if applicable) */
+    /* Read arbitrary data block (if applicable) and data is available. */
     if (format->data_size != 0) {
+        
+        /* Check to make sure Stream contains expected bytes. */
+        if (Stream_GetRemainingLength(stream) < format->data_size)
+            return 1;
+        
         format->data = Stream_Pointer(stream); /* data */
         Stream_Seek(stream, format->data_size);
+        
     }
+    
+    return 0;
 
 }
 
@@ -232,6 +247,14 @@
 void guac_rdp_ai_process_version(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
+    /* Verify we have at least 4 bytes available (UINT32) */
+    if (Stream_GetRemainingLength(stream) < 4) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Audio input Versoin PDU "
+                "does not contain the expected number of bytes. Audio input "
+                "redirection may not work as expected.");
+        return;
+    }
+    
     UINT32 version;
     Stream_Read_UINT32(stream, version);
 
@@ -258,15 +281,28 @@
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
 
+    /* Verify we have at least 8 bytes available (2 x UINT32) */
+    if (Stream_GetRemainingLength(stream) < 8) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Audio input Sound Formats "
+                "PDU does not contain the expected number of bytes. Audio "
+                "input redirection may not work as expected.");
+        return;
+    }
+    
     UINT32 num_formats;
     Stream_Read_UINT32(stream, num_formats); /* NumFormats */
     Stream_Seek_UINT32(stream); /* cbSizeFormatsPacket (MUST BE IGNORED) */
-
+    
     UINT32 index;
     for (index = 0; index < num_formats; index++) {
 
         guac_rdp_ai_format format;
-        guac_rdp_ai_read_format(stream, &format);
+        if (guac_rdp_ai_read_format(stream, &format)) {
+            guac_client_log(client, GUAC_LOG_WARNING, "Error occurred "
+                    "processing audio input formats.  Audio input redirection "
+                    "may not work as expected.");
+            return;
+        }
 
         /* Ignore anything but WAVE_FORMAT_PCM */
         if (format.tag != GUAC_RDP_WAVE_FORMAT_PCM)
@@ -306,6 +342,14 @@
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
 
+    /* Verify we have at least 8 bytes available (2 x UINT32) */
+    if (Stream_GetRemainingLength(stream) < 8) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Audio input Open PDU does "
+                "not contain the expected number of bytes. Audio input "
+                "redirection may not work as expected.");
+        return;
+    }
+    
     UINT32 packet_frames;
     UINT32 initial_format;
 
diff --git a/src/protocols/rdp/plugins/guacai/guacai.c b/src/protocols/rdp/plugins/guacai/guacai.c
index 15de865..b5383c4 100644
--- a/src/protocols/rdp/plugins/guacai/guacai.c
+++ b/src/protocols/rdp/plugins/guacai/guacai.c
@@ -52,10 +52,18 @@
 static void guac_rdp_ai_handle_data(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
+    /* Verify we have at least 1 byte in the stream (UINT8) */
+    if (Stream_GetRemainingLength(stream) < 1) {
+        guac_client_log(client, GUAC_LOG_WARNING, "Audio input PDU header does "
+                "not contain the expected number of bytes. Audio input "
+                "redirection may not work as expected.");
+        return;
+    }
+    
     /* Read message ID from received PDU */
     BYTE message_id;
     Stream_Read_UINT8(stream, message_id);
-
+    
     /* Invoke appropriate message processor based on ID */
     switch (message_id) {