/* packet-dcerpc-spoolss.c * Routines for SMB \PIPE\spoolss packet disassembly * Copyright 2001-2002, Tim Potter * * $Id: packet-dcerpc-spoolss.c,v 1.37 2002/06/07 06:10:53 tpot Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "packet-dcerpc.h" #include "packet-dcerpc-nt.h" #include "packet-dcerpc-spoolss.h" #include "packet-dcerpc-reg.h" #include "smb.h" #include "packet-smb-common.h" /* Global objects */ static int hf_spoolss_hnd = -1; static int hf_spoolss_rc = -1; static int hf_spoolss_offered = -1; static int hf_spoolss_needed = -1; static int hf_spoolss_returned = -1; static int hf_spoolss_buffer_size = -1; static int hf_spoolss_buffer_data = -1; static int hf_spoolss_relstr_offset = -1; static int hf_spoolss_printername = -1; static int hf_spoolss_servername = -1; static int hf_spoolss_drivername = -1; static int hf_spoolss_architecture = -1; static int hf_spoolss_username = -1; static int hf_spoolss_documentname = -1; static int hf_spoolss_outputfile = -1; static int hf_spoolss_datatype = -1; static int hf_spoolss_textstatus = -1; static int hf_spoolss_level = -1; /* Print job */ static int hf_spoolss_jobid = -1; static int hf_spoolss_jobstatus = -1; static int hf_spoolss_jobpriority = -1; static int hf_spoolss_jobposition = -1; static int hf_spoolss_jobtotalpages = -1; static int hf_spoolss_jobpagesprinted = -1; static int hf_spoolss_enumjobs_firstjob = -1; static int hf_spoolss_enumjobs_numjobs = -1; /* SYSTEM_TIME */ static int hf_spoolss_time_year = -1; static int hf_spoolss_time_month = -1; static int hf_spoolss_time_dow = -1; static int hf_spoolss_time_day = -1; static int hf_spoolss_time_hour = -1; static int hf_spoolss_time_minute = -1; static int hf_spoolss_time_second = -1; static int hf_spoolss_time_msec = -1; /* Printer data */ static int hf_spoolss_printerdata_value = -1; static int hf_spoolss_printerdata_type = -1; /* enumprinterdata */ static int hf_spoolss_enumprinterdata_index = -1; static int hf_spoolss_enumprinterdata_value_offered = -1; static int hf_spoolss_enumprinterdata_data_offered = -1; static int hf_spoolss_enumprinterdata_value_needed = -1; static int hf_spoolss_enumprinterdata_data_needed = -1; /* SetJob */ static int hf_spoolss_setjob_cmd = -1; /* WritePrinter */ static int hf_spoolss_writeprinter_numwritten = -1; /* GetPrinterDriver2 */ static int hf_spoolss_clientmajorversion = -1; static int hf_spoolss_clientminorversion = -1; static int hf_spoolss_servermajorversion = -1; static int hf_spoolss_serverminorversion = -1; static int hf_spoolss_driverpath = -1; static int hf_spoolss_datafile = -1; static int hf_spoolss_environment = -1; static int hf_spoolss_configfile = -1; static int hf_spoolss_helpfile = -1; static int hf_spoolss_monitorname = -1; static int hf_spoolss_defaultdatatype = -1; static int hf_spoolss_previousnames = -1; static int hf_spoolss_driverinfo_cversion = -1; static int hf_spoolss_dependentfiles = -1; /* rffpcnex */ static int hf_spoolss_rffpcnex_flags = -1; static int hf_spoolss_rffpcnex_options = -1; static int hf_spoolss_printerlocal = -1; static int hf_spoolss_notify_options_version = -1; static int hf_spoolss_notify_options_flags = -1; static int hf_spoolss_notify_options_flags_refresh = -1; static int hf_spoolss_notify_options_count = -1; static int hf_spoolss_notify_option_type = -1; static int hf_spoolss_notify_option_reserved1 = -1; static int hf_spoolss_notify_option_reserved2 = -1; static int hf_spoolss_notify_option_reserved3 = -1; static int hf_spoolss_notify_option_count = -1; static int hf_spoolss_notify_option_data_count = -1; static int hf_spoolss_notify_info_count = -1; static int hf_spoolss_notify_info_version = -1; static int hf_spoolss_notify_info_flags = -1; static int hf_spoolss_notify_info_data_type = -1; static int hf_spoolss_notify_info_data_count = -1; static int hf_spoolss_notify_info_data_id = -1; static int hf_spoolss_notify_info_data_value1 = -1; static int hf_spoolss_notify_info_data_value2 = -1; static int hf_spoolss_notify_info_data_bufsize = -1; static int hf_spoolss_notify_info_data_buffer = -1; static int hf_spoolss_notify_info_data_buffer_len = -1; static int hf_spoolss_notify_info_data_buffer_data = -1; static int hf_spoolss_notify_field = -1; static int hf_spoolss_rrpcn_changelow = -1; static int hf_spoolss_rrpcn_changehigh = -1; static int hf_spoolss_rrpcn_unk0 = -1; static int hf_spoolss_rrpcn_unk1 = -1; static int hf_spoolss_replyopenprinter_unk0 = -1; static int hf_spoolss_replyopenprinter_unk1 = -1; /* * Routines to dissect a spoolss BUFFER */ typedef struct { guint32 size; /* Size of buffer */ guint8 *data; /* Contents of buffer */ int offset; /* Offset to start of buffer */ proto_item *tree; /* Proto tree buffer located in */ } BUFFER; static int dissect_spoolss_buffer_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = pinfo->private_data; BUFFER *b = (BUFFER *)di->private_data; guint32 size; guint8 *data; if (di->conformant_run) return offset; /* Dissect size and data */ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_buffer_size, &size); offset = dissect_ndr_uint8s(tvb, offset, pinfo, tree, drep, hf_spoolss_buffer_data, size, &data); /* Return buffer info */ if (b) { b->size = size; b->data = data; b->offset = offset - size; b->tree = tree; } return offset; } /* Dissect a spoolss buffer and return buffer data */ static int dissect_spoolss_buffer(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, char *drep, BUFFER *b) { dcerpc_info *di = pinfo->private_data; if (b) memset(b, 0, sizeof(BUFFER)); di->private_data = b; offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, dissect_spoolss_buffer_data, NDR_POINTER_UNIQUE, "Buffer", -1, 0); return offset; } /* * 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 */ }; /* 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; }; static 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. */ static int prs_referents(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree _U_, GList **dp_list, GList **list, void ***ptr_data) { struct deferred_ptr_state s; int new_offset = offset; /* Create a list of void pointers to store return data */ if (ptr_data) { int len = g_list_length(*dp_list) * sizeof(void *); if (len > 0) { *ptr_data = malloc(len); memset(*ptr_data, 0, len); } else *ptr_data = NULL; } /* 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; } /* Display a policy handle in the protocol tree */ static gint ett_POLICY_HND = -1; static void display_pol(proto_tree *tree, tvbuff_t *tvb, int offset, const guint8 *policy_hnd) { proto_item *item; char *pol_name = NULL; int pol_open_frame = 0, pol_close_frame = 0; proto_tree *subtree; dcerpc_smb_fetch_pol(policy_hnd, &pol_name, &pol_open_frame, &pol_close_frame); item = proto_tree_add_text(tree, tvb, offset, 20, "Policy handle%s%s", pol_name ? ": " : "", pol_name ? pol_name : ""); subtree = proto_item_add_subtree(item, ett_POLICY_HND); if (pol_open_frame) proto_tree_add_text(subtree, tvb, offset, 0, "Opened in frame %u", pol_open_frame); if (pol_close_frame) proto_tree_add_text(subtree, tvb, offset, 0, "Closed in frame %u", pol_close_frame); proto_tree_add_text(subtree, tvb, offset, 20, "Policy Handle: %s", tvb_bytes_to_str(tvb, offset, 20)); } /* * SpoolssClosePrinter */ static int SpoolssClosePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, TRUE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); dcerpc_smb_store_pol((const guint8 *)&policy_hnd, NULL, 0, pinfo->fd->num); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssClosePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); 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; int data16_offset; 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_offset, NULL); text = fake_unicode(tvb, data16_offset, 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 g_free(text); proto_tree_add_text(subtree, tvb, old_offset, 4, "Length: %u", length); old_offset += 4; proto_tree_add_text(subtree, tvb, old_offset, 4, "Offset: %u", the_offset); old_offset += 4; proto_tree_add_text(subtree, tvb, old_offset, 4, "Max length: %u", max_len); old_offset += 4; proto_tree_add_text(subtree, tvb, old_offset, max_len * 2, "Data"); return offset; } /* Dissect some printer data. The get/set/enum printerdata routines all store value/data in a uint8 array. We could use the ndr routines for this but that would result in one item for each byte in the printer data. */ static gint ett_printerdata_data = -1; static gint ett_printerdata_value = -1; static int dissect_printerdata_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { proto_item *item; proto_tree *subtree; guint32 size; item = proto_tree_add_text(tree, tvb, offset, 0, "Printer data"); subtree = proto_item_add_subtree(item, ett_printerdata_data); offset = prs_uint32(tvb, offset, pinfo, subtree, &size, "Size"); offset = prs_uint8s(tvb, offset, pinfo, subtree, size, NULL, "Data"); proto_item_set_len(item, size + 4); return offset; } /* * SpoolssGetPrinterData */ static int SpoolssGetPrinterData_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; char *value_name = NULL; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd( tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); 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); g_free(value_name); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_offered, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssGetPrinterData_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 size; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerdata_type, NULL); offset = dissect_printerdata_data(tvb, offset, pinfo, tree, drep); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed"); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssGetPrinterDataEx */ static int SpoolssGetPrinterDataEx_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; char *key_name, *value_name; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_UNISTR2_dp, (void **)&key_name, NULL); /* * Register a cleanup function in case on of our tvbuff accesses * throws an exception. We need to clean up key_name. */ CLEANUP_PUSH(g_free, key_name); 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); /* * We're done with key_name, so we can call the cleanup handler to * free it, and then pop the cleanup handler. */ CLEANUP_CALL_AND_POP; /* * We're also done with value_name. */ g_free(value_name); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Size"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssGetPrinterDataEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 size; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerdata_type, NULL); 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 = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssSetPrinterData */ static int SpoolssSetPrinterData_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; char *value_name = NULL; guint32 size; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); 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); g_free(value_name); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerdata_type, NULL); offset = dissect_printerdata_data(tvb, offset, pinfo, tree, drep); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssSetPrinterData_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssSetPrinterDataEx */ static int SpoolssSetPrinterDataEx_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; char *key_name, *value_name; guint32 max_len; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); 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); g_free(key_name); g_free(value_name); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerdata_type, NULL); 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"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssSetPrinterDataEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* Yet another way to represent a unicode string - sheesh. This function dissects a NULL terminate unicode string at the current offset and returns the (char *) equivalent. This really should return UTF8 or something but we use fake_unicode() instead. */ static int dissect_spoolss_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, char *drep, char **data) { gint len, remaining; char *text; if (offset % 2) offset += 2 - (offset % 2); /* Get remaining data in buffer as a string */ remaining = tvb_length_remaining(tvb, offset) / 2; text = fake_unicode(tvb, offset, remaining); len = strlen(text); proto_tree_add_text(tree, tvb, offset, len * 2, "%s: %s", "UINT16UNI", tvb_bytes_to_str(tvb, offset, len * 2)); if (data) *data = text; else g_free(text); return offset + (len + 1) * 2; } static int prs_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, void **data, char *name) { gint len = 0, remaining; char *text; offset = prs_align(offset, 2); /* Get remaining data in buffer as a string */ remaining = tvb_length_remaining(tvb, offset)/2; text = fake_unicode(tvb, offset, remaining); len = strlen(text); if (name) proto_tree_add_text(tree, tvb, offset, (len + 1) * 2, "%s: %s", name ? name : "UINT16UNI", text); if (data) *data = text; else g_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; guint16 extra; item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE"); subtree = proto_item_add_subtree(item, ett_DEVMODE); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size"); /* The device name is stored in a 32-wchar buffer */ prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Devicename"); offset += 64; 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"); prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Form name"); offset += 64; 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 dissect_spoolss_relstr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep, int hf_index, int struct_start, char **data) { proto_item *item; proto_tree *subtree; guint32 relstr_offset, relstr_start, relstr_end, relstr_len; char *text; item = proto_tree_add_string(tree, hf_index, tvb, offset, 4, ""); subtree = proto_item_add_subtree(item, ett_RELSTR); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_relstr_offset, &relstr_offset); /* A relative offset of zero is a NULL string */ relstr_start = relstr_offset + struct_start; if (relstr_offset) relstr_end = dissect_spoolss_uint16uni( tvb, relstr_start, pinfo, subtree, drep, &text); else { text = g_strdup("NULL"); relstr_end = offset; } relstr_len = relstr_end - relstr_start; proto_item_append_text(item, text); if (data) *data = text; else g_free(text); return offset; } /* An array of relative strings. This is currently just a copy of the dissect_spoolss_relstr() function as I can't find an example driver that has more than one dependent file. */ static gint ett_RELSTR_ARRAY = -1; static int dissect_spoolss_relstrarray(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep, int hf_index, int struct_start, char **data) { proto_item *item; proto_tree *subtree; guint32 relstr_offset, relstr_start, relstr_end, relstr_len; char *text; item = proto_tree_add_string(tree, hf_index, tvb, offset, 4, ""); subtree = proto_item_add_subtree(item, ett_RELSTR_ARRAY); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_relstr_offset, &relstr_offset); /* A relative offset of zero is a NULL string */ relstr_start = relstr_offset + struct_start; if (relstr_offset) relstr_end = dissect_spoolss_uint16uni( tvb, relstr_start, pinfo, subtree, drep, &text); else { text = g_strdup("NULL"); relstr_end = offset; } relstr_len = relstr_end - relstr_start; proto_item_append_text(item, text); if (data) *data = text; else g_free(text); return offset; } 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; char *text = strdup("NULL"); offset = prs_uint32(tvb, offset, pinfo, tree, &relstr_offset, NULL); /* A relative offset of zero is a NULL string */ relstr_start = relstr_offset + struct_start; if (relstr_offset) relstr_end = prs_uint16uni(tvb, relstr_start, pinfo, tree, (void **)&text, NULL); else relstr_end = offset; 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 g_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) { int struct_start = offset; offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Description"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Name"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Comment"); 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, int len, GList **dp_list, void **data) { int struct_start = offset; guint32 rel_offset; offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Server name"); 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, "Share name"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Port name"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Driver name"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Comment"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Location"); /* This is a relative devicemode */ offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL); prs_DEVMODE(tvb, struct_start + rel_offset - 4, pinfo, tree, dp_list, NULL); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Separator file"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Print processor"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Datatype"); offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start, NULL, "Parameters"); /* This is a relative security descriptor */ offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL); /* * XXX - what *is* the length of this security descriptor? * "prs_PRINTER_INFO_2()" is passed to "defer_ptr()", but * "defer_ptr" takes, as an argument, a function with a * different calling sequence from "prs_PRINTER_INFO_2()", * lacking the "len" argument, so that won't work. */ dissect_nt_sec_desc(tvb, struct_start + rel_offset, tree, len); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Attributes"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Priority"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Default priority"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Start time"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "End time"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Jobs"); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Average PPM"); 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, int len, GList **dp_list, void **data) { offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags"); offset = dissect_nt_sec_desc(tvb, offset, tree, len); 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) offset = prs_DEVMODE(tvb, offset, pinfo, subtree, dp_list, data); 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 _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 ptr = 0; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* 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); /* Store printer name to match with reply packet */ dcv->private_data = 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); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssOpenPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 status; const guint8 *policy_hnd; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, &status); if (status == 0) { /* Associate the returned printer handle with a name */ if (dcv->private_data) { dcerpc_smb_store_pol(policy_hnd, dcv->private_data, pinfo->fd->num, 0); g_free(dcv->private_data); dcv->private_data = NULL; } } dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static const value_string printer_notify_option_data_vals[] = { { PRINTER_NOTIFY_SERVER_NAME, "Server name" }, { PRINTER_NOTIFY_PRINTER_NAME, "Printer name" }, { PRINTER_NOTIFY_SHARE_NAME, "Share name" }, { PRINTER_NOTIFY_PORT_NAME, "Port name" }, { PRINTER_NOTIFY_DRIVER_NAME, "Driver name" }, { PRINTER_NOTIFY_COMMENT, "Comment" }, { PRINTER_NOTIFY_LOCATION, "Location" }, { PRINTER_NOTIFY_DEVMODE, "Devmode" }, { PRINTER_NOTIFY_SEPFILE, "Sepfile" }, { PRINTER_NOTIFY_PRINT_PROCESSOR, "Print processor" }, { PRINTER_NOTIFY_PARAMETERS, "Parameters" }, { PRINTER_NOTIFY_DATATYPE, "Datatype" }, { PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "Security descriptor" }, { PRINTER_NOTIFY_ATTRIBUTES, "Attributes" }, { PRINTER_NOTIFY_PRIORITY, "Priority" }, { PRINTER_NOTIFY_DEFAULT_PRIORITY, "Default priority" }, { PRINTER_NOTIFY_START_TIME, "Start time" }, { PRINTER_NOTIFY_UNTIL_TIME, "Until time" }, { PRINTER_NOTIFY_STATUS, "Status" }, { PRINTER_NOTIFY_STATUS_STRING, "Status string" }, { PRINTER_NOTIFY_CJOBS, "Cjobs" }, { PRINTER_NOTIFY_AVERAGE_PPM, "Average PPM" }, { PRINTER_NOTIFY_TOTAL_PAGES, "Total pages" }, { PRINTER_NOTIFY_PAGES_PRINTED, "Pages printed" }, { PRINTER_NOTIFY_TOTAL_BYTES, "Total bytes" }, { PRINTER_NOTIFY_BYTES_PRINTED, "Bytes printed" }, { 0, NULL} }; static const value_string job_notify_option_data_vals[] = { { JOB_NOTIFY_PRINTER_NAME, "Printer name" }, { JOB_NOTIFY_MACHINE_NAME, "Machine name" }, { JOB_NOTIFY_PORT_NAME, "Port name" }, { JOB_NOTIFY_USER_NAME, "User name" }, { JOB_NOTIFY_NOTIFY_NAME, "Notify name" }, { JOB_NOTIFY_DATATYPE, "Data type" }, { JOB_NOTIFY_PRINT_PROCESSOR, "Print processor" }, { JOB_NOTIFY_PARAMETERS, "Parameters" }, { JOB_NOTIFY_DRIVER_NAME, "Driver name" }, { JOB_NOTIFY_DEVMODE, "Devmode" }, { JOB_NOTIFY_STATUS, "Status" }, { JOB_NOTIFY_STATUS_STRING, "Status string" }, { JOB_NOTIFY_SECURITY_DESCRIPTOR, "Security descriptor" }, { JOB_NOTIFY_DOCUMENT, "Document" }, { JOB_NOTIFY_PRIORITY, "Priority" }, { JOB_NOTIFY_POSITION, "Position" }, { JOB_NOTIFY_SUBMITTED, "Submitted" }, { JOB_NOTIFY_START_TIME, "Start time" }, { JOB_NOTIFY_UNTIL_TIME, "Until time" }, { JOB_NOTIFY_TIME, "Time" }, { JOB_NOTIFY_TOTAL_PAGES, "Total pages" }, { JOB_NOTIFY_PAGES_PRINTED, "Pages printed" }, { JOB_NOTIFY_TOTAL_BYTES, "Total bytes" }, { JOB_NOTIFY_BYTES_PRINTED, "Bytes printed" }, { 0, NULL} }; static int dissect_notify_field(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep, guint16 type, guint16 *data) { guint16 field; char *str; offset = dissect_ndr_uint16( tvb, offset, pinfo, NULL, drep, hf_spoolss_notify_field, &field); switch(type) { case PRINTER_NOTIFY_TYPE: str = val_to_str(field, printer_notify_option_data_vals, "Unknown"); break; case JOB_NOTIFY_TYPE: str = val_to_str(field, job_notify_option_data_vals, "Unknown"); break; default: str = "Unknown notify type"; break; } proto_tree_add_text(tree, tvb, offset - 2, 2, "Field: %s (%d)", str, field); if (data) *data = field; return offset; } static int dissect_NOTIFY_OPTION_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = pinfo->private_data; guint32 count, i; guint16 type; if (di->conformant_run) return offset; type = di->levels; offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_option_data_count, &count); for (i = 0; i < count; i++) offset = dissect_notify_field( tvb, offset, pinfo, tree, drep, type, NULL); return offset; } static const value_string printer_notify_types[] = { { PRINTER_NOTIFY_TYPE, "Printer notify" }, { JOB_NOTIFY_TYPE, "Job notify" }, { 0, NULL } }; static gint ett_NOTIFY_OPTION = -1; static int dissect_NOTIFY_OPTION(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; guint16 type; item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION"); subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION); offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_option_type, &type); offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_option_reserved1, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_option_reserved2, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_option_reserved3, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_option_count, NULL); offset = dissect_ndr_pointer( tvb, offset, pinfo, subtree, drep, dissect_NOTIFY_OPTION_DATA, NDR_POINTER_UNIQUE, "NOTIFY_OPTION_DATA", -1, type); return offset; } static int dissect_NOTIFY_OPTIONS_ARRAY(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { /* Why is a check for di->conformant_run not required here? */ offset = dissect_ndr_ucarray( tvb, offset, pinfo, tree, drep, dissect_NOTIFY_OPTION); return offset; } static gint ett_notify_options_flags = -1; static const true_false_string tfs_notify_options_flags_refresh = { "Data for all monitored fields is present", "Data for all monitored fields not present" }; static int dissect_notify_options_flags(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; guint32 flags; offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, hf_spoolss_notify_options_flags, &flags); item = proto_tree_add_text(tree, tvb, offset - 4, 4, "Flags: 0x%08x", flags); subtree = proto_item_add_subtree(item, ett_notify_options_flags); proto_tree_add_boolean( subtree, hf_spoolss_notify_options_flags_refresh, tvb, offset, 4, flags); return offset; } static int dissect_NOTIFY_OPTIONS_ARRAY_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = pinfo->private_data; if (di->conformant_run) return offset; offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_notify_options_version, NULL); offset = dissect_notify_options_flags(tvb, offset, pinfo, tree, drep); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_notify_options_count, NULL); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_NOTIFY_OPTIONS_ARRAY, NDR_POINTER_UNIQUE, "NOTIFY_OPTIONS", -1, 0); return offset; } /* * SpoolssRFFPCNEX */ static gint ett_rffpcnex_flags = -1; static int hf_spoolss_rffpcnex_flags_add_printer = -1; static int hf_spoolss_rffpcnex_flags_set_printer = -1; static int hf_spoolss_rffpcnex_flags_delete_printer = -1; static int hf_spoolss_rffpcnex_flags_failed_printer_connection = -1; static const true_false_string tfs_rffpcnex_flags_add_printer = { "Notify on add printer", "Don't notify on add printer" }; static const true_false_string tfs_rffpcnex_flags_set_printer = { "Notify on set printer", "Don't notify on set printer" }; static const true_false_string tfs_rffpcnex_flags_delete_printer = { "Notify on delete printer", "Don't notify on delete printer" }; static const true_false_string tfs_rffpcnex_flags_failed_connection_printer = { "Notify on failed printer connection", "Don't notify on failed printer connection" }; static int SpoolssRFFPCNEX_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 flags; proto_item *flags_item; proto_tree *flags_subtree; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, hf_spoolss_rffpcnex_flags, &flags); flags_item = proto_tree_add_text(tree, tvb, offset - 4, 4, "Flags: 0x%08x", flags); flags_subtree = proto_item_add_subtree(flags_item, ett_rffpcnex_flags); proto_tree_add_boolean( flags_subtree, hf_spoolss_rffpcnex_flags_add_printer, tvb, offset - 4, 4, flags); proto_tree_add_boolean( flags_subtree, hf_spoolss_rffpcnex_flags_set_printer, tvb, offset - 4, 4, flags); proto_tree_add_boolean( flags_subtree, hf_spoolss_rffpcnex_flags_delete_printer, tvb, offset - 4, 4, flags); proto_tree_add_boolean( flags_subtree, hf_spoolss_rffpcnex_flags_failed_printer_connection, tvb, offset - 4, 4, flags); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_rffpcnex_options, NULL); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Server", hf_spoolss_servername, 0); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerlocal, NULL); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_NOTIFY_OPTIONS_ARRAY_CTR, NDR_POINTER_UNIQUE, "NOTIFY_OPTIONS_CTR", -1, 0); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssRFFPCNEX_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssReplyOpenPrinter */ static int SpoolssReplyOpenPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 printerlocal; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_UNISTR2_dp, NULL, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerlocal, &printerlocal); dcv->private_data = (void *)printerlocal; offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerdata_type, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_replyopenprinter_unk0, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_replyopenprinter_unk1, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssReplyOpenPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 printerlocal = (guint32)dcv->private_data; e_ctx_hnd policy_hnd; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, TRUE, FALSE); dcerpc_smb_store_pol( (const guint8 *)&policy_hnd, "ReplyOpenPrinter handle", pinfo->fd->num, 0); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * BUFFER_DATA */ static gint ett_BUFFER_DATA = -1; static gint ett_BUFFER_DATA_BUFFER = -1; struct 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*/ int size; /* Size of buffer data */ }; static int prs_BUFFER_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, GList **dp_list, void **data) { proto_item *item, *subitem; proto_tree *subtree, *subsubtree; guint32 size; int data8_offset; 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"); subitem = proto_tree_add_text(subtree, tvb, offset, size, "Data"); subsubtree = proto_item_add_subtree(subitem, ett_BUFFER_DATA_BUFFER); offset = prs_uint8s(tvb, offset, pinfo, subsubtree, size, &data8_offset, 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->item = subitem; bd->tree = subsubtree; bd->tvb = tvb; bd->offset = data8_offset; bd->size = 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 _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, 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); dcv->private_data = (void *)level; offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssGetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; GList *dp_list = NULL; void **data_list; struct BUFFER_DATA *bd = NULL; gint16 level = (guint32)dcv->private_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); /* Parse packet */ offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_BUFFER, NULL, &data_list); if (data_list) bd = (struct BUFFER_DATA *)data_list[0]; if (bd && bd->tree) { 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; case 1: prs_PRINTER_INFO_1(bd->tvb, bd->offset, pinfo, bd->tree, &dp_list, NULL); break; case 2: prs_PRINTER_INFO_2(bd->tvb, bd->offset, pinfo, bd->tree, bd->size, &dp_list, NULL); break; case 3: prs_PRINTER_INFO_3(bd->tvb, bd->offset, pinfo, bd->tree, bd->size, &dp_list, NULL); break; default: proto_tree_add_text(bd->tree, tvb, offset, 0, "[Unknown info level %d]", level); break; } } offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed"); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SEC_DESC_BUF */ static gint ett_SEC_DESC_BUF = -1; static int prs_SEC_DESC_BUF(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, GList **dp_list, void **Data) { proto_item *item; proto_tree *subtree; guint32 len; item = proto_tree_add_text(tree, tvb, offset, 0, "SEC_DESC_BUF"); subtree = proto_item_add_subtree(item, ett_SEC_DESC_BUF); offset = prs_uint32(tvb, offset, pinfo, subtree, &len, "Max length"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Undocumented"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Length"); dissect_nt_sec_desc(tvb, offset, subtree, len); offset += len; 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 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"); switch(level) { case 3: { guint32 ptr; offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Devicemode container"); if (ptr) defer_ptr(dp_list, prs_DEVMODE_CTR, subtree); offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Security descriptor"); if (ptr) defer_ptr(dp_list, prs_SEC_DESC_BUF, subtree); break; } case 2: { guint32 ptr; offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Info"); if (ptr) defer_ptr(dp_list, prs_PRINTER_INFO_2, subtree); break; } default: proto_tree_add_text(subtree, tvb, offset, 0, "[Unknown info level %d]", level); break; } done: return offset; } /* * SpoolssSetPrinter */ static int SpoolssSetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, 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_SPOOL_PRINTER_INFO_LEVEL, NULL, NULL); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Command"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssSetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * FORM_REL */ static const value_string form_type_vals[] = { { FORM_USER, "FORM_USER" }, { FORM_BUILTIN, "FORM_BUILTIN" }, { FORM_PRINTER, "FORM_PRINTER" }, { 0, NULL } }; static gint ett_FORM_REL = -1; static int prs_FORM_REL(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int struct_start, GList **dp_list, void **data) { proto_item *item; proto_tree *subtree; guint32 flags; item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_REL"); subtree = proto_item_add_subtree(item, ett_FORM_REL); offset = prs_uint32(tvb, offset, pinfo, subtree, &flags, NULL); proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s", val_to_str(flags, form_type_vals, "Unknown type")); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Name"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Width"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Height"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Left margin"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Top margin"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Horizontal imageable length"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Vertical imageable length"); return offset; } /* * SpoolssEnumForms */ static int SpoolssEnumForms_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); dcv->private_data = (void *)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"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEnumForms_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 count; struct BUFFER_DATA *bd = NULL; void **data_list; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_BUFFER, NULL, &data_list); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed"); offset = prs_uint32(tvb, offset, pinfo, tree, &count, "Num entries"); if (data_list) bd = (struct BUFFER_DATA *)data_list[0]; CLEANUP_PUSH(g_free, bd); if (bd && bd->tree) { guint32 level = (guint32)dcv->private_data, i; GList *child_dp_list = NULL; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); proto_item_append_text(bd->item, ", FORM_%d", level); /* Unfortunately this array isn't in NDR format so we can't use prs_array(). The other weird thing is the struct_start being inside the loop rather than outside. Very strange. */ for (i = 0; i < count; i++) { int struct_start = bd->offset; bd->offset = prs_FORM_REL( bd->tvb, bd->offset, pinfo, bd->tree, struct_start, &child_dp_list, NULL); } } CLEANUP_CALL_AND_POP; offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssDeletePrinter */ static int SpoolssDeletePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; const guint8 *policy_hnd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssDeletePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; const guint8 *policy_hnd; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * AddPrinterEx */ #if 0 static int SpoolssAddPrinterEx_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 ptr; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Server name"); if (ptr) { char *printer_name; offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_UNISTR2_dp, (void *)&printer_name, NULL); if (printer_name) dcv->private_data = printer_name; } offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Level"); /* TODO: PRINTER INFO LEVEL */ 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, "User switch"); /* TODO: USER LEVEL */ dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } #endif static int SpoolssAddPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 status; const guint8 *policy_hnd; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, &status); if (status == 0) { /* Associate the returned printer handle with a name */ if (dcv->private_data) { if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr( pinfo->cinfo, COL_INFO, ", %s", (char *)dcv->private_data); dcerpc_smb_store_pol( policy_hnd, dcv->private_data, pinfo->fd->num, 0); g_free(dcv->private_data); dcv->private_data = NULL; } } dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssEnumPrinterData */ static int SpoolssEnumPrinterData_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 ndx; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd( tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumprinterdata_index, &ndx); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", index %d", ndx); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumprinterdata_value_offered, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumprinterdata_data_offered, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEnumPrinterData_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 data_size, value_size; proto_item *value_item; proto_tree *value_subtree; int uint16s_offset; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ value_item = proto_tree_add_text(tree, tvb, offset, 0, "Value"); value_subtree = proto_item_add_subtree(value_item, ett_printerdata_value); offset = prs_uint32(tvb, offset, pinfo, value_subtree, &value_size, "Value size"); offset = prs_uint16s(tvb, offset, pinfo, value_subtree, value_size, &uint16s_offset, NULL); if (value_size) { char *text = fake_unicode(tvb, uint16s_offset, value_size); proto_tree_add_text(value_subtree, tvb, uint16s_offset, value_size * 2, "Value: %s", text); proto_item_append_text(value_item, ": %s", text); if (text[0] && check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", text); g_free(text); } proto_item_set_len(value_item, value_size * 2 + 4); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumprinterdata_value_needed, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_printerdata_type, NULL); offset = dissect_printerdata_data(tvb, offset, pinfo, tree, drep); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumprinterdata_data_needed, NULL); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SpoolssEnumPrinters */ static int SpoolssEnumPrinters_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 ptr, level; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* 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"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEnumPrinters_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* 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 = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * AddPrinterDriver */ #if 0 static int SpoolssAddPrinterDriver_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Server", hf_spoolss_servername, 0); offset = dissect_spoolss_DRIVER_INFO_CTR( tvb, offset, pinfo, tree, drep); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } #endif static int SpoolssAddPrinterDriver_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * FORM_1 */ static gint ett_FORM_1 = -1; static int prs_FORM_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, flags; item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_1"); subtree = proto_item_add_subtree(item, ett_FORM_1); offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Name"); if (ptr) defer_ptr(dp_list, prs_UNISTR2_dp, subtree); offset = prs_uint32(tvb, offset, pinfo, subtree, &flags, NULL); proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s", val_to_str(flags, form_type_vals, "Unknown type")); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Unknown"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Width"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Height"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Left margin"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Top margin"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Horizontal imageable length"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Vertical imageable length"); return offset; } /* * FORM_CTR */ static gint ett_FORM_CTR = -1; static int prs_FORM_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, GList **dp_list, void **data) { proto_item *item; proto_tree *subtree; guint32 level; item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_CTR"); subtree = proto_item_add_subtree(item, ett_FORM_CTR); offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level"); switch(level) { case 1: offset = prs_struct_and_referents(tvb, offset, pinfo, subtree, prs_FORM_1, NULL, NULL); break; default: proto_tree_add_text(subtree, tvb, offset, 0, "[Unknown info level %d]", level); break; } return offset; } /* * AddForm */ static int SpoolssAddForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; const guint8 *policy_hnd; guint32 level; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, 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); /* Store info level to match with reply packet */ dcv->private_data = (void *)level; offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_FORM_CTR, NULL, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssAddForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * DeleteForm */ static int SpoolssDeleteForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; const guint8 *policy_hnd; char *form_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_UNISTR2_dp, (void **)&form_name, NULL); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", form_name); g_free(form_name); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssDeleteForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SetForm */ static int SpoolssSetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; const guint8 *policy_hnd; guint32 level; char *form_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_UNISTR2_dp, (void **)&form_name, NULL); CLEANUP_PUSH(g_free, form_name); offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, level %d", form_name, level); CLEANUP_CALL_AND_POP; offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_FORM_CTR, NULL, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssSetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * GetForm */ static int SpoolssGetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level; const guint8 *policy_hnd; char *form_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd); display_pol(tree, tvb, offset - 20, policy_hnd); offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_UNISTR2_dp, (void **)&form_name, NULL); CLEANUP_PUSH(g_free, form_name); offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); dcv->private_data = (void *)level; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, level %d", form_name, level); CLEANUP_CALL_AND_POP; offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_BUFFER, NULL, NULL); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered"); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssGetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; void **data_list; struct BUFFER_DATA *bd = NULL; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = prs_struct_and_referents(tvb, offset, pinfo, tree, prs_BUFFER, NULL, &data_list); offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed"); if (data_list) bd = (struct BUFFER_DATA *)data_list[0]; CLEANUP_PUSH(g_free, bd); if (bd && bd->tree) { guint32 level = (guint32)dcv->private_data; switch(level) { case 1: { int struct_start = bd->offset; GList *dp_list = NULL; bd->offset = prs_FORM_REL( bd->tvb, bd->offset, pinfo, bd->tree, struct_start, &dp_list, NULL); break; } default: proto_tree_add_text( bd->tree, bd->tvb, bd->offset, 0, "[Unknown info level %d]", level); break; } } CLEANUP_CALL_AND_POP; offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* A generic reply function that just parses the status code. Useful for unimplemented dissectors so the status code can be inserted into the INFO column. */ static int SpoolssGeneric_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; int len = tvb_length(tvb); proto_tree_add_text(tree, tvb, offset, 0, "[Unimplemented dissector: SPOOLSS]"); if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); offset = dissect_doserror(tvb, len - 4, pinfo, tree, drep, hf_spoolss_rc, NULL); return offset; } /* * SYSTEM_TIME */ static gint ett_SYSTEM_TIME; static int dissect_SYSTEM_TIME(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; guint16 year, month, day, hour, minute, second; item = proto_tree_add_text(tree, tvb, offset, 16, "SYSTEM_TIME: "); subtree = proto_item_add_subtree(item, ett_SYSTEM_TIME); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_year, &year); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_month, &month); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_dow, NULL); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_day, &day); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_hour, &hour); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_minute, &minute); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_second, &second); offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep, hf_spoolss_time_msec, NULL); proto_item_append_text(item, "%d/%02d/%02d %02d:%02d:%02d", year, month, day, hour, minute, second); return offset; } /* * JOB_INFO_1 */ static gint ett_JOB_INFO_1; static int dissect_spoolss_JOB_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; int struct_start = offset; char *document_name; item = proto_tree_add_text(tree, tvb, offset, 0, "JOB_INFO_1"); subtree = proto_item_add_subtree(item, ett_JOB_INFO_1); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_jobid, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_printername, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_servername, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_username, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_documentname, struct_start, &document_name); proto_item_append_text(item, ": %s", document_name); g_free(document_name); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_datatype, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_textstatus, struct_start, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_jobstatus, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_jobpriority, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_jobposition, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_jobtotalpages, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_jobpagesprinted, NULL); offset = dissect_SYSTEM_TIME(tvb, offset, pinfo, subtree, drep); proto_item_set_len(item, offset - struct_start); return offset; } /* * JOB_INFO_2 */ static gint ett_JOB_INFO_2; #if 0 static int prs_JOB_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, GList **dp_list, void **data) { proto_item *item; proto_tree *subtree; int struct_start = offset; guint32 rel_offset; item = proto_tree_add_text(tree, tvb, offset, 0, "JOB_INFO_2"); subtree = proto_item_add_subtree(item, ett_FORM_CTR); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Job ID"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Printer name"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Machine name"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "User name"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Document"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Notify name"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Data type"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Print processor"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Parameters"); offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start, NULL, "Driver name"); offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL); prs_DEVMODE(tvb, struct_start + rel_offset - 4, pinfo, tree, dp_list, NULL); /* XXX security descriptor */ offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Security descriptor"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Status"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Priority"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Position"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Start time"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Until time"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Total pages"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size"); offset = prs_struct_and_referents(tvb, offset, pinfo, subtree, prs_SYSTEM_TIME, NULL, NULL); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Time elapsed"); offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pages printed"); return offset; } #endif /* * EnumJobs */ static int SpoolssEnumJobs_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %d", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumjobs_firstjob, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumjobs_numjobs, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_level, &level); dcv->private_data = (void *)level; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_offered, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEnumJobs_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep _U_) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; gint16 level = (guint32)dcv->private_data; BUFFER buffer; guint32 num_jobs, i; int buffer_offset; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %d", dcv->req_frame); /* Parse packet */ offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, &buffer); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_needed, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_enumjobs_numjobs, &num_jobs); buffer_offset = buffer.offset; for (i = 0; i < num_jobs; i++) { switch(level) { case 1: buffer_offset = dissect_spoolss_JOB_INFO_1( tvb, buffer_offset, pinfo, buffer.tree, drep); break; case 2: default: proto_tree_add_text( buffer.tree, tvb, buffer_offset, buffer.size, "[Unknown info level %d]", level); goto done; } } done: offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * SetJob */ /* Set job command values */ #define JOB_CONTROL_PAUSE 1 #define JOB_CONTROL_RESUME 2 #define JOB_CONTROL_CANCEL 3 #define JOB_CONTROL_RESTART 4 #define JOB_CONTROL_DELETE 5 static const value_string setjob_commands[] = { { JOB_CONTROL_PAUSE, "Pause" }, { JOB_CONTROL_RESUME, "Resume" }, { JOB_CONTROL_CANCEL, "Cancel" }, { JOB_CONTROL_RESTART, "Restart" }, { JOB_CONTROL_DELETE, "Delete" }, { 0, NULL } }; static int SpoolssSetJob_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 jobid, cmd; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_jobid, &jobid); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_level, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_setjob_cmd, &cmd); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr( pinfo->cinfo, COL_INFO, ", %s jobid %d", val_to_str(cmd, setjob_commands, "Unknown command"), jobid); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssSetJob_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * GetJob */ static int SpoolssGetJob_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level, jobid; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_jobid, &jobid); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_level, &level); dcv->private_data = (void *)level; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d, jobid %d", level, jobid); offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_offered, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssGetJob_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; gint32 level = (guint32)dcv->private_data; BUFFER buffer; int buffer_offset; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, &buffer); if (!buffer.size) goto done; buffer_offset = buffer.offset; switch(level) { case 1: buffer_offset = dissect_spoolss_JOB_INFO_1( tvb, buffer_offset, pinfo, buffer.tree, drep); break; case 2: default: proto_tree_add_text( buffer.tree, tvb, buffer_offset, buffer.size, "[Unknown info level %d]", level); goto done; } done: offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_needed, NULL); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * StartPagePrinter */ static int SpoolssStartPagePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, FALSE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssStartPagePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * EndPagePrinter */ static int SpoolssEndPagePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, FALSE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEndPagePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * DOC_INFO_1 */ static gint ett_DOC_INFO_1 = -1; static int dissect_spoolss_doc_info_1(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; item = proto_tree_add_text(tree, tvb, offset, 0, "DOC_INFO_1"); subtree = proto_item_add_subtree(item, ett_DOC_INFO_1); offset = dissect_ndr_pointer( tvb, offset, pinfo, subtree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Document name", hf_spoolss_documentname, 0); offset = dissect_ndr_pointer( tvb, offset, pinfo, subtree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Output file", hf_spoolss_outputfile, 0); offset = dissect_ndr_pointer( tvb, offset, pinfo, subtree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Data type", hf_spoolss_datatype, 0); return offset; } static int dissect_spoolss_doc_info_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = pinfo->private_data; if (di->conformant_run) return offset; switch(di->levels) { case 1: offset = dissect_spoolss_doc_info_1( tvb, offset, pinfo, tree, drep); break; default: proto_tree_add_text(tree, tvb, offset, 0, "[Unknown info level %d]", di->levels); break; } return offset; } /* * DOC_INFO */ static gint ett_DOC_INFO = -1; static int dissect_spoolss_doc_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; guint32 level; item = proto_tree_add_text(tree, tvb, offset, 0, "DOC_INFO"); subtree = proto_item_add_subtree(item, ett_DOC_INFO); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_level, &level); offset = dissect_ndr_pointer(tvb, offset, pinfo, subtree, drep, dissect_spoolss_doc_info_data, NDR_POINTER_UNIQUE, "Document info", -1, level); return offset; } /* * DOC_INFO_CTR */ static gint ett_DOC_INFO_CTR = -1; static int dissect_spoolss_doc_info_ctr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; item = proto_tree_add_text(tree, tvb, offset, 0, "DOC_INFO_CTR"); subtree = proto_item_add_subtree(item, ett_DOC_INFO_CTR); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_level, NULL); offset = dissect_spoolss_doc_info( tvb, offset, pinfo, subtree, drep); return offset; } /* * StartDocPrinter */ static int SpoolssStartDocPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, FALSE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); offset = dissect_spoolss_doc_info_ctr(tvb, offset, pinfo, tree, drep); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssStartDocPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_jobid, NULL); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * EndDocPrinter */ static int SpoolssEndDocPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, FALSE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEndDocPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * WritePrinter */ static gint ett_writeprinter_buffer = -1; static int SpoolssWritePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; guint32 size; proto_item *item; proto_tree *subtree; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, FALSE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_buffer_size, &size); item = proto_tree_add_text(tree, tvb, offset, 0, "Buffer"); subtree = proto_item_add_subtree(item, ett_writeprinter_buffer); offset = dissect_ndr_uint8s(tvb, offset, pinfo, subtree, drep, hf_spoolss_buffer_data, size, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_buffer_size, NULL); proto_item_set_len(item, size + 4); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssWritePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_writeprinter_numwritten, NULL); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * DeletePrinterData */ static int SpoolssDeletePrinterData_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; char *value_name; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd( tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); 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); g_free(value_name); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssDeletePrinterData_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * DRIVER_INFO_1 */ static gint ett_DRIVER_INFO_1 = -1; static int dissect_DRIVER_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; int struct_start = offset; item = proto_tree_add_text(tree, tvb, offset, 0, "DRIVER_INFO_1"); subtree = proto_item_add_subtree(item, ett_DRIVER_INFO_1); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_drivername, struct_start, NULL); return offset; } /* * DRIVER_INFO_3 */ static const value_string driverinfo_cversion_vals[] = { { 0, "Windows 95/98/Me" }, { 2, "Windows NT 4.0" }, { 3, "Windows 2000/XP" }, { 0, NULL } }; static gint ett_DRIVER_INFO_3 = -1; static int dissect_DRIVER_INFO_3(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; int struct_start = offset; item = proto_tree_add_text(tree, tvb, offset, 0, "DRIVER_INFO_3"); subtree = proto_item_add_subtree(item, ett_DRIVER_INFO_3); offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, hf_spoolss_driverinfo_cversion, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_drivername, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_architecture, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_driverpath, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_datafile, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_configfile, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_helpfile, struct_start, NULL); offset = dissect_spoolss_relstrarray( tvb, offset, pinfo, subtree, drep, hf_spoolss_dependentfiles, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_monitorname, struct_start, NULL); offset = dissect_spoolss_relstr( tvb, offset, pinfo, subtree, drep, hf_spoolss_defaultdatatype, struct_start, NULL); return offset; } /* * EnumPrinterDrivers */ static int SpoolssEnumPrinterDrivers_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Name", hf_spoolss_servername, 0); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Environment", hf_spoolss_servername, 0); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_level, &level); dcv->private_data = (void *)level; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_offered, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssEnumPrinterDrivers_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level = (guint32)dcv->private_data, num_drivers, i; int buffer_offset; BUFFER buffer; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, &buffer); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_needed, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_returned, &num_drivers); buffer_offset = buffer.offset; for (i = 0; i < num_drivers; i++) { switch(level) { case 1: buffer_offset = dissect_DRIVER_INFO_1( tvb, buffer_offset, pinfo, buffer.tree, drep); break; case 3: buffer_offset = dissect_DRIVER_INFO_3( tvb, buffer_offset, pinfo, buffer.tree, drep); break; default: proto_tree_add_text( buffer.tree, tvb, buffer_offset, buffer.size, "[Unknown info level %d]", level); goto done; } } done: offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * GetPrinterDriver2 */ static int SpoolssGetPrinterDriver2_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; e_ctx_hnd policy_hnd; char *pol_name; guint32 level; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd( tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd, FALSE, FALSE); dcerpc_smb_fetch_pol((const guint8 *)&policy_hnd, &pol_name, 0, 0); if (check_col(pinfo->cinfo, COL_INFO) && pol_name) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", pol_name); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE, "Architecture", hf_spoolss_architecture, 0); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_level, &level); dcv->private_data = (void *)level; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_offered, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_clientmajorversion, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_clientminorversion, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssGetPrinterDriver2_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; guint32 level = (guint32)dcv->private_data; BUFFER buffer; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, &buffer); switch(level) { case 1: dissect_DRIVER_INFO_1( tvb, buffer.offset, pinfo, buffer.tree, drep); break; case 3: dissect_DRIVER_INFO_3( tvb, buffer.offset, pinfo, buffer.tree, drep); break; default: proto_tree_add_text( buffer.tree, tvb, buffer.offset, buffer.size, "[Unknown info level %d]", level); break; } offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_needed, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_servermajorversion, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_serverminorversion, NULL); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int dissect_notify_info_data_buffer(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; guint32 len = di->levels; offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_buffer_len, NULL); offset = dissect_ndr_uint16s( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_buffer_data, len, NULL); return offset; } static int dissect_NOTIFY_INFO_DATA_printer(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep, guint16 field) { guint32 value1; switch (field) { /* String notify data */ case PRINTER_NOTIFY_SERVER_NAME: case PRINTER_NOTIFY_PRINTER_NAME: case PRINTER_NOTIFY_SHARE_NAME: case PRINTER_NOTIFY_DRIVER_NAME: case PRINTER_NOTIFY_COMMENT: case PRINTER_NOTIFY_LOCATION: case PRINTER_NOTIFY_SEPFILE: case PRINTER_NOTIFY_PRINT_PROCESSOR: case PRINTER_NOTIFY_PARAMETERS: case PRINTER_NOTIFY_DATATYPE: case PRINTER_NOTIFY_PORT_NAME: offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_bufsize, &value1); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_notify_info_data_buffer, NDR_POINTER_UNIQUE, "String", hf_spoolss_notify_info_data_buffer, value1 / 2); break; /* Unknown notify data */ case PRINTER_NOTIFY_SECURITY_DESCRIPTOR: /* Secdesc */ case PRINTER_NOTIFY_DEVMODE: /* Device mode */ offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_bufsize, &value1); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_notify_info_data_buffer, NDR_POINTER_UNIQUE, "Buffer", hf_spoolss_notify_info_data_buffer, value1 / 2); break; default: offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_value1, NULL); offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_value2, NULL); break; } return offset; } static int dissect_NOTIFY_INFO_DATA_job(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep, guint16 field) { guint32 value1; switch (field) { /* String notify data */ case JOB_NOTIFY_PRINTER_NAME: case JOB_NOTIFY_MACHINE_NAME: case JOB_NOTIFY_PORT_NAME: case JOB_NOTIFY_USER_NAME: case JOB_NOTIFY_NOTIFY_NAME: case JOB_NOTIFY_DATATYPE: case JOB_NOTIFY_PRINT_PROCESSOR: case JOB_NOTIFY_PARAMETERS: case JOB_NOTIFY_DRIVER_NAME: case JOB_NOTIFY_STATUS_STRING: case JOB_NOTIFY_DOCUMENT: offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_bufsize, &value1); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_notify_info_data_buffer, NDR_POINTER_UNIQUE, "String", hf_spoolss_notify_info_data_buffer, value1 / 2); break; case JOB_NOTIFY_SUBMITTED: /* SYSTEM_TIME */ offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_buffer_len, NULL); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_SYSTEM_TIME, NDR_POINTER_UNIQUE, "SYSTEM_TIME", -1, 0); break; /* Unknown notify data */ case JOB_NOTIFY_DEVMODE: offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_bufsize, &value1); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_notify_info_data_buffer, NDR_POINTER_UNIQUE, "Buffer", hf_spoolss_notify_info_data_buffer, value1 / 2); break; default: offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_value1, NULL); offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_data_value2, NULL); } return offset; } static gint ett_NOTIFY_INFO_DATA; static int dissect_NOTIFY_INFO_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { proto_item *item; proto_tree *subtree; guint32 count; guint16 type, field; item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_INFO_DATA"); subtree = proto_item_add_subtree(item, ett_NOTIFY_INFO_DATA); offset = dissect_ndr_uint16( tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_info_data_type, &type); offset = dissect_notify_field( tvb, offset, pinfo, subtree, drep, type, &field); offset = dissect_ndr_uint32( tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_info_data_count, &count); offset = dissect_ndr_uint32( tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_info_data_id, NULL); offset = dissect_ndr_uint32( tvb, offset, pinfo, subtree, drep, hf_spoolss_notify_info_data_count, NULL); /* The value here depends on (type, field) */ switch (type) { case PRINTER_NOTIFY_TYPE: offset = dissect_NOTIFY_INFO_DATA_printer( tvb, offset, pinfo, subtree, drep, field); break; case JOB_NOTIFY_TYPE: offset = dissect_NOTIFY_INFO_DATA_job( tvb, offset, pinfo, subtree, drep, field); break; default: proto_tree_add_text( tree, tvb, offset, 0, "[Unknown notify type %d]", type); break; } return offset; } static int dissect_NOTIFY_INFO(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_version, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_flags, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_notify_info_count, NULL); offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, drep, dissect_NOTIFY_INFO_DATA); return offset; } /* * RFNPCNEX */ static int SpoolssRFNPCNEX_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd( tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_notify_options_flags(tvb, offset, pinfo, tree, drep); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_NOTIFY_OPTIONS_ARRAY_CTR, NDR_POINTER_UNIQUE, "NOTIFY_OPTIONS_ARRAY_CTR", -1, 0); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssRFNPCNEX_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_NOTIFY_INFO, NDR_POINTER_UNIQUE, "NOTIFY_INFO", -1, 0); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * RRPCN */ static int SpoolssRRPCN_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd( tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_rrpcn_changelow, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_rrpcn_changehigh, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_rrpcn_unk0, NULL); offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_rrpcn_unk1, NULL); offset = dissect_ndr_pointer( tvb, offset, pinfo, tree, drep, dissect_NOTIFY_INFO, NDR_POINTER_UNIQUE, "NOTIFY_INFO", -1, 0); /* Notify info */ dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssRRPCN_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_spoolss_rrpcn_unk0, NULL); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * ReplyClosePrinter */ static int SpoolssReplyClosePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, TRUE); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssReplyClosePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } /* * FCPN */ static int SpoolssFCPN_q(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL, FALSE, FALSE); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } static int SpoolssFCPN_r(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { dcerpc_info *di = (dcerpc_info *)pinfo->private_data; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); 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; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->rep_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Reply in frame %u", dcv->rep_frame); /* Parse packet */ dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); 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; dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; if (dcv->req_frame != 0) proto_tree_add_text(tree, tvb, offset, 0, "Request in frame %u", dcv->req_frame); /* Parse packet */ offset = dissect_doserror(tvb, offset, pinfo, tree, drep, hf_spoolss_rc, NULL); dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree); return offset; } #endif /* * List of subdissectors for this pipe. */ static dcerpc_sub_dissector dcerpc_spoolss_dissectors[] = { { SPOOLSS_ENUMPRINTERS, "EnumPrinters", SpoolssEnumPrinters_q, SpoolssEnumPrinters_r }, { SPOOLSS_OPENPRINTER, "OpenPrinter", NULL, SpoolssGeneric_r }, { SPOOLSS_SETJOB, "SetJob", SpoolssSetJob_q, SpoolssSetJob_r }, { SPOOLSS_GETJOB, "GetJob", SpoolssGetJob_q, SpoolssGetJob_r }, { SPOOLSS_ENUMJOBS, "EnumJobs", SpoolssEnumJobs_q, SpoolssEnumJobs_r }, { SPOOLSS_ADDPRINTER, "AddPrinter", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTER, "DeletePrinter", SpoolssDeletePrinter_q, SpoolssDeletePrinter_r }, { SPOOLSS_SETPRINTER, "SetPrinter", SpoolssSetPrinter_q, SpoolssSetPrinter_r }, { SPOOLSS_GETPRINTER, "GetPrinter", SpoolssGetPrinter_q, SpoolssGetPrinter_r }, { SPOOLSS_ADDPRINTERDRIVER, "AddPrinterDriver", NULL, SpoolssAddPrinterDriver_r }, { SPOOLSS_ENUMPRINTERDRIVERS, "EnumPrinterDrivers", SpoolssEnumPrinterDrivers_q, SpoolssEnumPrinterDrivers_r }, { SPOOLSS_GETPRINTERDRIVER, "GetPrinterDriver", NULL, SpoolssGeneric_r }, { SPOOLSS_GETPRINTERDRIVERDIRECTORY, "GetPrinterDriverDirectory", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTERDRIVER, "DeletePrinterDriver", NULL, SpoolssGeneric_r }, { SPOOLSS_ADDPRINTPROCESSOR, "AddPrintProcessor", NULL, SpoolssGeneric_r }, { SPOOLSS_ENUMPRINTPROCESSORS, "EnumPrintProcessor", NULL, SpoolssGeneric_r }, { SPOOLSS_GETPRINTPROCESSORDIRECTORY, "GetPrintProcessorDirectory", NULL, SpoolssGeneric_r }, { SPOOLSS_STARTDOCPRINTER, "StartDocPrinter", SpoolssStartDocPrinter_q, SpoolssStartDocPrinter_r }, { SPOOLSS_STARTPAGEPRINTER, "StartPagePrinter", SpoolssStartPagePrinter_q, SpoolssStartPagePrinter_r }, { SPOOLSS_WRITEPRINTER, "WritePrinter", SpoolssWritePrinter_q, SpoolssWritePrinter_r }, { SPOOLSS_ENDPAGEPRINTER, "EndPagePrinter", SpoolssEndPagePrinter_q, SpoolssEndPagePrinter_r }, { SPOOLSS_ABORTPRINTER, "AbortPrinter", NULL, SpoolssGeneric_r }, { SPOOLSS_READPRINTER, "ReadPrinter", NULL, SpoolssGeneric_r }, { SPOOLSS_ENDDOCPRINTER, "EndDocPrinter", SpoolssEndDocPrinter_q, SpoolssEndDocPrinter_r }, { SPOOLSS_ADDJOB, "AddJob", NULL, SpoolssGeneric_r }, { SPOOLSS_SCHEDULEJOB, "ScheduleJob", NULL, SpoolssGeneric_r }, { SPOOLSS_GETPRINTERDATA, "GetPrinterData", SpoolssGetPrinterData_q, SpoolssGetPrinterData_r }, { SPOOLSS_SETPRINTERDATA, "SetPrinterData", SpoolssSetPrinterData_q, SpoolssSetPrinterData_r }, { SPOOLSS_WAITFORPRINTERCHANGE, "WaitForPrinterChange", NULL, SpoolssGeneric_r }, { SPOOLSS_CLOSEPRINTER, "ClosePrinter", SpoolssClosePrinter_q, SpoolssClosePrinter_r }, { SPOOLSS_ADDFORM, "AddForm", SpoolssAddForm_q, SpoolssAddForm_r }, { SPOOLSS_DELETEFORM, "DeleteForm", SpoolssDeleteForm_q, SpoolssDeleteForm_r }, { SPOOLSS_GETFORM, "GetForm", SpoolssGetForm_q, SpoolssGetForm_r }, { SPOOLSS_SETFORM, "SetForm", SpoolssSetForm_q, SpoolssSetForm_r }, { SPOOLSS_ENUMFORMS, "EnumForms", SpoolssEnumForms_q, SpoolssEnumForms_r }, { SPOOLSS_ENUMPORTS, "EnumPorts", NULL, SpoolssGeneric_r }, { SPOOLSS_ENUMMONITORS, "EnumMonitors", NULL, SpoolssGeneric_r }, { SPOOLSS_ADDPORT, "AddPort", NULL, SpoolssGeneric_r }, { SPOOLSS_CONFIGUREPORT, "ConfigurePort", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPORT, "DeletePort", NULL, SpoolssGeneric_r }, { SPOOLSS_CREATEPRINTERIC, "CreatePrinterIC", NULL, SpoolssGeneric_r }, { SPOOLSS_PLAYGDISCRIPTONPRINTERIC, "PlayDiscriptOnPrinterIC", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTERIC, "DeletePrinterIC", NULL, SpoolssGeneric_r }, { SPOOLSS_ADDPRINTERCONNECTION, "AddPrinterConnection", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTERCONNECTION, "DeletePrinterConnection", NULL, SpoolssGeneric_r }, { SPOOLSS_PRINTERMESSAGEBOX, "PrinterMessageBox", NULL, SpoolssGeneric_r }, { SPOOLSS_ADDMONITOR, "AddMonitor", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEMONITOR, "DeleteMonitor", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTPROCESSOR, "DeletePrintProcessor", NULL, SpoolssGeneric_r }, { SPOOLSS_ADDPRINTPROVIDER, "AddPrintProvider", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTPROVIDER, "DeletePrintProvider", NULL, SpoolssGeneric_r }, { SPOOLSS_ENUMPRINTPROCDATATYPES, "EnumPrintProcDataTypes", NULL, SpoolssGeneric_r }, { SPOOLSS_RESETPRINTER, "ResetPrinter", NULL, SpoolssGeneric_r }, { SPOOLSS_GETPRINTERDRIVER2, "GetPrinterDriver2", SpoolssGetPrinterDriver2_q, SpoolssGetPrinterDriver2_r }, { SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION, "FindFirstPrinterChangeNotification", NULL, SpoolssGeneric_r }, { SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION, "FindNextPrinterChangeNotification", NULL, SpoolssGeneric_r }, { SPOOLSS_FCPN, "FCPN", SpoolssFCPN_q, SpoolssFCPN_r }, { SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD, "RouterFindFirstPrinterNotificationOld", NULL, SpoolssGeneric_r }, { SPOOLSS_REPLYOPENPRINTER, "ReplyOpenPrinter", SpoolssReplyOpenPrinter_q, SpoolssReplyOpenPrinter_r }, { SPOOLSS_ROUTERREPLYPRINTER, "RouterREplyPrinter", NULL, SpoolssGeneric_r }, { SPOOLSS_REPLYCLOSEPRINTER, "ReplyClosePrinter", SpoolssReplyClosePrinter_q, SpoolssReplyClosePrinter_r }, { SPOOLSS_ADDPORTEX, "AddPortEx", NULL, SpoolssGeneric_r }, { SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION, "RemoteFindFirstPrinterChangeNotification", NULL, SpoolssGeneric_r }, { SPOOLSS_SPOOLERINIT, "SpoolerInit", NULL, SpoolssGeneric_r }, { SPOOLSS_RESETPRINTEREX, "ResetPrinterEx", NULL, SpoolssGeneric_r }, { SPOOLSS_RFFPCNEX, "RFFPCNEX", SpoolssRFFPCNEX_q, SpoolssRFFPCNEX_r }, { SPOOLSS_RRPCN, "RRPCN", SpoolssRRPCN_q, SpoolssRRPCN_r }, { SPOOLSS_RFNPCNEX, "RFNPCNEX", SpoolssRFNPCNEX_q, SpoolssRFNPCNEX_r }, { SPOOLSS_OPENPRINTEREX, "OpenPrinterEx", SpoolssOpenPrinterEx_q, SpoolssOpenPrinterEx_r }, { SPOOLSS_ADDPRINTEREX, "AddPrinterEx", NULL, SpoolssAddPrinterEx_r }, { SPOOLSS_ENUMPRINTERDATA, "EnumPrinterData", SpoolssEnumPrinterData_q, SpoolssEnumPrinterData_r }, { SPOOLSS_DELETEPRINTERDATA, "DeletePrinterData", SpoolssDeletePrinterData_q, SpoolssDeletePrinterData_r }, { SPOOLSS_GETPRINTERDATAEX, "GetPrinterDataEx", SpoolssGetPrinterDataEx_q, SpoolssGetPrinterDataEx_r }, { SPOOLSS_SETPRINTERDATAEX, "SetPrinterDataEx", SpoolssSetPrinterDataEx_q, SpoolssSetPrinterDataEx_r }, { SPOOLSS_ENUMPRINTERDATAEX, "EnumPrinterDataEx", NULL, SpoolssGeneric_r }, { SPOOLSS_ENUMPRINTERKEY, "EnumPrinterKey", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTERDATAEX, "DeletePrinterDataEx", NULL, SpoolssGeneric_r }, { SPOOLSS_DELETEPRINTERDRIVEREX, "DeletePrinterDriverEx", NULL, SpoolssGeneric_r }, { SPOOLSS_ADDPRINTERDRIVEREX, "AddPrinterDriverEx", NULL, SpoolssGeneric_r }, { 0, NULL, NULL, NULL }, }; /* * Dissector initialisation function */ /* Protocol registration */ static int proto_dcerpc_spoolss = -1; static gint ett_dcerpc_spoolss = -1; void proto_register_dcerpc_spoolss(void) { static hf_register_info hf[] = { { &hf_spoolss_hnd, { "Context handle", "spoolss.hnd", FT_BYTES, BASE_NONE, NULL, 0x0, "SPOOLSS policy handle", HFILL }}, { &hf_spoolss_rc, { "Return code", "spoolss.rc", FT_UINT32, BASE_HEX, VALS(DOS_errors), 0x0, "SPOOLSS return code", HFILL }}, { &hf_spoolss_offered, { "Offered", "spoolss.offered", FT_UINT32, BASE_DEC, NULL, 0x0, "Size of buffer offered in this request", HFILL }}, { &hf_spoolss_needed, { "Needed", "spoolss.needed", FT_UINT32, BASE_DEC, NULL, 0x0, "Size of buffer required for request", HFILL }}, { &hf_spoolss_returned, { "Returned", "spoolss.returned", FT_UINT32, BASE_DEC, NULL, 0x0, "Number of items returned", HFILL }}, { &hf_spoolss_relstr_offset, { "Relative string offset", "spoolss.relstr.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset of relative string data", HFILL }}, { &hf_spoolss_printername, { "Printer name", "spoolss.printername", FT_STRING, BASE_NONE, NULL, 0, "Printer name", HFILL }}, { &hf_spoolss_servername, { "Server name", "spoolss.servername", FT_STRING, BASE_NONE, NULL, 0, "Server name", HFILL }}, { &hf_spoolss_architecture, { "Architecture name", "spoolss.architecture", FT_STRING, BASE_NONE, NULL, 0, "Architecture name", HFILL }}, { &hf_spoolss_drivername, { "Driver name", "spoolss.drivername", FT_STRING, BASE_NONE, NULL, 0, "Driver name", HFILL }}, { &hf_spoolss_username, { "User name", "spoolss.username", FT_STRING, BASE_NONE, NULL, 0, "User name", HFILL }}, { &hf_spoolss_documentname, { "Document name", "spoolss.document", FT_STRING, BASE_NONE, NULL, 0, "Document name", HFILL }}, { &hf_spoolss_outputfile, { "Output file", "spoolss.outputfile", FT_STRING, BASE_NONE, NULL, 0, "Output File", HFILL }}, { &hf_spoolss_datatype, { "Datatype", "spoolss.Datatype", FT_STRING, BASE_NONE, NULL, 0, "Datatype", HFILL }}, { &hf_spoolss_textstatus, { "Text status", "spoolss.textstatus", FT_STRING, BASE_NONE, NULL, 0, "Text status", HFILL }}, { &hf_spoolss_buffer_size, { "Buffer size", "spoolss.buffer.size", FT_UINT32, BASE_DEC, NULL, 0x0, "Size of buffer", HFILL }}, { &hf_spoolss_buffer_data, { "Buffer data", "spoolss.buffer.data", FT_BYTES, BASE_HEX, NULL, 0x0, "Contents of buffer", HFILL }}, { &hf_spoolss_enumjobs_firstjob, { "First job", "spoolss.enumjobs.firstjob", FT_UINT32, BASE_DEC, NULL, 0x0, "Index of first job to return", HFILL }}, { &hf_spoolss_enumjobs_numjobs, { "Num jobs", "spoolss.enumjobs.numjobs", FT_UINT32, BASE_DEC, NULL, 0x0, "Number of jobs to return", HFILL }}, { &hf_spoolss_level, { "Info level", "spoolss.enumjobs.level", FT_UINT32, BASE_DEC, NULL, 0x0, "Info level", HFILL }}, /* Print jobs */ { &hf_spoolss_jobid, { "Job ID", "spoolss.job.id", FT_UINT32, BASE_DEC, NULL, 0x0, "Job identification number", HFILL }}, { &hf_spoolss_jobstatus, { "Job status", "spoolss.job.status", FT_UINT32, BASE_DEC, NULL, 0x0, "Job status", HFILL }}, { &hf_spoolss_jobpriority, { "Job priority", "spoolss.job.priority", FT_UINT32, BASE_DEC, NULL, 0x0, "Job priority", HFILL }}, { &hf_spoolss_jobposition, { "Job position", "spoolss.job.position", FT_UINT32, BASE_DEC, NULL, 0x0, "Job position", HFILL }}, { &hf_spoolss_jobtotalpages, { "Job total pages", "spoolss.job.totalpages", FT_UINT32, BASE_DEC, NULL, 0x0, "Job total pages", HFILL }}, { &hf_spoolss_jobpagesprinted, { "Job pages printed", "spoolss.job.pagesprinted", FT_UINT32, BASE_DEC, NULL, 0x0, "Job identification number", HFILL }}, /* SYSTEM_TIME */ { &hf_spoolss_time_year, { "Year", "spoolss.time.year", FT_UINT32, BASE_DEC, NULL, 0x0, "Year", HFILL }}, { &hf_spoolss_time_month, { "Month", "spoolss.time.month", FT_UINT32, BASE_DEC, NULL, 0x0, "Month", HFILL }}, { &hf_spoolss_time_dow, { "Day of week", "spoolss.time.dow", FT_UINT32, BASE_DEC, NULL, 0x0, "Day of week", HFILL }}, { &hf_spoolss_time_day, { "Day", "spoolss.time.day", FT_UINT32, BASE_DEC, NULL, 0x0, "Day", HFILL }}, { &hf_spoolss_time_hour, { "Hour", "spoolss.time.hour", FT_UINT32, BASE_DEC, NULL, 0x0, "Hour", HFILL }}, { &hf_spoolss_time_minute, { "Minute", "spoolss.time.minute", FT_UINT32, BASE_DEC, NULL, 0x0, "Minute", HFILL }}, { &hf_spoolss_time_second, { "Second", "spoolss.time.second", FT_UINT32, BASE_DEC, NULL, 0x0, "Second", HFILL }}, { &hf_spoolss_time_msec, { "Millisecond", "spoolss.time.msec", FT_UINT32, BASE_DEC, NULL, 0x0, "Millisecond", HFILL }}, /* Printer data */ { &hf_spoolss_printerdata_value, { "Printer data value", "spoolss.printerdata.value", FT_STRING, BASE_NONE, NULL, 0, "Printer data value", HFILL }}, { &hf_spoolss_printerdata_type, { "Printer data type", "spoolss.printerdata.type", FT_UINT32, BASE_DEC, VALS(®_datatypes), 0, "Printer data type", HFILL }}, /* SetJob RPC */ { &hf_spoolss_setjob_cmd, { "Set job command", "spoolss.setjob.cmd", FT_UINT32, BASE_DEC, VALS(&setjob_commands), 0x0, "Printer data name", HFILL }}, /* WritePrinter */ { &hf_spoolss_writeprinter_numwritten, { "Num written", "spoolss.writeprinter.numwritten", FT_UINT32, BASE_DEC, NULL, 0x0, "Number of bytes written", HFILL }}, /* EnumPrinterData */ { &hf_spoolss_enumprinterdata_index, { "Enum index", "spoolss.enumprinterdata.index", FT_UINT32, BASE_DEC, NULL, 0x0, "Index for start of enumeration", HFILL }}, { &hf_spoolss_enumprinterdata_value_offered, { "Value size offered", "spoolss.enumprinterdata.value_offered", FT_UINT32, BASE_DEC, NULL, 0x0, "Buffer size offered for printerdata value", HFILL }}, { &hf_spoolss_enumprinterdata_data_offered, { "Data size offered", "spoolss.enumprinterdata.data_offered", FT_UINT32, BASE_DEC, NULL, 0x0, "Buffer size offered for printerdata data", HFILL }}, { &hf_spoolss_enumprinterdata_value_needed, { "Value size needed", "spoolss.enumprinterdata.value_needed", FT_UINT32, BASE_DEC, NULL, 0x0, "Buffer size needed for printerdata value", HFILL }}, { &hf_spoolss_enumprinterdata_data_needed, { "Data size needed", "spoolss.enumprinterdata.data_needed", FT_UINT32, BASE_DEC, NULL, 0x0, "Buffer size needed for printerdata data", HFILL }}, /* GetPrinterDriver2 */ { &hf_spoolss_clientmajorversion, { "Client major version", "spoolss.clientmajorversion", FT_UINT32, BASE_DEC, NULL, 0x0, "Client printer driver major version", HFILL }}, { &hf_spoolss_clientminorversion, { "Client minor version", "spoolss.clientminorversion", FT_UINT32, BASE_DEC, NULL, 0x0, "Client printer driver minor version", HFILL }}, { &hf_spoolss_servermajorversion, { "Server major version", "spoolss.servermajorversion", FT_UINT32, BASE_DEC, NULL, 0x0, "Server printer driver major version", HFILL }}, { &hf_spoolss_serverminorversion, { "Server minor version", "spoolss.serverminorversion", FT_UINT32, BASE_DEC, NULL, 0x0, "Server printer driver minor version", HFILL }}, { &hf_spoolss_driverpath, { "Driver path", "spoolss.driverpath", FT_STRING, BASE_NONE, NULL, 0, "Driver path", HFILL }}, { &hf_spoolss_datafile, { "Data file", "spoolss.datafile", FT_STRING, BASE_NONE, NULL, 0, "Data file", HFILL }}, { &hf_spoolss_configfile, { "Config file", "spoolss.configfile", FT_STRING, BASE_NONE, NULL, 0, "Printer name", HFILL }}, { &hf_spoolss_helpfile, { "Help file", "spoolss.helpfile", FT_STRING, BASE_NONE, NULL, 0, "Help file", HFILL }}, { &hf_spoolss_monitorname, { "Monitor name", "spoolss.monitorname", FT_STRING, BASE_NONE, NULL, 0, "Monitor name", HFILL }}, { &hf_spoolss_defaultdatatype, { "Default data type", "spoolss.defaultdatatype", FT_STRING, BASE_NONE, NULL, 0, "Default data type", HFILL }}, { &hf_spoolss_driverinfo_cversion, { "Driver version", "spoolss.driverversion", FT_UINT32, BASE_DEC, VALS(driverinfo_cversion_vals), 0, "Printer name", HFILL }}, { &hf_spoolss_dependentfiles, { "Dependent files", "spoolss.dependentfiles", FT_STRING, BASE_NONE, NULL, 0, "Dependent files", HFILL }}, /* rffpcnex */ { &hf_spoolss_rffpcnex_options, { "Options", "spoolss.rffpcnex.options", FT_UINT32, BASE_DEC, NULL, 0, "RFFPCNEX options", HFILL }}, { &hf_spoolss_printerlocal, { "Printer local", "spoolss.printer_local", FT_UINT32, BASE_DEC, NULL, 0, "Printer local", HFILL }}, { &hf_spoolss_rffpcnex_flags, { "RFFPCNEX flags", "spoolss.rffpcnex.flags", FT_UINT32, BASE_DEC, NULL, 0, "RFFPCNEX flags", HFILL }}, { &hf_spoolss_rffpcnex_flags_add_printer, { "Add printer", "spoolss.rffpcnex.flags.add_printer", FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_printer), PRINTER_CHANGE_ADD_PRINTER, "Add printer", HFILL }}, { &hf_spoolss_rffpcnex_flags_set_printer, { "Set printer", "spoolss.rffpcnex.flags.set_printer", FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_printer), PRINTER_CHANGE_SET_PRINTER, "Set printer", HFILL }}, { &hf_spoolss_rffpcnex_flags_delete_printer, { "Delete printer", "spoolss.rffpcnex.flags.delete_printer", FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_printer), PRINTER_CHANGE_DELETE_PRINTER, "Delete printer", HFILL }}, { &hf_spoolss_rffpcnex_flags_failed_printer_connection, { "Failed printer connection", "spoolss.rffpcnex.flags.failed_connection_printer", FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_failed_connection_printer), PRINTER_CHANGE_FAILED_CONNECTION_PRINTER, "Failed printer connection", HFILL }}, { &hf_spoolss_notify_options_version, { "Version", "spoolss.notify_options.version", FT_UINT32, BASE_DEC, NULL, 0, "Version", HFILL }}, { &hf_spoolss_notify_options_flags, { "Flags", "spoolss.notify_options.flags", FT_UINT32, BASE_DEC, NULL, 0, "Flags", HFILL }}, { &hf_spoolss_notify_options_count, { "Count", "spoolss.notify_options.count", FT_UINT32, BASE_DEC, NULL, 0, "Count", HFILL }}, { &hf_spoolss_notify_option_type, { "Type", "spoolss.notify_option.type", FT_UINT16, BASE_DEC, VALS(&printer_notify_types), 0, "Type", HFILL }}, { &hf_spoolss_notify_option_reserved1, { "Reserved1", "spoolss.notify_option.reserved1", FT_UINT16, BASE_DEC, NULL, 0, "Reserved1", HFILL }}, { &hf_spoolss_notify_option_reserved2, { "Reserved2", "spoolss.notify_option.reserved2", FT_UINT32, BASE_DEC, NULL, 0, "Reserved2", HFILL }}, { &hf_spoolss_notify_option_reserved3, { "Reserved3", "spoolss.notify_option.reserved3", FT_UINT32, BASE_DEC, NULL, 0, "Reserved3", HFILL }}, { &hf_spoolss_notify_option_count, { "Count", "spoolss.notify_option.count", FT_UINT32, BASE_DEC, NULL, 0, "Count", HFILL }}, { &hf_spoolss_notify_option_data_count, { "Count", "spoolss.notify_option_data.count", FT_UINT32, BASE_DEC, NULL, 0, "Count", HFILL }}, { &hf_spoolss_notify_options_flags_refresh, { "Refresh", "spoolss.notify_options.flags", FT_BOOLEAN, 32, TFS(&tfs_notify_options_flags_refresh), PRINTER_NOTIFY_OPTIONS_REFRESH, "Refresh", HFILL }}, { &hf_spoolss_notify_info_count, { "Count", "spoolss.notify_info.count", FT_UINT32, BASE_DEC, NULL, 0, "Count", HFILL }}, { &hf_spoolss_notify_info_version, { "Version", "spoolss.notify_info.version", FT_UINT32, BASE_DEC, NULL, 0, "Version", HFILL }}, { &hf_spoolss_notify_info_flags, { "Flags", "spoolss.notify_info.flags", FT_UINT32, BASE_HEX, NULL, 0, "Flags", HFILL }}, { &hf_spoolss_notify_info_data_type, { "Type", "spoolss.notify_info_data.type", FT_UINT16, BASE_DEC, VALS(&printer_notify_types), 0, "Type", HFILL }}, { &hf_spoolss_notify_field, { "Field", "spoolss.notify_field", FT_UINT16, BASE_DEC, NULL, 0, "Field", HFILL }}, { &hf_spoolss_notify_info_data_count, { "Count", "spoolss.notify_info_data.count", FT_UINT32, BASE_DEC, NULL, 0, "Count", HFILL }}, { &hf_spoolss_notify_info_data_id, { "Job Id", "spoolss.notify_info_data.jobid", FT_UINT32, BASE_DEC, NULL, 0, "Job Id", HFILL }}, { &hf_spoolss_notify_info_data_value1, { "Value1", "spoolss.notify_info_data.value1", FT_UINT32, BASE_HEX, NULL, 0, "Value1", HFILL }}, { &hf_spoolss_notify_info_data_value2, { "Value2", "spoolss.notify_info_data.value2", FT_UINT32, BASE_HEX, NULL, 0, "Value2", HFILL }}, { &hf_spoolss_notify_info_data_bufsize, { "Buffer size", "spoolss.notify_info_data.bufsize", FT_UINT32, BASE_DEC, NULL, 0, "Buffer size", HFILL }}, { &hf_spoolss_notify_info_data_buffer, { "Buffer", "spoolss.notify_info_data.buffer", FT_UINT32, BASE_HEX, NULL, 0, "Buffer", HFILL }}, { &hf_spoolss_notify_info_data_buffer_len, { "Buffer length", "spoolss.notify_info_data.buffer.len", FT_UINT32, BASE_HEX, NULL, 0, "Buffer length", HFILL }}, { &hf_spoolss_notify_info_data_buffer_data, { "Buffer data", "spoolss.notify_info_data.buffer.data", FT_BYTES, BASE_HEX, NULL, 0, "Buffer data", HFILL }}, { &hf_spoolss_rrpcn_changelow, { "Change low", "spoolss.rrpcn.changelow", FT_UINT32, BASE_DEC, NULL, 0, "Change low", HFILL }}, { &hf_spoolss_rrpcn_changehigh, { "Change high", "spoolss.rrpcn.changehigh", FT_UINT32, BASE_DEC, NULL, 0, "Change high", HFILL }}, { &hf_spoolss_rrpcn_unk0, { "Unknown 0", "spoolss.rrpcn.unk0", FT_UINT32, BASE_DEC, NULL, 0, "Unknown 0", HFILL }}, { &hf_spoolss_rrpcn_unk1, { "Unknown 1", "spoolss.rrpcn.unk1", FT_UINT32, BASE_DEC, NULL, 0, "Unknown 1", HFILL }}, { &hf_spoolss_replyopenprinter_unk0, { "Unknown 0", "spoolss.replyopenprinter.unk0", FT_UINT32, BASE_DEC, NULL, 0, "Unknown 0", HFILL }}, { &hf_spoolss_replyopenprinter_unk1, { "Unknown 1", "spoolss.replyopenprinter.unk1", FT_UINT32, BASE_DEC, NULL, 0, "Unknown 1", HFILL }}, }; static gint *ett[] = { &ett_dcerpc_spoolss, &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_SPOOL_PRINTER_INFO_LEVEL, &ett_PRINTER_INFO_0, &ett_PRINTER_INFO_1, &ett_PRINTER_INFO_2, &ett_PRINTER_INFO_3, &ett_RELSTR, &ett_RELSTR_ARRAY, &ett_POLICY_HND, &ett_FORM_REL, &ett_FORM_CTR, &ett_FORM_1, &ett_JOB_INFO_1, &ett_JOB_INFO_2, &ett_SEC_DESC_BUF, &ett_SYSTEM_TIME, &ett_DOC_INFO_1, &ett_DOC_INFO, &ett_DOC_INFO_CTR, &ett_printerdata_value, &ett_printerdata_data, &ett_writeprinter_buffer, &ett_DRIVER_INFO_1, &ett_DRIVER_INFO_3, &ett_rffpcnex_flags, &ett_notify_options_flags, &ett_NOTIFY_INFO_DATA, &ett_NOTIFY_OPTION, }; proto_dcerpc_spoolss = proto_register_protocol( "Microsoft Spool Subsystem", "SPOOLSS", "spoolss"); proto_register_field_array(proto_dcerpc_spoolss, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } /* 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) { /* Register protocol as dcerpc */ dcerpc_init_uuid(proto_dcerpc_spoolss, ett_dcerpc_spoolss, &uuid_dcerpc_spoolss, ver_dcerpc_spoolss, dcerpc_spoolss_dissectors); }