From Aaron Woo (via Jeff Weston): Optimized Link State Routing Protocol
[obnox/wireshark/wip.git] / packet-dcerpc.c
index 971d3324e4971e953894d440c6441162c1f72aae..ef4ec86ab95b50a6ea51b4040021698a68e6e084 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2001, Todd Sabin <tas@webspan.net>
  * Copyright 2003, Tim Potter <tpot@samba.org>
  *
- * $Id: packet-dcerpc.c,v 1.145 2003/10/14 00:45:54 guy Exp $
+ * $Id: packet-dcerpc.c,v 1.158 2003/12/08 20:58:01 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -506,7 +506,7 @@ static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
                              e_dce_cn_common_hdr_t *hdr, 
                              dcerpc_auth_info *auth_info)
 {
-       dcerpc_dissect_fnct_t *fn = NULL;
+       dcerpc_dissect_fnct_t *volatile fn = NULL;
 
        switch (hdr->ptype) {
        case PDU_BIND:
@@ -603,9 +603,10 @@ dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
     key->uuid = *uuid;
     key->ver = ver;
 
-    value->proto = proto;
+    value->proto = find_protocol_by_id(proto);
+    value->proto_id = proto;
     value->ett = ett;
-    value->name = proto_get_protocol_short_name (proto);
+    value->name = proto_get_protocol_short_name (value->proto);
     value->procs = procs;
     value->opnum_hf = opnum_hf;
 
@@ -1718,7 +1719,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
 static void
 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
-                dcerpc_auth_info *auth_info)
+                dcerpc_auth_info *auth_info, gboolean is_encrypted)
 {
     int length;
 
@@ -1732,9 +1733,15 @@ show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
         length = tvb_reported_length_remaining (tvb, offset);
         if (auth_info != NULL &&
             auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
-            proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
-                                "Encrypted stub data (%d byte%s)",
-                                length, plurality(length, "", "s"));
+            if (is_encrypted) {
+                proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+                                    "Encrypted stub data (%d byte%s)",
+                                    length, plurality(length, "", "s"));
+            } else {
+                proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+                                    "Decrypted stub data (%d byte%s)",
+                                    length, plurality(length, "", "s"));
+            }
         } else {
             proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
                                  "Stub data (%d byte%s)", length,
@@ -1746,19 +1753,23 @@ show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
 static int
 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
                     proto_tree *dcerpc_tree,
-                    tvbuff_t *volatile tvb, volatile gint offset,
+                    tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
                     char *drep, dcerpc_info *info,
                     dcerpc_auth_info *auth_info)
 {
+    volatile gint offset = 0;
     dcerpc_uuid_key key;
     dcerpc_uuid_value *sub_proto;
-    int length;
     proto_tree *volatile sub_tree = NULL;
     dcerpc_sub_dissector *proc;
     gchar *name = NULL;
     dcerpc_dissect_fnct_t *volatile sub_dissect;
     const char *volatile saved_proto;
     void *volatile saved_private_data;
+    guint length, reported_length;
+    tvbuff_t *volatile stub_tvb;
+    volatile guint auth_pad_len;
+    volatile int auth_pad_offset;
 
     key.uuid = info->call_data->uuid;
     key.ver = info->call_data->ver;
@@ -1770,7 +1781,11 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
          * We don't have a dissector for this UUID, or the protocol
          * for that UUID is disabled.
          */
-        show_stub_data (tvb, offset, dcerpc_tree, auth_info);
+        if (decrypted_tvb != NULL) {
+            show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
+                            FALSE);
+        } else
+            show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
         return -1;
     }
 
@@ -1795,7 +1810,7 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
 
     if (tree) {
         proto_item *sub_item;
-        sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
+        sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
                                         -1, FALSE);
 
         if (sub_item) {
@@ -1808,74 +1823,128 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
          */
 
        if (sub_proto->opnum_hf != -1)
-               proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
-                                          tvb, 0, 0, info->call_data->opnum,
-                                          "Operation: %s (%u)",
-                                          name, info->call_data->opnum);
+            proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
+                                       tvb, 0, 0, info->call_data->opnum,
+                                       "Operation: %s (%u)",
+                                       name, info->call_data->opnum);
        else
