From Stefan Metzmacher:
[obnox/wireshark/wip.git] / epan / dissectors / packet-dcerpc.c
index d590cf2ad2a2a8d2a4bbf1cdfb2b7d635f3d3e8b..14b852147d7a38b381917bd458e96d449f84cb17 100644 (file)
@@ -1210,7 +1210,10 @@ dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
                /* real run, dissect the elements */
                for(i=0;i<di->array_actual_count;i++){
+                       old_offset = offset;
                        offset = (*fnct)(tvb, offset, pinfo, tree, drep);
+                        if (offset <= old_offset)
+                                THROW(ReportedBoundsError);
                }
        }
 
@@ -2124,7 +2127,7 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
     dcerpc_dissect_fnct_t *volatile sub_dissect;
     const char *volatile saved_proto;
     void *volatile saved_private_data;
-    guint length, reported_length;
+    guint length = 0, reported_length = 0;
     tvbuff_t *volatile stub_tvb;
     volatile guint auth_pad_len;
     volatile int auth_pad_offset;
@@ -2180,8 +2183,9 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
            proc->dissect_rqst : proc->dissect_resp;
 
     if (tree) {
-        sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
-                                        -1, FALSE);
+        sub_item = proto_tree_add_item (tree, sub_proto->proto_id,
+                                       (decrypted_tvb != NULL)?decrypted_tvb:tvb,
+                                       0, -1, FALSE);
 
         if (sub_item) {
             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
@@ -2192,28 +2196,27 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
          * Put the operation number into the tree along with
          * the operation's name.
          */
-    if(sub_dissect == NULL)
        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);
-
-    if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
-               pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
-                                   tvb, 0, 0, info->call_data->rep_frame);
-        PROTO_ITEM_SET_GENERATED(pi);
-    }
-    if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
-               pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
-                                   tvb, 0, 0, info->call_data->req_frame);
-        PROTO_ITEM_SET_GENERATED(pi);
-    }
+                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);
+
+        if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
+            pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
+                                     tvb, 0, 0, info->call_data->rep_frame);
+            PROTO_ITEM_SET_GENERATED(pi);
+       }
+        if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
+            pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
+                                     tvb, 0, 0, info->call_data->req_frame);
+            PROTO_ITEM_SET_GENERATED(pi);
+       }
     } /* tree */
 
     if (decrypted_tvb != NULL) {
@@ -2228,12 +2231,13 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
 
             init_ndr_pointer_list(pinfo);
 
+            length = tvb_length(decrypted_tvb);
+            reported_length = tvb_reported_length(decrypted_tvb);
+
             /*
              * Remove the authentication padding from the stub data.
              */
             if (auth_info != NULL && auth_info->auth_pad_len != 0) {
-                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
@@ -2251,7 +2255,7 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
                     if (length > reported_length)
                         length = reported_length;
 
-                    stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+                    stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
                     auth_pad_len = auth_info->auth_pad_len;
                     auth_pad_offset = reported_length;
                 } else {
@@ -2264,6 +2268,8 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
                     stub_tvb = NULL;
                     auth_pad_len = reported_length;
                     auth_pad_offset = 0;
+                    length = 0;
+                    reported_length = 0;
                 }
             } else {
                 /*
@@ -2274,6 +2280,10 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
                 auth_pad_offset = 0;
             }
 
+            if (sub_item) {
+               proto_item_set_len(sub_item, length);
+            }
+
             if (stub_tvb != NULL) {
                 /*
                  * Catch all exceptions other than BoundsError, so that even
@@ -2285,25 +2295,31 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
                  * dissect; just re-throw that exception.
                  */
                 TRY {
-                    offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
+                    int remaining;
+
+                    offset = sub_dissect (stub_tvb, 0, pinfo, sub_tree,
                                           drep);
-                    if(tree) {
-                        proto_item_set_len(sub_item, offset);
-                    }
 
                     /* If we have a subdissector and it didn't dissect all
                        data in the tvb, make a note of it. */
-                    /* XXX - don't do this, as this could be just another RPC Req./Resp. in this PDU */
-                    /*if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
+                    remaining = tvb_reported_length_remaining(stub_tvb, offset);
+                    if (remaining > 0) {
+                        proto_tree_add_text(sub_tree, stub_tvb, offset,
+                                            remaining,
+                                            "[Long frame (%d byte%s)]",
+                                            remaining,
+                                            plurality(remaining, "", "s"));
                         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));
-                    }*/
+                                            "[Long frame (%d byte%s)]",
+                                            remaining,
+                                            plurality(remaining, "", "s"));
+
+                    }
                 } CATCH(BoundsError) {
                     RETHROW;
                 } CATCH_ALL {
-                    show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
+                    show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
                 } ENDTRY;
             }
 
@@ -2550,7 +2566,7 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                         * prepend a delimiter */
                        col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
                }
-      } 
+      }
 
       /* save context ID for use with dcerpc_add_conv_to_bind_table() */
       /* (if we have multiple contexts, this might cause "decode as"
@@ -2587,11 +2603,11 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
       if(uuid_name) {
                  proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
                                         offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
-          proto_item_append_text(iface_item, "%s", uuid_name);
+          proto_item_append_text(iface_item, "%s", uuid_name);
       } else {
           proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
                                         offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
-          proto_item_append_text(iface_item, "%s", uuid_str);
+          proto_item_append_text(iface_item, "%s", uuid_str);
       }
       }
       offset += 16;
@@ -2766,7 +2782,7 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
         if (ctx_tree) {
             proto_tree_add_guid_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
-                                          offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", 
+                                          offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
                                           guid_to_str((e_guid_t *) &trans_id));
         }
         offset += 16;
@@ -2995,7 +3011,7 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
        nor the first fragment then there is nothing more we can do
        so we just have to exit
     */
