Ethereal-dev: Re: [Ethereal-dev] New release rush - small patch for packet-dcerpc.c, big patch

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

From: Yaniv Kaul <ykaul@xxxxxxxxxxxx>
Date: Mon, 27 Oct 2003 15:02:17 +0200
I apologize for the (usual) mess I'm doing while submitting patches.
Attached please find a patch of packet-dcerpc-oxid.c against the Oct30 CVS - I hope it makes more sense.
I believe you can remove packet-dcerpc-dcom.h - it's not needed.

As for the mail - it's Mozilla 1.5 under Win. I don't know what it changes with the attachements (or why).

Guy Harris wrote:


On Oct 22, 2003, at 2:33 PM, Guy Harris wrote:

On Oct 22, 2003, at 4:52 AM, Yaniv Kaul wrote:

2. Big patch for packet-oxid.c, that is accompanied by a helper file - packet-dcerpc-dcom.c (which will also be used in future patches that I'll send regarding other DCOM interfaces).


...and another helper file, packet-dcerpc-dcom.h.

However, "packet-dcerpc-dcom.h" isn't used, and "packet-dcerpc-dcom.c" is included by "packet-dcerpc-oxid.c". Curently (as of 1.8), "packet-dcerpc-oxid.c" includes "packet-dcerpc-dcom.h"; is that what *should* be included, with "packet-dcerpc-dcom.c" being compiled as a separate source file?

(Also, for some reason, all the files attached to your message had "Content-Disposition: inline"; that meant that my mail reader at work (Mac OS X Mail.app) showed them, well, inline, rather than as attachments, as per RFC 2183:

    2.1  The Inline Disposition Type

       A bodypart should be marked `inline' if it is intended to be
       displayed automatically upon display of the message.  Inline
       bodyparts should be presented in the order in which they occur,
       subject to the normal semantics of multipart messages.

and, unfortunately, didn't have a way to let me extract them.

If you can make them show up as attachments, with "Content-Disposition: attachment":

    2.2  The Attachment Disposition Type

       Bodyparts can be designated `attachment' to indicate that they are
       separate from the main body of the mail message, and that their
       display should not be automatic, but contingent upon some further
       action of the user.  The MUA might instead present the user of a
bitmap terminal with an iconic representation of the attachments, or,
       on character terminals, with a list of attachments from which the
       user could select for viewing or storage.

that'd make it easier to extract them.)


--- ../ethereal-2003-10-27/packet-dcerpc-oxid.c	Sun Oct 12 18:03:10 2003
+++ ./packet-dcerpc-oxid.c	Mon Oct 27 14:57:42 2003
@@ -2,7 +2,7 @@
  * Routines for DCOM OXID Resolver
  * Copyright 2001, Todd Sabin <tas@xxxxxxxxxxx>
  *
- * $Id: packet-dcerpc-oxid.c,v 1.10 2003/10/12 16:03:10 sharpe Exp $
+ * $Id: packet-dcerpc-oxid.c,v 1.6 2003/06/26 04:30:28 tpot Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@xxxxxxxxxxxx>
@@ -32,7 +32,7 @@
 #include <glib.h>
 #include <epan/packet.h>
 #include "packet-dcerpc.h"
-#include "packet-dcerpc-dcom.h"
+#include "packet-dcerpc-dcom.c"
 #include "packet-smb-common.h"
 
 static int proto_oxid = -1;
@@ -46,130 +46,28 @@
 static int hf_aNetworkAddr = -1;
 static int hf_wAuthnSvc = -1;
 static int hf_wAuthzSvc = -1;
-static int hf_aPrinceName = -1;
-static int hf_Unknown1 = -1;
-static int hf_Unknown2 = -1;
+static int hf_aPrincName = -1;
+static int hf_oxid = -1;
+static int hf_cRequestedProseqs = -1;
+static int hf_RequestedProseqs = -1;
+static int hf_conformant_size = -1;
+static int hf_pAuthHint = -1;
+static int hf_IPID = -1;
+static int hf_pSetId = -1;
+static int hf_OID = -1;
 
 static gint ett_oxid = -1;
 
 static e_uuid_t uuid_oxid = { 0x99fcfec4, 0x5260, 0x101b, { 0xbb, 0xcb, 0x00, 0xaa, 0x00, 0x21, 0x34, 0x7a } };
 static guint16  ver_oxid = 0;
 
-static const char *
-authz_val2str(unsigned short authz) {
-	switch (authz) {
-		case 0:
-			return "RPC_C_AUTHZ_NONE";
-			break;
-		case 1:
-			return "RPC_C_AUTHZ_NAME";
-			break;
-		case 2:
-			return "RPC_C_AUTHZ_DCE";
-			break;
-		case 0xffff: 
-			return "Default";
-			break;
-		default: 
-			return "Unknown";
-			break;
-	}
-}
-
-static const char *
-authn_val2str(unsigned short authn) {
-	switch (authn) {
-		case 0:
-			return "RPC_C_AUTHN_NONE";
-			break;
-		case 1:
-			return "RPC_C_AUTHN_DCE_PRIVATE";
-			break;
-		case 2: 
-			return "RPC_C_AUTHN_DCE_PUBLIC";
-			break;
-		case 4: 
-			return "RPC_C_AUTHN_DEC_PUBLIC";
-			break;
-		case 9: 
-			return "RPC_C_AUTHN_GSS_NEGOTIATE";
-			break;
-		case 10:
-			return "RPC_C_AUTH_WINNT";
-			break;
-		case 14:
-			return "RPC_C_AUTHN_GSS_SCHANNEL";
-			break;
-		case 16: 
-			return "RPC_C_AUTHN_GSS_KERBEROS";
-			break;
-		case 17: 
-			return "RPC_C_AUTHN_MSN";
-			break;
-		case 18:
-			return "RPC_C_AUTHN_DPA";
-			break;
-		case 100:
-			return "RPC_C_AUTHN_MQ";
-			break;
-		case 0xffff:
-			return "RPC_C_AUTHN_DEFAULT";
-			break;
-		default:
-			return "Unknown";
-			break;
-	}
-}
-
-static const char *
-towerid_val2str(unsigned short tower) {
-	switch (tower) {
-		case 0x4:
-			return "NCACN_DNET_NSP";
-			break;
-		case 0x7: 
-			return "NCACN_IP_TCP";
-			break;
-		case 0x8:
-			return "NCADG_IP_UDP";
-			break;
-		case 0xC:
-			return "NCACN_SPX";
-			break;
-
-		case 0xD:
-			return "NCACN_NB_IPX";
-			break;
-		case 0xE:
-			return "NCADG_IPX";
-			break;
-		case 0x12: 
-			return "NCACN_NB_NB";
-			break;
-		case 0x1F:
-			return "NCACN_HTTP";
-			break;
-		default:
-			return "Unknown";
-			break;
-	}
-}
-
 static int
-oxid_server_alive2_dissect_rply(tvbuff_t *tvb, int offset, packet_info *pinfo, 
-				proto_tree *tree, char *drep) {
+oxid5_dissect_rply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) {
+
 	COMVERSION comver;
 	DUALSTRINGARRAY stringarray;
-	STRINGBINDING stringbind;
-	SECURITYBINDING securitybind;
- 	proto_item *bind_hdr, *entries_hdr, *sec_hdr;
-	proto_tree *bind_tree, *entries_tree, *sec_tree;	
-	char *aNetworkAddr = NULL;
-	char *aPrinceName = NULL;
-	unsigned short string_len = 0;
-	unsigned short security_len = 0;
 	unsigned char unknown1[8];
-	unsigned char unknown2[8];
+	guint32 len1;
 
 	dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_COMVERSION_MjrVer, &comver.MajorVersion);
 	offset += sizeof(comver.MajorVersion);
@@ -177,62 +75,126 @@
 	dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_COMVERSION_MnrVer, &comver.MinorVersion);
 	offset += sizeof(comver.MinorVersion);
 
-	dissect_dcerpc_uint64(tvb , offset, pinfo, tree, drep, hf_Unknown1, unknown1);
+	proto_tree_add_text(tree, tvb, offset, 4, "-alignment-");
+	offset += 4;
 
-	offset += sizeof(unknown1); /*FIXME - understand what those 8 bytes mean! don't skip'em!*/
-	string_len = dcerpc_tvb_get_ntohs(tvb, offset, drep) * 2;
-	bind_hdr = proto_tree_add_text(tree, tvb, offset, (int)string_len, "DUALSTRINGARRAY structure");
-	bind_tree = proto_item_add_subtree(bind_hdr, 0);
+	len1 = dcerpc_tvb_get_ntohl(tvb, offset, drep);
+	proto_tree_add_text(tree, tvb, offset, 4, "Size of DUALSTRINGARRAY to follow (in 16 bytes blocks): %d", len1);
+	offset += 4;
 
-	dissect_dcerpc_uint16(tvb, offset, pinfo, bind_tree, drep, hf_wNumEntries, &stringarray.wNumEntries);
-	offset += sizeof(stringarray.wNumEntries);
+	offset = dcom_dissect_DUALSTRINGARRAY(tvb, offset, pinfo, tree, drep, &stringarray, hf_wNumEntries, hf_wSecurityOffset, hf_aNetworkAddr, hf_aPrincName);
 
-	security_len = dcerpc_tvb_get_ntohs(tvb, offset, drep) * 2;
-	dissect_dcerpc_uint16(tvb, offset, pinfo, bind_tree, drep, hf_wSecurityOffset, &stringarray.wSecurityOffset);
-        offset += sizeof(stringarray.wSecurityOffset);
+	proto_tree_add_text(tree, tvb, offset, 8, "Unknown 8 bytes");
+	offset += 8;
+        return offset;
+}
 