-               proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
-                                          0, 0, info->call_data->opnum,
-                                          "Operation: %s (%u)",
-                                          name, info->call_data->opnum);
+            proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
+                                       0, 0, info->call_data->opnum,
+                                       "Operation: %s (%u)",
+                                       name, info->call_data->opnum);
     }
 
     sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
 
-    /* Call subdissector if we have no auth info, or a zero auth_level and
-       no decrypted data, or non-zero auth_level and sucessfully decrypted
-       data. */
-
-    if (sub_dissect && (auth_info == NULL ||
-                        (!auth_info->auth_level && !pinfo->decrypted_data) ||
-                       (auth_info->auth_level && pinfo->decrypted_data))) {
+    if (decrypted_tvb != NULL) {
+        /* Either there was no encryption or we successfully decrypted
+           the entrypted payload. */
+        if (sub_dissect) {
+            /* We have a subdissector - call it. */
             saved_proto = pinfo->current_proto;
             saved_private_data = pinfo->private_data;
             pinfo->current_proto = sub_proto->name;
             pinfo->private_data = (void *)info;
            
             init_ndr_pointer_list(pinfo);
+
             /*
-             * Catch ReportedBoundsError, so that even if the stub
-             * data is bad, we still show the verifier.
+             * Remove the authentication padding from the stub data.
              */
-            TRY {
-                offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
-            } CATCH(BoundsError) {
-                RETHROW;
-            } CATCH(ReportedBoundsError) {
-                show_reported_bounds_error(tvb, pinfo, tree);
-            } ENDTRY;
-
-            /* If there is auth padding at the end of the stub, display it */
             if (auth_info != NULL && auth_info->auth_pad_len != 0) {
-                proto_tree_add_text (sub_tree, tvb, offset, 
-                                     auth_info->auth_pad_len,
-                                     "Auth Padding (%u byte%s)",
-                                     auth_info->auth_pad_len,
-                                     plurality(auth_info->auth_pad_len, "", "s"));
-                offset += auth_info->auth_pad_len;
+                length = tvb_length(decrypted_tvb);
+                reported_length = tvb_reported_length(decrypted_tvb);
+                if (reported_length >= auth_info->auth_pad_len) {
+                    /*
+                     * OK, the padding length isn't so big that it
+                     * exceeds the stub length.  Trim the reported
+                     * length of the tvbuff.
+                     */
+                    reported_length -= auth_info->auth_pad_len;
+
+                    /*
+                     * If that exceeds the actual amount of data in
+                     * the tvbuff (which means we have at least one
+                     * byte of authentication padding in the tvbuff),
+                     * trim the actual amount.
+                     */
+                    if (length > reported_length)
+                        length = reported_length;
+
+                    stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+                    auth_pad_len = auth_info->auth_pad_len;
+                    auth_pad_offset = reported_length;
+                } else {
+                    /*
+                     * The padding length exceeds the stub length.
+                     * Don't bother dissecting the stub, trim the padding
+                     * length to what's in the stub data, and show the
+                     * entire stub as authentication padding.
+                     */
+                    stub_tvb = NULL;
+                    auth_pad_len = reported_length;
+                    auth_pad_offset = 0;
+                }
+            } else {
+                /*
+                 * No authentication padding.
+                 */
+                stub_tvb = decrypted_tvb;
+                auth_pad_len = 0;
+                auth_pad_offset = 0;
             }
 
-           /* If we have a subdissector and it didn't dissect all data in
-               the tvb, make a note of it. */
+            if (stub_tvb != NULL) {
+                /*
+                 * Catch all exceptions other than BoundsError, so that even
+                 * if the stub data is bad, we still show the authentication
+                 * padding, if any.
+                 *
+                 * If we get BoundsError, it means the frame was cut short
+                 * by a snapshot length, so there's nothing more to
+                 * dissect; just re-throw that exception.
+                 */
+                TRY {
+                    offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
+                                          drep);
+
+                    /* If we have a subdissector and it didn't dissect all
+                       data in the tvb, make a note of it. */
+
+                    if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
+                        if (check_col(pinfo->cinfo, COL_INFO))
+                            col_append_fstr(pinfo->cinfo, COL_INFO,
+                                            "[Long frame (%d bytes)]",
+                                            tvb_reported_length_remaining(stub_tvb, offset));
+                    }
+                } CATCH(BoundsError) {
+                    RETHROW;
+                } CATCH_ALL {
+                    show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
+                } ENDTRY;
+            }
 
-           if (tvb_length_remaining(tvb, offset)) {
-               if (check_col(pinfo->cinfo, COL_INFO))
-                       col_append_fstr(pinfo->cinfo, COL_INFO,
-                                       "[Long frame (%d bytes)]",
-                                       tvb_length_remaining(tvb, offset));
-           }
+            /* If there is auth padding at the end of the stub, display it */
+            if (auth_pad_len != 0) {
+                proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
+                                     auth_pad_len,
+                                     "Auth Padding (%u byte%s)",
+                                     auth_pad_len,
+                                     plurality(auth_pad_len, "", "s"));
+            }
 
             pinfo->current_proto = saved_proto;
             pinfo->private_data = saved_private_data;
         } else {
-            length = tvb_length_remaining (tvb, offset);
-            if (length > 0) {
-                proto_tree_add_text (sub_tree, tvb, offset, length,
-                                     "Stub data (%d byte%s)", length,
-                                     plurality(length, "", "s"));
+            /* No subdissector - show it as stub data. */
+            if(decrypted_tvb){
+               show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
+            } else {
+               show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
             }
         }
+    } else
+        show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
 
     tap_queue_packet(dcerpc_tap, pinfo, info);
     return 0;
