From Tim Potter: dissect some of the LSA RPCs stub data.
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 16 Dec 2001 20:17:10 +0000 (20:17 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 16 Dec 2001 20:17:10 +0000 (20:17 +0000)
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@4407 f5534014-38df-0310-8fa8-9805f1628bb7

Makefile.am
Makefile.nmake
packet-dcerpc-lsa.c
packet-dcerpc-nt.c [new file with mode: 0644]
packet-dcerpc-nt.h [new file with mode: 0644]

index b9b41cf94a35b61d4fe6e59ec4955ed33f2d22b2..5426155264ffec8571634808df66c1b6ba041858 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile.am
 # Automake file for Ethereal
 #
-# $Id: Makefile.am,v 1.396 2001/12/15 23:56:04 guy Exp $
+# $Id: Makefile.am,v 1.397 2001/12/16 20:17:09 guy Exp $
 #
 # Ethereal - Network traffic analyzer
 # By Gerald Combs <gerald@ethereal.com>
@@ -457,6 +457,8 @@ ETHEREAL_COMMON_SRC = \
        llcsaps.h      \
        nlpid.h        \
        oui.h          \
+       packet-dcerpc-nt.h \
+       packet-dcerpc-nt.c \
        pcap-util.c    \
        pcap-util.h    \
        ppptypes.h     \
index d7a86e1ebf0dd7240b2bfce4daf2b61edcd02479..9ffabcd9cf10a4321adf11b3e0878716da92b603 100644 (file)
@@ -1,7 +1,7 @@
 ## Makefile for building ethereal.exe with Microsoft C and nmake
 ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
 #
-# $Id: Makefile.nmake,v 1.153 2001/12/12 01:29:01 guy Exp $
+# $Id: Makefile.nmake,v 1.154 2001/12/16 20:17:09 guy Exp $
 
 include config.nmake
 include <win32.mak>
@@ -256,6 +256,7 @@ ETHEREAL_COMMON_OBJECTS = \
        getopt.obj       \
        in_cksum.obj     \
        ipproto.obj      \
+       packet-dcerpc-nt.obj \
        pcap-util.obj    \
        prefs.obj        \
        print.obj        \
index 97797d4a430ceccfb420ba3f1e6051fd19ce8824..0560f15cf92238a44a6dd6f55a185756523e9843 100644 (file)
@@ -1,8 +1,8 @@
 /* packet-dcerpc-lsa.c
- * Routines for SMB \\PIPE\\lsarpc packet disassembly
+ * Routines for SMB \PIPE\lsarpc packet disassembly
  * Copyright 2001, Tim Potter <tpot@samba.org>
  *
- * $Id: packet-dcerpc-lsa.c,v 1.2 2001/12/09 00:07:37 guy Exp $
+ * $Id: packet-dcerpc-lsa.c,v 1.3 2001/12/16 20:17:10 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #endif
 
 #include <glib.h>
+#include <string.h>
+
 #include "packet.h"
 #include "packet-dcerpc.h"
+#include "packet-dcerpc-nt.h"
 #include "packet-dcerpc-lsa.h"
+#include "smb.h"
 
-static int proto_dcerpc_lsa = -1;
-static gint ett_dcerpc_lsa = -1;
+/*
+ * Parse a unicode string.
+ *
+ *  typedef struct {
+ *    short length;
+ *    short size;
+ *    [size_is(size/2)] [length_is(length/2)] [unique] wchar_t *string;
+ *  } UNICODE_STRING;
+ *
+ */
 
-static e_uuid_t uuid_dcerpc_lsa = {
-        0x12345778, 0x1234, 0xabcd, 
-        { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab}
-};
+/* Convert a (little endian) unicode string to ASCII.  We fake it by just
+   taking every odd byte. */
 
-static guint16 ver_dcerpc_lsa = 0;
+static char *fake_unicode(guint16 *data, int len)
+{
+       char *buffer;
+       int i;
+
+       buffer = malloc(len + 1);
+
+       for (i = 0; i < len; i++)
+               buffer[i] = data[i] & 0xff;
+
+       buffer[len] = 0;
+
+       return buffer;
+}
+
+static int ett_UNISTR = -1;
+static int ett_UNISTR_hdr = -1;
+
+static int prs_UNISTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                     proto_tree *tree, int flags, GList **ptr_list, 
+                     char *name)
+{
+       proto_tree *scalars, *buffers;
+       guint16 length, size;
+
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "String header");
+               subtree = proto_item_add_subtree(item, ett_UNISTR_hdr);
+               
+               offset = prs_uint16(tvb, offset, pinfo, subtree, &length, 
+                                   "Length");
+
+               offset = prs_uint16(tvb, offset, pinfo, subtree, &size, 
+                                   "Size");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, subtree,
+                                     ptr_list, "Data");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+               guint32 max_len, stroffset, actual_count, i;
+               int old_offset;
+               guint16 *string;
+               char *astring;
+
+               /* Parse data */
+
+               old_offset = offset;
+
+               offset = prs_uint32(tvb, offset, pinfo, NULL, &max_len, 
+                                   "Max length");
+
+               offset = prs_uint32(tvb, offset, pinfo, NULL, &stroffset, 
+                                   "Offset");
+
+               offset = prs_uint32(tvb, offset, pinfo, NULL, 
+                                   &actual_count, "Actual length");
+
+               offset = prs_uint16s(tvb, offset, pinfo, NULL,
+                                    actual_count, &string, "Data");
+
+               /* Insert into display */
+
+               astring = fake_unicode(string, actual_count);
+
+               if (!astring || !astring[0])
+                       astring = strdup("(NULL)");
+
+               item = proto_tree_add_text(tree, tvb, old_offset, 
+                                          offset - old_offset, "String: %s", 
+                                          astring);
+
+               free(astring);
+
+               subtree = proto_item_add_subtree(item, ett_UNISTR);
+
+               proto_tree_add_text(subtree, tvb, old_offset, 4, 
+                                   "Max length: %d", max_len);
+               old_offset += 4;
+
+               proto_tree_add_text(subtree, tvb, old_offset, 4, 
+                                   "Offset: %d", stroffset);
+               old_offset += 4;
+
+               proto_tree_add_text(subtree, tvb, old_offset, 4,
+                                   "Actual length: %d", actual_count);
+               old_offset += 4;
+
+               if (prs_pop_ptr(ptr_list, "Data"))
+                       proto_tree_add_text(subtree, tvb, old_offset, 
+                                           actual_count * 2, "Data");
+       }
+
+       return offset;
+}
+
+/*
+ *  typedef struct {
+ *    char revision;
+ *    char subauth_count;
+ *    char authority[6];
+ *    [size_is(subauth_count)] long subauth[*];
+ *  } SID;
+ *
+ */
+
+static int ett_SID = -1;
+
+/* For some reason the SID structure is treated as a scalar type.  For
+   instance in an array of SIDs, I would have thought that this entire
+   structure should be in the scalars part of the RPC but instead is in
+   the buffers section.  I am probably misunderstanding NDR arrays
+   though. - tpot */
+
+static int prs_SID(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                  proto_tree *tree)
+{
+       guint8 subauth_count, id_auth[6];
+       int old_offset, i;
+       proto_item *item;
+       proto_tree *subtree;
+       guint32 ia, *subauths, subauth_max;
+       guint8 revision;
+       char sid_str[128];
+
+       old_offset = offset;
+
+       offset = prs_uint32(tvb, offset, pinfo, NULL, &subauth_max, 
+                           "Array max count");
+
+       offset = prs_uint8(tvb, offset, pinfo, NULL, &revision, "Revision");
+
+       offset = prs_uint8(tvb, offset, pinfo, NULL, &subauth_count, 
+                          "Subauth count");
+
+       for (i = 0; i < 6; i++)
+               offset = prs_uint8(tvb, offset, pinfo, NULL, &id_auth[i], 
+                                  "Authority");
+       
+       ia = id_auth[5] + (id_auth[4] << 8 ) + (id_auth[3] << 16) + 
+               (id_auth[2] << 24);
+
+       sprintf(sid_str, "S-%u-%u", revision, ia);
+
+       offset = prs_uint32s(tvb, offset, pinfo, NULL, subauth_count,
+                            &subauths, "Subauth count");
+
+       for (i = 0; i < subauth_count; i++) {
+               char sa[16];
+
+               sprintf(sa, "-%u", subauths[i]);
+               strcat(sid_str, sa);
+       }
+
+       /* Insert into display */
+
+       item = proto_tree_add_text(tree, tvb, offset, 0, "SID: %s", sid_str);
+       subtree = proto_item_add_subtree(item, ett_SID);
+
+       proto_tree_add_text(subtree, tvb, old_offset, 4, 
+                           "Subauth array max count: %d", subauth_max);
+
+       old_offset += 4;
+
+       proto_tree_add_text(subtree, tvb, old_offset, 1, "Revision: %d", 
+                           revision);
+
+       old_offset++;
+
+       proto_tree_add_text(subtree, tvb, old_offset, 1, "Subauth count: %d",
+                           subauth_count); 
+
+       old_offset++;
+
+       proto_tree_add_text(subtree, tvb, old_offset, 6, "Authority");
+
+       old_offset += 6;
+
+       proto_tree_add_text(subtree, tvb, old_offset, subauth_count * 4,
+                           "Subauthorities");
+
+       old_offset += subauth_count * 4;
+
+       return offset;
+}
+
+/*
+ * Close a policy handle.
+ *
+ *  long LsarClose(
+ *      [in,out] [context_handle] void **hnd
+ * );
+ *
+ */
+
+static int LsaClose_q(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                     proto_tree *tree, char *drep)
+{
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "ClosePolicy request");
+
+       offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+
+       return offset;
+}
+
+static int LsaClose_r(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                     proto_tree *tree, char *drep)
+{
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "ClosePolicy reply");
+
+       offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+       offset = prs_ntstatus(tvb, offset, pinfo, tree);
+
+       return offset;
+}
+
+/* 
+ * Dissect a SECURITY_DESCRIPTOR structure 
+ *
+ * typedef struct {
+ *   char revision;
+ *   char reserved;
+ *   short control;
+ *   [unique] SID *owner;
+ *   [unique] SID *group;
+ *   [unique] SEC_ACL *sacl;
+ *   [unique] SEC_ACL *dacl;
+ * } SECURITY_DESCRIPTOR;
+ *
+ */
+
+static int prs_SECURITY_DESCRIPTOR(tvbuff_t *tvb, int offset, 
+                                  packet_info *pinfo, proto_tree *tree, 
+                                  int flags)
+{
+       /* Not implemented */
+
+       return offset;
+}
+
+/* Dissect a SECURITY_QOS structure
+ *
+ *  typedef struct {
+ *   uint32 struct_len;
+ *   uint16 imp_level;
+ *   char track_context;
+ *   char effective_only;
+ * } SECURITY_QOS;
+ *
+ */
+
+static int ett_SECURITY_QOS = -1;
+static int ett_SECURITY_QOS_hdr = -1;
+
+static int prs_SECURITY_QOS(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                           proto_tree *tree, int flags)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "SECURITY_QOS header");
+               subtree = proto_item_add_subtree(item, ett_SECURITY_QOS_hdr);
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
+                                   "Struct length");
+
+               offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, 
+                                   "Implementation level");
+
+               offset = prs_uint8(tvb, offset, pinfo, subtree, NULL, 
+                                  "Track context");
+
+               offset = prs_uint8(tvb, offset, pinfo, subtree, NULL, 
+                                  "Effective only");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "SECURITY_QOS");
+               subtree = proto_item_add_subtree(item, ett_SECURITY_QOS);
+       }
+
+       return offset;
+}
+
+/*
+ * Dissect an OBJECT_ATTRIBUTES structure.
+ *
+ * typedef struct {
+ *   uint32 struct_len;
+ *   [unique] char *root_dir;
+ *   [unique] unistr2 *name;
+ *   uint32 attributes;
+ *   [unique] SECURITY_DESCRIPTOR *sec_desc;
+ *   [unique] SECURITY_QOS *sec_qos;
+ * } OBJECT_ATTRIBUTES;
+ *
+ */
+
+static int prs_OBJECT_ATTRIBUTES(tvbuff_t *tvb, int offset, 
+                                packet_info *pinfo, proto_tree *tree, 
+                                int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               offset = prs_uint32(tvb, offset, pinfo, tree, NULL, 
+                                   "Structure length");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, tree, ptr_list,
+                                     "Root directory");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, tree, ptr_list, 
+                                     "Name");
+
+               offset = prs_uint32(tvb, offset, pinfo, tree, NULL, 
+                                   "Attributes");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, tree, ptr_list,
+                                     "SECURITY_DESCRIPTOR");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, tree, ptr_list,
+                                     "SEC_QOS");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               if (prs_pop_ptr(ptr_list, "Root directory"))
+                   offset = prs_uint8(tvb, offset, pinfo, tree, NULL, 
+                                      "Root directory");
+                   
+               if (prs_pop_ptr(ptr_list, "Name"))
+                       offset = prs_UNISTR2(tvb, offset, pinfo, tree,
+                                            flags, NULL, "Name");
+
+               if (prs_pop_ptr(ptr_list, "SECURITY_DESCRIPTOR"))
+                       offset = prs_SECURITY_DESCRIPTOR(
+                               tvb, offset, pinfo, tree, flags);
+
+               if (prs_pop_ptr(ptr_list, "SEC_QOS"))
+                       offset = prs_SECURITY_QOS(
+                               tvb, offset, pinfo, tree, flags);
+
+       }
+
+       return offset;
+}
+
+/*
+ * Open a LSA policy handle.  Note that due to a bug in Microsoft's
+ * original IDL, only the first character of the server name is ever sent
+ * across the wire.  Since the server name is in UNC format this will be a
+ * single '\'.
+ * 
+ *  uint32 LsarOpenPolicy(
+ *       [in] [unique] wchar_t *server,
+ *       [in] [ref] OBJECT_ATTRIBUTES *attribs,
+ *       [in] uint32 access,
+ *      [out] [context_handle] void **hnd
+ * );
+ *
+ */ 
+
+static int LsaOpenPolicy_q(tvbuff_t * tvb, int offset,
+                          packet_info * pinfo, proto_tree * tree,
+                          char *drep)
+{
+       GList *ptr_list = NULL;
+       int flags = PARSE_SCALARS|PARSE_BUFFERS;
+       guint32 access;
+
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "OpenPolicy request");
+
+        offset = prs_push_ptr(tvb, offset, pinfo, tree, &ptr_list, "Server");
+
+        if (prs_pop_ptr(&ptr_list, "Server"))
+                offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Server");
+
+       offset = prs_OBJECT_ATTRIBUTES(tvb, offset, pinfo, tree, flags,
+                                      &ptr_list);
+
+        offset = prs_uint32(tvb, offset, pinfo, tree, &access, NULL);
+
+       proto_tree_add_text(tree, tvb, offset, 4, "Access: 0x%08x", access);
+
+        return offset;
+}
+
+static int LsaOpenPolicy_r(tvbuff_t * tvb, int offset,
+                            packet_info * pinfo, proto_tree * tree,
+                            char *drep)
+{
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "OpenPolicy reply");
+
+        offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+        offset = prs_ntstatus(tvb, offset, pinfo, tree);
+
+        return offset;
+}
+
+/*
+ * Parse a NAME_AND_SID structure.
+ *
+ * typedef struct {
+ *   UNICODE_STRING name;
+ *   [unique] SID *sid;
+ * } NAME_AND_SID;
+ *
+ */
+
+int ett_NAME_AND_SID = -1;
+int ett_NAME_AND_SID_hdr = -1;
+
+static int prs_NAME_AND_SID(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                           proto_tree *tree, int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "NAME_AND_SID header");
+               subtree = proto_item_add_subtree(item, ett_NAME_AND_SID_hdr);
+
+               offset = prs_UNISTR(tvb, offset, pinfo, subtree, 
+                                   PARSE_SCALARS, ptr_list, "Name");
+               offset = prs_push_ptr(tvb, offset, pinfo, subtree,
+                                     ptr_list, "SID");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "NAME_AND_SID");
+               subtree = proto_item_add_subtree(item, ett_NAME_AND_SID);
+
+               offset = prs_UNISTR(tvb, offset, pinfo, subtree, 
+                                   PARSE_BUFFERS, ptr_list, "Name");
+
+               if (prs_pop_ptr(ptr_list, "SID"))
+                       offset = prs_SID(tvb, offset, pinfo, subtree);
+       }
+
+       return offset;
+}
+
+/*
+ * Parse a POLICY_INFORMATION structure. 
+ *
+ * typedef union {
+ *   [case(1)] AUDIT_LOG_INFO audit_log;
+ *   [case(2)] AUDIT_SETTINGS audit_settings;
+ *   [case(3)] NAME_AND_SID primary_domain;
+ *   [case(5)] NAME_AND_SID account_domain;
+ *   [case(4)] UNICODE_STRING account;
+ *   [case(6)] SERVER_ROLE server_role;
+ *   [case(7)] REPLICA_SOURCE replica_source;
+ *   [case(8)] QUOTA_INFO default_quota;
+ *   [case(9)] HISTORY history;
+ *   [case(10)] AUDIT_SET_INFO audit_set;
+ *   [case(11)] AUDIT_QUERY_INFO audit_query;
+ * } POLICY_INFORMATION;
+ *
+ */
+
+static int ett_POLICY_INFORMATION = -1;
+
+static int prs_POLICY_INFORMATION(tvbuff_t *tvb, int offset,
+                                 packet_info *pinfo, proto_tree *tree, 
+                                 int flags)
+{
+       guint16 level;
+       proto_item *item;
+       proto_tree *subtree;
+       GList *ptr_list = NULL;
+
+       item = proto_tree_add_text(tree, tvb, offset, 0, "POLICY_INFORMATION");
+       subtree = proto_item_add_subtree(item, ett_POLICY_INFORMATION);
+
+       offset = prs_uint16(tvb, offset, pinfo, subtree, &level, "Info level");
+
+       switch (level) {
+       case 1: 
+/*             offset = prs_AUDIT_LOG_INFO(tvb, offset, pinfo, subtree); */
+               break;
+       case 2:
+/*             offset = prs_AUDIT_SETTINGS(tvb, offset, pinfo, subtree); */
+               break;
+       case 3:
+               offset = prs_NAME_AND_SID(tvb, offset, pinfo, subtree,
+                                         flags, &ptr_list);
+               break;
+       case 4:
+/*             offset = prs_UNISTR2(tvb, offset, pinfo, subtree); */
+               break;
+       case 5:
+               offset = prs_NAME_AND_SID(tvb, offset, pinfo, subtree, 
+                                         flags, &ptr_list);
+               break;
+       case 6:
+/*             offset = prs_SERVER_ROLE(tvb, offset, pinfo, subtree); */
+               break;
+       case 7:
+/*             offset = prs_REPLICA_SOURCE(tvb, offset, pinfo, subtree); */
+               break;
+       case 8:
+/*             offset = prs_QUOTA_INFO(tvb, offset, pinfo, subtree); */
+               break;
+       case 9:
+/*             offset = prs_HISTORY(tvb, offset, pinfo, subtree); */
+               break;
+       case 10:
+/*             offset = prs_AUDIT_SET_INFO(tvb, offset, pinfo, subtree); */
+               break;
+       case 11:
+/*             offset = prs_AUDIT_QUERY_INFO(tvb, offset, pinfo, subtree); */
+               break;
+       }
+
+       return offset;
+}
+
+/*
+ * uint32 LsarQueryInformationPolicy(
+ *       [in] [context_handle] void *hnd,
+ *       [in] uint16 level,
+ *      [out] [switch_is(level)] [ref] POLICY_INFORMATION **info
+ * );
+ *
+ */
+
+static int LsaQueryInfoPolicy_q(tvbuff_t *tvb, int offset,
+       packet_info *pinfo, proto_tree *tree, char *drep)
+{
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "QueryInfo request");
+
+       offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+       offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Info level");
+
+       return offset;
+}
+
+static int LsaQueryInfoPolicy_r(tvbuff_t *tvb, int offset,
+       packet_info *pinfo, proto_tree *tree, char *drep)
+{
+       GList *ptr_list = NULL;
+       int flags = PARSE_SCALARS|PARSE_BUFFERS;
+
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "QueryInfo reply");
+
+       offset = prs_push_ptr(tvb, offset, pinfo, tree, &ptr_list, 
+                             "POLICY_INFORMATION");
+
+       if (prs_pop_ptr(&ptr_list, "POLICY_INFORMATION"))
+               offset = prs_POLICY_INFORMATION(tvb, offset, pinfo, tree,
+                                               flags);
+
+       offset = prs_ntstatus(tvb, offset, pinfo, tree);
+
+       return offset;
+}
+
+/*
+ * Parse a DOM_RID structure.
+ *
+ * typedef struct {
+ *    short type;
+ *    long rid;
+ *    long dom_idx;
+ * } DOM_RID;
+ *
+ */
+
+static int ett_DOM_RID = -1;
+
+static int prs_DOM_RID(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                      proto_tree *tree, int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, "DOM_RID");
+               subtree = proto_item_add_subtree(item, ett_DOM_RID);
+
+               offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Type");
+       
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "RID");
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
+                                   "Domain index");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+       }
+
+       return offset;
+}
+
+/*
+ * Parse a DOM_RID_ARRAY structure.
+ *
+ * typedef struct {
+ *   long count;
+ *   [size_is(count)] [unique] DOM_RID *rids;
+ * } DOM_RID_ARRAY;
+ *
+ */
+
+static int ett_DOM_RID_ARRAY = -1;
+static int ett_DOM_RID_ARRAY_hdr = -1;
+
+static int prs_DOM_RID_ARRAY(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                            proto_tree *tree, int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "DOM_RID_ARRAY header");
+               subtree = proto_item_add_subtree(item, ett_DOM_RID_ARRAY_hdr);
+
+               
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL,
+                                   "Count");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, subtree, ptr_list, 
+                                     "RIDs");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+               guint32 count, i;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "DOM_RID_ARRAY");
+               subtree = proto_item_add_subtree(item, ett_DOM_RID_ARRAY);
+
+               if (!prs_pop_ptr(ptr_list, "RIDs"))
+                       goto done;
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, &count,
+                                   "Count");
+
+               for (i = 0; i < count; i++) {
+                       offset = prs_DOM_RID(tvb, offset, pinfo, subtree, 
+                                            PARSE_SCALARS, ptr_list);
+               }
+
+               for (i = 0; i < count; i++) {
+                       offset = prs_DOM_RID(tvb, offset, pinfo, subtree, 
+                                            PARSE_BUFFERS, ptr_list);
+               }
+done:
+       }
+
+       return offset;
+}
+
+/*
+ * Parse a NAME_AND_SID_ARRAY structure.
+ *
+ * typedef struct {
+ *   long count;
+ *   [size_is(count)] [unique] NAME_AND_SID *objects;
+ * } NAME_AND_SID_ARRAY;
+ *
+ */
+
+static int ett_NAME_AND_SID_ARRAY = -1;
+static int ett_NAME_AND_SID_ARRAY_hdr = -1;
+
+static int prs_NAME_AND_SID_ARRAY(tvbuff_t *tvb, int offset, 
+                                 packet_info *pinfo, proto_tree *tree, 
+                                 int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "NAME_AND_SID_ARRAY header");
+               subtree = proto_item_add_subtree(
+                       item, ett_NAME_AND_SID_ARRAY_hdr);
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
+                                   "Count");
+
+               offset = prs_push_ptr(tvb, offset, pinfo, subtree, ptr_list,
+                                     "NAME_AND_SIDs");
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
+                                   "Max count");
+
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+               guint32 count, i;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "NAME_AND_SID_ARRAY");
+               subtree = proto_item_add_subtree(
+                       item, ett_NAME_AND_SID_ARRAY);
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, &count, 
+                                   "Count");
+
+               if (!prs_pop_ptr(ptr_list, "NAME_AND_SIDs"))
+                       goto done;
+
+               for (i = 0; i < count; i++) {
+                       offset = prs_NAME_AND_SID(tvb, offset, pinfo, subtree,
+                                                 PARSE_SCALARS, ptr_list);
+               }
+
+               for (i = 0; i < count; i++) {
+                       offset = prs_NAME_AND_SID(tvb, offset, pinfo, subtree,
+                                                 PARSE_BUFFERS, ptr_list);
+               }
+       done:
+       }
+
+       return offset;
+}
+
+/*
+ * Parse a DOM_REF_INFO structure.
+ *
+ * typedef struct {
+ *   NAME_AND_SID_ARRAY domains;
+ *   long count;
+ * } DOM_REF_INFO;
+ *
+ */
+
+static int ett_DOM_REF_INFO = -1;
+static int ett_DOM_REF_INFO_hdr = -1;
+
+static int prs_DOM_REF_INFO(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                           proto_tree *tree, int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "DOM_REF_INFO header");
+               subtree = proto_item_add_subtree(item, ett_DOM_REF_INFO_hdr);
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "DOM_REF_INFO");
+               subtree = proto_item_add_subtree(item, ett_DOM_REF_INFO);
+
+               offset = prs_NAME_AND_SID_ARRAY(tvb, offset, pinfo, subtree, 
+                                               PARSE_SCALARS, ptr_list);
+
+               offset = prs_NAME_AND_SID_ARRAY(tvb, offset, pinfo, subtree, 
+                                               PARSE_BUFFERS, ptr_list);
+       }
+
+       return offset;
+}
+
+/*
+ * Convert a list of names to a list of SIDs.
+ *
+ *   uint32 LsarLookupNames(
+ *       [in] [context_handle] void *hnd,
+ *       [in] uint32 num_names,
+ *       [in] [size_is(num_names)] [ref] UNISTR2 *names,
+ *      [out] [ref] DOM_REF_INFO **domains,
+ *   [in,out] [ref] DOM_RID_ARRAY *rids,
+ *       [in] uint16 level,
+ *   [in,out] [ref] uint32 *num_mapped
+ * );
+ *
+ */
+
+static int LsaLookupNames_q(tvbuff_t *tvb, int offset,
+       packet_info *pinfo, proto_tree *tree, char *drep)
+{
+       GList *ptr_list = NULL;
+       guint32 count, i;
+
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "LookupNames request");
+
+       offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+
+       offset = prs_uint32(tvb, offset, pinfo, tree, &count, "Num names");
+
+       offset = prs_uint32(tvb, offset, pinfo, tree, &count, 
+                           "Name array max count");
+
+       for (i = 0; i < count; i++)
+               offset = prs_UNISTR(tvb, offset, pinfo, tree, PARSE_SCALARS, 
+                                   &ptr_list, "Name");
+
+       for (i = 0; i < count; i++)
+               offset = prs_UNISTR(tvb, offset, pinfo, tree, PARSE_BUFFERS,
+                                   &ptr_list, "Name");
 