-	entries_hdr = proto_tree_add_text(bind_tree, tvb, offset, (int)security_len, "STRING BINDING");
-	entries_tree = proto_item_add_subtree(entries_hdr, 0);
+static int
+resolveOxid2_dissect_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) {
+	unsigned char oxid[8];
+	guint16 cRequestedProseqs, RequestedProseqs;
+	guint32 i, conformant_size;
 
-	while(tvb_get_ntohs(tvb, offset) != 0) { /* check that this is not terminating zero */
-		
-		stringbind.wTowerId = dcerpc_tvb_get_ntohs(tvb, offset, drep);
-		proto_tree_add_text(entries_tree, tvb, offset, sizeof(stringbind.wTowerId), "Network Protocol ('TowerID'): %s (0x%x)",towerid_val2str(stringbind.wTowerId), stringbind.wTowerId);
+	dissect_dcerpc_uint64(tvb, offset, pinfo, tree, drep, hf_oxid, oxid);
+	offset += sizeof(oxid);
+	
+	dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_cRequestedProseqs, &cRequestedProseqs);	
+	offset += sizeof(RequestedProseqs);
+	
+	offset += 2; //alignment
+	dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_conformant_size, &conformant_size);
+	offset += sizeof(conformant_size);
+
+	for(i=0; i != cRequestedProseqs; i++) {
+		RequestedProseqs = dcerpc_tvb_get_ntohs(tvb, offset, drep);
+		proto_tree_add_text(tree, tvb, offset, sizeof(RequestedProseqs), "Protocol Sequence: %s (0x%x)", towerid_val2str(RequestedProseqs), RequestedProseqs);
+		offset += sizeof(RequestedProseqs);
+	}
 
-		offset += sizeof(stringbind.wTowerId);
+	return offset;
+}
 
-		offset = display_unicode_string(tvb, entries_tree, offset, hf_aNetworkAddr, &aNetworkAddr);	
-	}	
-	offset += 2; /* hop over the extra terminating zero */
+static int
+resolveOxid2_dissect_rply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) {
+	COMVERSION comver;
+        DUALSTRINGARRAY stringarray;
+	e_uuid_t IPID;
+	guint32 pAuthHint, len1;
+
+	proto_tree_add_text(tree, tvb, offset, 4, "Unknown 4 bytes");
+	offset +=4;
+
+	len1 = dcerpc_tvb_get_ntohl(tvb, offset, drep);
+        proto_tree_add_text(tree, tvb, offset, 4, "Size of DUALSTRINGARRAY to follow (in 16 bytes blocks): %d", len1);
+        offset += 4;
 	
-	sec_hdr = proto_tree_add_text(bind_tree, tvb, offset, 0, "SECURITY BINDING");
-        sec_tree = proto_item_add_subtree(sec_hdr, 0);
+	offset = dcom_dissect_DUALSTRINGARRAY(tvb, offset, pinfo, tree, drep, &stringarray, hf_wNumEntries, hf_wSecurityOffset, hf_aNetworkAddr, hf_aPrincName);
 
-	while(tvb_get_ntohs(tvb, offset) != 0) {
-		securitybind.wAuthnSvc = dcerpc_tvb_get_ntohs(tvb, offset, drep);
-                proto_tree_add_text(sec_tree, tvb, offset, sizeof(securitybind.wAuthnSvc), "Authentication Service: %s (0x%x)",authn_val2str(securitybind.wAuthnSvc),securitybind.wAuthnSvc);
-		offset += sizeof(securitybind.wAuthnSvc);
-
-		securitybind.wAuthzSvc = dcerpc_tvb_get_ntohs(tvb, offset, drep);
-		proto_tree_add_text(sec_tree, tvb, offset, sizeof(securitybind.wAuthzSvc), "Authorization Service: %s (0x%x)",authz_val2str(securitybind.wAuthzSvc),securitybind.wAuthzSvc);
-		offset += sizeof(securitybind.wAuthzSvc);
+	offset = dcom_dissect_uuid(tvb, offset, tree, drep, &IPID, hf_IPID, "IPID");
 
-		offset = display_unicode_string(tvb, sec_tree, offset, hf_aPrinceName, &aPrinceName);
-	}
-	offset += 2; /* hop over the extra terminating zero */
+	dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pAuthHint, &pAuthHint);
+        offset += sizeof(pAuthHint);
+
+	dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_COMVERSION_MjrVer, &comver.MajorVersion);
+        offset += sizeof(comver.MajorVersion);
+
+        dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_COMVERSION_MnrVer, &comver.MinorVersion);
+        offset += sizeof(comver.MinorVersion);
+
+	proto_tree_add_text(tree, tvb, offset, 4, "unknown 4 bytes (usually 0 - alignment?): %d", dcerpc_tvb_get_ntohl(tvb, offset, drep));
+	offset +=4;
+
+	return offset;
+}
+
+static int
+ComplexPing_dissect_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) {
+	unsigned char pSetId[8];
+	unsigned char OID[8];
+	int i;
+	guint16 SequenceNum, cAddToSet, cDelFromSet;
+
+	dissect_dcerpc_uint64(tvb, offset, pinfo, tree, drep, hf_pSetId, pSetId);
+        offset += sizeof(pSetId);
+
+	SequenceNum = dcerpc_tvb_get_ntohs(tvb, offset, drep);
+	proto_tree_add_text(tree, tvb, offset, sizeof(SequenceNum), "SeuqnceNum: %d", SequenceNum);
+	offset += sizeof(SequenceNum);
 	
-	dissect_dcerpc_uint64(tvb, offset, pinfo, tree, drep, hf_Unknown2, unknown2);
-	offset += sizeof(unknown2);
-        return offset;
+	cAddToSet = dcerpc_tvb_get_ntohs(tvb, offset, drep);
+        proto_tree_add_text(tree, tvb, offset, sizeof(cAddToSet), "cAddToSet: %d", cAddToSet);
+        offset += sizeof(cAddToSet);
+
+	cDelFromSet = dcerpc_tvb_get_ntohs(tvb, offset, drep);
+        proto_tree_add_text(tree, tvb, offset, sizeof(cDelFromSet), "cDelFromSet: %d", cDelFromSet);
+        offset += sizeof(cDelFromSet);
+
+	if(cAddToSet) {
+		proto_tree_add_text(tree, tvb, offset, sizeof(OID)*cAddToSet, "List of OIDs to add");
+		for(i=0; i != (int)cAddToSet; i++) {
+			dissect_dcerpc_uint64(tvb, offset, pinfo, tree, drep, hf_OID, OID);
+			offset += sizeof(OID);
+		}
+	}
+
+	if(cDelFromSet) {
+		proto_tree_add_text(tree, tvb, offset, sizeof(OID)*cDelFromSet, "List of OIDs to delete");
+		for(i=0; i != (int)cDelFromSet; i++) {
+                	dissect_dcerpc_uint64(tvb, offset, pinfo, tree, drep, hf_OID, OID);
+                	offset += sizeof(OID);
+        	}
+	}
+
+	return offset;
 }
 
 static dcerpc_sub_dissector oxid_dissectors[] = {
     { 0, "ResolveOxid", NULL, NULL },
     { 1, "SimplePing", NULL, NULL },
-    { 2, "ComplexPing", NULL, NULL },
+    { 2, "ComplexPing", ComplexPing_dissect_rqst, NULL },
     { 3, "ServerAlive", NULL, NULL },
-    { 4, "ResolveOxid2", NULL, NULL },
-    { 5, "ServerAlive2", NULL, oxid_server_alive2_dissect_rply },
+    { 4, "ResolveOxid2", resolveOxid2_dissect_rqst, resolveOxid2_dissect_rply },
+    { 5, "ServerAlive2", NULL, oxid5_dissect_rply },
     { 0, NULL, NULL, NULL },
 };
 