@@ -1891,34 +1960,43 @@ dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
     auth_info->auth_data = NULL;
 
     if (auth_info->auth_size != 0) {
-           dcerpc_auth_subdissector_fns *auth_fns;
-           tvbuff_t *auth_tvb;
+       dcerpc_auth_subdissector_fns *auth_fns;
+       tvbuff_t *auth_tvb;
 
-           auth_offset = hdr->frag_len - hdr->auth_len;
+       auth_offset = hdr->frag_len - hdr->auth_len;
 
-           auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
-                                     hdr->auth_len);
+       auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
+                                 hdr->auth_len);
 
-           auth_info->auth_data = auth_tvb;
+       auth_info->auth_data = auth_tvb;
 
-           if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
-                                                     auth_info->auth_type)))
-                   dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
-                                     hdr, auth_info);
-           else
-                   proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
-                                        "Auth Verifier");
+       if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+                                                 auth_info->auth_type))) {
+           /*
+            * Catch all exceptions, so that even if the verifier is bad
+            * or we don't have all of it, we still show the stub data.
+            */
+           TRY {
+               dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
+                                 hdr, auth_info);
+           } CATCH_ALL {
+               show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+           } ENDTRY;
+       } else {
+           proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
+                                "Auth Verifier");
+       }
     }
 
     return hdr->auth_len;
 }
 
 static void
-dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
-                        e_dce_cn_common_hdr_t *hdr, gboolean are_credentials, 
-                       dcerpc_auth_info *auth_info)
+dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
+                        proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
+                        gboolean are_credentials, dcerpc_auth_info *auth_info)
 {
-    int offset;
+    volatile int offset;
 
     /*
      * Initially set auth_level and auth_type to zero to indicate that we 
@@ -1926,63 +2004,86 @@ dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr
      */
     auth_info->auth_level = 0;
     auth_info->auth_type = 0;
+    auth_info->auth_size = 0;
+    auth_info->auth_pad_len = 0;
     
     /*
      * The authentication information is at the *end* of the PDU; in
      * request and response PDUs, the request and response stub data
      * come before it.
      *
-     * If the full packet is here, and we've got an auth len, and it's
-     * valid, then dissect the auth info.
+     * Is there any authentication data (i.e., is the authentication length
+     * non-zero), and is the authentication length valid (i.e., is it, plus
+     * 8 bytes for the type/level/pad length/reserved/context id, less than
+     * or equal to the fragment length minus the starting offset of the
+     * stub data?)
      */
 
-    if (tvb_length (tvb) >= hdr->frag_len
-        && hdr->auth_len
-        && (hdr->auth_len + 8 <= hdr->frag_len)) {
+    if (hdr->auth_len
+        && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
 
+        /*
+         * Yes, there is authentication data, and the length is valid.
+         * Do we have all the bytes of stub data?
+         * (If not, we'd throw an exception dissecting *that*, so don't
+         * bother trying to dissect the authentication information and
+         * throwing another exception there.)
+         */
         offset = hdr->frag_len - (hdr->auth_len + 8);
-
-        offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
-                                       hf_dcerpc_auth_type, 
-                                      &auth_info->auth_type);
-        offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
-                                       hf_dcerpc_auth_level, 
-                                      &auth_info->auth_level);
-
-        offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
-                                       hf_dcerpc_auth_pad_len, 
-                                      &auth_info->auth_pad_len);
-        offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
-                                       hf_dcerpc_auth_rsrvd, NULL);
-        offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
-                                        hf_dcerpc_auth_ctx_id, NULL);
-
-       /*
-        * Dissect the authentication data.
-        */
-       if (are_credentials) {
-           tvbuff_t *auth_tvb;
-           dcerpc_auth_subdissector_fns *auth_fns;
-
-           auth_tvb = tvb_new_subset(
-                   tvb, offset, hdr->auth_len, hdr->auth_len);
-
-           if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
-                                                     auth_info->auth_type)))
-                   dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, 
-                                     hdr, auth_info);
-           else
-                   proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
-                                        "Auth Credentials");
-       }
+        if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
+            /*
+             * Either there's no stub data, or the last byte of the stub
+             * data is present in the captured data, so we shouldn't
+             * get a BoundsError dissecting the stub data.
+             *
+             * Try dissecting the authentication data.
+             * Catch all exceptions, so that even if the auth info is bad
+             * or we don't have all of it, we still show the stuff we
+             * dissect after this, such as stub data.
+             */
+            TRY {
+                offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                                               hf_dcerpc_auth_type, 
+                                               &auth_info->auth_type);
+                offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                                               hf_dcerpc_auth_level, 
+                                               &auth_info->auth_level);
+
+                offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                                               hf_dcerpc_auth_pad_len, 
+                                               &auth_info->auth_pad_len);
+                offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                                               hf_dcerpc_auth_rsrvd, NULL);
+                offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                                                hf_dcerpc_auth_ctx_id, NULL);
+
+                /*
+                 * Dissect the authentication data.
+                 */
+                if (are_credentials) {
+                    tvbuff_t *auth_tvb;
+                    dcerpc_auth_subdissector_fns *auth_fns;
+
+                    auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
+                                              hdr->auth_len);
+
+                    if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+                                                              auth_info->auth_type)))
+                        dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, 
+                                          hdr, auth_info);
+                    else
+                        proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
+                                             "Auth Credentials");
+                }
        
-        /* Compute the size of the auth block.  Note that this should not 
-          include auth padding, since when NTLMSSP encryption is used, the
-          padding is actually inside the encrypted stub */
-       auth_info->auth_size = hdr->auth_len + 8;
-    } else {
-        auth_info->auth_size = 0;
-        auth_info->auth_pad_len = 0;
+                /* Compute the size of the auth block.  Note that this should not 
+                   include auth padding, since when NTLMSSP encryption is used, the
+                   padding is actually inside the encrypted stub */
+                   auth_info->auth_size = hdr->auth_len + 8;
+            } CATCH_ALL {
+                show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+            } ENDTRY;
+        }
     }
 }
 
@@ -2017,7 +2118,7 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                        proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
 {
     conversation_t *conv = NULL;
-    guint8 num_ctx_items;
+    guint8 num_ctx_items = 0;
     guint i;
     gboolean saw_ctx_item = FALSE;
     guint16 ctx_id;
@@ -2141,6 +2242,9 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
          key.uuid = if_id;
          key.ver = if_ver;
 
+         if (num_ctx_items > 1)
+                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
+               
          if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
                  col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
          else
@@ -2183,7 +2287,7 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * an authentication header, and associate it with an authentication
      * context, so subsequent PDUs can use that context.
      */
-    dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+    dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
 }
 
 static void
