aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2002-01-03 20:42:41 +0000
committerGuy Harris <guy@alum.mit.edu>2002-01-03 20:42:41 +0000
commit98b2ecb30478f423a7d7157ff247003095a8a1bd (patch)
tree9d7ed68e6795cb91e489f4b048c0ff1f3823b2c6
parentc57411dbb99eabbb82f118d82a4a974dfa11fad6 (diff)
SPOOLSS RPC dissector, from Tim Potter. This includes adding additional
DOS error codes to the table of them, and exporting that table to other dissectors for protocols using DOS error codes. svn path=/trunk/; revision=4470
-rw-r--r--packet-dcerpc-lsa.c32
-rw-r--r--packet-dcerpc-nt.c13
-rw-r--r--packet-dcerpc-nt.h6
-rw-r--r--packet-dcerpc-reg.c20
-rw-r--r--packet-dcerpc-reg.h19
-rw-r--r--packet-dcerpc-spoolss.c2673
-rw-r--r--packet-dcerpc.c33
-rw-r--r--packet-dcerpc.h12
-rw-r--r--packet-smb.c13
-rw-r--r--smb.h16
10 files changed, 2770 insertions, 67 deletions
diff --git a/packet-dcerpc-lsa.c b/packet-dcerpc-lsa.c
index 8021e04577..b54bd63c7c 100644
--- a/packet-dcerpc-lsa.c
+++ b/packet-dcerpc-lsa.c
@@ -2,7 +2,7 @@
* Routines for SMB \PIPE\lsarpc packet disassembly
* Copyright 2001, Tim Potter <tpot@samba.org>
*
- * $Id: packet-dcerpc-lsa.c,v 1.5 2001/12/17 08:31:26 guy Exp $
+ * $Id: packet-dcerpc-lsa.c,v 1.6 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -47,24 +47,6 @@
*
*/
-/* Convert a (little endian) unicode string to ASCII. We fake it by just
- taking every odd byte. */
-
-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;
@@ -257,7 +239,7 @@ static int LsaClose_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
if (check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "ClosePolicy request");
- offset = prs_policy_hnd(tvb, offset, pinfo, tree);
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
return offset;
}
@@ -268,7 +250,7 @@ static int LsaClose_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
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_policy_hnd(tvb, offset, pinfo, tree, NULL);
offset = prs_ntstatus(tvb, offset, pinfo, tree);
return offset;
@@ -456,7 +438,7 @@ static int LsaOpenPolicy_r(tvbuff_t * tvb, int offset,
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_policy_hnd(tvb, offset, pinfo, tree, NULL);
offset = prs_ntstatus(tvb, offset, pinfo, tree);
return offset;
@@ -601,7 +583,7 @@ static int LsaQueryInfoPolicy_q(tvbuff_t *tvb, int offset,
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_policy_hnd(tvb, offset, pinfo, tree, NULL);
offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Info level");
return offset;
@@ -864,7 +846,7 @@ static int LsaLookupNames_q(tvbuff_t *tvb, int offset,
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_policy_hnd(tvb, offset, pinfo, tree, NULL);
offset = prs_uint32(tvb, offset, pinfo, tree, &count, "Num names");
@@ -1092,7 +1074,7 @@ static int LsaLookupSids_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
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_policy_hnd(tvb, offset, pinfo, tree, NULL);
offset = prs_SID_ARRAY(tvb, offset, pinfo, tree, flags, &ptr_list);
diff --git a/packet-dcerpc-nt.c b/packet-dcerpc-nt.c
index 7af722d4b7..5fe5aeb242 100644
--- a/packet-dcerpc-nt.c
+++ b/packet-dcerpc-nt.c
@@ -2,7 +2,7 @@
* 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 $
+ * $Id: packet-dcerpc-nt.c,v 1.2 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -314,7 +314,7 @@ guint32 prs_pop_ptr(GList **ptr_list, char *name)
fake it by taking every odd byte. )-: The caller must free the
result returned. */
-static char *fake_unicode(guint16 *data, int len)
+char *fake_unicode(guint16 *data, int len)
{
char *buffer;
int i;
@@ -360,11 +360,18 @@ int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* Parse a policy handle. */
int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree)
+ proto_tree *tree, const guint8 **data)
{
+ const guint8 *data8;
+
offset = prs_align(offset, 4);
proto_tree_add_text(tree, tvb, offset, 20, "Policy Handle");
+ data8 = tvb_get_ptr(tvb, offset, 20);
+
+ if (data)
+ *data = data8;
+
return offset + 20;
}
diff --git a/packet-dcerpc-nt.h b/packet-dcerpc-nt.h
index be3a813e07..0eefb97e13 100644
--- a/packet-dcerpc-nt.h
+++ b/packet-dcerpc-nt.h
@@ -2,7 +2,7 @@
* 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 $
+ * $Id: packet-dcerpc-nt.h,v 1.2 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -55,11 +55,13 @@ int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* Parse some common RPC structures */
+char *fake_unicode(guint16 *data, int len);
+
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);
+ proto_tree *tree, const guint8 **data);
/* Routines for handling deferral of referants in NDR */
diff --git a/packet-dcerpc-reg.c b/packet-dcerpc-reg.c
index 7c7900c029..98097d89b2 100644
--- a/packet-dcerpc-reg.c
+++ b/packet-dcerpc-reg.c
@@ -2,7 +2,7 @@
* Routines for SMB \\PIPE\\winreg packet disassembly
* Copyright 2001, Tim Potter <tpot@samba.org>
*
- * $Id: packet-dcerpc-reg.c,v 1.1 2001/11/21 02:08:57 guy Exp $
+ * $Id: packet-dcerpc-reg.c,v 1.2 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -32,6 +32,24 @@
#include "packet-dcerpc.h"
#include "packet-dcerpc-reg.h"
+/* Registry data types */
+
+const value_string reg_datatypes[] = {
+ { REG_NONE, "REG_NONE" },
+ { REG_SZ, "REG_SZ" },
+ { REG_EXPAND_SZ, "REG_EXPAND_SZ" },
+ { REG_BINARY, "REG_BINARY" },
+ { REG_DWORD, "REG_DWORD" },
+ { REG_DWORD_LE, "REG_DWORD_LE" },
+ { REG_DWORD_BE, "REG_DWORD_BE" },
+ { REG_LINK, "REG_LINK" },
+ { REG_MULTI_SZ, "REG_MULTI_SZ" },
+ { REG_RESOURCE_LIST, "REG_RESOURCE_LIST" },
+ { REG_FULL_RESOURCE_DESCRIPTOR, "REG_FULL_RESOURCE_DESCRIPTOR" },
+ { REG_RESOURCE_REQUIREMENTS_LIST, "REG_RESOURCE_REQUIREMENTS_LIST" },
+ {0, NULL }
+};
+
static int proto_dcerpc_reg = -1;
static gint ett_dcerpc_reg = -1;
diff --git a/packet-dcerpc-reg.h b/packet-dcerpc-reg.h
index 941937a2b7..84027af938 100644
--- a/packet-dcerpc-reg.h
+++ b/packet-dcerpc-reg.h
@@ -2,7 +2,7 @@
* Routines for SMB \PIPE\winreg packet disassembly
* Copyright 2001, Tim Potter <tpot@samba.org>
*
- * $Id: packet-dcerpc-reg.h,v 1.3 2001/12/16 20:08:22 guy Exp $
+ * $Id: packet-dcerpc-reg.h,v 1.4 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -56,4 +56,21 @@
#define REG_ABORT_SHUTDOWN 0x19
#define REG_UNK_1A 0x1a
+/* Registry data types */
+
+#define REG_NONE 0
+#define REG_SZ 1
+#define REG_EXPAND_SZ 2
+#define REG_BINARY 3
+#define REG_DWORD 4
+#define REG_DWORD_LE 4 /* DWORD, little endian */
+#define REG_DWORD_BE 5 /* DWORD, big endian */
+#define REG_LINK 6
+#define REG_MULTI_SZ 7
+#define REG_RESOURCE_LIST 8
+#define REG_FULL_RESOURCE_DESCRIPTOR 9
+#define REG_RESOURCE_REQUIREMENTS_LIST 10
+
+extern const value_string reg_datatypes[];
+
#endif /* packet-dcerpc-reg.h */
diff --git a/packet-dcerpc-spoolss.c b/packet-dcerpc-spoolss.c
index 8129f29826..7348abfb04 100644
--- a/packet-dcerpc-spoolss.c
+++ b/packet-dcerpc-spoolss.c
@@ -1,8 +1,8 @@
/* packet-dcerpc-spoolss.c
- * Routines for SMB \\PIPE\\spoolss packet disassembly
+ * Routines for SMB \PIPE\spoolss packet disassembly
* Copyright 2001, Tim Potter <tpot@samba.org>
*
- * $Id: packet-dcerpc-spoolss.c,v 1.1 2001/11/21 02:08:57 guy Exp $
+ * $Id: packet-dcerpc-spoolss.c,v 1.2 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -28,29 +28,2566 @@
#endif
#include <glib.h>
+#include <string.h>
+
#include "packet.h"
#include "packet-dcerpc.h"
+#include "packet-dcerpc-nt.h"
#include "packet-dcerpc-spoolss.h"
+#include "packet-dcerpc-reg.h"
+#include "smb.h"
-static int proto_dcerpc_spoolss = -1;
-static gint ett_dcerpc_spoolss = -1;
+/*
+ * Hash table for matching responses to replies
+ */
-static e_uuid_t uuid_dcerpc_spoolss = {
- 0x12345678, 0x1234, 0xabcd,
- { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
+#define REQUEST_HASH_INIT_COUNT 100
+
+static GHashTable *request_hash;
+static GMemChunk *request_hash_key_chunk;
+static GMemChunk *request_hash_value_chunk;
+
+typedef struct {
+ dcerpc_info di;
+ guint16 opnum;
+} request_hash_key;
+
+typedef struct {
+ guint16 opnum; /* Tag for union */
+
+ guint32 request_num; /* Request frame number */
+ guint32 response_num; /* Response frame number */
+
+ /* Per-request information */
+
+ union {
+ struct {
+ char *printer_name;
+ } OpenPrinterEx;
+ struct {
+ int level;
+ } GetPrinter;
+ } data;
+
+} request_hash_value;
+
+/* Hash a request */
+
+static guint hash_request(gconstpointer k)
+{
+ request_hash_key *r = (request_hash_key *)k;
+
+ return r->di.smb_fid + r->di.call_id + r->di.smb_fid;
+}
+
+/* Compare two requests */
+
+static gint compare_request(gconstpointer k1, gconstpointer k2)
+{
+ request_hash_key *r1 = (request_hash_key *)k1;
+ request_hash_key *r2 = (request_hash_key *)k2;
+
+ return r1->opnum == r2->opnum && r1->di.call_id == r2->di.call_id &&
+ r1->di.smb_fid == r2->di.smb_fid &&
+ r1->di.conv->index == r2->di.conv->index;
+}
+
+/* Store private information for a SPOOLSS request */
+
+static void store_request_info(request_hash_key *key,
+ request_hash_value *value)
+{
+ request_hash_key *chunk_key;
+ request_hash_value *chunk_value;
+
+ chunk_key = g_mem_chunk_alloc(request_hash_key_chunk);
+ chunk_value = g_mem_chunk_alloc(request_hash_value_chunk);
+
+ memcpy(chunk_key, key, sizeof(*key));
+ memcpy(chunk_value, value, sizeof(*value));
+
+ g_hash_table_insert(request_hash, chunk_key, chunk_value);
+}
+
+/* Store private information for a SPOOLSS call with no private
+ information. This is basically for updating the request/response frame
+ numbers. */
+
+#define SPOOLSS_DUMMY (guint16)-1 /* Dummy opnum */
+
+static void store_request_info_none(packet_info *pinfo, dcerpc_info *di)
+{
+ request_hash_key key;
+ request_hash_value value;
+
+ memcpy(&key.di, di, sizeof(*di));
+ key.opnum = SPOOLSS_DUMMY;
+
+ value.opnum = SPOOLSS_DUMMY;
+ value.request_num = pinfo->fd->num;
+ value.response_num = 0;
+
+ store_request_info(&key, &value);
+}
+
+/* Store private information for a OpenPrinterEx request */
+
+static void store_request_info_OpenPrinterEx(packet_info *pinfo,
+ dcerpc_info *di,
+ char *printer_name)
+{
+ request_hash_key key;
+ request_hash_value value;
+
+ memcpy(&key.di, di, sizeof(*di));
+ key.opnum = SPOOLSS_OPENPRINTEREX;
+
+ value.opnum = SPOOLSS_OPENPRINTEREX;
+ value.data.OpenPrinterEx.printer_name = strdup(printer_name);
+ value.request_num = pinfo->fd->num;
+ value.response_num = 0;
+
+ store_request_info(&key, &value);
+}
+
+/* Store private information for a GetPrinter request */
+
+static void store_request_info_GetPrinter(packet_info *pinfo,
+ dcerpc_info *di,
+ int level)
+{
+ request_hash_key key;
+ request_hash_value value;
+
+ memcpy(&key.di, di, sizeof(*di));
+ key.opnum = SPOOLSS_GETPRINTER;
+
+ value.opnum = SPOOLSS_GETPRINTER;
+ value.data.GetPrinter.level = level;
+ value.request_num = pinfo->fd->num;
+ value.response_num = 0;
+
+ store_request_info(&key, &value);
+}
+
+/* Fetch private information for a SPOOLSS request */
+
+static request_hash_value *fetch_request_info(packet_info *pinfo,
+ dcerpc_info *di,
+ guint16 opnum)
+{
+ request_hash_key key;
+ request_hash_value *result;
+
+ key.di = *di;
+ key.opnum = opnum;
+
+ result = g_hash_table_lookup(request_hash, &key);
+
+ if (result && result->opnum != opnum)
+ g_warning("Tag for response packet at frame %d is %d, not %d",
+ pinfo->fd->num, result->opnum, opnum);
+
+ return result;
+}
+
+/* Add a text item like "Response in frame %d" using some request_info */
+
+static void add_request_text(proto_tree *tree, tvbuff_t *tvb, int offset,
+ request_hash_value *request_info)
+{
+ if (request_info && request_info->response_num)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "Response in frame %d",
+ request_info->response_num);
+}
+
+/* Add a text item like "Request in frame %d" using some request_info */
+
+static void add_response_text(proto_tree *tree, tvbuff_t *tvb, int offset,
+ request_hash_value *request_info)
+{
+ if (request_info && request_info->request_num)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "Request in frame %d",
+ request_info->request_num);
+}
+
+/*
+ * Hash table for matching policy handles to printer names
+ */
+
+static int printer_ndx; /* Hack for printer names */
+
+#define POLICY_HND_HASH_INIT_COUNT 100
+
+static GHashTable *policy_hnd_hash;
+static GMemChunk *policy_hnd_hash_key_chunk;
+static GMemChunk *policy_hnd_hash_value_chunk;
+
+typedef struct {
+ guint8 policy_hnd[20];
+} policy_hnd_hash_key;
+
+typedef struct {
+ char *printer_name;
+} policy_hnd_hash_value;
+
+static void dump_policy_hnd(const guint8 *policy_hnd)
+{
+ int i, csum = 0;
+
+ for(i = 0; i < 20; i++) {
+ fprintf(stderr, "%02x ", policy_hnd[i]);
+ csum += policy_hnd[i];
+ }
+
+ fprintf(stderr, "- %d\n", csum);
+}
+
+static guint hash_policy_hnd(gconstpointer k)
+{
+ policy_hnd_hash_key *p = (policy_hnd_hash_key *)k;
+ guint hash;
+
+ /* Bytes 4-7 of the policy handle are a timestamp so should make a
+ reasonable hash value */
+
+ hash = p->policy_hnd[4] + (p->policy_hnd[5] << 8) +
+ (p->policy_hnd[6] << 16) + (p->policy_hnd[7] << 24);
+
+ return hash;
+}
+
+static gint compare_policy_hnd(gconstpointer k1, gconstpointer k2)
+{
+ policy_hnd_hash_key *p1 = (policy_hnd_hash_key *)k1;
+ policy_hnd_hash_key *p2 = (policy_hnd_hash_key *)k2;
+
+ return memcmp(p1->policy_hnd, p2->policy_hnd, 20) == 0;
+}
+
+static gboolean is_null_policy_hnd(const guint8 *policy_hnd)
+{
+ static guint8 null_policy_hnd[20];
+
+ return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
+}
+
+/* Associate a policy handle with a printer name */
+
+static void store_printer_name(const guint8 *policy_hnd, char *printer_name)
+{
+ policy_hnd_hash_key *key;
+ policy_hnd_hash_value *value;
+
+ if (is_null_policy_hnd(policy_hnd))
+ return;
+
+ key = g_mem_chunk_alloc(policy_hnd_hash_key_chunk);
+ value = g_mem_chunk_alloc(policy_hnd_hash_value_chunk);
+
+ memcpy(key->policy_hnd, policy_hnd, 20);
+ value->printer_name = strdup(printer_name);
+
+ g_hash_table_insert(policy_hnd_hash, key, value);
+}
+
+/* Retrieve a printer name from a policy handle */
+
+static char *fetch_printer_name(const guint8 *policy_hnd)
+{
+ policy_hnd_hash_key key;
+ policy_hnd_hash_value *value;
+
+ if (is_null_policy_hnd(policy_hnd))
+ return NULL;
+
+ memcpy(&key.policy_hnd, policy_hnd, 20);
+
+ value = g_hash_table_lookup(policy_hnd_hash, &key);
+
+ if (value)
+ return value->printer_name;
+
+ return NULL;
+}
+
+/* Delete the association between a policy handle and printer name */
+
+static void delete_printer_name(guint8 *policy_hnd)
+{
+}
+
+/* Read a policy handle and append the printer name associated with it to
+ the packet info column */
+
+static void append_printer_name(packet_info *pinfo, tvbuff_t *tvb,
+ int offset, const guint8 *policy_hnd)
+{
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ char *printer_name;
+
+ printer_name = fetch_printer_name(policy_hnd);
+
+ if (printer_name)
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ printer_name);
+ }
+}
+
+/*
+ * New system for handling pointers and buffers. We act more like the NDR
+ * specification and have a list of deferred pointers which are processed
+ * after a structure has been parsed.
+ *
+ * Each structure has a parse function which takes as an argument a GList.
+ * As pointers are processed, they are appended onto this list. When the
+ * structure is complete, the pointers (referents) are processed by calling
+ * prs_referents(). In the case of function arguments, the
+ * prs_struct_and_referents() function is called as pointers are always
+ * processed immediately after the argument.
+ */
+
+typedef int prs_fn(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data);
+
+/* Deferred referent */
+
+struct deferred_ptr {
+ prs_fn *fn; /* Parse function to call */
+ proto_tree *tree; /* Tree context */
};
-static guint16 ver_dcerpc_spoolss = 1;
+/* A structure to hold needed ethereal state to pass to GList foreach
+ iterator. */
+
+struct deferred_ptr_state {
+ tvbuff_t *tvb;
+ int *poffset;
+ packet_info *pinfo;
+ GList **dp_list;
+ void **ptr_data;
+};
+
+void defer_ptr(GList **list, prs_fn *fn, proto_tree *tree)
+{
+ struct deferred_ptr *dr;
+
+ dr = g_malloc(sizeof(struct deferred_ptr));
+
+ dr->fn = fn;
+ dr->tree = tree;
+
+ *list = g_list_append(*list, dr);
+}
+
+/* Parse a pointer */
+
+static int prs_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, guint32 *data, char *name)
+{
+ guint32 ptr;
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &ptr, NULL);
+
+ if (tree && name)
+ proto_tree_add_text(tree, tvb, offset - 4, 4,
+ "%s pointer: 0x%08x", name, ptr);
+
+ if (data)
+ *data = ptr;
+
+ return offset;
+}
+
+/* Iterator function for prs_referents */
+
+static void dr_iterator(gpointer data, gpointer user_data)
+{
+ struct deferred_ptr *dp = (struct deferred_ptr *)data;
+ struct deferred_ptr_state *s = (struct deferred_ptr_state *)user_data;
+
+ /* Parse pointer */
+
+ *s->poffset = dp->fn(s->tvb, *s->poffset, s->pinfo, dp->tree,
+ s->dp_list, s->ptr_data);
+
+ if (s->ptr_data)
+ s->ptr_data++; /* Ready for next parse fn */
+}
+
+/* Call the parse function for each element in the deferred pointers list.
+ If there are any additional pointers in these structures they are pushed
+ onto parent_dp_list. */
+
+int prs_referents(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, GList **list,
+ void ***ptr_data)
+{
+ struct deferred_ptr_state s;
+ int new_offset = offset, list_len;
+
+ /* Create a list of void pointers to store return data */
+
+ if (ptr_data) {
+ list_len = g_list_length(*dp_list);
+ *ptr_data = malloc(list_len * sizeof(void *));
+ }
+
+ /* Set up iterator data */
+
+ s.tvb = tvb;
+ s.poffset = &new_offset;
+ s.pinfo = pinfo;
+ s.dp_list = dp_list;
+ s.ptr_data = ptr_data ? *ptr_data : NULL;
+
+ g_list_foreach(*list, dr_iterator, &s);
+
+ *list = NULL; /* XXX: free list */
+
+ return new_offset;
+}
+
+/* Parse a structure then clean up any deferred referants it creates. */
+
+static int prs_struct_and_referents(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ prs_fn *fn, void **data, void ***ptr_data)
+{
+ GList *dp_list = NULL;
+
+ offset = fn(tvb, offset, pinfo, tree, &dp_list, data);
+
+ offset = prs_referents(tvb, offset, pinfo, tree, &dp_list,
+ &dp_list, ptr_data);
+
+ return offset;
+}
+
+/* Parse a Win32 error, basically a DOS error. The spoolss API doesn't
+ use NT status codes. */
+
+static int prs_werror(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, guint32 *data)
+{
+ 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, DOS_errors,
+ "Unknown error"));
+
+ if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ val_to_str(status, DOS_errors,
+ "Unknown error"));
+
+ if (data)
+ *data = status;
+
+ return offset;
+}
+
+/*
+ * SpoolssClosePrinter
+ */
+
+static int SpoolssClosePrinter_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ const guint8 *policy_hnd;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "ClosePrinter request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, &policy_hnd);
+
+ append_printer_name(pinfo, tvb, offset, policy_hnd);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssClosePrinter_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "ClosePrinter response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/* Parse a UNISTR2 structure */
+
+static gint ett_UNISTR2 = -1;
+
+static int prs_UNISTR2_dp(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 length, the_offset, max_len;
+ int old_offset = offset;
+ guint16 *data16;
+ char *text;
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &length, NULL);
+ offset = prs_uint32(tvb, offset, pinfo, tree, &the_offset, NULL);
+ offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, NULL);
+
+ offset = prs_uint16s(tvb, offset, pinfo, tree, max_len, &data16, NULL);
+
+ text = fake_unicode(data16, max_len);
+
+ item = proto_tree_add_text(tree, tvb, old_offset, offset - old_offset,
+ "UNISTR2: %s", text);
+
+ subtree = proto_item_add_subtree(item, ett_UNISTR2);
+
+ if (data)
+ *data = text;
+ else
+ free(text);
+
+ proto_tree_add_text(subtree, tvb, old_offset, 4, "Length: %d", length);
+
+ old_offset += 4;
+
+ proto_tree_add_text(subtree, tvb, old_offset, 4, "Offset: %d",
+ the_offset);
+
+ old_offset += 4;
+
+ 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, max_len * 2, "Data");
+
+ return offset;
+}
+
+/*
+ * SpoolssGetPrinterData
+ */
+
+static int SpoolssGetPrinterData_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ char *value_name;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "GetPrinterData request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, (void **)&value_name,
+ NULL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
+
+ free(value_name);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Size");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssGetPrinterData_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ guint32 size, type;
+
+ /* Update information fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "GetPrinterData response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
+
+ proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
+ val_to_str(type, reg_datatypes, "Unknown type"));
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &size, "Size");
+
+ offset = prs_uint8s(tvb, offset, pinfo, tree, size, NULL, "Data");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssGetPrinterDataEx
+ */
+
+static int SpoolssGetPrinterDataEx_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ char *key_name, *value_name;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "GetPrinterDataEx request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, (void **)&key_name,
+ NULL);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, (void **)&value_name,
+ NULL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s",
+ key_name, value_name);
+
+ free(key_name);
+ free(value_name);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Size");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssGetPrinterDataEx_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ guint32 size, type;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "GetPrinterDataEx response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
+
+ proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
+ val_to_str(type, reg_datatypes, "Unknown type"));
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &size, "Size");
+
+ offset = prs_uint8s(tvb, offset, pinfo, tree, size, NULL, "Data");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssSetPrinterData
+ */
+
+static int SpoolssSetPrinterData_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ char *value_name;
+ guint32 type, max_len;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "SetPrinterData request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, (void **)&value_name,
+ NULL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
+
+ free(value_name);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
+
+ proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
+ val_to_str(type, reg_datatypes, "Unknown type"));
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, "Max length");
+
+ offset = prs_uint8s(tvb, offset, pinfo, tree, max_len, NULL,
+ "Data");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real length");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssSetPrinterData_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "SetPrinterData response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssSetPrinterDataEx
+ */
+
+static int SpoolssSetPrinterDataEx_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ char *key_name, *value_name;
+ guint32 type, max_len;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "SetPrinterDataEx request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, (void **)&key_name,
+ NULL);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, (void **)&value_name,
+ NULL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s",
+ key_name, value_name);
+
+ free(key_name);
+ free(value_name);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
+
+ proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
+ val_to_str(type, reg_datatypes, "Unknown type"));
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, "Max length");
+
+ offset = prs_uint8s(tvb, offset, pinfo, tree, max_len, NULL,
+ "Data");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real length");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssSetPrinterDataEx_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "SetPrinterDataEx response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/* Yet another way to represent a unicode string - sheesh. */
+
+static int prs_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, void **data, char *name)
+{
+ gint len = 0, remaining, i;
+ guint16 *ptr;
+ char *text;
+
+ offset = prs_align(offset, 2);
+
+ /* Get a pointer to remaining data in buffer */
+
+ remaining = tvb_length_remaining(tvb, offset);
+ ptr = (guint16 *)tvb_get_ptr(tvb, offset, remaining);
+
+ for (i = 0; i < remaining / 2; i++) {
+ if (ptr[i] == 0)
+ break;
+ len++;
+ }
+
+ text = fake_unicode(ptr, len);
+
+ if (name)
+ proto_tree_add_text(tree, tvb, offset, (len + 1) * 2,
+ "%s: %s", name ? name : "UINT16UNI",
+ text);
+
+ if (data)
+ *data = text;
+ else
+ free(text);
+
+ return offset + (len + 1) * 2;
+}
+
+/*
+ * DEVMODE
+ */
+
+static gint ett_DEVMODE = -1;
+
+static int prs_DEVMODE(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+ guint16 extra;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE");
+
+ subtree = proto_item_add_subtree(item, ett_DEVMODE);
+
+ offset = prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Devicename");
+
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Spec version");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Driver version");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Size");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, &extra, "Driver extra");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Fields");
+
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Orientation");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper size");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper length");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper width");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Scale");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Copies");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Default source");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Print quality");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Color");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Duplex");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Y resolution");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "TT option");
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Collate");
+
+ offset = prs_uint16s(tvb, offset, pinfo, subtree, 32, NULL, "Buffer");
+
+ offset = prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Form name");
+
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Log pixels");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Bits per pel");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pels width");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pels height");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Display flags");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Display frequency");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "ICM method");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "ICM intent");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Media type");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Dither type");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Panning width");
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Panning height");
+
+ if (extra != 0)
+ offset = prs_uint8s(tvb, offset, pinfo, subtree, extra, NULL,
+ "Private");
+
+ return offset;
+}
+
+/*
+ * Relative string given by offset into the current buffer. Note that
+ * the offset for subsequent relstrs are against the structure start, not
+ * the point where the offset is parsed from.
+ */
+
+static gint ett_RELSTR = -1;
+
+static int prs_relstr(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, int struct_start,
+ void **data, char *name)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 relstr_offset, relstr_start, relstr_end;
+ guint16 *ptr;
+ char *text;
+ gint len = 0, remaining, i;
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &relstr_offset, NULL);
+
+ relstr_start = relstr_offset + struct_start;
+
+ relstr_end = prs_uint16uni(tvb, relstr_start, pinfo, tree,
+ (void **)&text, NULL);
+
+ item = proto_tree_add_text(tree, tvb, relstr_start,
+ relstr_end - relstr_start, "%s: %s",
+ name ? name : "RELSTR", text);
+
+ subtree = proto_item_add_subtree(item, ett_RELSTR);
+
+ if (data)
+ *data = text;
+ else
+ free(text);
+
+ proto_tree_add_text(subtree, tvb, offset - 4, 4,
+ "Relative offset: %d", relstr_offset);
+
+ proto_tree_add_text(subtree, tvb, relstr_start,
+ relstr_end - relstr_start, "Data");
+
+ return offset;
+}
+
+/*
+ * PRINTER_INFO_0
+ */
+
+static gint ett_PRINTER_INFO_0 = -1;
+
+static int prs_PRINTER_INFO_0(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ int struct_start = offset;
+
+ offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
+ NULL, "Printer name");
+ offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
+ NULL, "Server name");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "CJobs");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total jobs");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total bytes");
+
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Year");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Month");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Day of week");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Day");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Hour");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Minute");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Second");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Milliseconds");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Global counter");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total pages");
+
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Major version");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Build version");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Session counter");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer errors");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Change id");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "C_setprinter");
+
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+ offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
+
+ return offset;
+}
+
+/*
+ * PRINTER_INFO_1
+ */
+
+static gint ett_PRINTER_INFO_1 = -1;
+
+static int prs_PRINTER_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ return offset;
+}
+
+/*
+ * PRINTER_INFO_2
+ */
+
+static gint ett_PRINTER_INFO_2 = -1;
+
+static int prs_PRINTER_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ return offset;
+}
+
+/*
+ * PRINTER_INFO_3
+ */
+
+static gint ett_PRINTER_INFO_3 = -1;
+
+static int prs_PRINTER_INFO_3(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ return offset;
+}
+
+/*
+ * DEVMODE_CTR
+ */
+
+static gint ett_DEVMODE_CTR = -1;
+
+static int prs_DEVMODE_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE_CTR");
+
+ subtree = proto_item_add_subtree(item, ett_DEVMODE_CTR);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Devicemode");
+
+ if (ptr)
+ defer_ptr(dp_list, prs_DEVMODE, subtree);
+
+ return offset;
+}
+
+/*
+ * PRINTER_DEFAULT structure
+ */
+
+static gint ett_PRINTER_DEFAULT = -1;
+
+static int prs_PRINTER_DEFAULT(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ GList *child_dp_list = NULL;
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0, access;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "PRINTER_DEFAULT");
+
+ subtree = proto_item_add_subtree(item, ett_PRINTER_DEFAULT);
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Datatype");
+
+ /* Not sure why this isn't a deferred pointer. I think this may be
+ two structures stuck together. */
+
+ if (ptr)
+ offset = prs_UNISTR2_dp(tvb, offset, pinfo, subtree, dp_list,
+ NULL);
+
+ offset = prs_DEVMODE_CTR(tvb, offset, pinfo, subtree,
+ &child_dp_list, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, &access, NULL);
+
+ proto_tree_add_text(subtree, tvb, offset - 4, 4,
+ "Access required: 0x%08x", access);
+
+ offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
+ &child_dp_list, NULL);
+
+ return offset;
+}
+
+/*
+ * USER_LEVEL_1 structure
+ */
+
+static gint ett_USER_LEVEL_1 = -1;
+
+static int prs_USER_LEVEL_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL_1");
+
+ subtree = proto_item_add_subtree(item, ett_USER_LEVEL_1);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Client name");
+
+ if (ptr)
+ defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User name");
+
+ if (ptr)
+ defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Build");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Major");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Minor");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Processor");
+
+ return offset;
+}
+
+/*
+ * USER_LEVEL structure
+ */
+
+static gint ett_USER_LEVEL = -1;
+
+static int prs_USER_LEVEL(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **parent_dp_list,
+ void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+ guint32 level;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL");
+
+ subtree = proto_item_add_subtree(item, ett_USER_LEVEL);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Info level");
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User level");
+
+ if (ptr) {
+ switch (level) {
+ case 1:
+ defer_ptr(parent_dp_list, prs_USER_LEVEL_1, subtree);
+ break;
+ default:
+ proto_tree_add_text(
+ tree, tvb, offset, 0,
+ "[GetPrinter level %d not decoded]", level);
+ break;
+ }
+ }
+
+ return offset;
+}
+
+/*
+ * SpoolssOpenPrinterEx
+ */
+
+static int SpoolssOpenPrinterEx_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ char *printer_name;
+ guint32 ptr = 0;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "OpenPrinterEx request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_OPENPRINTEREX);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+
+ /* Parse packet */
+
+ offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Printer name");
+
+ if (ptr) {
+ char *printer_name;
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp,
+ (void **)&printer_name,
+ NULL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ printer_name);
+
+ if (!request_info) {
+
+ /* Store printer name to match with response packet */
+
+ store_request_info_OpenPrinterEx(pinfo, di,
+ printer_name);
+ }
+
+ free(printer_name);
+ }
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_PRINTER_DEFAULT, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_USER_LEVEL, NULL, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssOpenPrinterEx_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ int start_offset = offset;
+ guint32 status;
+
+ /* Display informational data */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "OpenPrinterEx response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_OPENPRINTEREX);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_werror(tvb, offset, pinfo, tree, &status);
+
+ if (status == 0) {
+ const guint8 *policy_hnd;
+
+ /* Associate the returned printer handle with a name */
+
+ policy_hnd = tvb_get_ptr(tvb, start_offset, 20);
+
+ if (request_info) {
+ char *printer_name;
+
+ printer_name =
+ request_info->data.OpenPrinterEx.printer_name;
+
+ if (printer_name)
+ store_printer_name(policy_hnd, printer_name);
+ }
+ }
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * NOTIFY_OPTION_DATA structure
+ */
+
+static gint ett_NOTIFY_OPTION_DATA = -1;
+
+static int prs_NOTIFY_OPTION_DATA(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ GList **parent_dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 count, i;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION_DATA");
+
+ subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_DATA);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, &count, "Count");
+
+ for (i = 0; i < count; i++)
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL,
+ "Field");
+
+ return offset;
+}
+
+/*
+ * NOTIFY_OPTION structure
+ */
+
+static gint ett_NOTIFY_OPTION = -1;
+
+static int prs_NOTIFY_OPTION(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **parent_dp_list,
+ void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION");
+
+ subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION);
+
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Type");
+
+ offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Reserved");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Count");
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Fields");
+
+ if (ptr)
+ defer_ptr(parent_dp_list, prs_NOTIFY_OPTION_DATA, subtree);
+
+ return offset;
+}
+
+/*
+ * NOTIFY_OPTION_CTR structure
+ */
+
+static gint ett_NOTIFY_OPTION_CTR = -1;
+
+static int prs_NOTIFY_OPTION_CTR(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ GList **dp_list, void **data)
+{
+ GList *child_dp_list = NULL;
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 count, i, ptr;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0,
+ "NOTIFY_OPTION_CTR");
+
+ subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_CTR);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, &count, "Count");
+
+ for (i = 0; i < count; i++)
+ offset = prs_NOTIFY_OPTION(tvb, offset, pinfo, subtree,
+ &child_dp_list, NULL);
+
+ offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
+ &child_dp_list, NULL);
+
+ return offset;
+}
+
+/*
+ * NOTIFY_OPTION structure
+ */
+
+gint ett_NOTIFY_OPTION_ARRAY = -1;
+
+static int prs_NOTIFY_OPTION_ARRAY(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0,
+ "NOTIFY_OPTION_ARRAY");
+
+ subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_ARRAY);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Version");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Flags");
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Count");
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Option type");
+
+ if (ptr)
+ defer_ptr(dp_list, prs_NOTIFY_OPTION_CTR, subtree);
+
+ return offset;
+}
+
+/*
+ * SpoolssRFFPCNEX
+ */
+
+static int SpoolssRFFPCNEX_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ char *printer_name;
+ guint32 ptr = 0;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "RFFPCNEX request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Options");
+
+ offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Local machine");
+
+ if (ptr) {
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp,
+ (void *)&printer_name, NULL);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ printer_name);
+ }
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer local");
+
+ offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Option");
+
+ if (ptr) {
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_NOTIFY_OPTION_ARRAY,
+ NULL, NULL);
+ }
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssRFFPCNEX_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "RFFPCNEX response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssReplyOpenPrinter
+ */
+
+static int SpoolssReplyOpenPrinter_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ guint32 ptr = 0, type;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "ReplyOpenPrinter request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
+
+ proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
+ val_to_str(type, reg_datatypes, "Unknown type"));
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssReplyOpenPrinter_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "ReplyOpenPrinter response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * BUFFER_DATA
+ */
+
+static gint ett_BUFFER_DATA = -1;
+static gint ett_BUFFER_DATA_BUFFER = -1;
+
+struct BUFFER_DATA {
+ guint8 *data8; /* Pointer to buffer data */
+ proto_item *item; /* proto_item holding proto_tree */
+ proto_tree *tree; /* proto_tree holding buffer data */
+ tvbuff_t *tvb;
+ int offset; /* Offset where data starts in tvb*/
+};
+
+static int prs_BUFFER_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree, *subsubtree;
+ guint32 ptr = 0, size;
+ guint8 *data8;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER_DATA");
+
+ subtree = proto_item_add_subtree(item, ett_BUFFER_DATA);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, &size, "Size");
+
+ item = proto_tree_add_text(subtree, tvb, offset, size, "Data");
+
+ subsubtree = proto_item_add_subtree(item, ett_BUFFER_DATA_BUFFER);
+
+ offset = prs_uint8s(tvb, offset, pinfo, subsubtree, size, &data8,
+ NULL);
+
+ /* Return some info which will help the caller "cast" the buffer
+ data and dissect it further. */
+
+ if (data) {
+ struct BUFFER_DATA *bd;
+
+ bd = (struct BUFFER_DATA *)malloc(sizeof(struct BUFFER_DATA));
+
+ bd->data8 = data8;
+ bd->item = item;
+ bd->tree = subsubtree;
+ bd->tvb = tvb;
+ bd->offset = offset - size;
+
+ *data = bd;
+ }
+
+ return offset;
+}
+
+/*
+ * BUFFER
+ */
+
+static gint ett_BUFFER = -1;
+
+static int prs_BUFFER(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER");
+
+ subtree = proto_item_add_subtree(item, ett_BUFFER);
+
+ offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Data");
+
+ if (ptr)
+ defer_ptr(dp_list, prs_BUFFER_DATA, subtree);
+
+ return offset;
+}
+
+/*
+ * SpoolssGetPrinter
+ */
+
+static int SpoolssGetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ guint32 level;
+ const guint8 *policy_hnd;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "GetPrinter request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_GETPRINTER);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, &policy_hnd);
+
+ append_printer_name(pinfo, tvb, offset, policy_hnd);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_BUFFER, NULL, NULL);
+
+ if (!request_info) {
+
+ /* Store info level to match with response packet */
+
+ store_request_info_GetPrinter(pinfo, di, level);
+ }
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssGetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ void **data_list;
+ struct BUFFER_DATA *bd;
+ guint8 *data8;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "GetPrinter response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_GETPRINTER);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_BUFFER, (void **)&data8,
+ &data_list);
+
+ bd = (struct BUFFER_DATA *)data_list[0];
+
+ if (bd->tree && request_info) {
+ gint16 level = request_info->data.GetPrinter.level;
+
+ proto_item_append_text(bd->item, ", PRINTER_INFO_%d", level);
+
+ switch (level) {
+ case 0:
+ prs_PRINTER_INFO_0(bd->tvb, bd->offset, pinfo,
+ bd->tree, &dp_list, NULL);
+ break;
+
+ default:
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Unimplemented info level %d]",
+ level);
+ break;
+ }
+ }
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SPOOL_PRINTER_INFO_LEVEL
+ */
+
+static gint ett_SPOOL_PRINTER_INFO_LEVEL = -1;
+
+static int prs_SPOOL_PRINTER_INFO_LEVEL(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ GList **dp_list, void **data)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ guint32 ptr = 0, level;
+
+ item = proto_tree_add_text(tree, tvb, offset, 0,
+ "SPOOL_PRINTER_INFO_LEVEL");
+
+ subtree = proto_item_add_subtree(item, ett_SPOOL_PRINTER_INFO_LEVEL);
+
+ offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level");
+
+ /* ptr */
+
+ switch(level) {
+ }
+
+ return offset;
+}
+
+/*
+ * SpoolssSetPrinter
+ */
+
+static int SpoolssSetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ guint32 level;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "SetPrinter request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
+
+ /* printer_info_level */
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_SPOOL_PRINTER_INFO_LEVEL,
+ NULL, NULL);
+
+ /* devmode_ctr */
+
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Command");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssSetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "SetPrinter response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssEnumForms
+ */
+
+static int SpoolssEnumForms_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+ guint32 level;
+ const guint8 *policy_hnd;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "EnumForms request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, &policy_hnd);
+
+ append_printer_name(pinfo, tvb, offset, policy_hnd);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_BUFFER, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssEnumForms_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ GList *dp_list = NULL;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "EnumForms response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_BUFFER, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Num entries");
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssDeletePrinter
+ */
+
+static int SpoolssDeletePrinter_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ const guint8 *policy_hnd;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "DeletePrinter request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, &policy_hnd);
+
+ append_printer_name(pinfo, tvb, offset, policy_hnd);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssDeletePrinter_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "DeletePrinter response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * AddPrinterEx
+ */
+
+static int SpoolssAddPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ int start_offset = offset;
+ guint32 status;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterEx response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, NULL);
+
+ offset = prs_werror(tvb, offset, pinfo, tree, &status);
+
+ if (status == 0) {
+ const guint8 *policy_hnd;
+ char *printer_name;
+
+ /* Associate the returned printer handle with a name */
+
+ policy_hnd = tvb_get_ptr(tvb, start_offset, 20);
+
+ printer_name = strdup("<printer name here>");
+
+ store_printer_name(policy_hnd, printer_name);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ printer_name);
+
+ free(printer_name);
+ }
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssEnumPrinterData
+ */
+
+static int SpoolssEnumPrinterData_q(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ const guint8 *policy_hnd;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinterData request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_policy_hnd(tvb, offset, pinfo, tree, &policy_hnd);
+
+ append_printer_name(pinfo, tvb, offset, policy_hnd);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Index");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Value size");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Data size");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssEnumPrinterData_r(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree,
+ char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ guint32 data_size, type;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO,
+ "EnumPrinterData response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Value size");
+
+ /* unistr2_dp */
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real value size");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
+
+ proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
+ val_to_str(type, reg_datatypes, "Unknown type"));
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &data_size, "Data size");
+
+ offset = prs_uint8s(tvb, offset, pinfo, tree, data_size, NULL,
+ "Data");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real data size");
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+/*
+ * SpoolssEnumPrinters
+ */
+
+static int SpoolssEnumPrinters_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+ guint32 ptr, level;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinters request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
+
+ offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Devicemode");
+
+ if (ptr)
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_UNISTR2_dp, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", level, %d", level);
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_BUFFER, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssEnumPrinters_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinters response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
+ prs_BUFFER, NULL, NULL);
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
+
+ offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Returned");
+
+ offset = prs_werror(tvb, offset, pinfo, tree, NULL);
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+#if 0
+
+/* Templates for new subdissectors */
+
+/*
+ * FOO
+ */
+
+static int SpoolssFoo_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Foo request");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+
+ if (request_info)
+ add_request_text(tree, tvb, offset, request_info);
+ else
+ store_request_info_none(pinfo, di);
+
+ /* Parse packet */
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+static int SpoolssFoo_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
+ request_hash_value *request_info;
+
+ /* Update informational fields */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Foo response");
+
+ request_info = fetch_request_info(pinfo, di, SPOOLSS_DUMMY);
+ add_response_text(tree, tvb, offset, request_info);
+
+ if (request_info)
+ request_info->response_num = pinfo->fd->num;
+
+ /* Parse packet */
+
+ if (tvb_length_remaining(tvb, offset) != 0)
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "[Long frame (%d bytes): SPOOLSS]",
+ tvb_length_remaining(tvb, offset));
+
+ return offset;
+}
+
+#endif
+
+/*
+ * List of subdissectors for this pipe.
+ */
static dcerpc_sub_dissector dcerpc_spoolss_dissectors[] = {
- { SPOOLSS_ENUMPRINTERS, "SPOOLSS_ENUMPRINTERS", NULL, NULL },
+ { SPOOLSS_ENUMPRINTERS, "SPOOLSS_ENUMPRINTERS",
+ SpoolssEnumPrinters_q, SpoolssEnumPrinters_r },
{ SPOOLSS_SETJOB, "SPOOLSS_SETJOB", NULL, NULL },
{ SPOOLSS_GETJOB, "SPOOLSS_GETJOB", NULL, NULL },
{ SPOOLSS_ENUMJOBS, "SPOOLSS_ENUMJOBS", NULL, NULL },
{ SPOOLSS_ADDPRINTER, "SPOOLSS_ADDPRINTER", NULL, NULL },
- { SPOOLSS_DELETEPRINTER, "SPOOLSS_DELETEPRINTER", NULL, NULL },
- { SPOOLSS_SETPRINTER, "SPOOLSS_SETPRINTER", NULL, NULL },
- { SPOOLSS_GETPRINTER, "SPOOLSS_GETPRINTER", NULL, NULL },
+ { SPOOLSS_DELETEPRINTER, "SPOOLSS_DELETEPRINTER",
+ SpoolssDeletePrinter_q, SpoolssDeletePrinter_r },
+ { SPOOLSS_SETPRINTER, "SPOOLSS_SETPRINTER",
+ SpoolssSetPrinter_q, SpoolssSetPrinter_r },
+ { SPOOLSS_GETPRINTER, "SPOOLSS_GETPRINTER",
+ SpoolssGetPrinter_q, SpoolssGetPrinter_r },
{ SPOOLSS_ADDPRINTERDRIVER, "SPOOLSS_ADDPRINTERDRIVER", NULL, NULL },
{ SPOOLSS_ENUMPRINTERDRIVERS, "SPOOLSS_ENUMPRINTERDRIVERS", NULL, NULL },
{ SPOOLSS_GETPRINTERDRIVERDIRECTORY, "SPOOLSS_GETPRINTERDRIVERDIRECTORY", NULL, NULL },
@@ -65,47 +2602,137 @@ static dcerpc_sub_dissector dcerpc_spoolss_dissectors[] = {
{ SPOOLSS_ENDDOCPRINTER, "SPOOLSS_ENDDOCPRINTER", NULL, NULL },
{ SPOOLSS_ADDJOB, "SPOOLSS_ADDJOB", NULL, NULL },
{ SPOOLSS_SCHEDULEJOB, "SPOOLSS_SCHEDULEJOB", NULL, NULL },
- { SPOOLSS_GETPRINTERDATA, "SPOOLSS_GETPRINTERDATA", NULL, NULL },
- { SPOOLSS_SETPRINTERDATA, "SPOOLSS_SETPRINTERDATA", NULL, NULL },
- { SPOOLSS_CLOSEPRINTER, "SPOOLSS_CLOSEPRINTER", NULL, NULL },
+ { SPOOLSS_GETPRINTERDATA, "SPOOLSS_GETPRINTERDATA",
+ SpoolssGetPrinterData_q, SpoolssGetPrinterData_r },
+ { SPOOLSS_SETPRINTERDATA, "SPOOLSS_SETPRINTERDATA",
+ SpoolssSetPrinterData_q, SpoolssSetPrinterData_r },
+ { SPOOLSS_CLOSEPRINTER, "SPOOLSS_CLOSEPRINTER",
+ SpoolssClosePrinter_q, SpoolssClosePrinter_r },
{ SPOOLSS_ADDFORM, "SPOOLSS_ADDFORM", NULL, NULL },
{ SPOOLSS_DELETEFORM, "SPOOLSS_DELETEFORM", NULL, NULL },
{ SPOOLSS_GETFORM, "SPOOLSS_GETFORM", NULL, NULL },
{ SPOOLSS_SETFORM, "SPOOLSS_SETFORM", NULL, NULL },
- { SPOOLSS_ENUMFORMS, "SPOOLSS_ENUMFORMS", NULL, NULL },
+ { SPOOLSS_ENUMFORMS, "SPOOLSS_ENUMFORMS",
+ SpoolssEnumForms_q, SpoolssEnumForms_r },
{ SPOOLSS_ENUMPORTS, "SPOOLSS_ENUMPORTS", NULL, NULL },
{ SPOOLSS_ENUMMONITORS, "SPOOLSS_ENUMMONITORS", NULL, NULL },
{ SPOOLSS_ENUMPRINTPROCDATATYPES, "SPOOLSS_ENUMPRINTPROCDATATYPES", NULL, NULL },
{ SPOOLSS_GETPRINTERDRIVER2, "SPOOLSS_GETPRINTERDRIVER2", NULL, NULL },
{ SPOOLSS_FCPN, "SPOOLSS_FCPN", NULL, NULL },
- { SPOOLSS_REPLYOPENPRINTER, "SPOOLSS_REPLYOPENPRINTER", NULL, NULL },
+ { SPOOLSS_REPLYOPENPRINTER, "SPOOLSS_REPLYOPENPRINTER",
+ SpoolssReplyOpenPrinter_q, SpoolssReplyOpenPrinter_r },
{ SPOOLSS_REPLYCLOSEPRINTER, "SPOOLSS_REPLYCLOSEPRINTER", NULL, NULL },
- { SPOOLSS_RFFPCNEX, "SPOOLSS_RFFPCNEX", NULL, NULL },
+ { SPOOLSS_RFFPCNEX, "SPOOLSS_RFFPCNEX",
+ SpoolssRFFPCNEX_q, SpoolssRFFPCNEX_r },
{ SPOOLSS_RRPCN, "SPOOLSS_RRPCN", NULL, NULL },
{ SPOOLSS_RFNPCNEX, "SPOOLSS_RFNPCNEX", NULL, NULL },
- { SPOOLSS_OPENPRINTEREX, "SPOOLSS_OPENPRINTEREX", NULL, NULL },
- { SPOOLSS_ADDPRINTEREX, "SPOOLSS_ADDPRINTEREX", NULL, NULL },
- { SPOOLSS_ENUMPRINTERDATA, "SPOOLSS_ENUMPRINTERDATA", NULL, NULL },
+ { SPOOLSS_OPENPRINTEREX, "SPOOLSS_OPENPRINTEREX",
+ SpoolssOpenPrinterEx_q, SpoolssOpenPrinterEx_r },
+ { SPOOLSS_ADDPRINTEREX, "SPOOLSS_ADDPRINTEREX",
+ NULL, SpoolssAddPrinterEx_r },
+ { SPOOLSS_ENUMPRINTERDATA, "SPOOLSS_ENUMPRINTERDATA",
+ SpoolssEnumPrinterData_q, SpoolssEnumPrinterData_r },
{ SPOOLSS_DELETEPRINTERDATA, "SPOOLSS_DELETEPRINTERDATA", NULL, NULL },
- { SPOOLSS_GETPRINTERDATAEX, "SPOOLSS_GETPRINTERDATAEX", NULL, NULL },
- { SPOOLSS_SETPRINTERDATAEX, "SPOOLSS_SETPRINTERDATAEX", NULL, NULL },
+ { SPOOLSS_GETPRINTERDATAEX, "SPOOLSS_GETPRINTERDATAEX",
+ SpoolssGetPrinterDataEx_q, SpoolssGetPrinterDataEx_r },
+ { SPOOLSS_SETPRINTERDATAEX, "SPOOLSS_SETPRINTERDATAEX",
+ SpoolssSetPrinterDataEx_q, SpoolssSetPrinterDataEx_r },
{0, NULL, NULL, NULL },
};
+/*
+ * Dissector initialisation function
+ */
+
+static void spoolss_init(void)
+{
+ /* Initialise policy handle to printer name hash table */
+
+ if (policy_hnd_hash_key_chunk)
+ g_mem_chunk_destroy(policy_hnd_hash_key_chunk);
+
+ if (policy_hnd_hash_value_chunk)
+ g_mem_chunk_destroy(policy_hnd_hash_value_chunk);
+
+ policy_hnd_hash_key_chunk = g_mem_chunk_new(
+ "policy_hnd_hash_key_chunk", sizeof(policy_hnd_hash_key),
+ POLICY_HND_HASH_INIT_COUNT * sizeof(policy_hnd_hash_key),
+ G_ALLOC_ONLY);
+
+ policy_hnd_hash_value_chunk = g_mem_chunk_new(
+ "policy_hnd_hash_value_chunk", sizeof(policy_hnd_hash_value),
+ POLICY_HND_HASH_INIT_COUNT * sizeof(policy_hnd_hash_value),
+ G_ALLOC_ONLY);
+
+ policy_hnd_hash = g_hash_table_new(hash_policy_hnd,
+ compare_policy_hnd);
+
+ /* Initialise request/response matching hash table */
+
+ if (request_hash_key_chunk)
+ g_mem_chunk_destroy(request_hash_key_chunk);
+
+ request_hash_key_chunk = g_mem_chunk_new(
+ "request_hash_key_chunk", sizeof(request_hash_key),
+ REQUEST_HASH_INIT_COUNT * sizeof(request_hash_key),
+ G_ALLOC_ONLY);
+
+ request_hash_value_chunk = g_mem_chunk_new(
+ "request_hash_value_chunk", sizeof(request_hash_value),
+ REQUEST_HASH_INIT_COUNT * sizeof(request_hash_value),
+ G_ALLOC_ONLY);
+
+ request_hash = g_hash_table_new(hash_request, compare_request);
+}
+
+/* Protocol registration */
+
+static int proto_dcerpc_spoolss = -1;
+static gint ett_dcerpc_spoolss = -1;
+
void
proto_register_dcerpc_spoolss(void)
{
static gint *ett[] = {
&ett_dcerpc_spoolss,
+ &ett_NOTIFY_OPTION_ARRAY,
+ &ett_NOTIFY_OPTION_CTR,
+ &ett_NOTIFY_OPTION,
+ &ett_NOTIFY_OPTION_DATA,
+ &ett_PRINTER_DEFAULT,
+ &ett_DEVMODE_CTR,
+ &ett_DEVMODE,
+ &ett_USER_LEVEL,
+ &ett_USER_LEVEL_1,
+ &ett_BUFFER,
+ &ett_BUFFER_DATA,
+ &ett_BUFFER_DATA_BUFFER,
+ &ett_UNISTR2,
+ &ett_PRINTER_INFO_0,
+ &ett_PRINTER_INFO_1,
+ &ett_PRINTER_INFO_2,
+ &ett_PRINTER_INFO_3,
+ &ett_RELSTR,
};
proto_dcerpc_spoolss = proto_register_protocol(
"Microsoft Spool Subsystem", "SPOOLSS", "spoolss");
proto_register_subtree_array(ett, array_length(ett));
+
+ register_init_routine(spoolss_init);
}
+/* Protocol handoff */
+
+static e_uuid_t uuid_dcerpc_spoolss = {
+ 0x12345678, 0x1234, 0xabcd,
+ { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
+};
+
+static guint16 ver_dcerpc_spoolss = 1;
+
void
proto_reg_handoff_dcerpc_spoolss(void)
{
diff --git a/packet-dcerpc.c b/packet-dcerpc.c
index 3f66b627c5..9f04aeca90 100644
--- a/packet-dcerpc.c
+++ b/packet-dcerpc.c
@@ -2,7 +2,7 @@
* Routines for DCERPC packet disassembly
* Copyright 2001, Todd Sabin <tas@webspan.net>
*
- * $Id: packet-dcerpc.c,v 1.22 2001/12/17 23:08:51 guy Exp $
+ * $Id: packet-dcerpc.c,v 1.23 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -436,7 +436,7 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
tvbuff_t *tvb, gint offset,
e_uuid_t *uuid, guint16 ver,
guint16 opnum, gboolean is_rqst,
- char *drep)
+ char *drep, dcerpc_info *info)
{
dcerpc_uuid_key key;
dcerpc_uuid_value *sub_proto;
@@ -446,6 +446,7 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
gchar *name = NULL;
dcerpc_dissect_fnct_t *sub_dissect;
const char *saved_proto;
+ void *saved_private_data;
key.uuid = *uuid;
key.ver = ver;
@@ -498,9 +499,14 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
if (sub_dissect) {
saved_proto = pinfo->current_proto;
+ saved_private_data = pinfo->private_data;
pinfo->current_proto = sub_proto->name;
+ pinfo->private_data = (void *)info;
+
sub_dissect (tvb, offset, pinfo, sub_tree, drep);
+
pinfo->current_proto = saved_proto;
+ pinfo->private_data = saved_private_data;
} else {
length = tvb_length_remaining (tvb, offset);
if (length > 0) {
@@ -841,6 +847,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr
dcerpc_conv_key key;
dcerpc_conv_value *value;
int length, reported_length, stub_length;
+ dcerpc_info di;
key.conv = conv;
key.ctx_id = ctx_id;
@@ -860,11 +867,14 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr
length = stub_length;
if (reported_length > stub_length)
reported_length = stub_length;
+ di.conv = conv;
+ di.call_id = hdr->call_id;
+ di.smb_fid = key.smb_fid;
dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
tvb_new_subset (tvb, offset, length,
reported_length),
0, &value->uuid, value->ver,
- opnum, TRUE, hdr->drep);
+ opnum, TRUE, hdr->drep, &di);
}
}
}
@@ -905,6 +915,8 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr
int length, reported_length, stub_length;
if (value) {
+ dcerpc_info di;
+
/* handoff this call */
length = tvb_length_remaining(tvb, offset);
reported_length = tvb_reported_length_remaining(tvb, offset);
@@ -913,11 +925,14 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr
length = stub_length;
if (reported_length > stub_length)
reported_length = stub_length;
+ di.conv = conv;
+ di.call_id = hdr->call_id;
+ di.smb_fid = get_smb_fid(pinfo->private_data);
dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
tvb_new_subset (tvb, offset, length,
reported_length),
0, &value->uuid, value->ver,
- value->opnum, FALSE, hdr->drep);
+ value->opnum, FALSE, hdr->drep, &di);
}
}
}
@@ -1346,22 +1361,26 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/*
* Packet type specific stuff is next.
*/
+
switch (hdr.ptype) {
case PDU_REQ:
dcerpc_call_add_map (hdr.seqnum, conv, hdr.opnum,
hdr.if_ver, &hdr.if_id);
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
- &hdr.if_id, hdr.if_ver, hdr.opnum, TRUE, hdr.drep);
+ &hdr.if_id, hdr.if_ver, hdr.opnum, TRUE,
+ hdr.drep, NULL);
break;
case PDU_RESP:
{
dcerpc_call_value *v = dcerpc_call_lookup (hdr.seqnum, conv);
if (v) {
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
- &v->uuid, v->ver, v->opnum, FALSE, hdr.drep);
+ &v->uuid, v->ver, v->opnum, FALSE,
+ hdr.drep, NULL);
} else {
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
- &hdr.if_id, hdr.if_ver, hdr.opnum, FALSE, hdr.drep);
+ &hdr.if_id, hdr.if_ver, hdr.opnum, FALSE,
+ hdr.drep, NULL);
}
}
break;
diff --git a/packet-dcerpc.h b/packet-dcerpc.h
index c2799ccb17..5b36a622b2 100644
--- a/packet-dcerpc.h
+++ b/packet-dcerpc.h
@@ -1,7 +1,7 @@
/* packet-dcerpc.h
* Copyright 2001, Todd Sabin <tas@webspan.net>
*
- * $Id: packet-dcerpc.h,v 1.5 2001/12/06 23:30:35 guy Exp $
+ * $Id: packet-dcerpc.h,v 1.6 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -25,6 +25,8 @@
#ifndef __PACKET_DCERPC_H__
#define __PACKET_DCERPC_H__
+#include "conversation.h"
+
typedef struct _e_uuid_t {
guint32 Data1;
guint16 Data2;
@@ -155,4 +157,12 @@ typedef struct _dcerpc_private_info {
} data;
} dcerpc_private_info;
+/* Private data passed to subdissectors from the main DCERPC dissector. */
+
+typedef struct _dcerpc_info {
+ conversation_t *conv; /* Which TCP stream we are in */
+ guint32 call_id; /* Context id for this call */
+ guint16 smb_fid; /* FID for DCERPC over SMB */
+} dcerpc_info;
+
#endif /* packet-dcerpc.h */
diff --git a/packet-smb.c b/packet-smb.c
index 04198c42f5..154b709fd6 100644
--- a/packet-smb.c
+++ b/packet-smb.c
@@ -3,7 +3,7 @@
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
* 2001 Rewrite by Ronnie Sahlberg and Guy Harris
*
- * $Id: packet-smb.c,v 1.189 2001/12/18 08:55:49 guy Exp $
+ * $Id: packet-smb.c,v 1.190 2002/01/03 20:42:40 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -12343,7 +12343,9 @@ static const value_string errcls_types[] = {
{ 0, NULL }
};
-static const value_string DOS_errors[] = {
+const value_string DOS_errors[] = {
+ {0, "Success"},
+ {SMBE_insufficientbuffer, "Insufficient buffer"},
{SMBE_badfunc, "Invalid function (or system call)"},
{SMBE_badfile, "File not found (pathname error)"},
{SMBE_badpath, "Directory not found"},
@@ -12379,6 +12381,13 @@ static const value_string DOS_errors[] = {
{SMBE_unknownipc, "Unknown IPC Operation"},
{SMBE_noipc, "Don't support ipc"},
{SMBE_alreadyexists, "File already exists"},
+ {SMBE_unknownprinterdriver, "Unknown printer driver"},
+ {SMBE_invalidprintername, "Invalid printer name"},
+ {SMBE_printeralreadyexists, "Printer already exists"},
+ {SMBE_invaliddatatype, "Invalid data type"},
+ {SMBE_invalidenvironment, "Invalid environment"},
+ {SMBE_printerdriverinuse, "Printer driver in use"},
+ {SMBE_invalidparam, "Invalid parameter"},
{0, NULL}
};
diff --git a/smb.h b/smb.h
index 646ab9cbc7..f710139835 100644
--- a/smb.h
+++ b/smb.h
@@ -2,7 +2,7 @@
* Defines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: smb.h,v 1.30 2001/12/06 23:30:36 guy Exp $
+ * $Id: smb.h,v 1.31 2002/01/03 20:42:41 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -136,7 +136,9 @@
#define SMBE_unsup 50 /* Request unsupported, returned by Win 95, RJS 20Jun98 */
#define SMBE_nosuchshare 67 /* Share does not exits */
#define SMBE_filexists 80 /* File in operation already exists */
+#define SMBE_invalidparam 87 /* Invalid parameter */
#define SMBE_cannotopen 110 /* Cannot open the file specified */
+#define SMBE_insufficientbuffer 122/* Insufficient buffer size */
#define SMBE_unknownlevel 124
#define SMBE_alreadyexists 183 /* File already exists */
#define SMBE_badpipe 230 /* Named pipe invalid */
@@ -151,6 +153,15 @@
#define SMBE_unknownipc 2142
#define SMBE_noipc 66 /* don't support ipc */
+/* These errors seem to be only returned by the NT printer driver system */
+
+#define SMBE_unknownprinterdriver 1797 /* Unknown printer driver */
+#define SMBE_invalidprintername 1801 /* Invalid printer name */
+#define SMBE_printeralreadyexists 1802 /* Printer already exists */
+#define SMBE_invaliddatatype 1804 /* Invalid datatype */
+#define SMBE_invalidenvironment 1805 /* Invalid environment */
+#define SMBE_printerdriverinuse 3001 /* Printer driver in use */
+
/* Error codes for the ERRSRV class */
#define SMBE_error 1 /* Non specific error code */
@@ -284,7 +295,8 @@ extern gboolean smb_dcerpc_reassembly;
extern GHashTable *dcerpc_fragment_table;
/*
- * NT error codes.
+ * NT and DOS error codes used by other dissectors.
*/
extern const value_string NT_errors[];
+extern const value_string DOS_errors[];
#endif