-    if( !dcerpc_reassemble )
+    if( !dcerpc_reassemble || (tvb_length(tvb)!=tvb_reported_length(tvb)) )
         goto end_cn_stub;
 
     /* if we didnt get 'frame' we dont know where the PDU started and thus
@@ -3021,9 +3037,9 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
     /* defragmentation is a bit tricky, as there's no offset of the fragment
      * in the protocol data.
      *
-        * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
-        * in with the correct sequence.
-    */
+     * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
+     * in with the correct sequence.
+     */
     fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
                dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
                tvb_length(decrypted_tvb),
@@ -3060,8 +3076,8 @@ end_cn_stub:
            pinfo->fragmented = FALSE;
 
                expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
-                       "%s fragment, %u bytes reassembled here in #%u",
-                       fragment_type(hdr->flags), fd_head->len, fd_head->reassembled_in);
+                       "%s fragment, reassembled",
+                       fragment_type(hdr->flags));
 
            dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
                next_tvb, hdr->drep, di, auth_info);
@@ -3195,7 +3211,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                         * prepend a delimiter */
                        col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
                }
-    } 
+    }
 
     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                     hf_dcerpc_opnum, &opnum);
@@ -3212,7 +3228,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
         if (dcerpc_tree) {
             proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
-                                          offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s", 
+                                          offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
                                           guid_to_str((e_guid_t *) &obj_id));
         }
         offset += 16;
@@ -3291,6 +3307,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                                call_value->req_time=pinfo->fd->abs_ts;
                                call_value->rep_frame=0;
                                call_value->max_ptr=0;
+                               call_value->se_data = NULL;
                                call_value->private_data = NULL;
                                g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
 
@@ -3330,8 +3347,8 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* no bind information, simply show stub data */
         pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
         PROTO_ITEM_SET_GENERATED(pi);
-           expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u (Call ID:%u)", 
-            ctx_id, hdr->call_id);
+           expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
+            ctx_id);
            show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
         }
     }
@@ -3373,7 +3390,7 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                         * prepend a delimiter */
                        col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
                }
-    } 
+    }
 
 
     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
@@ -3468,7 +3485,7 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
         PROTO_ITEM_SET_GENERATED(pi);
         } else {
-                   pi = proto_tree_add_text(dcerpc_tree, 
+                   pi = proto_tree_add_text(dcerpc_tree,
                                        tvb, 0, 0, "No request to this DCE/RPC call found");
                    expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
                            "No request to this DCE/RPC call found");
@@ -3481,8 +3498,8 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
             /* no bind information, simply show stub data */
             pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
             PROTO_ITEM_SET_GENERATED(pi);
-               expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u (Call ID:%u)", 
-                ctx_id, hdr->call_id);
+               expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
+                ctx_id);
             show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
         }
     }
@@ -3517,7 +3534,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                         * prepend a delimiter */
                        col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
                }
-    } 
+    }
 
     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_cancel_count, NULL);
@@ -3619,7 +3636,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
         PROTO_ITEM_SET_GENERATED(pi);
         } else {
-                   pi = proto_tree_add_text(dcerpc_tree, 
+                   pi = proto_tree_add_text(dcerpc_tree,
                                        tvb, 0, 0, "No request to this DCE/RPC call found");
                    expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
                            "No request to this DCE/RPC call found");
@@ -4496,6 +4513,7 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
        call_value->req_time=pinfo->fd->abs_ts;
        call_value->rep_frame=0;
        call_value->max_ptr=0;
+       call_value->se_data = NULL;
        call_value->private_data = NULL;
        g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
 
@@ -4516,6 +4534,7 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
         v.req_frame = pinfo->fd->num;
         v.rep_frame = 0;
         v.max_ptr = 0;
+        v.se_data=NULL;
         v.private_data=NULL;
         value = &v;
     }
@@ -4579,6 +4598,7 @@ dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
         v.opnum = hdr->opnum;
         v.req_frame=0;
         v.rep_frame=pinfo->fd->num;
+        v.se_data=NULL;
         v.private_data=NULL;
         value = &v;
     }
@@ -4602,7 +4622,7 @@ dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
        pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
     PROTO_ITEM_SET_GENERATED(pi);
     } else {
-               pi = proto_tree_add_text(dcerpc_tree, 
+               pi = proto_tree_add_text(dcerpc_tree,
                                    tvb, 0, 0, "No request to this DCE/RPC call found");
                expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
                        "No request to this DCE/RPC call found");
@@ -4662,6 +4682,8 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     int offset = 0;
     conversation_t *conv;
     int auth_level;
+    char *uuid_str;
+    const char *uuid_name = NULL;
 
     /*
      * Check if this looks like a CL DCERPC call.  All dg packets
@@ -4816,15 +4838,21 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
     if (tree) {
         proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
-            offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s", 
+            offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
             guid_to_str((e_guid_t *) &hdr.obj_id));
     }
     offset += 16;
 
     if (tree) {
-        proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
-                                      offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s",
-                                      guid_to_str((e_guid_t *) &hdr.if_id));
+        uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
+        uuid_name = guids_get_uuid_name(&hdr.if_id);
+        if(uuid_name) {
+                 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
+                                        offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
+        } else {
+          proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
+                                        offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
+        }
     }
     offset += 16;
 
@@ -4967,7 +4995,10 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         break;
 
     case PDU_FACK:
-        dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
+        /* Body is optional */
+        /* XXX - we assume "frag_len" is the length of the body */
+        if (hdr.frag_len != 0)
+            dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
         break;
 
     case PDU_REJECT: