Ethereal-dev: [Ethereal-dev] [PATCH] fix for multiple dcerpc connections over single socket

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Tim Potter <tpot@xxxxxxxxx>
Date: Sun, 18 Nov 2001 10:48:34 +1100
Hi everyone.  Here's another msrpc patch.  Microsoft DCERPC over SMB
allows more than one DCERPC connection to be open over a single TCP/IP
socket.  Unfortunately there is no information in the DCERPC header
to determine which bind a particular request belongs to.  This 
information is the fid returned by the ntcreate&x and sent in the
smbtrans header.

I've added an extra entry to the conversation hash key which should
be zero for non-MSRPC DCERPC calls but set to the fid for MSRPC.
Hopefully I've done this in a nice transport independent way (I
alluded to this in my last message to the list) without making
the dcerpc dissector too ugly.

Guy, Ronnie, I would appreciate your input on this.


Regards,

Tim.
Index: packet-smb-pipe.c
===================================================================
RCS file: /cvsroot/ethereal/packet-smb-pipe.c,v
retrieving revision 1.41
diff -u -r1.41 packet-smb-pipe.c
--- packet-smb-pipe.c	2001/11/16 07:56:27	1.41
+++ packet-smb-pipe.c	2001/11/17 23:42:34
@@ -54,6 +54,7 @@
 #include "smb.h"
 #include "packet-smb-pipe.h"
 #include "packet-smb-browse.h"
+#include "packet-dcerpc.h"
 
 static int proto_smb_lanman = -1;
 static int hf_function_code = -1;
@@ -2198,10 +2199,19 @@
 static gboolean
 dissect_pipe_msrpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 {
+	dcerpc_private_info dcerpc_priv;
+	smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
         gboolean result;
 
+	dcerpc_priv.transport_type = DCERPC_TRANSPORT_SMB;
+	dcerpc_priv.data.smb.fid = smb_priv->fid;
+
+	pinfo->private_data = &dcerpc_priv;
+
         result = dissector_try_heuristic(msrpc_heur_subdissector_list, tvb,
                                          pinfo, parent_tree);
+
+	pinfo->private_data = smb_priv;
 
         if (!result)
                 dissect_data(tvb, 0, pinfo, parent_tree);
Index: packet-dcerpc.c
===================================================================
RCS file: /cvsroot/ethereal/packet-dcerpc.c,v
retrieving revision 1.14
diff -u -r1.14 packet-dcerpc.c
--- packet-dcerpc.c	2001/11/12 09:04:11	1.14
+++ packet-dcerpc.c	2001/11/17 23:42:40
@@ -234,6 +234,7 @@
 typedef struct _dcerpc_conv_key {
     conversation_t *conv;
     guint16 ctx_id;
+    guint16 smb_fid;
 } dcerpc_conv_key;
 
 static GMemChunk *dcerpc_conv_key_chunk;
@@ -251,14 +252,15 @@
     dcerpc_conv_key *key1 = (dcerpc_conv_key *)k1;
     dcerpc_conv_key *key2 = (dcerpc_conv_key *)k2;
     return (key1->conv == key2->conv
-            && key1->ctx_id == key2->ctx_id);
+            && key1->ctx_id == key2->ctx_id
+	    && key1->smb_fid == key2->smb_fid);
 }
 
 static guint
 dcerpc_conv_hash (gconstpointer k)
 {
     dcerpc_conv_key *key = (dcerpc_conv_key *)k;
-    return ((guint)key->conv) + key->ctx_id;
+    return ((guint)key->conv) + key->ctx_id + key->smb_fid;
 }
 
 
@@ -450,8 +452,10 @@
     }
 
     if (tree) {
+
         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, 
                                         tvb_length (tvb) - offset, FALSE);
+
         if (sub_item) {
             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
         }
@@ -536,6 +540,26 @@
 }
 
 
+/* We need to hash in the SMB fid number to generate a unique hash table
+   key as DCERPC over SMB allows several pipes over the same TCP/IP
+   socket. */
+
+static guint16 get_smb_fid(void *private_data)
+{
+	dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
+	
+	if (!priv)
+		return 0;	/* Nothing to see here */
+
+	/* DCERPC over smb */
+
+	if (priv->transport_type == DCERPC_TRANSPORT_SMB)
+		return priv->data.smb.fid;
+
+	/* Some other transport... */
+
+	return 0;
+}
 
 /*
  * Connection oriented packet types
@@ -618,6 +642,7 @@
         key = g_mem_chunk_alloc (dcerpc_conv_key_chunk);
         key->conv = conv;
         key->ctx_id = ctx_id;
+	key->smb_fid = get_smb_fid(pinfo->private_data);
 
         value = g_mem_chunk_alloc (dcerpc_conv_value_chunk);
         value->uuid = if_id;
@@ -798,6 +823,7 @@
 
         key.conv = conv;
         key.ctx_id = ctx_id;
+	key.smb_fid = get_smb_fid(pinfo->private_data);
 
         value = g_hash_table_lookup (dcerpc_convs, &key);
         if (value) {
Index: packet-dcerpc.h
===================================================================
RCS file: /cvsroot/ethereal/packet-dcerpc.h,v
retrieving revision 1.2
diff -u -r1.2 packet-dcerpc.h
--- packet-dcerpc.h	2001/07/11 01:25:45	1.2
+++ packet-dcerpc.h	2001/11/17 23:42:41
@@ -100,5 +100,20 @@
 /* registration function for subdissectors */
 void dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver, dcerpc_sub_dissector *procs);
 
+/* Private data structure to pass to DCERPC dissector. This is used to
+   pass transport specific information down to the dissector from the
+   dissector that parsed this encapsulated calls. */
+
+#define DCERPC_TRANSPORT_SMB  1
+
+typedef struct _dcerpc_private_info {
+    int transport_type;		/* Tag */
+
+    union {
+	struct {		/* DCERPC_TRANSPORT_SMB */
+	    guint16 fid;
+	} smb;
+    } data;
+} dcerpc_private_info;
 
 #endif /* packet-dcerpc.h */