@@ -2270,7 +2374,7 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - do we need to do anything with the authentication level
      * we get back from this?
      */
-    dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+    dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
 
     if (check_col (pinfo->cinfo, COL_INFO)) {
         if (num_results != 0 && result == 0) {
@@ -2356,10 +2460,10 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
                         dcerpc_auth_info *auth_info, guint32 alloc_hint,
                         guint32 frame)
 {
-    gboolean save_fragmented, payload_ok;
+    gboolean save_fragmented;
     fragment_data *fd_head=NULL;
     guint32 tot_len;
-    tvbuff_t *payload_tvb;
+    tvbuff_t *payload_tvb, *decrypted_tvb;
 
     save_fragmented = pinfo->fragmented;
 
@@ -2368,21 +2472,19 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
            auth_info->auth_size, tvb_length_remaining(tvb, offset) - 
            auth_info->auth_size);    
 
-    payload_ok = TRUE;
-
     /* Decrypt the PDU if it is encrypted */
 
-    pinfo->decrypted_data = NULL;
-
-    if (auth_info->auth_type) {
+    if (auth_info->auth_type &&
+        auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
+           /*
+            * We know the authentication type, and the authentication
+            * level is "Packet privacy", meaning the payload is
+            * encrypted; attempt to decrypt it.
+            */
            dcerpc_auth_subdissector_fns *auth_fns;
            
-           if (dcerpc_tree)
-                   proto_tree_add_text(
-                           dcerpc_tree, payload_tvb, 0, -1,
-                           "Encrypted Stub Data (%d byte%s)",
-                           tvb_length(payload_tvb),
-                           plurality(tvb_length(payload_tvb), "", "s"));
+           /* Start out assuming we won't succeed in decrypting. */
+           decrypted_tvb = NULL;
 
            if ((auth_fns = get_auth_subdissector_fns(
                         auth_info->auth_level, auth_info->auth_type))) {
@@ -2393,30 +2495,31 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
                            hdr->ptype == PDU_REQ, auth_info);      
                    
                    if (result) {
-                           int len = tvb_length(result);
+                           if (dcerpc_tree)
+                               proto_tree_add_text(
+                                           dcerpc_tree, payload_tvb, 0, -1,
+                                           "Encrypted stub data (%d byte%s)",
+                                           tvb_reported_length(payload_tvb),
+
+                           plurality(tvb_length(payload_tvb), "", "s"));
 
                            add_new_data_source(
-                                   pinfo, result, "Decrypted Stub Data");
+                                   pinfo, result, "Decrypted stub data");
                            
-                           pinfo->decrypted_data = result;
-
-                           proto_tree_add_text(
-                                   dcerpc_tree, result, 0, len,
-                                   "Decrypted Stub Data (%d byte%s)",
-                                   len, plurality(len, "", "s"));
-                   } else
-                           payload_ok = FALSE;
+                           /* We succeeded. */
+                           decrypted_tvb = result;
+                   }
            }
-    }
+    } else
+           decrypted_tvb = payload_tvb;
 
     /* if this packet is not fragmented, just dissect it and exit */
     if(PFC_NOT_FRAGMENTED(hdr)){
        pinfo->fragmented = FALSE;
 
        dcerpc_try_handoff(
-               pinfo, tree, dcerpc_tree, 
-               pinfo->decrypted_data ? pinfo->decrypted_data : payload_tvb, 
-               0, hdr->drep, di, auth_info);
+               pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+               hdr->drep, di, auth_info);
        
        pinfo->fragmented = save_fragmented;
        return;