+       offset = prs_DOM_RID_ARRAY(tvb, offset, pinfo, tree, 
+                                  PARSE_SCALARS|PARSE_BUFFERS, &ptr_list);
 
+       offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Info level");
+
+       offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Num mapped");
+               
+       return offset;
+}
+
+static int LsaLookupNames_r(tvbuff_t *tvb, int offset,
+       packet_info *pinfo, proto_tree *tree, char *drep)
+{
+       GList *ptr_list = NULL;
+
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "LookupNames reply");
+
+       offset = prs_push_ptr(tvb, offset, pinfo, tree, &ptr_list, "Domains");
+
+       if (prs_pop_ptr(&ptr_list, "Domains"))
+               offset = prs_DOM_REF_INFO(tvb, offset, pinfo, tree,
+                                         PARSE_SCALARS|PARSE_BUFFERS, 
+                                         &ptr_list);
+
+       offset = prs_DOM_RID_ARRAY(tvb, offset, pinfo, tree, 
+                                  PARSE_SCALARS|PARSE_BUFFERS, &ptr_list);
+
+       offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Num mapped");
+
+       offset = prs_ntstatus(tvb, offset, pinfo, tree);
+
+       g_assert(g_list_length(ptr_list) == 0);
+
+       return offset;
+}
+
+/*
+ * Parse a SID_ARRAY structure.
+ *
+ * typedef struct {
+ *   long count;
+ *   [size_is(count)] [unique] PSID *sids;
+ * } SID_ARRAY;
+ *
+ */
+
+static int ett_SID_ARRAY = -1;
+static int ett_SID_ARRAY_hdr = -1;
+
+static int prs_SID_ARRAY(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                        proto_tree *tree, int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "SID_ARRAY header");
+               subtree = proto_item_add_subtree(item, ett_SID_ARRAY_hdr);
+
+               
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL,
+                                   "Count");
+               
+               offset = prs_push_ptr(tvb, offset, pinfo, subtree, ptr_list, 
+                                     "SIDs");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+               guint32 count, i;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "SID_ARRAY");
+               subtree = proto_item_add_subtree(item, ett_SID_ARRAY);
+
+               if (!prs_pop_ptr(ptr_list, "SIDs"))
+                       goto done;
+               
+               offset = prs_uint32(tvb, offset, pinfo, subtree, &count, 
+                                   "Count");
+
+               for (i = 0; i < count; i++)
+                       offset = prs_push_ptr(tvb, offset, pinfo, 
+                                             subtree, ptr_list, "SID"); 
+
+               for (i = 0; i < count; i++) {
+                       if (prs_pop_ptr(ptr_list, "SID"))
+                               offset = prs_SID(tvb, offset, pinfo, subtree);
+               }
+       done:
+       }
+
+       return offset;
+}
+
+/*
+ * Parse an ACCOUNT_NAME structure.
+ *
+ * typedef struct {
+ *   unsigned short type;
+ *   UNICODE_STRING name;
+ *   long dom_idx;
+ * } ACCOUNT_NAME;
+ *
+ */
+
+static int prs_ACCOUNT_NAME(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                           proto_tree *tree, int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Type");
+
+               offset = prs_uint32(tvb, offset, pinfo, tree, NULL, 
+                                   "Domain index");
+               
+               offset = prs_UNISTR(tvb, offset, pinfo, tree,
+                                   PARSE_SCALARS, ptr_list, "Name");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               offset = prs_UNISTR(tvb, offset, pinfo, tree,
+                                   PARSE_BUFFERS, ptr_list, "Name");
+       }
+
+       return offset;
+}
+
+/*
+ * Parse an ACCOUNT_NAME_ARRAY structure.
+ *
+ * typedef struct {
+ *   long count;
+ *   [size_is(count)] [unique] ACCOUNT_NAME *domains;
+ * } ACCOUNT_NAME_ARRAY;
+ *
+ */
+
+static int prs_ACCOUNT_NAME_ARRAY(tvbuff_t *tvb, int offset,
+                                 packet_info *pinfo, proto_tree *tree, 
+                                 int flags, GList **ptr_list)
+{
+       if (flags & PARSE_SCALARS) {
+               proto_item *item;
+               proto_tree *subtree;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "ACCOUNT_NAME_ARRAY header");
+               subtree = proto_item_add_subtree(item, ett_SID_ARRAY_hdr);
+
+               offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
+                                   "Count");
+               
+               offset = prs_push_ptr(tvb, offset, pinfo, subtree, ptr_list,
+                                     "ACCOUNT_NAMEs");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               proto_item *item;
+               proto_tree *subtree;
+               guint32 count, i;
+
+               item = proto_tree_add_text(tree, tvb, offset, 0, 
+                                          "ACCOUNT_NAME_ARRAY");
+               subtree = proto_item_add_subtree(item, ett_SID_ARRAY);
+
+               if (!prs_pop_ptr(ptr_list, "ACCOUNT_NAMEs"))
+                       goto done;
+               
+               offset = prs_uint32(tvb, offset, pinfo, subtree, &count, 
+                                   "Count");
+
+               for (i = 0; i < count; i++) {
+                       offset = prs_ACCOUNT_NAME(tvb, offset, pinfo, subtree, 
+                                                 PARSE_SCALARS, ptr_list);
+               }
+
+               for (i = 0; i < count; i++) {
+                       offset = prs_ACCOUNT_NAME(tvb, offset, pinfo, subtree, 
+                                                 PARSE_BUFFERS, ptr_list);
+               }
+       done:
+       }
+
+       return offset;
+}
+
+/*
+ * Convert a list of SIDs to a list of names.
+ *
+ * long LsarLookupSids(
+ *       [in] [context_handle] void *hnd,
+ *       [in] [ref] SID_ARRAY *sids,
+ *      [out] [ref] DOM_REF_INFO **domains,
+ *   [in,out] [ref] ACCOUNT_NAME_ARRAY *names,
+ *       [in] unsigned short level,
+ *   [in,out] [ref] long *num_mapped
+ * );
+ *
+ */
+
+static int LsaLookupSids_q(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                          proto_tree *tree, char *drep)
+{
+       GList *ptr_list = NULL;
+       int flags = PARSE_SCALARS|PARSE_BUFFERS;
+
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "LookupSids request");
+
+       offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+
+       offset = prs_SID_ARRAY(tvb, offset, pinfo, tree, flags, &ptr_list);
+
+       offset = prs_ACCOUNT_NAME_ARRAY(tvb, offset, pinfo, tree, flags, 
+                                       &ptr_list);
+       
+       offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Info level");
+       
+       offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Num mapped");
+
+       return offset;
+}
+
+static int LsaLookupSids_r(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                          proto_tree *tree, char *drep)
+{
+       GList *ptr_list = NULL;
+
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_set_str(pinfo->cinfo, COL_INFO, "LookupSids reply");
+
+       offset = prs_push_ptr(tvb, offset, pinfo, tree, &ptr_list,
+                        "DOM_REF_INFO");
+
+       if (prs_pop_ptr(&ptr_list, "DOM_REF_INFO"))
+               offset = prs_DOM_REF_INFO(tvb, offset, pinfo, tree,
+                                         PARSE_SCALARS|PARSE_BUFFERS,
+                                         &ptr_list);
+
+       offset = prs_ACCOUNT_NAME_ARRAY(tvb, offset, pinfo, tree, 
+                                       PARSE_SCALARS|PARSE_BUFFERS,
+                                       &ptr_list);
+       
+       offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Num mapped");
+       
+       offset = prs_ntstatus(tvb, offset, pinfo, tree);
+
+       return offset;
+}
+
+/*
+ * List of subdissectors for this pipe.
+ */
 
 static dcerpc_sub_dissector dcerpc_lsa_dissectors[] = {
-        { LSA_CLOSE, "LSA_CLOSE", NULL, NULL },
+        { LSA_CLOSE, "LSA_CLOSE", LsaClose_q, LsaClose_r },
         { LSA_DELETE, "LSA_DELETE", NULL, NULL },
         { LSA_ENUM_PRIVS, "LSA_ENUM_PRIVS", NULL, NULL },
         { LSA_QUERYSECOBJ, "LSA_QUERYSECOBJ", NULL, NULL },
         { LSA_SETSECOBJ, "LSA_SETSECOBJ", NULL, NULL },
         { LSA_CHANGEPASSWORD, "LSA_CHANGEPASSWORD", NULL, NULL },
-        { LSA_OPENPOLICY, "LSA_OPENPOLICY", NULL, NULL },
-        { LSA_QUERYINFOPOLICY, "LSA_QUERYINFOPOLICY", NULL, NULL },
+        { LSA_OPENPOLICY, "LSA_OPENPOLICY", 
+         LsaOpenPolicy_q, LsaOpenPolicy_r },
+        { LSA_QUERYINFOPOLICY, "LSA_QUERYINFOPOLICY", 
+         LsaQueryInfoPolicy_q, LsaQueryInfoPolicy_r },
         { LSA_SETINFOPOLICY, "LSA_SETINFOPOLICY", NULL, NULL },
         { LSA_CLEARAUDITLOG, "LSA_CLEARAUDITLOG", NULL, NULL },
         { LSA_CREATEACCOUNT, "LSA_CREATEACCOUNT", NULL, NULL },
         { LSA_ENUM_ACCOUNTS, "LSA_ENUM_ACCOUNTS", NULL, NULL },
         { LSA_CREATETRUSTDOM, "LSA_CREATETRUSTDOM", NULL, NULL },
         { LSA_ENUMTRUSTDOM, "LSA_ENUMTRUSTDOM", NULL, NULL },
-        { LSA_LOOKUPNAMES, "LSA_LOOKUPNAMES", NULL, NULL },
-        { LSA_LOOKUPSIDS, "LSA_LOOKUPSIDS", NULL, NULL },
+        { LSA_LOOKUPNAMES, "LSA_LOOKUPNAMES",
+         LsaLookupNames_q, LsaLookupNames_r },
+        { LSA_LOOKUPSIDS, "LSA_LOOKUPSIDS", 
+         LsaLookupSids_q, LsaLookupSids_r },
         { LSA_CREATESECRET, "LSA_CREATESECRET", NULL, NULL },
         { LSA_OPENACCOUNT, "LSA_OPENACCOUNT", NULL, NULL },
         { LSA_ENUMPRIVSACCOUNT, "LSA_ENUMPRIVSACCOUNT", NULL, NULL },
@@ -95,11 +1189,33 @@ static dcerpc_sub_dissector dcerpc_lsa_dissectors[] = {
         {0, NULL, NULL,  NULL },
 };
 
+/* Protocol registration */
+
+static int proto_dcerpc_lsa = -1;
+static gint ett_dcerpc_lsa = -1;
+
 void 
 proto_register_dcerpc_lsa(void)
 {
         static gint *ett[] = {
                 &ett_dcerpc_lsa,
+               &ett_UNISTR,
+               &ett_UNISTR_hdr,
+               &ett_NAME_AND_SID,
+               &ett_NAME_AND_SID_hdr,
+               &ett_SID,
+               &ett_POLICY_INFORMATION,
+               &ett_DOM_REF_INFO,
+               &ett_DOM_REF_INFO_hdr,
+               &ett_DOM_RID_ARRAY,
+               &ett_DOM_RID_ARRAY_hdr,
+               &ett_DOM_RID,
+               &ett_SID_ARRAY,
+               &ett_SID_ARRAY_hdr,
+               &ett_NAME_AND_SID_ARRAY,
+               &ett_NAME_AND_SID_ARRAY_hdr,
+               &ett_SECURITY_QOS,
+               &ett_SECURITY_QOS_hdr,
         };
 
         proto_dcerpc_lsa = proto_register_protocol(
@@ -108,6 +1224,15 @@ proto_register_dcerpc_lsa(void)
         proto_register_subtree_array(ett, array_length(ett));
 }
 
+/* Protocol handoff */
+
+static e_uuid_t uuid_dcerpc_lsa = {
+        0x12345778, 0x1234, 0xabcd, 
+        { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab}
+};
+
+static guint16 ver_dcerpc_lsa = 0;
+
 void
 proto_reg_handoff_dcerpc_lsa(void)
 {
diff --git a/packet-dcerpc-nt.c b/packet-dcerpc-nt.c
new file mode 100644 (file)
index 0000000..7af722d
--- /dev/null
@@ -0,0 +1,370 @@
+/* packet-dcerpc-nt.c
+ * Routines for DCERPC over SMB packet disassembly
+ * Copyright 2001, Tim Potter <tpot@samba.org>
+ *
+ * $Id: packet-dcerpc-nt.c,v 1.1 2001/12/16 20:17:10 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include "packet.h"
+#include "packet-dcerpc.h"
+#include "packet-dcerpc-nt.h"
+#include "smb.h"
+
+/*
+ * This file contains helper routines that are used by the DCERPC over SMB
+ * dissectors for ethereal.
+ */
+
+/* Align offset to a n-byte boundary */
+
+int prs_align(int offset, int n)
+{
+       if (offset % n)
+               offset += n - (offset % n);
+       
+       return offset;
+}
+
+/* Parse a 8-bit integer */
+
+int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo,
+             proto_tree *tree, guint8 *data, char *name)
+{
+       guint8 i;
+       
+       /* No alignment required */
+
+       i = tvb_get_guint8(tvb, offset);
+       offset++;
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset - 1, 1, 
+                                   "%s: %d", name, i);
+
+       if (data)
+               *data = i;
+
+       return offset;
+}
+
+int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *tree, int count, guint8 **data, char *name)
+{
+       const guint8 *ptr;
+       
+       /* No alignment required */
+
+       ptr = tvb_get_ptr(tvb, offset, count);
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset, count, "%s", name);
+
+       if (data)
+               *data = (guint8 *)ptr;
+
+       offset += count;
+
+       return offset;
+}
+
+/* Parse a 16-bit integer */
+
+int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *tree, guint16 *data, char *name)
+{
+       guint16 i;
+       
+       offset = prs_align(offset, 2);
+       
+       i = tvb_get_letohs(tvb, offset);
+       offset += 2;
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset - 2, 2, 
+                                   "%s: %d", name, i);
+       if (data)
+               *data = i;
+
+       return offset;
+}
+
+/* Parse a number of uint16's */
+
+int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo,
+               proto_tree *tree, int count, guint16 **data, char *name)
+{
+       const guint8 *ptr;
+       
+       offset = prs_align(offset, 2);
+       
+       ptr = tvb_get_ptr(tvb, offset, count * 2);
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset, count * 2, 
+                                   "%s", name);
+       if (data)
+               *data = (guint16 *)ptr;
+
+       offset += count * 2;
+
+       return offset;
+}
+
+/* Parse a 32-bit integer */
+
+int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *tree, guint32 *data, char *name)
+{
+       guint32 i;
+       
+       offset = prs_align(offset, 4);
+       
+       i = tvb_get_letohl(tvb, offset);
+       offset += 4;
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset - 4, 4, 
+                                   "%s: %d", name, i);
+
+       if (data)
+               *data = i;
+
+       return offset;
+}
+
+/* Parse a number of 32-bit integers */
+
+int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo,
+               proto_tree *tree, int count, guint32 **data, char *name)
+{
+       const guint8 *ptr;
+       
+       offset = prs_align(offset, 4);
+       
+       ptr = tvb_get_ptr(tvb, offset, count * 4);
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset - 4, 4, 
+                                   "%s", name);
+       if (data)
+               *data = (guint32 *)ptr;
+
+       offset += count * 4;
+
+       return offset;
+}
+
+/* Parse a NT status code */
+
+int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                proto_tree *tree)
+{
+       guint32 status;
+
+       offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
+
+       if (tree)
+               proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
+                                   val_to_str(status, NT_errors, "???"));
+
+       return offset;
+}
+
+/*
+ * We need to keep track of deferred referrents as they appear in the
+ * packet after all the non-pointer objects.
+ * to keep track of pointers as they are parsed as scalars and need to be
+ * remembered for the next call to the prs function.
+ *
+ * Pointers are stored in a linked list and pushed in the PARSE_SCALARS
+ * section of the prs function and popped in the PARSE_BUFFERS section.  If
+ * we try to pop off a referrent that has a different name then we are
+ * expecting then something has gone wrong.
+ */
+
+#undef DEBUG_PTRS
+
+struct ptr {
+       char *name;
+       guint32 value;
+};
+
+/* Create a new pointer */
+
+static struct ptr *new_ptr(char *name, guint32 value)
+{
+       struct ptr *p;
+
+       p = g_malloc(sizeof(struct ptr));
+
+       p->name = g_strdup(name);
+       p->value = value;
+
+       return p;
+}
+
+/* Free a pointer */
+
+static void free_ptr(struct ptr *p)
+{
+       if (p) {
+               g_free(p->name);
+               g_free(p);
+       }
+}
+
+/* Parse a pointer and store it's value in a linked list */
+
+int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                proto_tree *tree, GList **ptr_list, char *name)
+{
+       struct ptr *p;
+       guint32 value;
+
+       offset = prs_uint32(tvb, offset, pinfo, tree, &value, NULL);
+
+       if (name && tree)
+               proto_tree_add_text(tree, tvb, offset - 4, 4, 
+                                   "%s pointer: 0x%08x", name, value);
+
+       p = new_ptr(name, value);
+
+       *ptr_list = g_list_append(*ptr_list, p);
+
+#ifdef DEBUG_PTRS
+       fprintf(stderr, "DEBUG_PTRS: pushing %s ptr = 0x%08x, %d ptrs in "
+               "list\n", name, value, g_list_length(*ptr_list));
+#endif
+
+       return offset;
+}
+
+/* Pop a pointer of a given name.  Return it's value. */
+
+guint32 prs_pop_ptr(GList **ptr_list, char *name)
+{
+       GList *elt;
+       struct ptr *p;
+       guint32 result;
+
+       g_assert(g_list_length(*ptr_list) != 0);        /* List too short */
+
+       /* Get pointer at head of list */
+
+       elt = g_list_first(*ptr_list);
+       p = (struct ptr *)elt->data;
+       result = p->value;
+
+#ifdef DEBUG_PTRS
+       if (strcmp(p->name, name) != 0) {
+               fprintf(stderr, "DEBUG_PTRS: wrong pointer (%s != %s)\n",
+                       p->name, name);
+       }
+#endif
+
+       /* Free pointer record */
+
+       *ptr_list = g_list_remove_link(*ptr_list, elt);
+
+#ifdef DEBUG_PTRS
+       fprintf(stderr, "DEBUG_PTRS: popping %s ptr = 0x%08x, %d ptrs in "
+               "list\n", p->name, p->value, g_list_length(*ptr_list));
+#endif
+
+       free_ptr(p);
+
+       return result;
+}
+
+/*
+ * Parse a UNISTR2 structure 
+ *
+ * typedef struct {
+ *   short length;
+ *   short size;
+ *   [size_is(size/2)] [length_is(length/2)] [unique] wchar_t *string;
+ * } UNICODE_STRING;
+ *
+ */
+
+/* Convert a string from little-endian unicode to ascii.  At the moment we
+   fake it by taking every odd byte.  )-:  The caller must free the
+   result returned. */
+
+static char *fake_unicode(guint16 *data, int len)
+{
+       char *buffer;
+       int i;
+
+       buffer = malloc(len + 1);
+
+       for (i = 0; i < len; i++)
+               buffer[i] = data[i] & 0xff;
+
+       buffer[len] = 0;
+
+       return buffer;
+}
+
+/* Parse a UNISTR2 structure */
+
+int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
+               proto_tree *tree, int flags, char **data, char *name)
+{
+       guint32 len = 0, unknown = 0, max_len = 0;
+
+       if (flags & PARSE_SCALARS) {
+               offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
+               offset = prs_uint32(tvb, offset, pinfo, tree, &unknown, 
+                                   "Offset");
+               offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, 
+                                   "Max length");
+       }
+
+       if (flags & PARSE_BUFFERS) {
+               guint16 *data16;
+
+               offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
+                                    &data16, "Buffer");
+
+               if (data)
+                       *data = fake_unicode(data16, max_len);
+       }
+
+       return offset;
+}
+
+/* Parse a policy handle. */
+
+int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                  proto_tree *tree)
+{
+       offset = prs_align(offset, 4);
+
+       proto_tree_add_text(tree, tvb, offset, 20, "Policy Handle");
+
+       return offset + 20;
+}
diff --git a/packet-dcerpc-nt.h b/packet-dcerpc-nt.h
new file mode 100644 (file)
index 0000000..be3a813
--- /dev/null
@@ -0,0 +1,74 @@
+/* packet-dcerpc-nt.h
+ * Routines for DCERPC over SMB packet disassembly
+ * Copyright 2001, Tim Potter <tpot@samba.org>
+ *
+ * $Id: packet-dcerpc-nt.h,v 1.1 2001/12/16 20:17:10 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __PACKET_DCERPC_NT_H
+#define __PACKET_DCEPRC_NT_H
+
+/* Routines for parsing simple types */
+
+int prs_align(int offset, int n);
+
+int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo,
+             proto_tree *tree, guint8 *data, char *name);
+
+int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *tree, int count, guint8 **data, char *name);
+
+int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *tree, guint16 *data, char *name);
+
+int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo,
+               proto_tree *tree, int count, guint16 **data, char *name);
+
+int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *tree, guint32 *data, char *name);
+
+int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo,
+               proto_tree *tree, int count, guint32 **data, char *name);
+
+/* Parse NT status code */
+
+int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                proto_tree *tree);
+
+/* Parse some common RPC structures */
+
+int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
+               proto_tree *tree, int flags, char **data, char *name);
+
+int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, 
+                  proto_tree *tree);
+
+/* Routines for handling deferral of referants in NDR */
+
+#define PARSE_SCALARS 1
+#define PARSE_BUFFERS 2
+
+int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                proto_tree *tree, GList **ptr_list, char *name);
+
+guint32 prs_pop_ptr(GList **ptr_list, char *name);
+
+#endif /* packet-dcerpc-nt.h */