@@ -259,12 +221,24 @@
                   { "Authentication Service", "oxid5.AuthnSvc", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
                 { &hf_wAuthzSvc,
                   { "Autherization Service", "oxid5.AuthzSvc", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
-		{ &hf_aPrinceName,
-                  { "aPrinceName", "oxid5.aPrinceName", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
-		{ &hf_Unknown1,
-		  { "unknown 8 bytes 1", "oxid5.unknown1", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }},
-		{ &hf_Unknown2,
-                  { "unknown 8 bytes 2", "oxid5.unknown2", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }},
+		{ &hf_aPrincName,
+                  { "aPrincName", "oxid5.aPrincName", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+		{ &hf_oxid,
+		  { "OXID", "ResolveOxid2.OXID", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }},
+		{ &hf_cRequestedProseqs,
+		  { "cRequestedProseqs", "ResolveOxid2.cRequestedProseqs", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+		{ &hf_conformant_size,
+		  { "array conformant size", "ResolveOxid2.conformant_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+		{ &hf_RequestedProseqs,
+		  { "RequestedProseqs", "ResolveOxid2.RequestedProseqs", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+		{ &hf_IPID,
+ 		  { "IPID", "ResolveOxid2.ipid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+		{ &hf_pAuthHint,
+		  { "Authentication Hint", "ResolveOxid2.pAuthHint", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
+		{ &hf_OID,
+		  { "OID", "ComplexPing.OID", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }},
+		{ &hf_pSetId,
+		  { "pSetId", "ComplexPing.pSetId", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }},
 	};
 	static gint *ett[] = {
 		&ett_oxid
@@ -277,6 +251,14 @@
 void
 proto_reg_handoff_oxid (void)
 {
+	header_field_info *hf_info;
+
 	/* Register the protocol as dcerpc */
 	dcerpc_init_uuid (proto_oxid, ett_oxid, &uuid_oxid, ver_oxid, oxid_dissectors, hf_opnum);
+
+	/* Set opnum strings from subdissector list */
+
+	hf_info = proto_registrar_get_nth(hf_opnum);
+	hf_info->strings = value_string_from_subdissectors(
+		oxid_dissectors); //, array_length(oxid_dissectors));
 }
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif


#include <string.h>

#include <glib.h>
#include <epan/packet.h>

#include "packet-dcerpc.h"
#include "packet-smb-common.h"

typedef struct tagCOMVERSION
{
        guint16 MajorVersion;
        guint16 MinorVersion;
    } COMVERSION;

typedef struct tagORPC_EXTENT
    {
        e_uuid_t id;
        guint32 size;
/*        guint8 data[];  */
    } ORPC_EXTENT;

typedef struct tagORPC_EXTENT_ARRAY
    {
        guint32 size;
        guint32 reserved;
        ORPC_EXTENT **extent;
    } ORPC_EXTENT_ARRAY;

typedef struct tagORPCTHIS {
    COMVERSION version;
    guint32 flags;
    guint32 reserved1;
    e_uuid_t  cid;
    ORPC_EXTENT_ARRAY *extensions;
 } ORPCTHIS;

typedef struct tagMInterfacePointer {
    guint32 ulCntData;
/*  guint8 abData[];  */
 } MInterfacePointer,  *PMInterfacePointer;

typedef struct tagORPCTHAT {
    guint32 flags;
    ORPC_EXTENT_ARRAY *extensions;
 } ORPCTHAT;

typedef struct tagSTRINGBINDING {
    unsigned short wTowerId;     // Cannot be zero.
    char *aNetworkAddr; // Zero terminated.
 } STRINGBINDING;

typedef struct tagSECURITYBINDING {
    unsigned short wAuthnSvc;  // Cannot be zero.
    unsigned short wAuthzSvc;  // Must not be zero.
    char  *aPrinceName; // Zero terminated.
 }  SECURITYBINDING;

typedef struct tagDUALSTRINGARRAY {
    unsigned short wNumEntries;     // Number of entries in array.
    unsigned short wSecurityOffset; // Offset of security info.
        STRINGBINDING stringbind;
        SECURITYBINDING securitybind;
/*  [size_is(wNumEntries)] unsigned short aStringArray[]; */
    } DUALSTRINGARRAY;

static const char *
authz_val2str(unsigned short authz) {
	switch (authz) {
		case 0:
			return "RPC_C_AUTHZ_NONE";
			break;
		case 1:
			return "RPC_C_AUTHZ_NAME";
			break;
		case 2:
			return "RPC_C_AUTHZ_DCE";
			break;
		case 0xffff: 
			return "Default";
			break;
		default: 
			return "Unknown";
			break;
	}
}

static const char *
authn_val2str(unsigned short authn) {
	switch (authn) {
		case 0:
			return "RPC_C_AUTHN_NONE";
			break;
		case 1:
			return "RPC_C_AUTHN_DCE_PRIVATE";
			break;
		case 2: 
			return "RPC_C_AUTHN_DCE_PUBLIC";
			break;
		case 4: 
			return "RPC_C_AUTHN_DEC_PUBLIC";
			break;
		case 9: 
			return "RPC_C_AUTHN_GSS_NEGOTIATE";
			break;
		case 10:
			return "RPC_C_AUTH_WINNT";
			break;
		case 14:
			return "RPC_C_AUTHN_GSS_SCHANNEL";
			break;
		case 16: 
			return "RPC_C_AUTHN_GSS_KERBEROS";
			break;
		case 17: 
			return "RPC_C_AUTHN_MSN";
			break;
		case 18:
			return "RPC_C_AUTHN_DPA";
			break;
		case 100:
			return "RPC_C_AUTHN_MQ";
			break;
		case 0xffff:
			return "RPC_C_AUTHN_DEFAULT";
			break;
		default:
			return "Unknown";
			break;
	}
}

static const char *
towerid_val2str(unsigned short tower) {
	switch (tower) {
		case 0x4:
			return "NCACN_DNET_NSP";
			break;
		case 0x7: 
			return "NCACN_IP_TCP";
			break;
		case 0x8:
			return "NCADG_IP_UDP";
			break;
		case 0xC:
			return "NCACN_SPX";
			break;

		case 0xD:
			return "NCACN_NB_IPX";
			break;
		case 0xE:
			return "NCADG_IPX";
			break;
		case 0x12: 
			return "NCACN_NB_NB";
			break;
		case 0x1F:
			return "NCACN_HTTP";
			break;
		default:
			return "Unknown";
			break;
	}
}
static const char *
objref_flags_val2str(unsigned long flags) {
	switch (flags) {
		case 0x0:
			return "NULL - not a reference to an object";
			break; 
		case 0x1:
			return "standard marshaled objref";
			break;
		case 0x2:
			return "handler marshaled objref";
			break;
		case 0x4:
			return "custom marshaled objref";
			break;
		default:
			return "unknown objref flag!";
			break;
	}
}

static const char *
hresult_val2str(unsigned long hres) {
        switch (hres) {
		case 0x0:
				return "S_OK";
				break;
		case 0x80000002:
		case 0x8007000E:
				return "E_OUTOFMEMORY";
				break;
		case 0x80000003:
		case 0x80070057:
				return "E_INVALIDARG";
				break;
		case 0x80000004:
		case 0x80004002:
				return "E_NOINTERFACE";
				break;
		case 0x8000FFFF:
				return "E_UNEXPECTED";
				break;
		case 0x80040154:
                                return "REGDB_E_CLASSNOTREG";
                                break;
		case 0x80070005:
                                return "E_ACCESSDENIED";
                                break;
		case 0x80070776:
				return "RPC_E_INVALID_OXID";
				break;
		case 0x80070777:
				return "RPC_E_INVALID_OID";
				break;
		case 0x80070778:
				return "RPC_E_INVALID_SET";
				break;
		case 0x80080004: 
				return "CO_E_BAD_PATH (Bad path to object)";
				break;
		default:
				return "Unknown HRESULT - try at Winerror.h";
				break;
		}
}

static int
dcom_dissect_DUALSTRINGARRAY(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep, DUALSTRINGARRAY *stringarray, int hf_wNumEntries, int hf_wSecurityOffset, int hf_aNetworkAddr, int hf_aPrinceName) {
	
	proto_item *bind_hdr, *entries_hdr, *sec_hdr;
    	proto_tree *bind_tree, *entries_tree, *sec_tree;
    	unsigned short string_len = 0;
	unsigned short security_len = 0;
	
	string_len = dcerpc_tvb_get_ntohs(tvb, offset, drep) * 2;
	bind_hdr = proto_tree_add_text(tree, tvb, offset, (int)string_len + 4, "DUALSTRINGARRAY structure");
	bind_tree = proto_item_add_subtree(bind_hdr, 0);

	dissect_dcerpc_uint16(tvb, offset, pinfo, bind_tree, drep, hf_wNumEntries, &stringarray->wNumEntries);
	offset += sizeof(stringarray->wNumEntries);

	security_len = dcerpc_tvb_get_ntohs(tvb, offset, drep) * 2;
	dissect_dcerpc_uint16(tvb, offset, pinfo, bind_tree, drep, hf_wSecurityOffset, &stringarray->wSecurityOffset);
        offset += sizeof(stringarray->wSecurityOffset);
	
	if(stringarray->wNumEntries == 0)
		return offset;

	entries_hdr = proto_tree_add_text(bind_tree, tvb, offset, (int)security_len, "STRING BINDING");
	entries_tree = proto_item_add_subtree(entries_hdr, 0);

	while(tvb_get_ntohs(tvb, offset) != 0) { // check that this is not terminating zero
		
		stringarray->stringbind.wTowerId = dcerpc_tvb_get_ntohs(tvb, offset, drep);
		proto_tree_add_text(entries_tree, tvb, offset, sizeof(stringarray->stringbind.wTowerId), "Network Protocol ('TowerID'): %s (0x%x)",towerid_val2str(stringarray->stringbind.wTowerId), stringarray->stringbind.wTowerId);

		offset += sizeof(stringarray->stringbind.wTowerId);

		offset = display_unicode_string(tvb, entries_tree, offset, hf_aNetworkAddr, &stringarray->stringbind.aNetworkAddr);	
	}	
	offset += 2; // hop over the extra terminating zero
	
	sec_hdr = proto_tree_add_text(bind_tree, tvb, offset, string_len - security_len , "SECURITY BINDING");
        sec_tree = proto_item_add_subtree(sec_hdr, 0);

	while(tvb_get_ntohs(tvb, offset) != 0) {
		stringarray->securitybind.wAuthnSvc = dcerpc_tvb_get_ntohs(tvb, offset, drep);
                proto_tree_add_text(sec_tree, tvb, offset, sizeof(stringarray->securitybind.wAuthnSvc), "Authentication Service: %s (0x%x)",authn_val2str(stringarray->securitybind.wAuthnSvc),stringarray->securitybind.wAuthnSvc);
		offset += sizeof(stringarray->securitybind.wAuthnSvc);

		stringarray->securitybind.wAuthzSvc = dcerpc_tvb_get_ntohs(tvb, offset, drep);
		proto_tree_add_text(sec_tree, tvb, offset, sizeof(stringarray->securitybind.wAuthzSvc), "Authorization Service: %s (0x%x)",authz_val2str(stringarray->securitybind.wAuthzSvc),stringarray->securitybind.wAuthzSvc);
		offset += sizeof(stringarray->securitybind.wAuthzSvc);

		offset = display_unicode_string(tvb, sec_tree, offset, hf_aPrinceName, &stringarray->securitybind.aPrinceName);
	}
	offset += 2; // hop over the extra terminating zero

	if ((string_len % 4) != 0) { // align to 4 bytes boundary
		proto_tree_add_text(tree, tvb, offset, string_len %4, "-alignment-");
		offset += (string_len %4);
	}
	return offset;
}
static void
dcom_format_uuid(e_uuid_t CLSID, char* uuid_str) {
        int uuid_str_len;

	uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", CLSID.Data1, CLSID.Data2, CLSID.Data3,CLSID.Data4[0], CLSID.Data4[1], CLSID.Data4[2], CLSID.Data4[3], CLSID.Data4[4], CLSID.Data4[5], CLSID.Data4[6], CLSID.Data4[7]);

        if(uuid_str_len >= DCERPC_UUID_STR_LEN)
                memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
}

static int
dcom_dissect_uuid(tvbuff_t *tvb, int offset, proto_tree *tree, char *drep, e_uuid_t *CLSID, int hf_CLSID, char *name) {

	char uuid_str[DCERPC_UUID_STR_LEN];

	dcerpc_tvb_get_uuid(tvb, offset, drep, CLSID);

	dcom_format_uuid(*CLSID, uuid_str);

    	proto_tree_add_string_format(tree, hf_CLSID, tvb, offset, sizeof(e_uuid_t), uuid_str,"%s: %s", name, uuid_str);
        offset += sizeof(e_uuid_t);


	return offset;
}