@@ -2427,13 +2530,14 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
 
     /* if we are not doing reassembly and this is the first fragment
        then just dissect it and exit
+       XXX - if we're not doing reassembly, can we decrypt an
+       encrypted stub?
     */
     if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
 
        dcerpc_try_handoff(
-               pinfo, tree, dcerpc_tree,
-               pinfo->decrypted_data ? pinfo->decrypted_data : 
-               payload_tvb, 0, hdr->drep, di, auth_info);
+               pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+               hdr->drep, di, auth_info);
        
         if (check_col(pinfo->cinfo, COL_INFO)) {
             col_append_fstr(pinfo->cinfo, COL_INFO,
@@ -2443,11 +2547,6 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
         return;
     }
 
-    /* Replace encrypted payload with decrypted version for reassembly. */
-
-    if (pinfo->decrypted_data)
-           payload_tvb = (tvbuff_t *)pinfo->decrypted_data;
-
     /* if we have already seen this packet, see if it was reassembled
        and if so dissect the full pdu.
        then exit 
@@ -2478,11 +2577,17 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
        thus we must reassemble it.
     */
 
+    /* Do we have any non-encrypted data to reassemble? */
+    if (decrypted_tvb == NULL) {
+      /* No.  We can't even try to reassemble.  */
+      goto end_cn_stub;
+    }
+
     /* if this is the first fragment we need to start reassembly
     */
     if(hdr->flags&PFC_FIRST_FRAG){
-       fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
-                    0, tvb_length(payload_tvb), TRUE);
+       fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
+                    0, tvb_length(decrypted_tvb), TRUE);
        fragment_set_tot_len(pinfo, frame,
                 dcerpc_co_reassemble_table, alloc_hint);
 
@@ -2493,9 +2598,9 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
     if(!(hdr->flags&PFC_LAST_FRAG)){
        tot_len = fragment_get_tot_len(pinfo, frame,
                 dcerpc_co_reassemble_table);
-       fragment_add(payload_tvb, 0, pinfo, frame,
+       fragment_add(decrypted_tvb, 0, pinfo, frame,
                 dcerpc_co_reassemble_table,
-                tot_len-alloc_hint, tvb_length(payload_tvb),
+                tot_len-alloc_hint, tvb_length(decrypted_tvb),
                 TRUE);
 
        goto end_cn_stub;
@@ -2505,10 +2610,10 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
     */
     tot_len = fragment_get_tot_len(pinfo, frame,
                dcerpc_co_reassemble_table);
-    fd_head = fragment_add(payload_tvb, 0, pinfo,
+    fd_head = fragment_add(decrypted_tvb, 0, pinfo,
                frame,
                dcerpc_co_reassemble_table,
-               tot_len-alloc_hint, tvb_length(payload_tvb),
+               tot_len-alloc_hint, tvb_length(decrypted_tvb),
                TRUE);
 
 end_cn_stub:
@@ -2521,7 +2626,7 @@ end_cn_stub:
            tvbuff_t *next_tvb;
 
            next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
-           tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb);
+           tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
            add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
            show_fragment_tree(fd_head, &dcerpc_frag_items,
                dcerpc_tree, pinfo, next_tvb);
@@ -2529,11 +2634,11 @@ end_cn_stub:
            pinfo->fragmented = FALSE;
 
            dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
-               0, hdr->drep, di, auth_info);
+               next_tvb, hdr->drep, di, auth_info);
 
        } else {
-           proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, payload_tvb, 0, 0, 
-                               fd_head->reassembled_in);
+           proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
+                               decrypted_tvb, 0, 0, fd_head->reassembled_in);
            if (check_col(pinfo->cinfo, COL_INFO)) {
                col_append_fstr(pinfo->cinfo, COL_INFO,
                        " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
@@ -2541,12 +2646,18 @@ end_cn_stub:
        }
     } else {
        /* Reassembly not complete - some fragments
-          are missing */
+          are missing.  Just show the stub data. */
 
        if (check_col(pinfo->cinfo, COL_INFO)) {
            col_append_fstr(pinfo->cinfo, COL_INFO,
                        " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
        }
+
+       if(decrypted_tvb){
+               show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
+       } else {
+               show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
+       }
     }
 
     pinfo->fragmented = save_fragmented;
@@ -2606,13 +2717,13 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - what if this was set when the connection was set up,
      * and we just have a security context?
      */
-    dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+    dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
 
     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
                               pinfo->srcport, pinfo->destport, 0);
     if (!conv)
-        show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+        show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
     else {
         dcerpc_matched_key matched_key, *new_matched_key;
         dcerpc_call_value *value;
@@ -2708,7 +2819,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                                    hdr, di, &auth_info, alloc_hint,
                                    value->req_frame);
        } else
