diff options
-rw-r--r-- | packet-dcerpc-lsa.c | 32 | ||||
-rw-r--r-- | packet-dcerpc-nt.c | 13 | ||||
-rw-r--r-- | packet-dcerpc-nt.h | 6 | ||||
-rw-r--r-- | packet-dcerpc-reg.c | 20 | ||||
-rw-r--r-- | packet-dcerpc-reg.h | 19 | ||||
-rw-r--r-- | packet-dcerpc-spoolss.c | 2673 | ||||
-rw-r--r-- | packet-dcerpc.c | 33 | ||||
-rw-r--r-- | packet-dcerpc.h | 12 | ||||
-rw-r--r-- | packet-smb.c | 13 | ||||
-rw-r--r-- | smb.h | 16 |
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} }; @@ -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 |