-           show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+           show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
     }
 }
 
@@ -2741,7 +2852,7 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - what if this was set when the connection was set up,
      * and we just have a security context?
      */
-    dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+    dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
 
     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
@@ -2749,7 +2860,7 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
     if (!conv) {
         /* no point in creating one here, really */
-        show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+        show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
     } else {
        dcerpc_matched_key matched_key, *new_matched_key;
 
@@ -2809,7 +2920,7 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                                    hdr, di, &auth_info, alloc_hint,
                                    value->rep_frame);
         } else
-            show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+            show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
     }
 }
 
@@ -2852,7 +2963,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - what if this was set when the connection was set up,
      * and we just have a security context?
      */
-    dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+    dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
 
     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
                               pinfo->srcport, pinfo->destport, 0);
@@ -3066,9 +3177,9 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
 /*
  * DCERPC dissector for connection oriented calls
  */
-static int
+static gboolean
 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
-                   proto_tree *tree, gboolean can_desegment)
+                   proto_tree *tree, gboolean can_desegment, int *pkt_len)
 {
     static char nulls[4] = { 0 };
     int start_offset;
@@ -3103,18 +3214,18 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
      * Check if this looks like a C/O DCERPC call
      */
     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
-        return -1;
+        return FALSE;  /* not enough information to check */
     }
     start_offset = offset;
     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
     if (hdr.rpc_ver != 5)
-        return -1;
+        return FALSE;
     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
-        return -1;
+        return FALSE;
     hdr.ptype = tvb_get_guint8 (tvb, offset++);
     if (hdr.ptype > 19)
-        return -1;
+        return FALSE;
 
     hdr.flags = tvb_get_guint8 (tvb, offset++);
     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
@@ -3131,7 +3242,8 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
         && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
         pinfo->desegment_offset = start_offset;
         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
-        return 0;      /* desegmentation required */
+        *pkt_len = 0;  /* desegmentation required */
+        return TRUE;
     }
 
     if (check_col (pinfo->cinfo, COL_PROTOCOL))
@@ -3141,7 +3253,7 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
            pckt_vals[hdr.ptype].strptr, hdr.call_id);
 
     if (tree) {
-      offset = start_offset;
+        offset = start_offset;
         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
         if (ti) {
             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
@@ -3182,6 +3294,23 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
         offset += 4;
     }
 
+    /*
+     * None of the stuff done above should throw an exception, because
+     * we would have rejected this as "not DCE RPC" if we didn't have all
+     * of it.  (XXX - perhaps we should request reassembly if we have
+     * enough of the header to consider it DCE RPC but not enough to
+     * get the fragment length; in that case the stuff still wouldn't
+     * throw an exception.)
+     *
+     * The rest of the stuff might, so return the PDU length to our caller.
+     * XXX - should we construct a tvbuff containing only the PDU and
+     * use that?  Or should we have separate "is this a DCE RPC PDU",
+     * "how long is it", and "dissect it" routines - which might let us
+     * do most of the work in "tcp_dissect_pdus()"?
+     */
+    if (pkt_len != NULL)
+        *pkt_len = hdr.frag_len + padding;
+
     /*
      * Packet type specific stuff is next.
      */
@@ -3200,7 +3329,7 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
         /*
          * Nothing after the common header other than credentials.
          */
-        dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE, 
+        dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE, 
                                &auth_info);
         break;
 
@@ -3226,7 +3355,7 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
          * Nothing after the common header other than an authentication
          * verifier.
          */
-        dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE, 
+        dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE, 
                                &auth_info);
         break;
 
@@ -3239,11 +3368,11 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
 
     default:
         /* might as well dissect the auth info */
-        dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE, 
+        dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE, 
                                &auth_info);
         break;
     }
-    return hdr.frag_len + padding;
+    return TRUE;
 }
 
 /*
@@ -3257,7 +3386,7 @@ dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
      * Only one PDU per transport packet, and only one transport
      * packet per PDU.
      */
-    if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
+    if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
         /*
          * It wasn't a DCERPC PDU.
          */
@@ -3277,18 +3406,36 @@ dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 static gboolean
 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-    int offset = 0;
+    volatile int offset = 0;
     int pdu_len;
-    gboolean ret = FALSE;
+    volatile gboolean is_dcerpc_pdu;
+    volatile gboolean ret = FALSE;
 
     /*
      * There may be multiple PDUs per transport packet; keep
      * processing them.
      */
     while (tvb_reported_length_remaining(tvb, offset) != 0) {
-        pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
-                                     dcerpc_cn_desegment);
-        if (pdu_len == -1) {
+        /*
+         * Catch ReportedBoundsError, so that even if the stub data is bad,
+         * we don't abort the full DCE RPC dissection - there might be more
+         * than one DCE RPC PDU in the data being dissected.
+         *
+         * If we get BoundsError, it means the frame was cut short by a
+         * snapshot length, so there's nothing more to dissect; just
+         * re-throw that exception.
+         */
+        is_dcerpc_pdu = FALSE;
+        TRY {
+            is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
+                                               dcerpc_cn_desegment, &pdu_len);
+        } CATCH(BoundsError) {
+            RETHROW;
+        } CATCH(ReportedBoundsError) {
+            show_reported_bounds_error(tvb, pinfo, tree);
+        } ENDTRY;
+
+        if (!is_dcerpc_pdu) {
             /*
              * Not a DCERPC PDU.
              */
@@ -3493,11 +3640,10 @@ dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
     int length, reported_length, stub_length;
     gboolean save_fragmented;
     fragment_data *fd_head;
+    tvbuff_t *next_tvb;
 
-    if (check_col (pinfo->cinfo, COL_INFO)) {
-        col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
-                         di->call_data->opnum);
-    }
+    if (check_col (pinfo->cinfo, COL_INFO))
+        col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", di->call_data->opnum );
 
     length = tvb_length_remaining (tvb, offset);
     reported_length = tvb_reported_length_remaining (tvb, offset);
@@ -3517,16 +3663,26 @@ dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
     if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
                !tvb_bytes_exist(tvb, offset, stub_length) ){
        if(hdr->frag_num == 0) {
+
+
+    if (check_col (pinfo->cinfo, COL_INFO))
+        col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
+                     di->call_data->uuid.Data1, di->call_data->uuid.Data2, di->call_data->uuid.Data3, di->call_data->uuid.Data4[0],
+                     di->call_data->uuid.Data4[1], di->call_data->uuid.Data4[2], di->call_data->uuid.Data4[3],
+                     di->call_data->uuid.Data4[4], di->call_data->uuid.Data4[5], di->call_data->uuid.Data4[6],
+                     di->call_data->uuid.Data4[7], di->call_data->ver);
+
+
            /* First fragment, possibly the only fragment */
 
            /*
             * XXX - authentication info?
             */
            pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
-           dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
-                               tvb_new_subset (tvb, offset, length,
-                                               reported_length),
-                               0, hdr->drep, di, NULL);
+           next_tvb = tvb_new_subset (tvb, offset, length,
+                                      reported_length);
+           dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
+                               next_tvb, hdr->drep, di, NULL);
        } else {
            /* PDU is fragmented and this isn't the first fragment */
            if (check_col(pinfo->cinfo, COL_INFO)) {
@@ -3560,8 +3716,6 @@ dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
                        !(hdr->flags1 & PFCL1_LASTFRAG));
        if (fd_head != NULL) {
            /* We completed reassembly */
-           tvbuff_t *next_tvb;
-
            next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
            tvb_set_child_real_data_tvbuff(tvb, next_tvb);
            add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
@@ -3573,7 +3727,7 @@ dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
             */
            pinfo->fragmented = FALSE;
            dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
-                               0, hdr->drep, di, NULL);
+                               next_tvb, hdr->drep, di, NULL);
        } else {
            /* Reassembly isn't completed yet */
            if (check_col(pinfo->cinfo, COL_INFO)) {
@@ -4299,7 +4453,7 @@ proto_register_dcerpc (void)
           { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
 
         { &hf_dcerpc_dg_fack_window_size,
-          { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+          { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
 
         { &hf_dcerpc_dg_fack_max_tsdu,
           { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},