diff options
Diffstat (limited to 'epan/dissectors/packet-dcerpc-spoolss.c')
-rw-r--r-- | epan/dissectors/packet-dcerpc-spoolss.c | 8226 |
1 files changed, 8226 insertions, 0 deletions
diff --git a/epan/dissectors/packet-dcerpc-spoolss.c b/epan/dissectors/packet-dcerpc-spoolss.c new file mode 100644 index 0000000000..86220411b3 --- /dev/null +++ b/epan/dissectors/packet-dcerpc-spoolss.c @@ -0,0 +1,8226 @@ +/* packet-dcerpc-spoolss.c + * Routines for SMB \PIPE\spoolss packet disassembly + * Copyright 2001-2003, Tim Potter <tpot@samba.org> + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* TODO list: + + - audit of item lengths + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> +#include <string.h> + +#include <epan/packet.h> +#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" + +/* GetPrinterDriver2 */ + +static int hf_clientmajorversion = -1; +static int hf_clientminorversion = -1; +static int hf_servermajorversion = -1; +static int hf_serverminorversion = -1; +static int hf_driverpath = -1; +static int hf_datafile = -1; +static int hf_configfile = -1; +static int hf_helpfile = -1; +static int hf_monitorname = -1; +static int hf_defaultdatatype = -1; +static int hf_driverinfo_cversion = -1; +static int hf_dependentfiles = -1; + +/* GetPrinter */ + +/* Times */ + +static int hf_start_time = -1; +static int hf_end_time = -1; +static int hf_elapsed_time = -1; + +/****************************************************************************/ + +/* + * New hf index values - I'm in the process of doing a bit of a cleanup -tpot + */ + +static int hf_opnum = -1; +static int hf_hnd = -1; +static int hf_rc = -1; +static int hf_offered = -1; +static int hf_needed = -1; +static int hf_returned = -1; +static int hf_buffer_size = -1; +static int hf_buffer_data = -1; +static int hf_offset = -1; +static int hf_level = -1; +static int hf_access_required = -1; + +static int hf_printername = -1; +static int hf_machinename = -1; +static int hf_notifyname = -1; +static int hf_printerdesc = -1; +static int hf_printercomment = -1; +static int hf_servername = -1; +static int hf_sharename = -1; +static int hf_portname = -1; +static int hf_printerlocation = -1; +static int hf_drivername = -1; +static int hf_architecture = -1; +static int hf_username = -1; +static int hf_documentname = -1; +static int hf_outputfile = -1; +static int hf_datatype = -1; +static int hf_textstatus = -1; +static int hf_sepfile = -1; +static int hf_printprocessor = -1; +static int hf_parameters = -1; + +/* Printer information */ + +static int hf_printer_cjobs = -1; +static int hf_printer_total_jobs = -1; +static int hf_printer_total_bytes = -1; +static int hf_printer_global_counter = -1; +static int hf_printer_total_pages = -1; +static int hf_printer_major_version = -1; +static int hf_printer_build_version = -1; +static int hf_printer_unk7 = -1; +static int hf_printer_unk8 = -1; +static int hf_printer_unk9 = -1; +static int hf_printer_session_ctr = -1; +static int hf_printer_unk11 = -1; +static int hf_printer_printer_errors = -1; +static int hf_printer_unk13 = -1; +static int hf_printer_unk14 = -1; +static int hf_printer_unk15 = -1; +static int hf_printer_unk16 = -1; +static int hf_printer_changeid = -1; +static int hf_printer_unk18 = -1; +static int hf_printer_unk20 = -1; +static int hf_printer_c_setprinter = -1; +static int hf_printer_unk22 = -1; +static int hf_printer_unk23 = -1; +static int hf_printer_unk24 = -1; +static int hf_printer_unk25 = -1; +static int hf_printer_unk26 = -1; +static int hf_printer_unk27 = -1; +static int hf_printer_unk28 = -1; +static int hf_printer_unk29 = -1; +static int hf_printer_flags = -1; +static int hf_printer_priority = -1; +static int hf_printer_default_priority = -1; +static int hf_printer_jobs = -1; +static int hf_printer_averageppm = -1; +static int hf_printer_guid = -1; +static int hf_printer_action = -1; + +/* Printer data */ + +static int hf_printerdata = -1; +static int hf_printerdata_key = -1; +static int hf_printerdata_value = -1; +static int hf_printerdata_type = -1; +static int hf_printerdata_size = -1; /* Length of printer data */ +static int hf_printerdata_data = -1; +static int hf_printerdata_data_sz = -1; +static int hf_printerdata_data_dword = -1; + +/* Devicemode */ + +static int hf_devmodectr_size = -1; + +static int hf_devmode = -1; +static int hf_devmode_size = -1; +static int hf_devmode_spec_version = -1; +static int hf_devmode_driver_version = -1; +static int hf_devmode_size2 = -1; +static int hf_devmode_driver_extra_len = -1; +static int hf_devmode_fields = -1; +static int hf_devmode_orientation = -1; +static int hf_devmode_paper_size = -1; +static int hf_devmode_paper_width = -1; +static int hf_devmode_paper_length = -1; +static int hf_devmode_scale = -1; +static int hf_devmode_copies = -1; +static int hf_devmode_default_source = -1; +static int hf_devmode_print_quality = -1; +static int hf_devmode_color = -1; +static int hf_devmode_duplex = -1; +static int hf_devmode_y_resolution = -1; +static int hf_devmode_tt_option = -1; +static int hf_devmode_collate = -1; +static int hf_devmode_log_pixels = -1; +static int hf_devmode_bits_per_pel = -1; +static int hf_devmode_pels_width = -1; +static int hf_devmode_pels_height = -1; +static int hf_devmode_display_flags = -1; +static int hf_devmode_display_freq = -1; +static int hf_devmode_icm_method = -1; +static int hf_devmode_icm_intent = -1; +static int hf_devmode_media_type = -1; +static int hf_devmode_dither_type = -1; +static int hf_devmode_reserved1 = -1; +static int hf_devmode_reserved2 = -1; +static int hf_devmode_panning_width = -1; +static int hf_devmode_panning_height = -1; +static int hf_devmode_driver_extra = -1; + +static int hf_devmode_fields_orientation = -1; +static int hf_devmode_fields_papersize = -1; +static int hf_devmode_fields_paperlength = -1; +static int hf_devmode_fields_paperwidth = -1; +static int hf_devmode_fields_scale = -1; +static int hf_devmode_fields_position = -1; +static int hf_devmode_fields_nup = -1; +static int hf_devmode_fields_copies = -1; +static int hf_devmode_fields_defaultsource = -1; +static int hf_devmode_fields_printquality = -1; +static int hf_devmode_fields_color = -1; +static int hf_devmode_fields_duplex = -1; +static int hf_devmode_fields_yresolution = -1; +static int hf_devmode_fields_ttoption = -1; +static int hf_devmode_fields_collate = -1; +static int hf_devmode_fields_formname = -1; +static int hf_devmode_fields_logpixels = -1; +static int hf_devmode_fields_bitsperpel = -1; +static int hf_devmode_fields_pelswidth = -1; +static int hf_devmode_fields_pelsheight = -1; +static int hf_devmode_fields_displayflags = -1; +static int hf_devmode_fields_displayfrequency = -1; +static int hf_devmode_fields_icmmethod = -1; +static int hf_devmode_fields_icmintent = -1; +static int hf_devmode_fields_mediatype = -1; +static int hf_devmode_fields_dithertype = -1; +static int hf_devmode_fields_panningwidth = -1; +static int hf_devmode_fields_panningheight = -1; + +/* Print job */ + +static int hf_job_id = -1; +static int hf_job_priority = -1; +static int hf_job_position = -1; +static int hf_job_totalpages = -1; +static int hf_job_totalbytes = -1; +static int hf_job_pagesprinted = -1; +static int hf_job_bytesprinted = -1; +static int hf_job_size = -1; + +static int hf_job_status = -1; +static int hf_job_status_paused = -1; +static int hf_job_status_error = -1; +static int hf_job_status_deleting = -1; +static int hf_job_status_spooling = -1; +static int hf_job_status_printing = -1; +static int hf_job_status_offline = -1; +static int hf_job_status_paperout = -1; +static int hf_job_status_printed = -1; +static int hf_job_status_deleted = -1; +static int hf_job_status_blocked = -1; +static int hf_job_status_user_intervention = -1; + +/* Forms */ + +static int hf_form = -1; +static int hf_form_level = -1; +static int hf_form_name = -1; +static int hf_form_flags = -1; +static int hf_form_unknown = -1; +static int hf_form_width = -1; +static int hf_form_height = -1; +static int hf_form_left_margin = -1; +static int hf_form_top_margin = -1; +static int hf_form_horiz_len = -1; +static int hf_form_vert_len = -1; + +static int hf_enumforms_num = -1; + +/* Print notify */ + +static int hf_notify_options_version = -1; +static int hf_notify_options_flags = -1; +static int hf_notify_options_flags_refresh = -1; +static int hf_notify_options_count = -1; +static int hf_notify_option_type = -1; +static int hf_notify_option_reserved1 = -1; +static int hf_notify_option_reserved2 = -1; +static int hf_notify_option_reserved3 = -1; +static int hf_notify_option_count = -1; +static int hf_notify_option_data_count = -1; +static int hf_notify_info_count = -1; +static int hf_notify_info_version = -1; +static int hf_notify_info_flags = -1; +static int hf_notify_info_data_type = -1; +static int hf_notify_info_data_count = -1; +static int hf_notify_info_data_id = -1; +static int hf_notify_info_data_value1 = -1; +static int hf_notify_info_data_value2 = -1; +static int hf_notify_info_data_bufsize = -1; +static int hf_notify_info_data_buffer = -1; +static int hf_notify_info_data_buffer_len = -1; +static int hf_notify_info_data_buffer_data = -1; + +static int hf_notify_field = -1; + +static int hf_printerlocal = -1; + +static int hf_rrpcn_changelow = -1; +static int hf_rrpcn_changehigh = -1; +static int hf_rrpcn_unk0 = -1; +static int hf_rrpcn_unk1 = -1; + +static int hf_replyopenprinter_unk0 = -1; +static int hf_replyopenprinter_unk1 = -1; + +/****************************************************************************/ + +/* + * Dissect SPOOLSS specific access rights + */ + +static int hf_server_access_admin = -1; +static int hf_server_access_enum = -1; +static int hf_printer_access_admin = -1; +static int hf_printer_access_use = -1; +static int hf_job_access_admin = -1; + +static void +spoolss_printer_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree, + guint32 access) +{ + proto_tree_add_boolean( + tree, hf_printer_access_use, tvb, offset, 4, access); + + proto_tree_add_boolean( + tree, hf_printer_access_admin, tvb, offset, 4, access); +} + +struct access_mask_info spoolss_printer_access_mask_info = { + "SPOOLSS printer", + spoolss_printer_specific_rights, + NULL, /* Generic mapping table */ + NULL /* Standard mapping table */ +}; + +static void +spoolss_printserver_specific_rights(tvbuff_t *tvb, gint offset, + proto_tree *tree, guint32 access) +{ + proto_tree_add_boolean( + tree, hf_server_access_enum, tvb, offset, 4, access); + + proto_tree_add_boolean( + tree, hf_server_access_admin, tvb, offset, 4, access); +} + +struct access_mask_info spoolss_printserver_access_mask_info = { + "SPOOLSS print server", + spoolss_printserver_specific_rights, + NULL, /* Generic mapping table */ + NULL /* Standard mapping table */ +}; + +static void +spoolss_job_specific_rights(tvbuff_t *tvb, gint offset, + proto_tree *tree, guint32 access) +{ + proto_tree_add_boolean( + tree, hf_job_access_admin, tvb, offset, 4, access); +} + +struct access_mask_info spoolss_job_access_mask_info = { + "SPOOLSS job", + spoolss_job_specific_rights, + NULL, /* Generic mapping table */ + NULL /* Standard mapping table */ +}; + +/* + * Routines to dissect a spoolss BUFFER + */ + +typedef struct { + tvbuff_t *tvb; + proto_item *tree; /* Proto tree buffer located in */ + proto_item *item; +} BUFFER; + +static gint ett_BUFFER = -1; + +static int +dissect_spoolss_buffer_data(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + BUFFER *b = (BUFFER *)di->private_data; + proto_item *item; + guint32 size; + const guint8 *data; + + if (di->conformant_run) + return offset; + + /* Dissect size and data */ + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_buffer_size, &size); + + offset = dissect_ndr_uint8s(tvb, offset, pinfo, NULL, drep, + hf_buffer_data, size, &data); + + item = proto_tree_add_item( + tree, hf_buffer_data, tvb, offset - size, + size, drep[0] & 0x10); + + /* Return buffer info */ + + if (b) { + + /* I'm not sure about this. Putting the buffer into + it's own tvb makes sense and the dissection code is + much clearer, but the data is a proper subset of + the actual tvb. Not adding the new data source + makes the hex display confusing as it switches + between the 'DCERPC over SMB' tvb and the buffer + tvb with no visual cues as to what is going on. */ + + b->tvb = tvb_new_real_data(data, size, size); + tvb_set_child_real_data_tvbuff(tvb, b->tvb); + add_new_data_source(pinfo, b->tvb, "SPOOLSS buffer"); + + b->item = item; + b->tree = proto_item_add_subtree(item, ett_BUFFER); + } + + 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, guint8 *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); + + return offset; +} + +/* + * SYSTEM_TIME + */ + +static gint ett_SYSTEM_TIME; + +static int hf_time_year = -1; +static int hf_time_month = -1; +static int hf_time_dow = -1; +static int hf_time_day = -1; +static int hf_time_hour = -1; +static int hf_time_minute = -1; +static int hf_time_second = -1; +static int hf_time_msec = -1; + +static int +dissect_SYSTEM_TIME(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep, char *name, + gboolean add_subtree, char **data) +{ + proto_item *item = NULL; + proto_tree *subtree = tree; + guint16 year, month, day, hour, minute, second, millisecond; + char *str; + + if (add_subtree) { + item = proto_tree_add_text(tree, tvb, offset, 16, name); + subtree = proto_item_add_subtree(item, ett_SYSTEM_TIME); + } + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_year, &year); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_month, &month); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_dow, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_day, &day); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_hour, &hour); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_minute, &minute); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_second, &second); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, hf_time_msec, &millisecond); + + str = g_strdup_printf("%d/%02d/%02d %02d:%02d:%02d.%03d", + year, month, day, hour, minute, second, + millisecond); + + if (add_subtree) + proto_item_append_text(item, ": %s", str); + + if (data) + *data = str; + else + g_free(str); + + return offset; +} + +static int +dissect_SYSTEM_TIME_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + char *str; + + offset = dissect_SYSTEM_TIME( + tvb, offset, pinfo, tree, drep, NULL, FALSE, &str); + + dcv->private_data = str; + + return offset; +} + +/* + * SpoolssClosePrinter + */ + +static int SpoolssClosePrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + e_ctx_hnd policy_hnd; + char *pol_name; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, TRUE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + if (check_col(pinfo->cinfo, COL_INFO) && pol_name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + pol_name); + + return offset; +} + +static int SpoolssClosePrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + 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, + guint8 *drep _U_, guint32 type) +{ + proto_item *item; + proto_tree *subtree; + guint32 size; + + item = proto_tree_add_text(tree, tvb, offset, 0, "Data"); + + subtree = proto_item_add_subtree(item, ett_printerdata_data); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_printerdata_size, &size); + + if (size) { + + offset = dissect_ndr_uint8s( + tvb, offset, pinfo, subtree, drep, + hf_printerdata_data, size, NULL); + + switch(type) { + case DCERPC_REG_SZ: { + char *data = tvb_fake_unicode(tvb, offset - size, size/2, TRUE); + + proto_item_append_text(item, ": %s", data); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, " = %s", data); + + proto_tree_add_string_hidden( + tree, hf_printerdata_data_sz, tvb, + offset - size, size, data); + + g_free(data); + + break; + } + case DCERPC_REG_DWORD: { + guint32 data = tvb_get_letohl(tvb, offset - size); + + proto_item_append_text(item, ": 0x%08x", data); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, " = 0x%08x", + data); + + proto_tree_add_uint_hidden( + tree, hf_printerdata_data_dword, tvb, + offset - size, 4, data); + + break; + } + case DCERPC_REG_BINARY: + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, + " = <binary data>"); + break; + + default: + break; + } + } + + 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, + guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + char *value_name; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + value_name = dcv->private_data; + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_value, TRUE, value_name ? NULL : &value_name); + + dcv->private_data = value_name; + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_offered, NULL); + + return offset; +} + +static int SpoolssGetPrinterData_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 type; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_printerdata_type, &type); + + if (check_col(pinfo->cinfo, COL_INFO)) { + char *data = dcv->private_data ? dcv->private_data : "????"; + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", data); + } + + offset = dissect_printerdata_data( + tvb, offset, pinfo, tree, drep, type); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SpoolssGetPrinterDataEx + */ + +static int SpoolssGetPrinterDataEx_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_key, TRUE, &key_name); + + /* + * 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 = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_value, TRUE, &value_name); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s", + key_name, value_name); + + if (!dcv->private_data) + dcv->private_data = g_strdup_printf( + "%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 = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + return offset; +} + +static int SpoolssGetPrinterDataEx_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 size, type; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printerdata_type, &type); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_returned, &size); + + if (check_col(pinfo->cinfo, COL_INFO)) { + char *data = dcv->private_data ? dcv->private_data : "????"; + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", data); + } + + if (size) + dissect_printerdata_data(tvb, offset, pinfo, tree, drep, type); + + offset += size; + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SpoolssSetPrinterData + */ + +static int SpoolssSetPrinterData_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + char *value_name = NULL; + guint32 type; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_value, TRUE, &value_name); + + 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_printerdata_type, &type); + + offset = dissect_printerdata_data( + tvb, offset, pinfo, tree, drep, type); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_offered, NULL); + + return offset; +} + +static int SpoolssSetPrinterData_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SpoolssSetPrinterDataEx + */ + +static int hf_setprinterdataex_max_len = -1; +static int hf_setprinterdataex_real_len = -1; +static int hf_setprinterdataex_data = -1; + +static int SpoolssSetPrinterDataEx_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + char *key_name, *value_name; + guint32 max_len; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_key, TRUE, &key_name); + + CLEANUP_PUSH(g_free, key_name); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_value, TRUE, &value_name); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s", + key_name, value_name); + + CLEANUP_CALL_AND_POP; + g_free(value_name); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_printerdata_type, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_setprinterdataex_max_len, &max_len); + + offset = dissect_ndr_uint8s( + tvb, offset, pinfo, tree, drep, + hf_setprinterdataex_data, max_len, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_setprinterdataex_real_len, NULL); + + return offset; +} + +static int SpoolssSetPrinterDataEx_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + 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 tvb_fake_unicode() instead. */ + +/* XXX - "name" should be an hf_ value for an FT_STRING. */ +static int +dissect_spoolss_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint8 *drep _U_, char **data, + char *name) +{ + 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 = tvb_fake_unicode(tvb, offset, remaining, TRUE); + len = strlen(text); + + proto_tree_add_text(tree, tvb, offset, len * 2, "%s: %s", + name ? name : "String", text); + + if (data) + *data = text; + else + g_free(text); + + return offset + (len + 1) * 2; +} + +/* + * DEVMODE + */ + +/* Devicemode orientation values */ + +static const value_string devmode_orientation_vals[] = +{ + { DEVMODE_ORIENTATION_PORTRAIT, "Portrait" }, + { DEVMODE_ORIENTATION_LANDSCAPE, "Landscape" }, + { 0, NULL } +}; + +/* Paper size values. International paper sizes is a fascinating + topic. No seriously! (-: */ + +static const value_string devmode_papersize_vals[] = +{ + { DEVMODE_PAPERSIZE_LETTER, "Letter" }, + { DEVMODE_PAPERSIZE_LETTERSMALL, "Letter (small)" }, + { DEVMODE_PAPERSIZE_TABLOID, "Tabloid" }, + { DEVMODE_PAPERSIZE_LEDGER, "Ledger" }, + { DEVMODE_PAPERSIZE_LEGAL, "Legal" }, + { DEVMODE_PAPERSIZE_STATEMENT, "Statement" }, + { DEVMODE_PAPERSIZE_EXECUTIVE, "Executive" }, + { DEVMODE_PAPERSIZE_A3, "A3" }, + { DEVMODE_PAPERSIZE_A4, "A4" }, + { DEVMODE_PAPERSIZE_A4SMALL, "A4 (small)" }, + { DEVMODE_PAPERSIZE_A5, "A5" }, + { DEVMODE_PAPERSIZE_B4, "B4" }, + { DEVMODE_PAPERSIZE_B5, "B5" }, + { DEVMODE_PAPERSIZE_FOLIO, "Folio" }, + { DEVMODE_PAPERSIZE_QUARTO, "Quarto" }, + { DEVMODE_PAPERSIZE_10X14, "10x14" }, + { DEVMODE_PAPERSIZE_11X17, "11x17" }, + { DEVMODE_PAPERSIZE_NOTE, "Note" }, + { DEVMODE_PAPERSIZE_ENV9, "Envelope #9" }, + { DEVMODE_PAPERSIZE_ENV10, "Envelope #10" }, + { DEVMODE_PAPERSIZE_ENV11, "Envelope #11" }, + { DEVMODE_PAPERSIZE_ENV12, "Envelope #12" }, + { DEVMODE_PAPERSIZE_ENV14, "Envelope #14" }, + { DEVMODE_PAPERSIZE_CSHEET, "C sheet" }, + { DEVMODE_PAPERSIZE_DSHEET, "D sheet" }, + { DEVMODE_PAPERSIZE_ESHEET, "E sheet" }, + { DEVMODE_PAPERSIZE_ENVDL, "Envelope DL" }, + { DEVMODE_PAPERSIZE_ENVC5, "Envelope C5" }, + { DEVMODE_PAPERSIZE_ENVC3, "Envelope C3" }, + { DEVMODE_PAPERSIZE_ENVC4, "Envelope C4" }, + { DEVMODE_PAPERSIZE_ENVC6, "Envelope C6" }, + { DEVMODE_PAPERSIZE_ENVC65, "Envelope C65" }, + { DEVMODE_PAPERSIZE_ENVB4, "Envelope B4" }, + { DEVMODE_PAPERSIZE_ENVB5, "Envelope B5" }, + { DEVMODE_PAPERSIZE_ENVB6, "Envelope B6" }, + { DEVMODE_PAPERSIZE_ENVITALY, "Envelope (Italy)" }, + { DEVMODE_PAPERSIZE_ENVMONARCH, "Envelope (Monarch)" }, + { DEVMODE_PAPERSIZE_ENVPERSONAL, "Envelope (Personal)" }, + { DEVMODE_PAPERSIZE_FANFOLDUS, "Fanfold (US)" }, + { DEVMODE_PAPERSIZE_FANFOLDSTDGERMAN, "Fanfold (Std German)" }, + { DEVMODE_PAPERSIZE_FANFOLDLGLGERMAN, "Fanfold (Legal German)" }, + { DEVMODE_PAPERSIZE_ISOB4, "B4 (ISO)" }, + { DEVMODE_PAPERSIZE_JAPANESEPOSTCARD, "Japanese postcard" }, + { DEVMODE_PAPERSIZE_9X11, "9x11" }, + { DEVMODE_PAPERSIZE_10X11, "10x11" }, + { DEVMODE_PAPERSIZE_15X11, "15x11" }, + { DEVMODE_PAPERSIZE_ENVINVITE, "Envelope (Invite)" }, + { DEVMODE_PAPERSIZE_RESERVED48, "Reserved (48)" }, + { DEVMODE_PAPERSIZE_RESERVED49, "Reserved (49)" }, + { DEVMODE_PAPERSIZE_LETTEREXTRA, "Letter (Extra)" }, + { DEVMODE_PAPERSIZE_LEGALEXTRA, "Legal (Extra)" }, + { DEVMODE_PAPERSIZE_TABLOIDEXTRA, "Tabloid (Extra)" }, + { DEVMODE_PAPERSIZE_A4EXTRA, "A4 (Extra)" }, + { DEVMODE_PAPERSIZE_LETTERTRANS, "Letter (Transverse)" }, + { DEVMODE_PAPERSIZE_A4TRANS, "A4 (Transverse)" }, + { DEVMODE_PAPERSIZE_LETTEREXTRATRANS, "Letter (Extra, Transverse)" }, + { DEVMODE_PAPERSIZE_APLUS, "A+" }, + { DEVMODE_PAPERSIZE_BPLUS, "B+" }, + { DEVMODE_PAPERSIZE_LETTERPLUS, "Letter+" }, + { DEVMODE_PAPERSIZE_A4PLUS, "A4+" }, + { DEVMODE_PAPERSIZE_A5TRANS, "A5 (Transverse)" }, + { DEVMODE_PAPERSIZE_B5TRANS, "B5 (Transverse)" }, + { DEVMODE_PAPERSIZE_A3EXTRA, "A3 (Extra)" }, + { DEVMODE_PAPERSIZE_A5EXTRA, "A5 (Extra)" }, + { DEVMODE_PAPERSIZE_B5EXTRA, "B5 (Extra)" }, + { DEVMODE_PAPERSIZE_A2, "A2" }, + { DEVMODE_PAPERSIZE_A3TRANS, "A3 (Transverse)" }, + { DEVMODE_PAPERSIZE_A3EXTRATRANS, "A3 (Extra, Transverse" }, + { DEVMODE_PAPERSIZE_DBLJAPANESEPOSTCARD, "Double Japanese Postcard" }, + { DEVMODE_PAPERSIZE_A6, "A6" }, + { DEVMODE_PAPERSIZE_JENVKAKU2, "Japanese Envelope (Kaku #2)" }, + { DEVMODE_PAPERSIZE_JENVKAKU3, "Japanese Envelope (Kaku #3)" }, + { DEVMODE_PAPERSIZE_JENVCHOU3, "Japanese Envelope (Chou #3)" }, + { DEVMODE_PAPERSIZE_JENVCHOU4, "Japaneve Envelope (Chou #4)" }, + { DEVMODE_PAPERSIZE_LETTERROT, "Letter (Rotated)" }, + { DEVMODE_PAPERSIZE_A3ROT, "A3 (Rotated)" }, + { DEVMODE_PAPERSIZE_A4ROT, "A4 (Rotated)" }, + { DEVMODE_PAPERSIZE_A5ROT, "A5 (Rotated)" }, + { DEVMODE_PAPERSIZE_B4JISROT, "B4 (JIS, Rotated)" }, + { DEVMODE_PAPERSIZE_B5JISROT, "B5 (JIS, Rotated)"}, + { DEVMODE_PAPERSIZE_JAPANESEPOSTCARDROT, + "Japanese Postcard (Rotated)" }, + { DEVMODE_PAPERSIZE_DBLJAPANESEPOSTCARDROT82, + "Double Japanese Postcard (Rotated)" }, + { DEVMODE_PAPERSIZE_A6ROT, "A6 (Rotated)" }, + { DEVMODE_PAPERSIZE_JENVKAKU2ROT, + "Japanese Envelope (Kaku #2, Rotated)" }, + { DEVMODE_PAPERSIZE_JENVKAKU3ROT, + "Japanese Envelope (Kaku #3, Rotated)" }, + { DEVMODE_PAPERSIZE_JENVCHOU3ROT, + "Japanese Envelope (Chou #3, Rotated)" }, + { DEVMODE_PAPERSIZE_JENVCHOU4ROT, + "Japanese Envelope (Chou #4, Rotated)" }, + { DEVMODE_PAPERSIZE_B6JIS, "B6 (JIS)" }, + { DEVMODE_PAPERSIZE_B6JISROT, "B6 (JIS, Rotated)" }, + { DEVMODE_PAPERSIZE_12X11, "12x11" }, + { DEVMODE_PAPERSIZE_JENVYOU4, "Japanese Envelope (You #4)" }, + { DEVMODE_PAPERSIZE_JENVYOU4ROT, + "Japanese Envelope (You #4, Rotated" }, + { DEVMODE_PAPERSIZE_P16K, "PRC 16K" }, + { DEVMODE_PAPERSIZE_P32K, "PRC 32K" }, + { DEVMODE_PAPERSIZE_P32KBIG, "P32K (Big)" }, + { DEVMODE_PAPERSIZE_PENV1, "PRC Envelope #1" }, + { DEVMODE_PAPERSIZE_PENV2, "PRC Envelope #2" }, + { DEVMODE_PAPERSIZE_PENV3, "PRC Envelope #3" }, + { DEVMODE_PAPERSIZE_PENV4, "PRC Envelope #4" }, + { DEVMODE_PAPERSIZE_PENV5, "PRC Envelope #5" }, + { DEVMODE_PAPERSIZE_PENV6, "PRC Envelope #6" }, + { DEVMODE_PAPERSIZE_PENV7, "PRC Envelope #7" }, + { DEVMODE_PAPERSIZE_PENV8, "PRC Envelope #8" }, + { DEVMODE_PAPERSIZE_PENV9, "PRC Envelope #9" }, + { DEVMODE_PAPERSIZE_PENV10, "PRC Envelope #10" }, + { DEVMODE_PAPERSIZE_P16KROT, "PRC 16K (Rotated)" }, + { DEVMODE_PAPERSIZE_P32KROT, "PRC 32K (Rotated)" }, + { DEVMODE_PAPERSIZE_P32KBIGROT, "PRC 32K (Big, Rotated)" }, + { DEVMODE_PAPERSIZE_PENV1ROT, "PRC Envelope #1 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV2ROT, "PRC Envelope #2 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV3ROT, "PRC Envelope #3 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV4ROT, "PRC Envelope #4 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV5ROT, "PRC Envelope #5 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV6ROT, "PRC Envelope #6 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV7ROT, "PRC Envelope #7 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV8ROT, "PRC Envelope #8 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV9ROT, "PRC Envelope #9 (Rotated)" }, + { DEVMODE_PAPERSIZE_PENV10ROT, "PRC Envelope #10 (Rotated)" }, + { 0, NULL } +}; + +/* List of observed specversions */ + +static const value_string devmode_specversion_vals[] = +{ + { 0x0320, "Observed" }, + { 0x0400, "Observed" }, + { 0x0401, "Observed" }, + { 0x040d, "Observed" }, + { 0, NULL } +}; + +/* Paper sources */ + +static const value_string devmode_papersource_vals[] = +{ + { DEVMODE_PAPERSOURCE_UPPER, "Upper" }, + { DEVMODE_PAPERSOURCE_LOWER, "Lower" }, + { DEVMODE_PAPERSOURCE_MIDDLE, "Middle" }, + { DEVMODE_PAPERSOURCE_MANUAL, "Manual" }, + { DEVMODE_PAPERSOURCE_ENV, "Envelope" }, + { DEVMODE_PAPERSOURCE_ENVMANUAL, "Envelope Manual" }, + { DEVMODE_PAPERSOURCE_AUTO, "Auto" }, + { DEVMODE_PAPERSOURCE_TRACTOR, "Tractor" }, + { DEVMODE_PAPERSOURCE_SMALLFMT, "Small Format" }, + { DEVMODE_PAPERSOURCE_LARGEFMAT, "Large Format" }, + { DEVMODE_PAPERSOURCE_LARGECAP, "Large Capacity" }, + { DEVMODE_PAPERSOURCE_CASSETTE, "Cassette" }, + { DEVMODE_PAPERSOURCE_FORMSRC, "Form Source" }, + { 0, NULL } +}; + +/* Print quality */ + +static const value_string devmode_printquality_vals[] = +{ + { DEVMODE_PRINTQUALITY_HIGH, "High" }, + { DEVMODE_PRINTQUALITY_MEDIUM, "Medium" }, + { DEVMODE_PRINTQUALITY_LOW, "Low" }, + { DEVMODE_PRINTQUALITY_DRAFT, "Draft" }, + { 0, NULL } +}; + +/* Color */ + +static const value_string devmode_colour_vals[] = +{ + { DEVMODE_COLOUR_COLOUR, "Colour" }, + { DEVMODE_COLOUR_MONO, "Monochrome" }, + { 0, NULL } +}; + +/* TrueType options */ + +static const value_string devmode_ttoption_vals[] = +{ + { 0, "Not set" }, + { DEVMODE_TTOPTION_BITMAP, "Bitmap" }, + { DEVMODE_TTOPTION_DOWNLOAD, "Download" }, + { DEVMODE_TTOPTION_DOWNLOAD_OUTLINE, "Download outline" }, + { DEVMODE_TTOPTION_SUBDEV, "Substitute device fonts" }, + { 0, NULL } +}; + +/* Collate info */ + +static const value_string devmode_collate_vals[] = +{ + { DEVMODE_COLLATE_FALSE, "False" }, + { DEVMODE_COLLATE_TRUE, "True" }, + { 0, NULL } +}; + +/* Duplex info */ + +static const value_string devmode_duplex_vals[] = +{ + { DEVMODE_DUPLEX_SIMPLEX, "Simplex" }, + { DEVMODE_DUPLEX_VERT, "Vertical" }, + { DEVMODE_DUPLEX_HORIZ, "Horizontal" }, + { 0, NULL } +}; + +static const value_string devmode_displayflags_vals[] = +{ + { 0, "Colour" }, + { DEVMODE_DISPLAYFLAGS_GRAYSCALE, "Grayscale" }, + { DEVMODE_DISPLAYFLAGS_INTERLACED, "Interlaced" }, + { 0, NULL } +}; + +static const value_string devmode_icmmethod_vals[] = +{ + { DEVMODE_ICMMETHOD_NONE, "None" }, + { DEVMODE_ICMMETHOD_SYSTEM, "System" }, + { DEVMODE_ICMMETHOD_DRIVER, "Driver" }, + { DEVMODE_ICMMETHOD_DEVICE, "Device" }, + { 0, NULL } +}; + +static const value_string devmode_icmintent_vals[] = +{ + { 0, "Not set" }, + { DEVMODE_ICMINTENT_SATURATE, "Saturate" }, + { DEVMODE_ICMINTENT_CONTRAST, "Contrast" }, + { DEVMODE_ICMINTENT_COLORIMETRIC, "Colorimetric" }, + { DEVMODE_ICMINTENT_ABS_COLORIMETRIC, "Absolute colorimetric" }, + { 0, NULL } +}; + +static const value_string devmode_mediatype_vals[] = +{ + { 0, "Not set" }, + { DEVMODE_MEDIATYPE_STANDARD, "Standard" }, + { DEVMODE_MEDIATYPE_TRANSPARENCY, "Transparency" }, + { DEVMODE_MEDIATYPE_GLOSSY, "Glossy" }, + { 0, NULL } +}; + +static const value_string devmode_dithertype_vals[] = +{ + { 0, "Not set" }, + { DEVMODE_DITHERTYPE_NONE, "None" }, + { DEVMODE_DITHERTYPE_COARSE, "Coarse" }, + { DEVMODE_DITHERTYPE_LINE, "Line" }, + { DEVMODE_DITHERTYPE_LINEART, "Line art" }, + { DEVMODE_DITHERTYPE_ERRORDIFFUSION, "Error diffusion" }, + { DEVMODE_DITHERTYPE_RESERVED6, "Reserved 6" }, + { DEVMODE_DITHERTYPE_RESERVED7, "Reserved 7" }, + { DEVMODE_DITHERTYPE_GRAYSCALE, "Grayscale" }, + { 0, NULL } +}; + +static gint ett_DEVMODE_fields; + +static int +dissect_DEVMODE_fields(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_, guint32 *pdata) +{ + proto_item *item; + proto_tree *subtree; + guint32 fields; + + proto_tree_add_uint_hidden( + tree, hf_devmode, tvb, offset, 0, 1); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, + hf_devmode_fields, &fields); + + item = proto_tree_add_text(tree, tvb, offset - 4, 4, + "Fields: 0x%08x", fields); + + subtree = proto_item_add_subtree(item, ett_DEVMODE_fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_orientation, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_papersize, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_paperlength, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_paperwidth, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_scale, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_position, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_nup, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_copies, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_defaultsource, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_printquality, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_color, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_duplex, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_yresolution, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_ttoption, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_collate, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_formname, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_logpixels, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_bitsperpel, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_pelswidth, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_pelsheight, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_displayflags, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_displayfrequency, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_icmmethod, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_icmintent, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_mediatype, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_dithertype, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_panningwidth, + tvb, offset - 4, 4, fields); + + proto_tree_add_boolean( + subtree, hf_devmode_fields_panningheight, + tvb, offset - 4, 4, fields); + + if (pdata) + *pdata = fields; + + return offset; +} + +static gint ett_DEVMODE = -1; + +static int dissect_DEVMODE(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + proto_item *item; + proto_tree *subtree; + guint16 driver_extra; + gint16 print_quality; + guint32 fields; + int struct_start = offset; + + if (di->conformant_run) + return offset; + + item = proto_tree_add_text(tree, tvb, offset, 0, "Devicemode"); + subtree = proto_item_add_subtree(item, ett_DEVMODE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_devmode_size, + NULL); + + /* The device name is stored in a 32-wchar buffer */ + + dissect_spoolss_uint16uni(tvb, offset, pinfo, subtree, drep, NULL, + "Devicename"); + offset += 64; + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_spec_version, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_driver_version, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_size2, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_driver_extra_len, &driver_extra); + + offset = dissect_DEVMODE_fields( + tvb, offset, pinfo, subtree, drep, &fields); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_orientation, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_paper_size, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_paper_length, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_paper_width, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_scale, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_copies, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_default_source, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, NULL, drep, + hf_devmode_print_quality, &print_quality); + + if (print_quality < 0) + proto_tree_add_item( + subtree, hf_devmode_print_quality, tvb, + offset - 2, 2, drep[0] & 0x10); + else + proto_tree_add_text( + subtree, tvb, offset - 4, 4, + "Print Quality: %d dpi", print_quality); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_color, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_duplex, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_y_resolution, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_tt_option, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_collate, NULL); + + dissect_spoolss_uint16uni(tvb, offset, pinfo, subtree, drep, NULL, + "Form name"); + offset += 64; + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_devmode_log_pixels, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_bits_per_pel, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_pels_width, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_pels_height, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_display_flags, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_display_freq, NULL); + + /* TODO: Some of the remaining fields are optional. See + rpc_parse/parse_spoolss.c in the Samba source for details. */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_icm_method, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_icm_intent, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_media_type, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_dither_type, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_reserved1, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_reserved2, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_panning_width, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_devmode_panning_height, NULL); + + if (driver_extra) + offset = dissect_ndr_uint8s( + tvb, offset, pinfo, subtree, drep, + hf_devmode_driver_extra, driver_extra, NULL); + + proto_item_set_len(item, offset - struct_start); + + return offset; +} + +/* + * DEVMODE_CTR + */ + +static gint ett_DEVMODE_CTR = -1; + +static int dissect_DEVMODE_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 size; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Devicemode container"); + + subtree = proto_item_add_subtree(item, ett_DEVMODE_CTR); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_devmodectr_size, &size); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, subtree, drep, + dissect_DEVMODE, NDR_POINTER_UNIQUE, "Devicemode", -1); + + 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, guint8 *drep, int hf_index, + int struct_start, char **data) +{ + proto_item *item; + proto_tree *subtree; + guint32 relstr_offset, relstr_start, relstr_end; + char *text; + + /* Peek ahead to read the string. We need this for the + proto_tree_add_string() call so filtering will work. */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_offset, &relstr_offset); + + relstr_start = relstr_offset + struct_start; + + if (relstr_offset) + relstr_end = dissect_spoolss_uint16uni( + tvb, relstr_start, pinfo, NULL, drep, &text, NULL); + else /* relstr_offset == 0 is a NULL string */ + text = g_strdup(""); + + /* OK now add the proto item with the string value */ + + item = proto_tree_add_string(tree, hf_index, tvb, offset, 4, text); + subtree = proto_item_add_subtree(item, ett_RELSTR); + + dissect_ndr_uint32( + tvb, offset - 4, pinfo, subtree, drep, hf_offset, NULL); + + if (relstr_offset) + dissect_spoolss_uint16uni( + tvb, relstr_start, pinfo, subtree, drep, NULL, NULL); + + 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, guint8 *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_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, NULL); + 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; +} + +/* + * PRINTER_INFO_0 + */ + +static int hf_printer_status = -1; + +static const value_string printer_status_vals[] = +{ + { PRINTER_STATUS_OK, "OK" }, + { PRINTER_STATUS_PAUSED, "Paused" }, + { PRINTER_STATUS_ERROR, "Error" }, + { PRINTER_STATUS_PENDING_DELETION, "Pending deletion" }, + { PRINTER_STATUS_PAPER_JAM, "Paper jam" }, + { PRINTER_STATUS_PAPER_OUT, "Paper out" }, + { PRINTER_STATUS_MANUAL_FEED, "Manual feed" }, + { PRINTER_STATUS_PAPER_PROBLEM, "Paper problem" }, + { PRINTER_STATUS_OFFLINE, "Offline" }, + { PRINTER_STATUS_IO_ACTIVE, "IO active" }, + { PRINTER_STATUS_BUSY, "Busy" }, + { PRINTER_STATUS_PRINTING, "Printing" }, + { PRINTER_STATUS_OUTPUT_BIN_FULL, "Output bin full" }, + { PRINTER_STATUS_NOT_AVAILABLE, "Not available" }, + { PRINTER_STATUS_WAITING, "Waiting" }, + { PRINTER_STATUS_PROCESSING, "Processing" }, + { PRINTER_STATUS_INITIALIZING, "Initialising" }, + { PRINTER_STATUS_WARMING_UP, "Warming up" }, + { PRINTER_STATUS_TONER_LOW, "Toner low" }, + { PRINTER_STATUS_NO_TONER, "No toner" }, + { PRINTER_STATUS_PAGE_PUNT, "Page punt" }, + { PRINTER_STATUS_USER_INTERVENTION, "User intervention" }, + { PRINTER_STATUS_OUT_OF_MEMORY, "Out of memory" }, + { PRINTER_STATUS_DOOR_OPEN, "Door open" }, + { PRINTER_STATUS_SERVER_UNKNOWN, "Server unknown" }, + { PRINTER_STATUS_POWER_SAVE, "Power save" }, + { 0, NULL } +}; + +static gint ett_PRINTER_INFO_0 = -1; + +static int dissect_PRINTER_INFO_0(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printername, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_servername, + 0, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_cjobs, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_total_jobs, + NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_total_bytes, + NULL); + + offset = dissect_SYSTEM_TIME( + tvb, offset, pinfo, tree, drep, "Unknown time", TRUE, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_global_counter, + NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_total_pages, + NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_major_version, + NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_build_version, + NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk7, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk8, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk9, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_session_ctr, + NULL); + + offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, + hf_printer_unk11, NULL); + + offset = dissect_ndr_uint32( tvb, offset, pinfo, tree, drep, + hf_printer_printer_errors, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk13, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk14, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk15, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk16, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_changeid, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk18, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_status, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_unk20, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printer_c_setprinter, + NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk22, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk23, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk24, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk25, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk26, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk27, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk28, NULL); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, tree, drep, hf_printer_unk29, NULL); + + return offset; +} + +/* + * PRINTER_INFO_1 + */ + +static gint ett_PRINTER_INFO_1 = -1; + +static int dissect_PRINTER_INFO_1(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_printer_flags, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printerdesc, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printername, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printercomment, + 0, NULL); + + return offset; +} + +/* Job status */ + +static const true_false_string tfs_job_status_paused = { + "Job is paused", + "Job is not paused" +}; + +static const true_false_string tfs_job_status_error = { + "Job has an error", + "Job is OK" +}; + +static const true_false_string tfs_job_status_deleting = { + "Job is being deleted", + "Job is not being deleted" +}; + +static const true_false_string tfs_job_status_spooling = { + "Job is being spooled", + "Job is not being spooled" +}; + +static const true_false_string tfs_job_status_printing = { + "Job is being printed", + "Job is not being printed" +}; + +static const true_false_string tfs_job_status_offline = { + "Job is offline", + "Job is not offline" +}; + +static const true_false_string tfs_job_status_paperout = { + "Job is out of paper", + "Job is not out of paper" +}; + +static const true_false_string tfs_job_status_printed = { + "Job has completed printing", + "Job has not completed printing" +}; + +static const true_false_string tfs_job_status_deleted = { + "Job has been deleted", + "Job has not been deleted" +}; + +static const true_false_string tfs_job_status_blocked = { + "Job has been blocked", + "Job has not been blocked" +}; + +static const true_false_string tfs_job_status_user_intervention = { + "User intervention required", + "User intervention not required" +}; + +static gint ett_job_status = -1; + +static int +dissect_job_status(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 status; + + offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, + hf_job_status, &status); + + item = proto_tree_add_text(tree, tvb, offset - 4, 4, + "Status: 0x%08x", status); + + subtree = proto_item_add_subtree(item, ett_job_status); + + proto_tree_add_boolean( + subtree, hf_job_status_user_intervention, tvb, offset - 4, 4, + status); + + proto_tree_add_boolean( + subtree, hf_job_status_blocked, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_deleted, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_printed, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_paperout, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_offline, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_printing, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_spooling, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_deleting, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_error, tvb, offset - 4, 4, status); + + proto_tree_add_boolean( + subtree, hf_job_status_paused, tvb, offset - 4, 4, status); + + return offset; +} + +/* Printer attributes */ + +static gint ett_printer_attributes = -1; + +static int hf_printer_attributes = -1; +static int hf_printer_attributes_queued = -1; +static int hf_printer_attributes_direct = -1; +static int hf_printer_attributes_default = -1; +static int hf_printer_attributes_shared = -1; +static int hf_printer_attributes_network = -1; +static int hf_printer_attributes_hidden = -1; +static int hf_printer_attributes_local = -1; +static int hf_printer_attributes_enable_devq = -1; +static int hf_printer_attributes_keep_printed_jobs = -1; +static int hf_printer_attributes_do_complete_first = -1; +static int hf_printer_attributes_work_offline = -1; +static int hf_printer_attributes_enable_bidi = -1; +static int hf_printer_attributes_raw_only = -1; +static int hf_printer_attributes_published = -1; + +static const true_false_string tfs_printer_attributes_queued = { + "Printer starts printing after last page spooled", + "Printer starts printing while spooling" +}; + +static const true_false_string tfs_printer_attributes_direct = { + "Jobs sent directly to printer", + "Jobs are spooled to printer before printing" +}; + +static const true_false_string tfs_printer_attributes_default = { + "Printer is the default printer", + "Printer is not the default printer" +}; + +static const true_false_string tfs_printer_attributes_shared = { + "Printer is shared", + "Printer is not shared" +}; + +static const true_false_string tfs_printer_attributes_network = { + "Printer is a network printer connection", + "Printer is not a network printer connection" +}; + +static const true_false_string tfs_printer_attributes_hidden = { + "Reserved", + "Reserved" +}; + +static const true_false_string tfs_printer_attributes_local = { + "Printer is a local printer", + "Printer is not a local printer" +}; + +static const true_false_string tfs_printer_attributes_enable_devq = { + "Call DevQueryPrint", + "Do not call DevQueryPrint" +}; + +static const true_false_string tfs_printer_attributes_keep_printed_jobs = { + "Jobs are kept after they are printed", + "Jobs are deleted after printing" +}; + +static const true_false_string tfs_printer_attributes_do_complete_first = { + "Jobs that have completed spooling are scheduled before still spooling jobs", + "Jobs are scheduled in the order they start spooling" +}; + +static const true_false_string tfs_printer_attributes_work_offline = { + "The printer is currently connected", + "The printer is currently not connected" +}; + +static const true_false_string tfs_printer_attributes_enable_bidi = { + "Bidirectional communications are supported", + "Bidirectional communications are not supported" +}; + +static const true_false_string tfs_printer_attributes_raw_only = { + "Only raw data type print jobs can be spooled", + "All data type print jobs can be spooled" +}; + +static const true_false_string tfs_printer_attributes_published = { + "Printer is published in the directory", + "Printer is not published in the directory" +}; + +static int +dissect_printer_attributes(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 attributes; + + offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, + hf_printer_attributes, &attributes); + + item = proto_tree_add_text(tree, tvb, offset - 4, 4, + "Attributes: 0x%08x", attributes); + + subtree = proto_item_add_subtree(item, ett_printer_attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_published, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_raw_only, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_enable_bidi, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_work_offline, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_do_complete_first, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_keep_printed_jobs, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_enable_devq, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_local, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_hidden, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_network, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_shared, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_default, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_direct, + tvb, offset - 4, 4, attributes); + + proto_tree_add_boolean( + subtree, hf_printer_attributes_queued, + tvb, offset - 4, 4, attributes); + + return offset; +} + +/* + * PRINTER_INFO_2 + */ + +static gint ett_PRINTER_INFO_2 = -1; + +static int dissect_PRINTER_INFO_2(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + guint32 devmode_offset, secdesc_offset; + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_servername, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printername, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_sharename, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_portname, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_drivername, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printercomment, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printerlocation, + 0, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_offset, + &devmode_offset); + + dissect_DEVMODE(tvb, devmode_offset - 4, pinfo, tree, drep); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_sepfile, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printprocessor, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_datatype, + 0, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_parameters, + 0, 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. + */ + + /* TODO: I think the length is only used to fix up the hex display + pane. We should be able to use proto_item_set_len() to avoid + having to calculate the length. -tpot */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_offset, + &secdesc_offset); + + dissect_nt_sec_desc( + tvb, secdesc_offset, pinfo, tree, drep, + tvb_length_remaining(tvb, secdesc_offset), + &spoolss_printer_access_mask_info); + + offset = dissect_printer_attributes(tvb, offset, pinfo, tree, drep); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_printer_priority, + NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_printer_default_priority, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_start_time, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_end_time, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_printer_status, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_printer_jobs, + NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_printer_averageppm, NULL); + + return offset; +} + +/* + * PRINTER_INFO_3 + */ + +static gint ett_PRINTER_INFO_3 = -1; + +static int dissect_PRINTER_INFO_3(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_printer_flags, NULL); + + offset = dissect_nt_sec_desc( + tvb, offset, pinfo, tree, drep, + tvb_length_remaining(tvb, offset), + &spoolss_printer_access_mask_info); + + return offset; +} + +/* + * PRINTER_INFO_7 + */ + +static gint ett_PRINTER_INFO_7 = -1; + +static const value_string getprinter_action_vals[] = { + { DS_PUBLISH, "Publish" }, + { DS_UNPUBLISH, "Unpublish" }, + { DS_UPDATE, "Update" }, + + /* Not sure what the constant values are here */ + +/* { DS_PENDING, "Pending" }, */ +/* { DS_REPUBLISH, "Republish" }, */ + + { 0, NULL } +}; + +static int dissect_PRINTER_INFO_7(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, tree, drep, hf_printer_guid, + 0, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_printer_action, NULL); + + return offset; +} + +/* + * PRINTER_DATATYPE structure + */ + +static gint ett_PRINTER_DATATYPE = -1; + +static int dissect_PRINTER_DATATYPE(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + dcerpc_info *di = pinfo->private_data; + + if (di->conformant_run) + return offset; + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_datatype, TRUE, NULL); + + return offset; +} + +/* + * USER_LEVEL_1 structure + */ + +static gint ett_USER_LEVEL_1 = -1; + +static int hf_userlevel_size = -1; +static int hf_userlevel_client = -1; +static int hf_userlevel_user = -1; +static int hf_userlevel_build = -1; +static int hf_userlevel_major = -1; +static int hf_userlevel_minor = -1; +static int hf_userlevel_processor = -1; + +static int dissect_USER_LEVEL_1(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + guint32 level; + + /* Guy has pointed out that this dissection looks wrong. In + the ethereal output for a USER_LEVEL_1 it looks like the + info level and container pointer are transposed. I'm not + even sure this structure is a container. */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_level, &level); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_userlevel_size, NULL); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "Client", hf_userlevel_client, 0); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "User", hf_userlevel_user, 0); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_userlevel_build, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_userlevel_major, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_userlevel_minor, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_userlevel_processor, NULL); + + return offset; +} + +/* + * USER_LEVEL_CTR structure + */ + +static gint ett_USER_LEVEL_CTR = -1; + +static int dissect_USER_LEVEL_CTR(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + proto_item *item; + proto_tree *subtree; + guint32 level; + + if (di->conformant_run) + return offset; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "User level container"); + + subtree = proto_item_add_subtree(item, ett_USER_LEVEL_CTR); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_level, &level); + + switch(level) { + case 1: + offset = dissect_ndr_pointer( + tvb, offset, pinfo, subtree, drep, + dissect_USER_LEVEL_1, NDR_POINTER_UNIQUE, + "User level 1", -1); + break; + default: + proto_tree_add_text( + tree, tvb, offset, 0, + "[Info level %d not decoded]", level); + break; + } + + return offset; +} + +/* + * SpoolssOpenPrinterEx + */ + +static int SpoolssOpenPrinterEx_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + char *name; + + /* Parse packet */ + + offset = dissect_ndr_pointer_cb( + tvb, offset, pinfo, tree, drep, + dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE, + "Printer name", hf_printername, cb_wstr_postprocess, + GINT_TO_POINTER(CB_STR_COL_INFO | CB_STR_SAVE | 1)); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_PRINTER_DATATYPE, NDR_POINTER_UNIQUE, + "Printer datatype", -1); + + offset = dissect_DEVMODE_CTR(tvb, offset, pinfo, tree, drep); + + /* Luckily we can use the string stored in dcv->private_data as it + appears before the printer datatype since we are at the top + level. */ + + name = (char *)dcv->private_data; + + if (name) { + if (name[0] == '\\' && name[1] == '\\') + name += 2; + + /* Determine if we are opening a printer or a print server */ + + if (strchr(name, '\\')) + offset = dissect_nt_access_mask( + tvb, offset, pinfo, tree, drep, + hf_access_required, + &spoolss_printer_access_mask_info, NULL); + else + offset = dissect_nt_access_mask( + tvb, offset, pinfo, tree, drep, + hf_access_required, + &spoolss_printserver_access_mask_info, NULL); + } else { + + /* We can't decide what type of object being opened */ + + offset = dissect_nt_access_mask( + tvb, offset, pinfo, tree, drep, hf_access_required, + NULL, NULL); + } + + offset = dissect_USER_LEVEL_CTR(tvb, offset, pinfo, tree, drep); + + return offset; +} + +static int SpoolssOpenPrinterEx_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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; + proto_item *hnd_item; + guint32 status; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, &hnd_item, + TRUE, FALSE); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, &status); + + if (status == 0) { + + /* Associate the returned printer handle with a name */ + + if (dcv->private_data) { + char *pol_name; + + pol_name = g_strdup_printf( + "OpenPrinterEx(%s)", + (char *)dcv->private_data); + + dcerpc_smb_store_pol_name(&policy_hnd, pinfo, pol_name); + + g_free(pol_name); + g_free(dcv->private_data); + dcv->private_data = NULL; + } + + /* + * If we have a name for the handle, attach it to the item. + * + * XXX - we can't just do that above, as this may be called + * twice (see "dissect_pipe_dcerpc()", which calls the + * DCE RPC dissector twice), and in the first call we're + * not building a protocol tree (so we don't have an item + * to which to attach it) and in the second call + * "dcv->private_data" is NULL so we don't construct a + * name. + */ + + if (hnd_item != NULL) { + char *name; + + if (dcerpc_smb_fetch_pol(&policy_hnd, &name, NULL, NULL, + pinfo->fd->num) && name != NULL) + proto_item_append_text(hnd_item, ": %s", name); + } + } + + 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, guint8 *drep, guint16 type, + guint16 *data) +{ + guint16 field; + char *str; + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, NULL, drep, + hf_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, guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 count, i; + guint16 type; + + if (di->conformant_run) + return offset; + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_option_data_count, &count); + + type = GPOINTER_TO_INT(dcv->private_data); + + 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 char *notify_plural(int count) +{ + if (count == 1) + return "notification"; + + return "notifies"; +} + +static gint ett_NOTIFY_OPTION = -1; + +static int +dissect_NOTIFY_OPTION(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + proto_item *item; + proto_tree *subtree; + guint16 type; + guint32 count; + + 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_notify_option_type, &type); + + proto_item_append_text( + item, ": %s", val_to_str(type, printer_notify_types, + "Unknown (%d)")); + + offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep, + hf_notify_option_reserved1, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_notify_option_reserved2, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_notify_option_reserved3, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_notify_option_count, &count); + + proto_item_append_text( + item, ", %d %s", count, notify_plural(count)); + + dcv->private_data = GINT_TO_POINTER((int)type); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, subtree, drep, + dissect_NOTIFY_OPTION_DATA, NDR_POINTER_UNIQUE, + "Notify Option Data", -1); + + return offset; +} + +static int +dissect_NOTIFY_OPTIONS_ARRAY(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 flags; + + offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, + hf_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_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, + guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + + if (di->conformant_run) + return offset; + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_notify_options_version, NULL); + + offset = dissect_notify_options_flags(tvb, offset, pinfo, tree, drep); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_notify_options_count, NULL); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_NOTIFY_OPTIONS_ARRAY, NDR_POINTER_UNIQUE, + "Notify Options Array", -1); + + return offset; +} + +/* + * SpoolssRFFPCNEX + */ + +static gint ett_rffpcnex_flags = -1; + +static int hf_rffpcnex_flags = -1; +static int hf_rffpcnex_options = -1; + +static int hf_rffpcnex_flags_add_printer = -1; +static int hf_rffpcnex_flags_set_printer = -1; +static int hf_rffpcnex_flags_delete_printer = -1; +static int hf_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 hf_rffpcnex_flags_add_job = -1; +static int hf_rffpcnex_flags_set_job = -1; +static int hf_rffpcnex_flags_delete_job = -1; +static int hf_rffpcnex_flags_write_job = -1; + +static const true_false_string tfs_rffpcnex_flags_add_job = { + "Notify on add job", + "Don't notify on add job" +}; + +static const true_false_string tfs_rffpcnex_flags_set_job = { + "Notify on set job", + "Don't notify on set job" +}; + +static const true_false_string tfs_rffpcnex_flags_delete_job = { + "Notify on delete job", + "Don't notify on delete job" +}; + +static const true_false_string tfs_rffpcnex_flags_write_job = { + "Notify on writejob", + "Don't notify on write job" +}; + +static int hf_rffpcnex_flags_add_form = -1; +static int hf_rffpcnex_flags_set_form = -1; +static int hf_rffpcnex_flags_delete_form = -1; + +static const true_false_string tfs_rffpcnex_flags_add_form = { + "Notify on add form", + "Don't notify on add form" +}; + +static const true_false_string tfs_rffpcnex_flags_set_form = { + "Notify on set form", + "Don't notify on set form" +}; + +static const true_false_string tfs_rffpcnex_flags_delete_form = { + "Notify on delete form", + "Don't notify on delete form" +}; + +static int hf_rffpcnex_flags_add_port = -1; +static int hf_rffpcnex_flags_configure_port = -1; +static int hf_rffpcnex_flags_delete_port = -1; + +static const true_false_string tfs_rffpcnex_flags_add_port = { + "Notify on add port", + "Don't notify on add port" +}; + +static const true_false_string tfs_rffpcnex_flags_configure_port = { + "Notify on configure port", + "Don't notify on configure port" +}; + +static const true_false_string tfs_rffpcnex_flags_delete_port = { + "Notify on delete port", + "Don't notify on delete port" +}; + +static int hf_rffpcnex_flags_add_print_processor = -1; +static int hf_rffpcnex_flags_delete_print_processor = -1; + +static const true_false_string tfs_rffpcnex_flags_add_print_processor = { + "Notify on add driver", + "Don't notify on add driver" +}; + +static const true_false_string tfs_rffpcnex_flags_delete_print_processor = { + "Notify on add driver", + "Don't notify on add driver" +}; + +static int hf_rffpcnex_flags_add_driver = -1; +static int hf_rffpcnex_flags_set_driver = -1; +static int hf_rffpcnex_flags_delete_driver = -1; + +static const true_false_string tfs_rffpcnex_flags_add_driver = { + "Notify on add driver", + "Don't notify on add driver" +}; + +static const true_false_string tfs_rffpcnex_flags_set_driver = { + "Notify on set driver", + "Don't notify on set driver" +}; + +static const true_false_string tfs_rffpcnex_flags_delete_driver = { + "Notify on delete driver", + "Don't notify on delete driver" +}; + +static int hf_rffpcnex_flags_timeout = -1; + +static const true_false_string tfs_rffpcnex_flags_timeout = { + "Notify on timeout", + "Don't notify on timeout" +}; + +static int SpoolssRFFPCNEX_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + guint32 flags; + proto_item *flags_item; + proto_tree *flags_subtree; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, + hf_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_rffpcnex_flags_timeout, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_delete_driver, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_set_driver, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_add_driver, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, + hf_rffpcnex_flags_delete_print_processor, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_add_print_processor, + tvb, offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_delete_port, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_configure_port, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_add_port, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_delete_form, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_set_form, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_add_form, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_write_job, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_delete_job, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_set_job, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_add_job, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, + hf_rffpcnex_flags_failed_printer_connection, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_delete_printer, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_set_printer, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_rffpcnex_flags_add_printer, tvb, + offset - 4, 4, flags); + + if (flags & SPOOLSS_PRINTER_CHANGE_PRINTER) + proto_item_append_text(flags_item, ", change printer"); + + if (flags & SPOOLSS_PRINTER_CHANGE_JOB) + proto_item_append_text(flags_item, ", change job"); + + if (flags & SPOOLSS_PRINTER_CHANGE_FORM) + proto_item_append_text(flags_item, ", change form"); + + if (flags & SPOOLSS_PRINTER_CHANGE_PORT) + proto_item_append_text(flags_item, ", change port"); + + if (flags & SPOOLSS_PRINTER_CHANGE_PRINTER_DRIVER) + proto_item_append_text(flags_item, ", change printer driver"); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_rffpcnex_options, NULL); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "Server", hf_servername, 0); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printerlocal, NULL); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_NOTIFY_OPTIONS_ARRAY_CTR, NDR_POINTER_UNIQUE, + "Notify Options Container", -1); + + return offset; +} + +static int SpoolssRFFPCNEX_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SpoolssReplyOpenPrinter + */ + +static int SpoolssReplyOpenPrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 printerlocal; + char *name = NULL; + + /* Parse packet */ + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_servername, TRUE, &name); + + if (check_col(pinfo->cinfo, COL_INFO) && name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", name); + + if (!dcv->private_data && name) + dcv->private_data = name; + else + g_free(name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printerlocal, + &printerlocal); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_printerdata_type, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_replyopenprinter_unk0, + NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_replyopenprinter_unk1, + NULL); + + return offset; +} + +static int SpoolssReplyOpenPrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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; + proto_item *hnd_item; + guint32 status; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, &hnd_item, + TRUE, FALSE); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, &status); + + if (status == 0) { + + /* Associate the returned printer handle with a name */ + + if (dcv->private_data) { + char *pol_name; + + pol_name = g_strdup_printf( + "OpenPrinter(%s)", + (char *)dcv->private_data); + + dcerpc_smb_store_pol_name(&policy_hnd, pinfo, pol_name); + + g_free(pol_name); + g_free(dcv->private_data); + dcv->private_data = NULL; + } + + /* + * If we have a name for the handle, attach it to the item. + * + * XXX - we can't just do that above, as this may be called + * twice (see "dissect_pipe_dcerpc()", which calls the + * DCE RPC dissector twice), and in the first call we're + * not building a protocol tree (so we don't have an item + * to which to attach it) and in the second call + * "dcv->private_data" is NULL so we don't construct a + * name. + */ + + if (hnd_item != NULL) { + char *name; + + if (dcerpc_smb_fetch_pol(&policy_hnd, &name, NULL, NULL, + pinfo->fd->num) && name != NULL) + proto_item_append_text(hnd_item, ": %s", name); + } + } + + return offset; +} + +/* + * SpoolssGetPrinter + */ + + + +static int SpoolssGetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_level, &level); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); + + dcv->private_data = (void *)level; + + offset = dissect_spoolss_buffer( + tvb, offset, pinfo, tree, drep, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_offered, NULL); + + return offset; +} + +static gint ett_PRINTER_INFO = -1; + +static int SpoolssGetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + BUFFER buffer; + gint16 level = (guint32)dcv->private_data; + proto_item *item; + proto_tree *subtree = NULL; + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); + + /* Parse packet */ + + offset = dissect_spoolss_buffer( + tvb, offset, pinfo, tree, drep, &buffer); + + if (buffer.tvb) { + switch(level) { + case 0: + case 1: + case 2: + case 3: + case 7: + item = proto_tree_add_text( + buffer.tree, buffer.tvb, 0, -1, + "Print info level %d", level); + + subtree = proto_item_add_subtree( + item, ett_PRINTER_INFO); + break; + } + + switch(level) { + case 0: + dissect_PRINTER_INFO_0( + buffer.tvb, 0, pinfo, subtree, drep); + break; + case 1: + dissect_PRINTER_INFO_1( + buffer.tvb, 0, pinfo, subtree, drep); + break; + case 2: + dissect_PRINTER_INFO_2( + buffer.tvb, 0, pinfo, subtree, drep); + break; + case 3: + dissect_PRINTER_INFO_3( + buffer.tvb, 0, pinfo, subtree, drep); + break; + case 7: + dissect_PRINTER_INFO_7( + buffer.tvb, 0, pinfo, subtree, drep); + break; + default: + proto_tree_add_text( + buffer.tree, buffer.tvb, 0, -1, + "[Unknown printer info level %d]", level); + break; + } + } + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SEC_DESC_BUF + */ + +static gint ett_SEC_DESC_BUF = -1; + +static int hf_secdescbuf_maxlen = -1; +static int hf_secdescbuf_undoc = -1; +static int hf_secdescbuf_len = -1; + +static int +dissect_SEC_DESC_BUF(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 len; + + /* XXX: I think this is really a array of bytes which can be + dissected using dissect_ndr_cvstring(). The dissected data + can be passed to dissect_nt_sec_desc(). The problem is that + dissect_nt_cvstring() passes back a char * where it really + should pass back a tvb. */ + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Security descriptor buffer"); + + subtree = proto_item_add_subtree(item, ett_SEC_DESC_BUF); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_secdescbuf_maxlen, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_secdescbuf_undoc, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_secdescbuf_len, &len); + + dissect_nt_sec_desc( + tvb, offset, pinfo, subtree, drep, len, + &spoolss_printer_access_mask_info); + + offset += len; + + return offset; +} + +/* + * SPOOL_PRINTER_INFO_LEVEL + */ + +static gint ett_SPOOL_PRINTER_INFO_LEVEL = -1; + +/* spool printer info */ + +static int hf_spool_printer_info_devmode_ptr = -1; +static int hf_spool_printer_info_secdesc_ptr = -1; + +static int +dissect_SPOOL_PRINTER_INFO(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + 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 = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_level, &level); + + switch(level) { + case 3: { + guint32 devmode_ptr, secdesc_ptr; + + /* I can't seem to get this working with the correct + dissect_ndr_pointer() function so let's cheat and + dissect the pointers by hand. )-: */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_spool_printer_info_devmode_ptr, + &devmode_ptr); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_spool_printer_info_secdesc_ptr, + &secdesc_ptr); + + if (devmode_ptr) + offset = dissect_DEVMODE_CTR( + tvb, offset, pinfo, subtree, drep); + + if (secdesc_ptr) + offset = dissect_SEC_DESC_BUF( + tvb, offset, pinfo, subtree, drep); + + break; + } + case 2: + default: + proto_tree_add_text( + subtree, tvb, offset, 0, + "[Unknown spool printer info level %d]", level); + break; + } + + return offset; +} + +/* + * SpoolssSetPrinter + */ + +static int hf_setprinter_cmd = -1; + +static const value_string setprinter_cmd_vals[] = { + { SPOOLSS_PRINTER_CONTROL_UNPAUSE, "Unpause" }, + { SPOOLSS_PRINTER_CONTROL_PAUSE, "Pause" }, + { SPOOLSS_PRINTER_CONTROL_RESUME, "Resume" }, + { SPOOLSS_PRINTER_CONTROL_PURGE, "Purge" }, + { SPOOLSS_PRINTER_CONTROL_SET_STATUS, "Set status" }, + { 0, NULL } +}; + +static int SpoolssSetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + guint32 level; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_level, &level); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); + + offset = dissect_SPOOL_PRINTER_INFO( + tvb, offset, pinfo, tree, drep); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_setprinter_cmd, NULL); + + return offset; +} + +static int SpoolssSetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * FORM_REL + */ + +static const value_string form_type_vals[] = +{ + { SPOOLSS_FORM_USER, "User" }, + { SPOOLSS_FORM_BUILTIN, "Builtin" }, + { SPOOLSS_FORM_PRINTER, "Printer" }, + { 0, NULL } +}; + +static gint ett_FORM_REL = -1; + +static int dissect_FORM_REL(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep, int struct_start) +{ + proto_item *item; + proto_tree *subtree; + guint32 flags; + int item_start = offset; + char *name = NULL; + + item = proto_tree_add_text(tree, tvb, offset, 0, "Form"); + + subtree = proto_item_add_subtree(item, ett_FORM_REL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_form_flags, &flags); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_form_name, + struct_start, &name); + + if (name) { + proto_item_append_text(item, ": %s", name); + g_free(name); + } + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_width, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_height, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_left_margin, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_top_margin, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_horiz_len, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_vert_len, NULL); + + proto_item_set_len(item, offset - item_start); + + return offset; +} + +/* + * SpoolssEnumForms + */ + +static int SpoolssEnumForms_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_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_offered, NULL); + + return offset; +} + +static int SpoolssEnumForms_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + BUFFER buffer; + guint32 level = (guint32)dcv->private_data, i, count; + int buffer_offset; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_spoolss_buffer( + tvb, offset, pinfo, tree, drep, &buffer); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_enumforms_num, &count); + + /* 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. */ + + buffer_offset = 0; + + for (i = 0; i < count; i++) { + int struct_start = buffer_offset; + + buffer_offset = dissect_FORM_REL( + buffer.tvb, buffer_offset, pinfo, buffer.tree, drep, + struct_start); + } + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SpoolssDeletePrinter + */ + +static int SpoolssDeletePrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + return offset; +} + +static int SpoolssDeletePrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +static int SpoolssAddPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *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; + proto_item *hnd_item; + guint32 status; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, &hnd_item, + TRUE, FALSE); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_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_name( + &policy_hnd, pinfo, dcv->private_data); + + g_free(dcv->private_data); + dcv->private_data = NULL; + } + + /* + * If we have a name for the handle, attach it to the item. + * + * XXX - we can't just do that above, as this may be called + * twice (see "dissect_pipe_dcerpc()", which calls the + * DCE RPC dissector twice), and in the first call we're + * not building a protocol tree (so we don't have an item + * to which to attach it) and in the second call + * "dcv->private_data" is NULL so we don't construct a + * name. + */ + + if (hnd_item != NULL) { + char *name; + + if (dcerpc_smb_fetch_pol(&policy_hnd, &name, NULL, NULL, + pinfo->fd->num) && name != NULL) + proto_item_append_text(hnd_item, ": %s", name); + } + } + + return offset; +} + +/* + * SpoolssEnumPrinterData + */ + +static int hf_enumprinterdata_enumindex = -1; +static int hf_enumprinterdata_value_offered = -1; +static int hf_enumprinterdata_data_offered = -1; +static int hf_enumprinterdata_value_len = -1; +static int hf_enumprinterdata_value_needed = -1; +static int hf_enumprinterdata_data_needed = -1; + +static int SpoolssEnumPrinterData_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + guint32 ndx; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_enumprinterdata_enumindex, &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_enumprinterdata_value_offered, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_enumprinterdata_data_offered, NULL); + + return offset; +} + +static int SpoolssEnumPrinterData_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + guint32 value_len, type; + char *value; + proto_item *value_item; + proto_tree *value_subtree; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* 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 = dissect_ndr_uint32( + tvb, offset, pinfo, value_subtree, drep, + hf_enumprinterdata_value_len, &value_len); + + if (value_len) { + dissect_spoolss_uint16uni( + tvb, offset, pinfo, value_subtree, drep, &value, + "Value name"); + + offset += value_len * 2; + + if (check_col(pinfo->cinfo, COL_INFO) && value && value[0]) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value); + + proto_item_append_text(value_item, ": %s", value); + + proto_tree_add_string_hidden( + tree, hf_printerdata_value, tvb, offset, 0, value); + + g_free(value); + } + + proto_item_set_len(value_item, value_len * 2 + 4); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, value_subtree, drep, + hf_enumprinterdata_value_needed, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_printerdata_type, &type); + + offset = dissect_printerdata_data( + tvb, offset, pinfo, tree, drep, type); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_enumprinterdata_data_needed, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SpoolssEnumPrinters + */ + +static gint ett_enumprinters_flags = -1; + +static int hf_enumprinters_flags = -1; +static int hf_enumprinters_flags_local = -1; +static int hf_enumprinters_flags_name = -1; +static int hf_enumprinters_flags_shared = -1; +static int hf_enumprinters_flags_default = -1; +static int hf_enumprinters_flags_connections = -1; +static int hf_enumprinters_flags_network = -1; +static int hf_enumprinters_flags_remote = -1; + +static int SpoolssEnumPrinters_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + guint32 level, flags; + proto_tree *flags_subtree; + proto_item *flags_item; + + /* Parse packet */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_enumprinters_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_enumprinters_flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_network, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_shared, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_remote, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_name, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_connections, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_local, tvb, + offset - 4, 4, flags); + + proto_tree_add_boolean( + flags_subtree, hf_enumprinters_flags_default, tvb, + offset - 4, 4, flags); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, + NDR_POINTER_UNIQUE, "Server name", hf_servername, 0); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_level, &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_offered, NULL); + + return offset; +} + +static int SpoolssEnumPrinters_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + guint32 num_drivers; + + /* Parse packet */ + + offset = dissect_spoolss_buffer( + tvb, offset, pinfo, tree, drep, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_returned, + &num_drivers); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * AddPrinterDriver + */ +#if 0 +static int SpoolssAddPrinterDriver_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + + /* Parse packet */ + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "Server", hf_servername, 0); + + offset = dissect_spoolss_DRIVER_INFO_CTR( + tvb, offset, pinfo, tree, drep); + + return offset; +} +#endif +static int SpoolssAddPrinterDriver_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep _U_) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * FORM_1 + */ + +static gint ett_FORM_1 = -1; + +static int dissect_FORM_1(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 flags; + + item = proto_tree_add_text(tree, tvb, offset, 0, "Form level 1"); + + subtree = proto_item_add_subtree(item, ett_FORM_1); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, subtree, drep, NDR_POINTER_UNIQUE, + "Name", hf_form_name, 0); + + /* Eek - we need to know whether this pointer was NULL or not. + Currently there is not any way to do this. */ + + if (tvb_length_remaining(tvb, offset) == 0) + goto done; + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_form_flags, &flags); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_unknown, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_width, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_height, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_left_margin, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_top_margin, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_horiz_len, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_form_vert_len, NULL); + + done: + return offset; +} + +/* + * FORM_CTR + */ + +static gint ett_FORM_CTR = -1; + +static int dissect_FORM_CTR(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 level; + + item = proto_tree_add_text(tree, tvb, offset, 0, "Form container"); + + subtree = proto_item_add_subtree(item, ett_FORM_CTR); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_form_level, &level); + + switch(level) { + case 1: + offset = dissect_FORM_1(tvb, offset, pinfo, subtree, drep); + break; + + default: + proto_tree_add_text( + subtree, tvb, offset, 0, + "[Unknown form info level %d]", level); + break; + } + + return offset; +} + +/* + * AddForm + */ + +static int SpoolssAddForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_form_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 = dissect_FORM_CTR(tvb, offset, pinfo, tree, drep); + + return offset; +} + +static int SpoolssAddForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * DeleteForm + */ + +static int SpoolssDeleteForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + char *name = NULL; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, + sizeof(guint16), hf_form_name, TRUE, &name); + + if (check_col(pinfo->cinfo, COL_INFO) && name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", name); + + g_free(name); + + return offset; +} + +static int SpoolssDeleteForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SetForm + */ + +static int SpoolssSetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + char *name = NULL; + guint32 level; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, + sizeof(guint16), hf_form_name, TRUE, &name); + + if (check_col(pinfo->cinfo, COL_INFO) && name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", name); + + g_free(name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_form_level, &level); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); + + offset = dissect_FORM_CTR(tvb, offset, pinfo, tree, drep); + + return offset; +} + +static int SpoolssSetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * GetForm + */ + +static int SpoolssGetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level; + char *name; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, + sizeof(guint16), hf_form_name, TRUE, &name); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_form_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_offered, NULL); + + return offset; +} + +static int SpoolssGetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + BUFFER buffer; + guint32 level = (guint32)dcv->private_data; + + proto_tree_add_uint_hidden( + tree, hf_form, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_spoolss_buffer( + tvb, offset, pinfo, tree, drep, &buffer); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level); + + if (buffer.tvb) { + int buffer_offset = 0; + + switch(level) { + case 1: { + int struct_start = buffer_offset; + + buffer_offset = dissect_FORM_REL( + buffer.tvb, buffer_offset, pinfo, tree, drep, + struct_start); + break; + } + + default: + proto_tree_add_text( + buffer.tree, buffer.tvb, buffer_offset, -1, + "[Unknown form info level %d]", level); + break; + } + } + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + 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, guint8 *drep _U_) +{ + int len = tvb_length(tvb); + + proto_tree_add_text(tree, tvb, offset, 0, + "[Unimplemented dissector: SPOOLSS]"); + + offset = dissect_doserror( + tvb, len - 4, pinfo, tree, drep, hf_rc, NULL); + + 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, guint8 *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 level 1"); + + subtree = proto_item_add_subtree(item, ett_JOB_INFO_1); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_job_id, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_printername, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_servername, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_username, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_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_datatype, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_textstatus, + struct_start, NULL); + + offset = dissect_job_status(tvb, offset, pinfo, subtree, drep); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_job_priority, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_job_position, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_job_totalpages, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_job_pagesprinted, NULL); + + offset = dissect_SYSTEM_TIME( + tvb, offset, pinfo, subtree, drep, "Job Submission Time", + TRUE, NULL); + + proto_item_set_len(item, offset - struct_start); + + return offset; +} + +/* + * JOB_INFO_2 + */ + +static gint ett_JOB_INFO_2; + +static int +dissect_spoolss_JOB_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + int struct_start = offset; + char *document_name; + guint32 devmode_offset, secdesc_offset; + + item = proto_tree_add_text(tree, tvb, offset, 0, "Job info level 2"); + + subtree = proto_item_add_subtree(item, ett_JOB_INFO_2); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_job_id, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_printername, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_machinename, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_username, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_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_notifyname, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_datatype, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_printprocessor, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_parameters, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_drivername, + struct_start, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_offset, + &devmode_offset); + + dissect_DEVMODE( + tvb, devmode_offset - 4 + struct_start, pinfo, subtree, drep); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_textstatus, + struct_start, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_offset, + &secdesc_offset); + + dissect_nt_sec_desc( + tvb, secdesc_offset, pinfo, subtree, drep, + tvb_length_remaining(tvb, secdesc_offset), + &spoolss_job_access_mask_info); + + offset = dissect_job_status(tvb, offset, pinfo, subtree, drep); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_job_priority, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_job_position, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_start_time, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_end_time, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_job_totalpages, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_job_size, NULL); + + offset = dissect_SYSTEM_TIME( + tvb, offset, pinfo, subtree, drep, "Job Submission Time", + TRUE, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, hf_elapsed_time, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_job_pagesprinted, NULL); + + proto_item_set_len(item, offset - struct_start); + + return offset; +} + +/* + * EnumJobs + */ + +static int hf_enumjobs_firstjob = -1; +static int hf_enumjobs_numjobs = -1; + +static int SpoolssEnumJobs_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, + hf_hnd, NULL, NULL, FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_enumjobs_firstjob, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_enumjobs_numjobs, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_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_offered, NULL); + + return offset; +} + +static int SpoolssEnumJobs_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *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; + + /* Parse packet */ + + offset = dissect_spoolss_buffer( + tvb, offset, pinfo, tree, drep, &buffer); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_enumjobs_numjobs, + &num_jobs); + + buffer_offset = 0; + + for (i = 0; i < num_jobs; i++) { + switch(level) { + case 1: + buffer_offset = dissect_spoolss_JOB_INFO_1( + buffer.tvb, buffer_offset, pinfo, + buffer.tree, drep); + break; + case 2: + buffer_offset = dissect_spoolss_JOB_INFO_2( + buffer.tvb, buffer_offset, pinfo, + buffer.tree, drep); + break; + default: + proto_tree_add_text( + buffer.tree, buffer.tvb, 0, -1, + "[Unknown job info level %d]", level); + break; + } + + } + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * SetJob + */ + +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 hf_setjob_cmd = -1; + +static int SpoolssSetJob_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + guint32 jobid, cmd; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_job_id, &jobid); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_level, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_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 (%d)"), + jobid); + + return offset; +} + +static int SpoolssSetJob_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * GetJob + */ + +static int SpoolssGetJob_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level, jobid; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_job_id, &jobid); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_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_offered, NULL); + + return offset; +} + +static int SpoolssGetJob_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *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; + + /* Parse packet */ + + offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, + &buffer); + + if (buffer.tvb) { + int buffer_offset = 0; + + switch(level) { + case 1: + buffer_offset = dissect_spoolss_JOB_INFO_1( + buffer.tvb, buffer_offset, pinfo, + buffer.tree, drep); + break; + case 2: + default: + proto_tree_add_text( + buffer.tree, buffer.tvb, buffer_offset, -1, + "[Unknown job info level %d]", level); + break; + } + } + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * StartPagePrinter + */ + +static int SpoolssStartPagePrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + e_ctx_hnd policy_hnd; + char *pol_name; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, FALSE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + if (check_col(pinfo->cinfo, COL_INFO) && pol_name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + pol_name); + + return offset; +} + +static int SpoolssStartPagePrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * EndPagePrinter + */ + +static int SpoolssEndPagePrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + e_ctx_hnd policy_hnd; + char *pol_name; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, FALSE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + if (check_col(pinfo->cinfo, COL_INFO) && pol_name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + pol_name); + + return offset; +} + +static int SpoolssEndPagePrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + 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, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Document info level 1"); + + subtree = proto_item_add_subtree(item, ett_DOC_INFO_1); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, subtree, drep, NDR_POINTER_UNIQUE, + "Document name", hf_documentname, 0); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, subtree, drep, NDR_POINTER_UNIQUE, + "Output file", hf_outputfile, 0); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, subtree, drep, NDR_POINTER_UNIQUE, + "Data type", hf_datatype, 0); + + return offset; +} + +static int +dissect_spoolss_doc_info_data(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + guint32 info_level = 1; /* XXX */ + + if (di->conformant_run) + return offset; + + switch(info_level) { + case 1: + offset = dissect_spoolss_doc_info_1( + tvb, offset, pinfo, tree, drep); + break; + default: + proto_tree_add_text( + tree, tvb, offset, 0, + "[Unknown documentinfo level %d]", info_level); + 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, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 level; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Document info"); + + subtree = proto_item_add_subtree(item, ett_DOC_INFO); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_level, &level); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, subtree, drep, + dissect_spoolss_doc_info_data, + NDR_POINTER_UNIQUE, "Document info", -1); + + 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, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Document info container"); + + subtree = proto_item_add_subtree(item, ett_DOC_INFO_CTR); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_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, + guint8 *drep) +{ + e_ctx_hnd policy_hnd; + char *pol_name; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, FALSE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + 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); + + return offset; +} + +static int SpoolssStartDocPrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_job_id, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * EndDocPrinter + */ + +static int SpoolssEndDocPrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + e_ctx_hnd policy_hnd; + char *pol_name; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, FALSE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + if (check_col(pinfo->cinfo, COL_INFO) && pol_name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + pol_name); + + + return offset; +} + +static int SpoolssEndDocPrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * WritePrinter + */ + +static gint ett_writeprinter_buffer = -1; + +static int hf_writeprinter_numwritten = -1; + +static int SpoolssWritePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + e_ctx_hnd policy_hnd; + char *pol_name; + guint32 size; + proto_item *item; + proto_tree *subtree; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, FALSE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + 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_buffer_size, &size); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %d bytes", 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_buffer_data, size, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_buffer_size, NULL); + + proto_item_set_len(item, size + 4); + + return offset; +} + +static int SpoolssWritePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + guint32 size; + + /* Parse packet */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_writeprinter_numwritten, + &size); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, ", %d bytes written", size); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * DeletePrinterData + */ + +static int SpoolssDeletePrinterData_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + char *value_name; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_value, TRUE, &value_name); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name); + + g_free(value_name); + + return offset; +} + +static int SpoolssDeletePrinterData_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + 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, + guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + int struct_start = offset; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Driver info level 1"); + + subtree = proto_item_add_subtree(item, ett_DRIVER_INFO_1); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_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, + guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + int struct_start = offset; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Driver info level 3"); + + subtree = proto_item_add_subtree(item, ett_DRIVER_INFO_3); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep, + hf_driverinfo_cversion, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_drivername, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_architecture, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_driverpath, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_datafile, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_configfile, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_helpfile, + struct_start, NULL); + + offset = dissect_spoolss_relstrarray( + tvb, offset, pinfo, subtree, drep, hf_dependentfiles, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_monitorname, + struct_start, NULL); + + offset = dissect_spoolss_relstr( + tvb, offset, pinfo, subtree, drep, hf_defaultdatatype, + struct_start, NULL); + + return offset; +} + +/* + * EnumPrinterDrivers + */ + +static int SpoolssEnumPrinterDrivers_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + guint32 level; + + /* Parse packet */ + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "Name", hf_servername, 0); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "Environment", hf_servername, 0); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_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_offered, NULL); + + return offset; +} + +static int SpoolssEnumPrinterDrivers_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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; + + /* Parse packet */ + + offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, + &buffer); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_returned, + &num_drivers); + + buffer_offset = 0; + + for (i = 0; i < num_drivers; i++) { + switch(level) { + case 1: + buffer_offset = dissect_DRIVER_INFO_1( + buffer.tvb, buffer_offset, pinfo, + buffer.tree, drep); + break; + case 3: + buffer_offset = dissect_DRIVER_INFO_3( + buffer.tvb, buffer_offset, pinfo, + buffer.tree, drep); + break; + default: + proto_tree_add_text( + buffer.tree, buffer.tvb, buffer_offset, -1, + "[Unknown driver info level %d]", level); + goto done; + } + } + +done: + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * GetPrinterDriver2 + */ + +static int SpoolssGetPrinterDriver2_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, &policy_hnd, NULL, + FALSE, FALSE); + + dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL, + pinfo->fd->num); + + if (check_col(pinfo->cinfo, COL_INFO) && pol_name) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + pol_name); + + offset = dissect_ndr_str_pointer_item( + tvb, offset, pinfo, tree, drep, NDR_POINTER_UNIQUE, + "Architecture", hf_architecture, 0); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_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_offered, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_clientmajorversion, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_clientminorversion, NULL); + + return offset; +} + +static int SpoolssGetPrinterDriver2_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *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; + + /* Parse packet */ + + offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, + &buffer); + + if (buffer.tvb) { + switch(level) { + case 1: + dissect_DRIVER_INFO_1( + buffer.tvb, 0, pinfo, buffer.tree, drep); + break; + case 3: + dissect_DRIVER_INFO_3( + buffer.tvb, 0, pinfo, buffer.tree, drep); + break; + default: + proto_tree_add_text( + buffer.tree, buffer.tvb, 0, -1, + "[Unknown driver info level %d]", level); + break; + } + } + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_servermajorversion, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_serverminorversion, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +static int +dissect_notify_info_data_buffer(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + guint32 len; + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_buffer_len, &len); + + offset = dissect_ndr_uint16s( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_buffer_data, len); + + return offset; +} + +static void cb_notify_str_postprocess(packet_info *pinfo _U_, + proto_tree *tree _U_, + proto_item *item, tvbuff_t *tvb, + int start_offset, int end_offset, + void *callback_args) +{ + gint levels, hf_index = GPOINTER_TO_INT(callback_args); + guint32 len; + char *s; + + /* Align start_offset on 4-byte boundary. */ + + if (start_offset % 4) + start_offset += 4 - (start_offset % 4); + + /* Get string length */ + + len = tvb_get_letohl(tvb, start_offset); + + s = tvb_fake_unicode( + tvb, start_offset + 4, (end_offset - start_offset - 4) / 2, TRUE); + + /* Append string to upper-level proto_items */ + + levels = 2; + + if (levels > 0 && item && s && s[0]) { + proto_item_append_text(item, ": %s", s); + item = item->parent; + levels--; + if (levels > 0) { + proto_item_append_text(item, ": %s", s); + item = item->parent; + levels--; + while (levels > 0) { + proto_item_append_text(item, " %s", s); + item = item->parent; + levels--; + } + } + } + + /* Add hidden field so filter brings up any notify data */ + + if (hf_index != -1) + proto_tree_add_string_hidden( + tree, hf_index, tvb, start_offset, len, s); + + g_free(s); +} + +/* Return the hf_index for a printer notify field. This is used to + add a hidden string to the display so that filtering will bring + up relevant notify data. */ + +static int +printer_notify_hf_index(int field) +{ + int result = -1; + + switch(field) { + case PRINTER_NOTIFY_SERVER_NAME: + result = hf_servername; + break; + case PRINTER_NOTIFY_PRINTER_NAME: + result = hf_printername; + break; + case PRINTER_NOTIFY_SHARE_NAME: + result = hf_sharename; + break; + case PRINTER_NOTIFY_PORT_NAME: + result = hf_portname; + break; + case PRINTER_NOTIFY_DRIVER_NAME: + result = hf_drivername; + break; + case PRINTER_NOTIFY_COMMENT: + result = hf_printercomment; + break; + case PRINTER_NOTIFY_LOCATION: + result = hf_printerlocation; + break; + case PRINTER_NOTIFY_SEPFILE: + result = hf_sepfile; + break; + case PRINTER_NOTIFY_PRINT_PROCESSOR: + result = hf_printprocessor; + break; + case PRINTER_NOTIFY_PARAMETERS: + result = hf_parameters; + break; + case PRINTER_NOTIFY_DATATYPE: + result = hf_parameters; + break; + } + + return result; +} + +static int +job_notify_hf_index(int field) +{ + int result = -1; + + switch(field) { + case JOB_NOTIFY_PRINTER_NAME: + result = hf_printername; + break; + case JOB_NOTIFY_MACHINE_NAME: + result = hf_machinename; + break; + case JOB_NOTIFY_PORT_NAME: + result = hf_portname; + break; + case JOB_NOTIFY_USER_NAME: + result = hf_username; + break; + case JOB_NOTIFY_NOTIFY_NAME: + result = hf_notifyname; + break; + case JOB_NOTIFY_DATATYPE: + result = hf_datatype; + break; + case JOB_NOTIFY_PRINT_PROCESSOR: + result = hf_printprocessor; + break; + case JOB_NOTIFY_DRIVER_NAME: + result = hf_drivername; + break; + case JOB_NOTIFY_DOCUMENT: + result = hf_documentname; + break; + case JOB_NOTIFY_PRIORITY: + result = hf_job_priority; + break; + case JOB_NOTIFY_POSITION: + result = hf_job_position; + break; + case JOB_NOTIFY_TOTAL_PAGES: + result = hf_job_totalpages; + break; + case JOB_NOTIFY_PAGES_PRINTED: + result = hf_job_pagesprinted; + break; + case JOB_NOTIFY_TOTAL_BYTES: + result = hf_job_totalbytes; + break; + case JOB_NOTIFY_BYTES_PRINTED: + result = hf_job_bytesprinted; + break; + } + + return result; +} + +static int +dissect_NOTIFY_INFO_DATA_printer(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, proto_item *item, + guint8 *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_notify_info_data_bufsize, &value1); + + offset = dissect_ndr_pointer_cb( + tvb, offset, pinfo, tree, drep, + dissect_notify_info_data_buffer, + NDR_POINTER_UNIQUE, "String", + hf_notify_info_data_buffer, + cb_notify_str_postprocess, + GINT_TO_POINTER(printer_notify_hf_index(field))); + + break; + + case PRINTER_NOTIFY_ATTRIBUTES: + + /* Value 1 is the printer attributes */ + + offset = dissect_printer_attributes( + tvb, offset, pinfo, tree, drep); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_notify_info_data_value2, NULL); + + break; + + case PRINTER_NOTIFY_STATUS: { + guint32 status; + + /* Value 1 is the printer status */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_printer_status, &status); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_notify_info_data_value2, NULL); + + proto_item_append_text( + item, ": %s", + val_to_str(status, printer_status_vals, "Unknown")); + + break; + } + + /* Unknown notify data */ + + case PRINTER_NOTIFY_SECURITY_DESCRIPTOR: /* Secdesc */ + case PRINTER_NOTIFY_DEVMODE: /* Devicemode */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_bufsize, &value1); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_notify_info_data_buffer, + NDR_POINTER_UNIQUE, "Buffer", + hf_notify_info_data_buffer); + + break; + + default: + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_value1, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_value2, NULL); + + break; + } + return offset; +} + +static void notify_job_time_cb(packet_info *pinfo, proto_tree *tree _U_, + proto_item *item, tvbuff_t *tvb _U_, + int start_offset _U_, int end_offset _U_, + void *callback_args _U_) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + char *str = (char *)dcv->private_data; + + /* Append job string stored in dcv->private_data by + dissect_SYSTEM_TIME_ptr() in the current item as well + as the parent. */ + + proto_item_append_text(item, ": %s", str); + + if (item) + proto_item_append_text(item->parent, ": %s", str); +} + +static int +dissect_NOTIFY_INFO_DATA_job(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, proto_item *item, guint8 *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_notify_info_data_bufsize, &value1); + + offset = dissect_ndr_pointer_cb( + tvb, offset, pinfo, tree, drep, + dissect_notify_info_data_buffer, + NDR_POINTER_UNIQUE, "String", + hf_notify_info_data_buffer, + cb_notify_str_postprocess, + GINT_TO_POINTER(job_notify_hf_index(field))); + + break; + + case JOB_NOTIFY_STATUS: + offset = dissect_job_status( + tvb, offset, pinfo, tree, drep); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_notify_info_data_value2, NULL); + + break; + + case JOB_NOTIFY_SUBMITTED: + + /* SYSTEM_TIME */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_buffer_len, NULL); + + offset = dissect_ndr_pointer_cb( + tvb, offset, pinfo, tree, drep, + dissect_SYSTEM_TIME_ptr, NDR_POINTER_UNIQUE, + "Time submitted", -1, notify_job_time_cb, NULL); + + break; + + case JOB_NOTIFY_PRIORITY: + case JOB_NOTIFY_POSITION: + case JOB_NOTIFY_TOTAL_PAGES: + case JOB_NOTIFY_PAGES_PRINTED: + case JOB_NOTIFY_TOTAL_BYTES: + case JOB_NOTIFY_BYTES_PRINTED: { + guint32 value; + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_value1, &value); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_value2, NULL); + + proto_item_append_text(item, ": %d", value); + + proto_tree_add_uint_hidden( + tree, job_notify_hf_index(field), tvb, + offset, 4, value); + + break; + } + + /* Unknown notify data */ + + case JOB_NOTIFY_DEVMODE: + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_bufsize, &value1); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_notify_info_data_buffer, + NDR_POINTER_UNIQUE, "Buffer", + hf_notify_info_data_buffer); + + break; + + default: + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_notify_info_data_value1, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_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, guint8 *drep) +{ + proto_item *item; + proto_tree *subtree; + guint32 count; + guint16 type, field; + char *field_string; + + item = proto_tree_add_text(tree, tvb, offset, 0, "%s", ""); + + subtree = proto_item_add_subtree(item, ett_NOTIFY_INFO_DATA); + + offset = dissect_ndr_uint16( + tvb, offset, pinfo, subtree, drep, + hf_notify_info_data_type, &type); + + offset = dissect_notify_field( + tvb, offset, pinfo, subtree, drep, type, &field); + + switch(type) { + case PRINTER_NOTIFY_TYPE: + field_string = val_to_str( + field, printer_notify_option_data_vals, + "Unknown (%d)"); + break; + case JOB_NOTIFY_TYPE: + field_string = val_to_str( + field, job_notify_option_data_vals, + "Unknown (%d)"); + break; + default: + field_string = "Unknown field"; + break; + } + + proto_item_append_text( + item, "%s, %s", + val_to_str(type, printer_notify_types, "Unknown (%d)"), + field_string); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_notify_info_data_count, &count); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_notify_info_data_id, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_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, item, drep, field); + break; + case JOB_NOTIFY_TYPE: + offset = dissect_NOTIFY_INFO_DATA_job( + tvb, offset, pinfo, subtree, item, 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, guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + guint32 count; + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_notify_info_version, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_notify_info_flags, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_notify_info_count, &count); + + if (!di->conformant_run && check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, ", %d %s", count, + notify_plural(count)); + + 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, guint8 *drep) +{ + guint32 changeid; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_rrpcn_changelow, &changeid); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, ", changeid %d", changeid); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_NOTIFY_OPTIONS_ARRAY_CTR, NDR_POINTER_UNIQUE, + "Notify Options Array Container", -1); + + return offset; +} + +static int SpoolssRFNPCNEX_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_NOTIFY_INFO, NDR_POINTER_UNIQUE, + "Notify Info", -1); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * RRPCN + */ + +static int SpoolssRRPCN_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + guint32 changeid; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_rrpcn_changelow, &changeid); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr( + pinfo->cinfo, COL_INFO, ", changeid %d", changeid); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_rrpcn_changehigh, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_rrpcn_unk0, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_rrpcn_unk1, NULL); + + offset = dissect_ndr_pointer( + tvb, offset, pinfo, tree, drep, + dissect_NOTIFY_INFO, NDR_POINTER_UNIQUE, + "Notify Info", -1); + + /* Notify info */ + + return offset; +} + +static int SpoolssRRPCN_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_rrpcn_unk0, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * ReplyClosePrinter + */ + +static int SpoolssReplyClosePrinter_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, TRUE); + + return offset; +} + +static int SpoolssReplyClosePrinter_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * FCPN + */ + +static int SpoolssFCPN_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + return offset; +} + +static int SpoolssFCPN_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +/* + * RouterReplyPrinter + */ + +static int hf_routerreplyprinter_condition = -1; +static int hf_routerreplyprinter_unknown1 = -1; +static int hf_routerreplyprinter_changeid = -1; + +static int SpoolssRouterReplyPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_routerreplyprinter_condition, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_routerreplyprinter_unknown1, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_routerreplyprinter_changeid, NULL); + + return offset; +} + +static int SpoolssRouterReplyPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +static int hf_keybuffer_size = -1; +static int hf_keybuffer_data = -1; + +static int +dissect_spoolss_keybuffer(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = pinfo->private_data; + guint32 size; + int end_offset; + + if (di->conformant_run) + return offset; + + /* Dissect size and data */ + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_keybuffer_size, &size); + + end_offset = offset + (size*2); + if (end_offset < offset) { + /* + * Overflow - make the end offset one past the end of + * the packet data, so we throw an exception (as the + * size is almost certainly too big). + */ + end_offset = tvb_reported_length_remaining(tvb, offset) + 1; + } + + while (offset < end_offset) + offset = dissect_spoolss_uint16uni( + tvb, offset, pinfo, tree, drep, NULL, "Key"); + + return offset; +} + + +static int SpoolssEnumPrinterKey_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + char *key_name; + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_key, TRUE, &key_name); + + if (check_col(pinfo->cinfo, COL_INFO)) { + char *kn = key_name; + + if (!key_name[0]) + kn = "\"\""; + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", kn); + } + + g_free(key_name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + return offset; +} + +static int SpoolssEnumPrinterKey_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + /* Parse packet */ + + offset = dissect_spoolss_keybuffer(tvb, offset, pinfo, tree, drep); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +static int hf_enumprinterdataex_num_values = -1; +static int hf_enumprinterdataex_name_offset = -1; +static int hf_enumprinterdataex_name_len = -1; +static int hf_enumprinterdataex_name = -1; +static int hf_enumprinterdataex_val_type = -1; +static int hf_enumprinterdataex_val_offset = -1; +static int hf_enumprinterdataex_val_len = -1; +static int hf_enumprinterdataex_val_dword_low = -1; +static int hf_enumprinterdataex_val_dword_high = -1; +static int hf_enumprinterdataex_val_sz = -1; + +static int SpoolssEnumPrinterDataEx_q(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + char *key_name; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_nt_policy_hnd( + tvb, offset, pinfo, tree, drep, hf_hnd, NULL, NULL, + FALSE, FALSE); + + offset = dissect_ndr_cvstring( + tvb, offset, pinfo, tree, drep, sizeof(guint16), + hf_printerdata_key, TRUE, &key_name); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", key_name); + + g_free(key_name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_offered, NULL); + + return offset; +} + +static gint ett_printer_enumdataex_value = -1; + +static int +dissect_spoolss_printer_enum_values(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + guint32 start_offset = offset; + guint32 name_offset, name_len, val_offset, val_len, val_type; + char *name; + proto_item *item; + proto_tree *subtree; + + /* Get offset of value name */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_enumprinterdataex_name_offset, &name_offset); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, NULL, drep, + hf_enumprinterdataex_name_len, &name_len); + + dissect_spoolss_uint16uni( + tvb, start_offset + name_offset, pinfo, NULL, drep, + &name, "Name"); + + item = proto_tree_add_text(tree, tvb, offset, 0, "Name: "); + + subtree = proto_item_add_subtree(item, ett_printer_enumdataex_value); + + proto_item_append_text(item, name); + + proto_tree_add_text( + subtree, tvb, offset - 8, 4, "Name offset: %d", name_offset); + + proto_tree_add_text( + subtree, tvb, offset - 4, 4, "Name len: %d", name_len); + + proto_tree_add_text( + subtree, tvb, start_offset + name_offset, (strlen(name) + 1) * 2, + "Name: %s", name); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, hf_printerdata_type, + &val_type); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_enumprinterdataex_val_offset, &val_offset); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, subtree, drep, + hf_enumprinterdataex_val_len, &val_len); + + if (val_len == 0) { + proto_tree_add_text(subtree, tvb, start_offset + val_offset, 4, + "Value: (null)"); + goto done; + } + + switch(val_type) { + case DCERPC_REG_DWORD: { + guint32 value; + guint16 low, high; + int offset2 = start_offset + val_offset; + + /* Needs to be broken into two 16-byte ints because it may + not be aligned. */ + + offset2 = dissect_ndr_uint16( + tvb, offset2, pinfo, subtree, drep, + hf_enumprinterdataex_val_dword_low, &low); + + offset2 = dissect_ndr_uint16( + tvb, offset2, pinfo, subtree, drep, + hf_enumprinterdataex_val_dword_high, &high); + + value = (high << 16) | low; + + proto_tree_add_text(subtree, tvb, start_offset + val_offset, 4, + "Value: %d", value); + + proto_item_append_text(item, ", Value: %d", value); + + break; + } + case DCERPC_REG_SZ: { + char *value; + + dissect_spoolss_uint16uni( + tvb, start_offset + val_offset, pinfo, subtree, drep, + &value, "Value"); + + proto_item_append_text(item, ", Value: %s", value); + + g_free(value); + + break; + } + case DCERPC_REG_BINARY: + + /* FIXME: nicer way to display this */ + + proto_tree_add_text( + subtree, tvb, start_offset + val_offset, val_len, + "Value: <binary data>"); + break; + + case DCERPC_REG_MULTI_SZ: + + /* FIXME: implement REG_MULTI_SZ support */ + + proto_tree_add_text( + subtree, tvb, start_offset + val_offset, val_len, + "Value: <REG_MULTI_SZ not implemented>"); + break; + + default: + proto_tree_add_text( + subtree, tvb, start_offset + val_offset, val_len, + "%s: unknown type %d", name, val_type); + } + + done: + g_free(name); + + return offset; +} + +static gint ett_PRINTER_DATA_CTR; + +static int SpoolssEnumPrinterDataEx_r(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, + guint8 *drep) +{ + guint32 size, num_values; + + proto_tree_add_uint_hidden( + tree, hf_printerdata, tvb, offset, 0, 1); + + /* Parse packet */ + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, + hf_buffer_size, &size); + + dissect_ndr_uint32( + tvb, offset + size + 4, pinfo, NULL, drep, hf_returned, + &num_values); + + if (size) { + proto_item *item; + proto_tree *subtree; + int offset2 = offset; + guint32 i; + + item = proto_tree_add_text( + tree, tvb, offset, 0, "Printer data"); + + subtree = proto_item_add_subtree(item, ett_PRINTER_DATA_CTR); + + for (i=0; i < num_values; i++) + offset2 = dissect_spoolss_printer_enum_values( + tvb, offset2, pinfo, subtree, drep); + } + + offset += size; + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_needed, NULL); + + offset = dissect_ndr_uint32( + tvb, offset, pinfo, tree, drep, hf_returned, NULL); + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + return offset; +} + +#if 0 + +/* Templates for new subdissectors */ + +/* + * FOO + */ + +static int SpoolssFoo_q(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + + /* Parse packet */ + + return offset; +} + +static int SpoolssFoo_r(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep) +{ + dcerpc_info *di = (dcerpc_info *)pinfo->private_data; + dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; + + /* Parse packet */ + + offset = dissect_doserror( + tvb, offset, pinfo, tree, drep, hf_rc, NULL); + + 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", + SpoolssRouterReplyPrinter_q, SpoolssRouterReplyPrinter_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", + SpoolssEnumPrinterDataEx_q, SpoolssEnumPrinterDataEx_r }, + { SPOOLSS_ENUMPRINTERKEY, "EnumPrinterKey", + SpoolssEnumPrinterKey_q, SpoolssEnumPrinterKey_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[] = { + + /* GetPrinterDriver2 */ + + { &hf_clientmajorversion, + { "Client major version", "spoolss.clientmajorversion", FT_UINT32, BASE_DEC, + NULL, 0x0, "Client printer driver major version", HFILL }}, + { &hf_clientminorversion, + { "Client minor version", "spoolss.clientminorversion", FT_UINT32, BASE_DEC, + NULL, 0x0, "Client printer driver minor version", HFILL }}, + { &hf_servermajorversion, + { "Server major version", "spoolss.servermajorversion", FT_UINT32, BASE_DEC, + NULL, 0x0, "Server printer driver major version", HFILL }}, + { &hf_serverminorversion, + { "Server minor version", "spoolss.serverminorversion", FT_UINT32, BASE_DEC, + NULL, 0x0, "Server printer driver minor version", HFILL }}, + { &hf_driverpath, + { "Driver path", "spoolss.driverpath", FT_STRING, BASE_NONE, + NULL, 0, "Driver path", HFILL }}, + { &hf_datafile, + { "Data file", "spoolss.datafile", FT_STRING, BASE_NONE, + NULL, 0, "Data file", HFILL }}, + { &hf_configfile, + { "Config file", "spoolss.configfile", FT_STRING, BASE_NONE, + NULL, 0, "Printer name", HFILL }}, + { &hf_helpfile, + { "Help file", "spoolss.helpfile", FT_STRING, BASE_NONE, + NULL, 0, "Help file", HFILL }}, + { &hf_monitorname, + { "Monitor name", "spoolss.monitorname", FT_STRING, BASE_NONE, + NULL, 0, "Monitor name", HFILL }}, + { &hf_defaultdatatype, + { "Default data type", "spoolss.defaultdatatype", FT_STRING, BASE_NONE, + NULL, 0, "Default data type", HFILL }}, + { &hf_driverinfo_cversion, + { "Driver version", "spoolss.driverversion", FT_UINT32, BASE_DEC, + VALS(driverinfo_cversion_vals), 0, "Printer name", HFILL }}, + { &hf_dependentfiles, + { "Dependent files", "spoolss.dependentfiles", FT_STRING, BASE_NONE, + NULL, 0, "Dependent files", HFILL }}, + + { &hf_printer_status, + { "Status", "spoolss.printer_status", FT_UINT32, BASE_DEC, + VALS(printer_status_vals), 0, "Status", HFILL }}, + + /* Setprinter RPC */ + + { &hf_setprinter_cmd, + { "Command", "spoolss.setprinter_cmd", FT_UINT32, BASE_DEC, + VALS(setprinter_cmd_vals), 0, "Command", HFILL }}, + + /* Enumprinters */ + + { &hf_enumprinters_flags, + { "Flags", "spoolss.enumprinters.flags", + FT_UINT32, BASE_HEX, NULL, 0, "Flags", HFILL }}, + + { &hf_enumprinters_flags_local, + { "Enum local", "spoolss.enumprinters.flags.enum_local", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_LOCAL, "Enum local", HFILL }}, + + { &hf_enumprinters_flags_name, + { "Enum name", "spoolss.enumprinters.flags.enum_name", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_NAME, "Enum name", HFILL }}, + + { &hf_enumprinters_flags_shared, + { "Enum shared", "spoolss.enumprinters.flags.enum_shared", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_SHARED, "Enum shared", HFILL }}, + + { &hf_enumprinters_flags_default, + { "Enum default", "spoolss.enumprinters.flags.enum_default", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_DEFAULT, "Enum default", HFILL }}, + + { &hf_enumprinters_flags_connections, + { "Enum connections", "spoolss.enumprinters.flags.enum_connections", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_CONNECTIONS, "Enum connections", HFILL }}, + + { &hf_enumprinters_flags_network, + { "Enum network", "spoolss.enumprinters.flags.enum_network", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_NETWORK, "Enum network", HFILL }}, + + { &hf_enumprinters_flags_remote, + { "Enum remote", "spoolss.enumprinters.flags.enum_remote", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ENUM_REMOTE, "Enum remote", HFILL }}, + + /* GetPrinter */ + + { &hf_start_time, + { "Start time", "spoolss.start_time", + FT_UINT32, BASE_DEC, NULL, 0, "Start time", HFILL }}, + + { &hf_end_time, + { "End time", "spoolss.end_time", + FT_UINT32, BASE_DEC, NULL, 0, "End time", HFILL }}, + + { &hf_elapsed_time, + { "Elapsed time", "spoolss.elapsed_time", + FT_UINT32, BASE_DEC, NULL, 0, "Elapsed time", HFILL }}, + + /* + * New hf index values + */ + + { &hf_opnum, + { "Operation", "spoolss.opnum", FT_UINT16, BASE_DEC, + NULL, 0x0, "Operation", HFILL }}, + + { &hf_hnd, + { "Context handle", "spoolss.hnd", FT_BYTES, BASE_NONE, + NULL, 0x0, "SPOOLSS policy handle", HFILL }}, + + { &hf_rc, + { "Return code", "spoolss.rc", FT_UINT32, BASE_HEX, + VALS(DOS_errors), 0x0, "SPOOLSS return code", HFILL }}, + + { &hf_offered, + { "Offered", "spoolss.offered", FT_UINT32, BASE_DEC, + NULL, 0x0, "Size of buffer offered in this request", + HFILL }}, + + { &hf_needed, + { "Needed", "spoolss.needed", FT_UINT32, BASE_DEC, + NULL, 0x0, "Size of buffer required for request", HFILL }}, + + { &hf_returned, + { "Returned", "spoolss.returned", FT_UINT32, BASE_DEC, + NULL, 0x0, "Number of items returned", HFILL }}, + + { &hf_buffer_size, + { "Buffer size", "spoolss.buffer.size", FT_UINT32, BASE_DEC, + NULL, 0x0, "Size of buffer", HFILL }}, + + { &hf_buffer_data, + { "Buffer data", "spoolss.buffer.data", FT_BYTES, BASE_HEX, + NULL, 0x0, "Contents of buffer", HFILL }}, + + { &hf_offset, + { "Offset", "spoolss.offset", FT_UINT32, BASE_DEC, + NULL, 0x0, "Offset of data", HFILL }}, + + { &hf_level, + { "Info level", "spoolss.enumjobs.level", FT_UINT32, + BASE_DEC, NULL, 0x0, "Info level", HFILL }}, + + + { &hf_printername, + { "Printer name", "spoolss.printername", FT_STRING, + BASE_NONE, NULL, 0, "Printer name", HFILL }}, + + { &hf_machinename, + { "Machine name", "spoolss.machinename", FT_STRING, + BASE_NONE, NULL, 0, "Machine name", HFILL }}, + + { &hf_notifyname, + { "Notify name", "spoolss.notifyname", FT_STRING, + BASE_NONE, NULL, 0, "Notify name", HFILL }}, + + { &hf_printerdesc, + { "Printer description", "spoolss.printerdesc", FT_STRING, + BASE_NONE, NULL, 0, "Printer description", HFILL }}, + + { &hf_printercomment, + { "Printer comment", "spoolss.printercomment", FT_STRING, + BASE_NONE, NULL, 0, "Printer comment", HFILL }}, + + { &hf_servername, + { "Server name", "spoolss.servername", FT_STRING, BASE_NONE, + NULL, 0, "Server name", HFILL }}, + + { &hf_sharename, + { "Share name", "spoolss.sharename", FT_STRING, BASE_NONE, + NULL, 0, "Share name", HFILL }}, + + { &hf_portname, + { "Port name", "spoolss.portname", FT_STRING, BASE_NONE, + NULL, 0, "Port name", HFILL }}, + + { &hf_printerlocation, + { "Printer location", "spoolss.printerlocation", FT_STRING, + BASE_NONE, NULL, 0, "Printer location", HFILL }}, + + { &hf_architecture, + { "Architecture name", "spoolss.architecture", FT_STRING, + BASE_NONE, NULL, 0, "Architecture name", HFILL }}, + + { &hf_drivername, + { "Driver name", "spoolss.drivername", FT_STRING, BASE_NONE, + NULL, 0, "Driver name", HFILL }}, + + { &hf_username, + { "User name", "spoolss.username", FT_STRING, BASE_NONE, + NULL, 0, "User name", HFILL }}, + + { &hf_documentname, + { "Document name", "spoolss.document", FT_STRING, BASE_NONE, + NULL, 0, "Document name", HFILL }}, + + { &hf_outputfile, + { "Output file", "spoolss.outputfile", FT_STRING, BASE_NONE, + NULL, 0, "Output File", HFILL }}, + + { &hf_datatype, + { "Datatype", "spoolss.Datatype", FT_STRING, BASE_NONE, + NULL, 0, "Datatype", HFILL }}, + + { &hf_textstatus, + { "Text status", "spoolss.textstatus", FT_STRING, BASE_NONE, + NULL, 0, "Text status", HFILL }}, + + { &hf_sepfile, + { "Separator file", "spoolss.setpfile", FT_STRING, BASE_NONE, + NULL, 0, "Separator file", HFILL }}, + + { &hf_parameters, + { "Parameters", "spoolss.parameters", FT_STRING, BASE_NONE, + NULL, 0, "Parameters", HFILL }}, + + { &hf_printprocessor, + { "Print processor", "spoolss.printprocessor", FT_STRING, + BASE_NONE, NULL, 0, "Print processor", HFILL }}, + + /* Printer data */ + + { &hf_printerdata, + { "Data", "spoolss.printerdata", FT_UINT32, + BASE_HEX, NULL, 0, "Data", HFILL }}, + + { &hf_printerdata_key, + { "Key", "spoolss.printerdata.key", FT_STRING, + BASE_NONE, NULL, 0, "Printer data key", HFILL }}, + + { &hf_printerdata_value, + { "Value", "spoolss.printerdata.value", + FT_STRING, BASE_NONE, NULL, 0, "Printer data value", + HFILL }}, + + { &hf_printerdata_type, + { "Type", "spoolss.printerdata.type", + FT_UINT32, BASE_DEC, VALS(reg_datatypes), 0, + "Printer data type", HFILL }}, + + { &hf_printerdata_size, + { "Size", "spoolss.printerdata.size", + FT_UINT32, BASE_DEC, NULL, 0, "Printer data size", + HFILL }}, + + { &hf_printerdata_data, + { "Data", "spoolss.printerdata.data", FT_BYTES, BASE_HEX, + NULL, 0x0, "Printer data", HFILL }}, + + { &hf_printerdata_data_dword, + { "DWORD data", "spoolss.printerdata.data.dword", + FT_UINT32, BASE_HEX, NULL, 0, "DWORD data", HFILL }}, + + { &hf_printerdata_data_sz, + { "String data", "spoolss.printerdata.data.sz", + FT_STRING, BASE_NONE, NULL, 0, "String data", + HFILL }}, + + /* Devicemode */ + + { &hf_devmodectr_size, + { "Devicemode ctr size", "spoolss.devicemodectr.size", + FT_UINT32, BASE_DEC, NULL, 0, "Devicemode ctr size", + HFILL }}, + + { &hf_devmode, + { "Devicemode", "spoolss.devmode", FT_UINT32, + BASE_HEX, NULL, 0, "Devicemode", HFILL }}, + + { &hf_devmode_size, + { "Size", "spoolss.devmode.size", + FT_UINT32, BASE_DEC, NULL, 0, "Size", HFILL }}, + + { &hf_devmode_spec_version, + { "Spec version", "spoolss.devmode.spec_version", + FT_UINT16, BASE_DEC, VALS(devmode_specversion_vals), + 0, "Spec version", HFILL }}, + + { &hf_devmode_driver_version, + { "Driver version", "spoolss.devmode.driver_version", + FT_UINT16, BASE_DEC, NULL, 0, "Driver version", HFILL }}, + + { &hf_devmode_size2, + { "Size2", "spoolss.devmode.size2", + FT_UINT16, BASE_DEC, NULL, 0, "Size2", HFILL }}, + + { &hf_devmode_fields, + { "Fields", "spoolss.devmode.fields", + FT_UINT32, BASE_HEX, NULL, 0, "Fields", HFILL }}, + + { &hf_devmode_orientation, + { "Orientation", "spoolss.devmode.orientation", + FT_UINT16, BASE_DEC, VALS(devmode_orientation_vals), + 0, "Orientation", HFILL }}, + + { &hf_devmode_paper_size, + { "Paper size", "spoolss.devmode.paper_size", + FT_UINT16, BASE_DEC, VALS(devmode_papersize_vals), + 0, "Paper size", HFILL }}, + + { &hf_devmode_paper_width, + { "Paper width", "spoolss.devmode.paper_width", + FT_UINT16, BASE_DEC, NULL, 0, "Paper width", HFILL }}, + + { &hf_devmode_paper_length, + { "Paper length", "spoolss.devmode.paper_length", + FT_UINT16, BASE_DEC, NULL, 0, "Paper length", HFILL }}, + + { &hf_devmode_scale, + { "Scale", "spoolss.devmode.scale", + FT_UINT16, BASE_DEC, NULL, 0, "Scale", HFILL }}, + + { &hf_devmode_copies, + { "Copies", "spoolss.devmode.copies", + FT_UINT16, BASE_DEC, NULL, 0, "Copies", HFILL }}, + + { &hf_devmode_default_source, + { "Default source", "spoolss.devmode.default_source", + FT_UINT16, BASE_DEC, VALS(devmode_papersource_vals), + 0, "Default source", HFILL }}, + + { &hf_devmode_print_quality, + { "Print quality", "spoolss.devmode.print_quality", + FT_UINT16, BASE_DEC, VALS(devmode_printquality_vals), + 0, "Print quality", HFILL }}, + + { &hf_devmode_color, + { "Color", "spoolss.devmode.color", + FT_UINT16, BASE_DEC, VALS(devmode_colour_vals), 0, + "Color", HFILL }}, + + { &hf_devmode_duplex, + { "Duplex", "spoolss.devmode.duplex", + FT_UINT16, BASE_DEC, VALS(devmode_duplex_vals), 0, + "Duplex", HFILL }}, + + { &hf_devmode_y_resolution, + { "Y resolution", "spoolss.devmode.y_resolution", + FT_UINT16, BASE_DEC, NULL, 0, "Y resolution", HFILL }}, + + { &hf_devmode_tt_option, + { "TT option", "spoolss.devmode.tt_option", + FT_UINT16, BASE_DEC, VALS(devmode_ttoption_vals), 0, + "TT option", HFILL }}, + + { &hf_devmode_collate, + { "Collate", "spoolss.devmode.collate", + FT_UINT16, BASE_DEC, VALS(devmode_collate_vals), 0, + "Collate", HFILL }}, + + { &hf_devmode_log_pixels, + { "Log pixels", "spoolss.devmode.log_pixels", + FT_UINT16, BASE_DEC, NULL, 0, "Log pixels", HFILL }}, + + { &hf_devmode_bits_per_pel, + { "Bits per pel", "spoolss.devmode.bits_per_pel", + FT_UINT32, BASE_DEC, NULL, 0, "Bits per pel", HFILL }}, + + { &hf_devmode_pels_width, + { "Pels width", "spoolss.devmode.pels_width", + FT_UINT32, BASE_DEC, NULL, 0, "Pels width", HFILL }}, + + { &hf_devmode_pels_height, + { "Pels height", "spoolss.devmode.pels_height", + FT_UINT32, BASE_DEC, NULL, 0, "Pels height", HFILL }}, + + { &hf_devmode_display_flags, + { "Display flags", "spoolss.devmode.display_flags", + FT_UINT32, BASE_DEC, VALS(devmode_displayflags_vals), 0, + "Display flags", HFILL }}, + + { &hf_devmode_display_freq, + { "Display frequency", "spoolss.devmode.display_freq", + FT_UINT32, BASE_DEC, NULL, 0, "Display frequency", + HFILL }}, + + { &hf_devmode_icm_method, + { "ICM method", "spoolss.devmode.icm_method", + FT_UINT32, BASE_DEC, VALS(devmode_icmmethod_vals), 0, + "ICM method", HFILL }}, + + { &hf_devmode_icm_intent, + { "ICM intent", "spoolss.devmode.icm_intent", + FT_UINT32, BASE_DEC, VALS(devmode_icmintent_vals), 0, + "ICM intent", HFILL }}, + + { &hf_devmode_media_type, + { "Media type", "spoolss.devmode.media_type", + FT_UINT32, BASE_DEC, VALS(devmode_mediatype_vals), 0, + "Media type", HFILL }}, + + { &hf_devmode_dither_type, + { "Dither type", "spoolss.devmode.dither_type", + FT_UINT32, BASE_DEC, VALS(devmode_dithertype_vals), 0, + "Dither type", HFILL }}, + + { &hf_devmode_reserved1, + { "Reserved1", "spoolss.devmode.reserved1", + FT_UINT32, BASE_DEC, NULL, 0, "Reserved1", HFILL }}, + + { &hf_devmode_reserved2, + { "Reserved2", "spoolss.devmode.reserved2", + FT_UINT32, BASE_DEC, NULL, 0, "Reserved2", HFILL }}, + + { &hf_devmode_panning_width, + { "Panning width", "spoolss.devmode.panning_width", + FT_UINT32, BASE_DEC, NULL, 0, "Panning width", HFILL }}, + + { &hf_devmode_panning_height, + { "Panning height", "spoolss.devmode.panning_height", + FT_UINT32, BASE_DEC, NULL, 0, "Panning height", HFILL }}, + + { &hf_devmode_driver_extra_len, + { "Driver extra length", + "spoolss.devmode.driver_extra_len", + FT_UINT32, BASE_DEC, NULL, 0, "Driver extra length", + HFILL }}, + + { &hf_devmode_driver_extra, + { "Driver extra", "spoolss.devmode.driver_extra", + FT_BYTES, BASE_NONE, NULL, 0, "Driver extra", HFILL }}, + + /* Devicemode fields */ + + { &hf_devmode_fields_orientation, + { "Orientation", "spoolss.devmode.fields.orientation", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_ORIENTATION, "Orientation", HFILL }}, + + { &hf_devmode_fields_papersize, + { "Paper size", "spoolss.devmode.fields.paper_size", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PAPERSIZE, "Paper size", HFILL }}, + + { &hf_devmode_fields_paperlength, + { "Paper length", "spoolss.devmode.fields.paper_length", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PAPERLENGTH, "Paper length", HFILL }}, + + { &hf_devmode_fields_paperwidth, + { "Paper width", "spoolss.devmode.fields.paper_width", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PAPERWIDTH, "Paper width", HFILL }}, + + { &hf_devmode_fields_scale, + { "Scale", "spoolss.devmode.fields.scale", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_SCALE, "Scale", HFILL }}, + + { &hf_devmode_fields_position, + { "Position", "spoolss.devmode.fields.position", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_POSITION, "Position", HFILL }}, + + { &hf_devmode_fields_nup, + { "N-up", "spoolss.devmode.fields.nup", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_NUP, "N-up", HFILL }}, + + { &hf_devmode_fields_copies, + { "Copies", "spoolss.devmode.fields.copies", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_COPIES, "Copies", HFILL }}, + + { &hf_devmode_fields_defaultsource, + { "Default source", "spoolss.devmode.fields.default_source", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_DEFAULTSOURCE, "Default source", HFILL }}, + + { &hf_devmode_fields_printquality, + { "Print quality", "spoolss.devmode.fields.print_quality", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PRINTQUALITY, "Print quality", HFILL }}, + + { &hf_devmode_fields_color, + { "Color", "spoolss.devmode.fields.color", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_COLOR, "Color", HFILL }}, + + { &hf_devmode_fields_duplex, + { "Duplex", "spoolss.devmode.fields.duplex", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_DUPLEX, "Duplex", HFILL }}, + + { &hf_devmode_fields_yresolution, + { "Y resolution", "spoolss.devmode.fields.y_resolution", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_YRESOLUTION, "Y resolution", HFILL }}, + + { &hf_devmode_fields_ttoption, + { "TT option", "spoolss.devmode.fields.tt_option", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_TTOPTION, "TT option", HFILL }}, + + { &hf_devmode_fields_collate, + { "Collate", "spoolss.devmode.fields.collate", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_COLLATE, "Collate", HFILL }}, + + { &hf_devmode_fields_formname, + { "Form name", "spoolss.devmode.fields.form_name", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_FORMNAME, "Form name", HFILL }}, + + { &hf_devmode_fields_logpixels, + { "Log pixels", "spoolss.devmode.fields.log_pixels", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_LOGPIXELS, "Log pixels", HFILL }}, + + { &hf_devmode_fields_bitsperpel, + { "Bits per pel", "spoolss.devmode.fields.bits_per_pel", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_BITSPERPEL, "Bits per pel", HFILL }}, + + { &hf_devmode_fields_pelswidth, + { "Pels width", "spoolss.devmode.fields.pels_width", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PELSWIDTH, "Pels width", HFILL }}, + + { &hf_devmode_fields_pelsheight, + { "Pels height", "spoolss.devmode.fields.pels_height", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PELSHEIGHT, "Pels height", HFILL }}, + + { &hf_devmode_fields_displayflags, + { "Display flags", "spoolss.devmode.fields.display_flags", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_DISPLAYFLAGS, "Display flags", HFILL }}, + + { &hf_devmode_fields_displayfrequency, + { "Display frequency", + "spoolss.devmode.fields.display_frequency", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_DISPLAYFREQUENCY, "Display frequency", HFILL }}, + + { &hf_devmode_fields_icmmethod, + { "ICM method", "spoolss.devmode.fields.icm_method", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_ICMMETHOD, "ICM method", HFILL }}, + + { &hf_devmode_fields_icmintent, + { "ICM intent", "spoolss.devmode.fields.icm_intent", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_ICMINTENT, "ICM intent", HFILL }}, + + { &hf_devmode_fields_mediatype, + { "Media type", "spoolss.devmode.fields.media_type", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_MEDIATYPE, "Media type", HFILL }}, + + { &hf_devmode_fields_dithertype, + { "Dither type", "spoolss.devmode.fields.dither_type", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_DITHERTYPE, "Dither type", HFILL }}, + + { &hf_devmode_fields_panningwidth, + { "Panning width", "spoolss.devmode.fields.panning_width", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PANNINGWIDTH, "Panning width", HFILL }}, + + { &hf_devmode_fields_panningheight, + { "Panning height", "spoolss.devmode.fields.panning_height", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + DEVMODE_PANNINGHEIGHT, "Panning height", HFILL }}, + + /* EnumPrinterData RPC */ + + { &hf_enumprinterdata_enumindex, + { "Enum index", "spoolss.enumprinterdata.enumindex", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Index for start of enumeration", HFILL }}, + + { &hf_enumprinterdata_value_offered, + { "Value size offered", + "spoolss.enumprinterdata.value_offered", FT_UINT32, + BASE_DEC, NULL, 0x0, + "Buffer size offered for printerdata value", HFILL }}, + + { &hf_enumprinterdata_data_offered, + { "Data size offered", + "spoolss.enumprinterdata.data_offered", FT_UINT32, + BASE_DEC, NULL, 0x0, + "Buffer size offered for printerdata data", HFILL }}, + + { &hf_enumprinterdata_value_len, + { "Value length", + "spoolss.enumprinterdata.value_len", FT_UINT32, + BASE_DEC, NULL, 0x0, + "Size of printerdata value", HFILL }}, + + { &hf_enumprinterdata_value_needed, + { "Value size needed", + "spoolss.enumprinterdata.value_needed", FT_UINT32, + BASE_DEC, NULL, 0x0, + "Buffer size needed for printerdata value", HFILL }}, + + { &hf_enumprinterdata_data_needed, + { "Data size needed", + "spoolss.enumprinterdata.data_needed", FT_UINT32, BASE_DEC, + NULL, 0x0, "Buffer size needed for printerdata data", + HFILL }}, + + /* Print jobs */ + + { &hf_job_id, + { "Job ID", "spoolss.job.id", FT_UINT32, BASE_DEC, + NULL, 0x0, "Job identification number", HFILL }}, + + { &hf_job_status, + { "Job status", "spoolss.job.status", FT_UINT32, BASE_DEC, + NULL, 0x0, "Job status", HFILL }}, + + { &hf_job_status_paused, + { "Paused", "spoolss.job.status.paused", FT_BOOLEAN, 32, + TFS(&tfs_job_status_paused), JOB_STATUS_PAUSED, + "Paused", HFILL }}, + + { &hf_job_status_error, + { "Error", "spoolss.job.status.error", FT_BOOLEAN, 32, + TFS(&tfs_job_status_error), JOB_STATUS_ERROR, + "Error", HFILL }}, + + { &hf_job_status_deleting, + { "Deleting", "spoolss.job.status.deleting", FT_BOOLEAN, 32, + TFS(&tfs_job_status_deleting), JOB_STATUS_DELETING, + "Deleting", HFILL }}, + + { &hf_job_status_spooling, + { "Spooling", "spoolss.job.status.spooling", FT_BOOLEAN, 32, + TFS(&tfs_job_status_spooling), JOB_STATUS_SPOOLING, + "Spooling", HFILL }}, + + { &hf_job_status_printing, + { "Printing", "spoolss.job.status.printing", FT_BOOLEAN, 32, + TFS(&tfs_job_status_printing), JOB_STATUS_PRINTING, + "Printing", HFILL }}, + + { &hf_job_status_offline, + { "Offline", "spoolss.job.status.offline", FT_BOOLEAN, 32, + TFS(&tfs_job_status_offline), JOB_STATUS_OFFLINE, + "Offline", HFILL }}, + + { &hf_job_status_paperout, + { "Paperout", "spoolss.job.status.paperout", FT_BOOLEAN, 32, + TFS(&tfs_job_status_paperout), JOB_STATUS_PAPEROUT, + "Paperout", HFILL }}, + + { &hf_job_status_printed, + { "Printed", "spoolss.job.status.printed", FT_BOOLEAN, 32, + TFS(&tfs_job_status_printed), JOB_STATUS_PRINTED, + "Printed", HFILL }}, + + { &hf_job_status_deleted, + { "Deleted", "spoolss.job.status.deleted", FT_BOOLEAN, 32, + TFS(&tfs_job_status_deleted), JOB_STATUS_DELETED, + "Deleted", HFILL }}, + + { &hf_job_status_blocked, + { "Blocked", "spoolss.job.status.blocked", FT_BOOLEAN, 32, + TFS(&tfs_job_status_blocked), JOB_STATUS_BLOCKED, + "Blocked", HFILL }}, + + { &hf_job_status_user_intervention, + { "User intervention", + "spoolss.job.status.user_intervention", FT_BOOLEAN, 32, + TFS(&tfs_job_status_user_intervention), + JOB_STATUS_USER_INTERVENTION, "User intervention", + HFILL }}, + + { &hf_job_priority, + { "Job priority", "spoolss.job.priority", FT_UINT32, + BASE_DEC, NULL, 0x0, "Job priority", HFILL }}, + + { &hf_job_position, + { "Job position", "spoolss.job.position", FT_UINT32, + BASE_DEC, NULL, 0x0, "Job position", HFILL }}, + + { &hf_job_totalpages, + { "Job total pages", "spoolss.job.totalpages", FT_UINT32, + BASE_DEC, NULL, 0x0, "Job total pages", HFILL }}, + + { &hf_job_totalbytes, + { "Job total bytes", "spoolss.job.totalbytes", FT_UINT32, + BASE_DEC, NULL, 0x0, "Job total bytes", HFILL }}, + + { &hf_job_bytesprinted, + { "Job bytes printed", "spoolss.job.bytesprinted", + FT_UINT32, BASE_DEC, NULL, 0x0, "Job bytes printed", + HFILL }}, + + { &hf_job_pagesprinted, + { "Job pages printed", "spoolss.job.pagesprinted", + FT_UINT32, BASE_DEC, NULL, 0x0, "Job pages printed", + HFILL }}, + + { &hf_job_size, + { "Job size", "spoolss.job.size", FT_UINT32, BASE_DEC, + NULL, 0x0, "Job size", HFILL }}, + + /* Forms */ + + { &hf_form, + { "Data", "spoolss.form", FT_UINT32, + BASE_HEX, NULL, 0, "Data", HFILL }}, + + { &hf_form_level, + { "Level", "spoolss.form.level", FT_UINT32, + BASE_DEC, NULL, 0, "Level", HFILL }}, + + { &hf_form_name, + { "Name", "spoolss.form.name", FT_STRING, BASE_NONE, + NULL, 0, "Name", HFILL }}, + + { &hf_form_flags, + { "Flags", "spoolss.form.flags", FT_UINT32, + BASE_DEC, VALS(form_type_vals), 0, "Flags", HFILL }}, + + { &hf_form_unknown, + { "Unknown", "spoolss.form.unknown", FT_UINT32, + BASE_HEX, NULL, 0, "Unknown", HFILL }}, + + { &hf_form_width, + { "Width", "spoolss.form.width", FT_UINT32, + BASE_DEC, NULL, 0, "Width", HFILL }}, + + { &hf_form_height, + { "Height", "spoolss.form.height", FT_UINT32, + BASE_DEC, NULL, 0, "Height", HFILL }}, + + { &hf_form_left_margin, + { "Left margin", "spoolss.form.left", FT_UINT32, + BASE_DEC, NULL, 0, "Left", HFILL }}, + + { &hf_form_top_margin, + { "Top", "spoolss.form.top", FT_UINT32, + BASE_DEC, NULL, 0, "Top", HFILL }}, + + { &hf_form_horiz_len, + { "Horizontal", "spoolss.form.horiz", FT_UINT32, + BASE_DEC, NULL, 0, "Horizontal", HFILL }}, + + { &hf_form_vert_len, + { "Vertical", "spoolss.form.vert", FT_UINT32, + BASE_DEC, NULL, 0, "Vertical", HFILL }}, + + { &hf_enumforms_num, + { "Num", "spoolss.enumforms.num", FT_UINT32, + BASE_DEC, NULL, 0, "Num", HFILL }}, + + /* Print notify */ + + { &hf_notify_options_version, + { "Version", "spoolss.notify_options.version", FT_UINT32, + BASE_DEC, NULL, 0, "Version", HFILL }}, + + { &hf_notify_options_flags, + { "Flags", "spoolss.notify_options.flags", FT_UINT32, + BASE_DEC, NULL, 0, "Flags", HFILL }}, + + { &hf_notify_options_count, + { "Count", "spoolss.notify_options.count", FT_UINT32, + BASE_DEC, NULL, 0, "Count", HFILL }}, + + { &hf_notify_option_type, + { "Type", "spoolss.notify_option.type", FT_UINT16, BASE_DEC, + VALS(printer_notify_types), 0, "Type", HFILL }}, + + { &hf_notify_option_reserved1, + { "Reserved1", "spoolss.notify_option.reserved1", FT_UINT16, + BASE_DEC, NULL, 0, "Reserved1", HFILL }}, + + { &hf_notify_option_reserved2, + { "Reserved2", "spoolss.notify_option.reserved2", FT_UINT32, + BASE_DEC, NULL, 0, "Reserved2", HFILL }}, + + { &hf_notify_option_reserved3, + { "Reserved3", "spoolss.notify_option.reserved3", FT_UINT32, + BASE_DEC, NULL, 0, "Reserved3", HFILL }}, + + { &hf_notify_option_count, + { "Count", "spoolss.notify_option.count", FT_UINT32, + BASE_DEC, NULL, 0, "Count", HFILL }}, + + { &hf_notify_option_data_count, + { "Count", "spoolss.notify_option_data.count", FT_UINT32, + BASE_DEC, NULL, 0, "Count", HFILL }}, + + { &hf_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_notify_info_count, + { "Count", "spoolss.notify_info.count", FT_UINT32, BASE_DEC, + NULL, 0, "Count", HFILL }}, + + { &hf_notify_info_version, + { "Version", "spoolss.notify_info.version", FT_UINT32, + BASE_DEC, NULL, 0, "Version", HFILL }}, + + { &hf_notify_info_flags, + { "Flags", "spoolss.notify_info.flags", FT_UINT32, BASE_HEX, + NULL, 0, "Flags", HFILL }}, + + { &hf_notify_info_data_type, + { "Type", "spoolss.notify_info_data.type", FT_UINT16, + BASE_DEC, VALS(printer_notify_types), 0, "Type", HFILL }}, + + { &hf_notify_field, + { "Field", "spoolss.notify_field", FT_UINT16, BASE_DEC, + NULL, 0, "Field", HFILL }}, + + { &hf_notify_info_data_count, + { "Count", "spoolss.notify_info_data.count", FT_UINT32, + BASE_DEC, NULL, 0, "Count", HFILL }}, + + { &hf_notify_info_data_id, + { "Job Id", "spoolss.notify_info_data.jobid", FT_UINT32, + BASE_DEC, NULL, 0, "Job Id", HFILL }}, + + { &hf_notify_info_data_value1, + { "Value1", "spoolss.notify_info_data.value1", FT_UINT32, + BASE_HEX, NULL, 0, "Value1", HFILL }}, + + { &hf_notify_info_data_value2, + { "Value2", "spoolss.notify_info_data.value2", FT_UINT32, + BASE_HEX, NULL, 0, "Value2", HFILL }}, + + { &hf_notify_info_data_bufsize, + { "Buffer size", "spoolss.notify_info_data.bufsize", + FT_UINT32, BASE_DEC, NULL, 0, "Buffer size", HFILL }}, + + { &hf_notify_info_data_buffer, + { "Buffer", "spoolss.notify_info_data.buffer", FT_UINT32, + BASE_HEX, NULL, 0, "Buffer", HFILL }}, + + { &hf_notify_info_data_buffer_len, + { "Buffer length", "spoolss.notify_info_data.buffer.len", + FT_UINT32, BASE_HEX, NULL, 0, "Buffer length", HFILL }}, + + { &hf_notify_info_data_buffer_data, + { "Buffer data", "spoolss.notify_info_data.buffer.data", + FT_BYTES, BASE_HEX, NULL, 0, "Buffer data", HFILL }}, + + /* RffpCNex RPC */ + + { &hf_rffpcnex_options, + { "Options", "spoolss.rffpcnex.options", FT_UINT32, BASE_DEC, + NULL, 0, "RFFPCNEX options", HFILL }}, + + { &hf_printerlocal, /* XXX: move me */ + { "Printer local", "spoolss.printer_local", FT_UINT32, + BASE_DEC, NULL, 0, "Printer local", HFILL }}, + + { &hf_rffpcnex_flags, + { "RFFPCNEX flags", "spoolss.rffpcnex.flags", FT_UINT32, + BASE_DEC, NULL, 0, "RFFPCNEX flags", HFILL }}, + + { &hf_rffpcnex_flags_add_printer, + { "Add printer", "spoolss.rffpcnex.flags.add_printer", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_printer), + SPOOLSS_PRINTER_CHANGE_ADD_PRINTER, "Add printer", + HFILL }}, + + { &hf_rffpcnex_flags_set_printer, + { "Set printer", "spoolss.rffpcnex.flags.set_printer", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_printer), + SPOOLSS_PRINTER_CHANGE_SET_PRINTER, "Set printer", + HFILL }}, + + { &hf_rffpcnex_flags_delete_printer, + { "Delete printer", "spoolss.rffpcnex.flags.delete_printer", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_printer), + SPOOLSS_PRINTER_CHANGE_DELETE_PRINTER, "Delete printer", + HFILL }}, + + { &hf_rffpcnex_flags_add_job, + { "Add job", "spoolss.rffpcnex.flags.add_job", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_job), + SPOOLSS_PRINTER_CHANGE_ADD_JOB, "Add job", HFILL }}, + + { &hf_rffpcnex_flags_set_job, + { "Set job", "spoolss.rffpcnex.flags.set_job", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_job), + SPOOLSS_PRINTER_CHANGE_SET_JOB, "Set job", HFILL }}, + + { &hf_rffpcnex_flags_delete_job, + { "Delete job", "spoolss.rffpcnex.flags.delete_job", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_job), + SPOOLSS_PRINTER_CHANGE_DELETE_JOB, "Delete job", HFILL }}, + + { &hf_rffpcnex_flags_write_job, + { "Write job", "spoolss.rffpcnex.flags.write_job", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_write_job), + SPOOLSS_PRINTER_CHANGE_WRITE_JOB, "Write job", HFILL }}, + + { &hf_rffpcnex_flags_add_form, + { "Add form", "spoolss.rffpcnex.flags.add_form", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_form), + SPOOLSS_PRINTER_CHANGE_ADD_FORM, "Add form", HFILL }}, + + { &hf_rffpcnex_flags_set_form, + { "Set form", "spoolss.rffpcnex.flags.set_form", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_form), + SPOOLSS_PRINTER_CHANGE_SET_FORM, "Set form", HFILL }}, + + { &hf_rffpcnex_flags_delete_form, + { "Delete form", "spoolss.rffpcnex.flags.delete_form", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_form), + SPOOLSS_PRINTER_CHANGE_DELETE_FORM, "Delete form", + HFILL }}, + + { &hf_rffpcnex_flags_add_port, + { "Add port", "spoolss.rffpcnex.flags.add_port", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_port), + SPOOLSS_PRINTER_CHANGE_ADD_PORT, "Add port", HFILL }}, + + { &hf_rffpcnex_flags_configure_port, + { "Configure port", "spoolss.rffpcnex.flags.configure_port", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_configure_port), + SPOOLSS_PRINTER_CHANGE_CONFIGURE_PORT, "Configure port", + HFILL }}, + + { &hf_rffpcnex_flags_delete_port, + { "Delete port", "spoolss.rffpcnex.flags.delete_port", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_port), + SPOOLSS_PRINTER_CHANGE_DELETE_PORT, "Delete port", + HFILL }}, + + { &hf_rffpcnex_flags_add_print_processor, + { "Add processor", "spoolss.rffpcnex.flags.add_processor", + FT_BOOLEAN, 32, + TFS(&tfs_rffpcnex_flags_add_print_processor), + SPOOLSS_PRINTER_CHANGE_ADD_PRINT_PROCESSOR, + "Add processor", HFILL }}, + + { &hf_rffpcnex_flags_delete_print_processor, + { "Delete processor", + "spoolss.rffpcnex.flags.delete_processor", FT_BOOLEAN, 32, + TFS(&tfs_rffpcnex_flags_delete_print_processor), + SPOOLSS_PRINTER_CHANGE_DELETE_PRINT_PROCESSOR, + "Delete processor", HFILL }}, + + { &hf_rffpcnex_flags_add_driver, + { "Add driver", "spoolss.rffpcnex.flags.add_driver", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_driver), + SPOOLSS_PRINTER_CHANGE_ADD_PRINTER_DRIVER, "Add driver", + HFILL }}, + + { &hf_rffpcnex_flags_set_driver, + { "Set driver", "spoolss.rffpcnex.flags.set_driver", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_driver), + SPOOLSS_PRINTER_CHANGE_SET_PRINTER_DRIVER, "Set driver", + HFILL }}, + + { &hf_rffpcnex_flags_delete_driver, + { "Delete driver", "spoolss.rffpcnex.flags.delete_driver", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_driver), + SPOOLSS_PRINTER_CHANGE_DELETE_PRINTER_DRIVER, + "Delete driver", HFILL }}, + + { &hf_rffpcnex_flags_timeout, + { "Timeout", "spoolss.rffpcnex.flags.timeout", + FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_timeout), + SPOOLSS_PRINTER_CHANGE_TIMEOUT, "Timeout", HFILL }}, + + { &hf_rffpcnex_flags_failed_printer_connection, + { "Failed printer connection", + "spoolss.rffpcnex.flags.failed_connection_printer", + FT_BOOLEAN, 32, + TFS(&tfs_rffpcnex_flags_failed_connection_printer), + SPOOLSS_PRINTER_CHANGE_FAILED_CONNECTION_PRINTER, + "Failed printer connection", HFILL }}, + + /* RRPCN RPC */ + + { &hf_rrpcn_changelow, + { "Change low", "spoolss.rrpcn.changelow", FT_UINT32, + BASE_DEC, NULL, 0, "Change low", HFILL }}, + + { &hf_rrpcn_changehigh, + { "Change high", "spoolss.rrpcn.changehigh", FT_UINT32, + BASE_DEC, NULL, 0, "Change high", HFILL }}, + + { &hf_rrpcn_unk0, + { "Unknown 0", "spoolss.rrpcn.unk0", FT_UINT32, BASE_DEC, + NULL, 0, "Unknown 0", HFILL }}, + + { &hf_rrpcn_unk1, + { "Unknown 1", "spoolss.rrpcn.unk1", FT_UINT32, BASE_DEC, + NULL, 0, "Unknown 1", HFILL }}, + + /* ReplyOpenPrinter RPC */ + + { &hf_replyopenprinter_unk0, + { "Unknown 0", "spoolss.replyopenprinter.unk0", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 0", HFILL }}, + + { &hf_replyopenprinter_unk1, + { "Unknown 1", "spoolss.replyopenprinter.unk1", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 1", HFILL }}, + + /* Printer attributes */ + + { &hf_printer_attributes, + { "Attributes", "spoolss.printer_attributes", FT_UINT32, + BASE_HEX, NULL, 0, "Attributes", HFILL }}, + + { &hf_printer_attributes_queued, + { "Queued", "spoolss.printer_attributes.queued", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_queued), + PRINTER_ATTRIBUTE_QUEUED, "Queued", HFILL }}, + + { &hf_printer_attributes_direct, + { "Direct", "spoolss.printer_attributes.direct", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_direct), + PRINTER_ATTRIBUTE_DIRECT, "Direct", HFILL }}, + + { &hf_printer_attributes_default, + { "Default (9x/ME only)", + "spoolss.printer_attributes.default",FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_default), + PRINTER_ATTRIBUTE_DEFAULT, "Default", HFILL }}, + + { &hf_printer_attributes_shared, + { "Shared", "spoolss.printer_attributes.shared", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_shared), + PRINTER_ATTRIBUTE_SHARED, "Shared", HFILL }}, + + { &hf_printer_attributes_network, + { "Network", "spoolss.printer_attributes.network", + FT_BOOLEAN, 32, TFS(&tfs_printer_attributes_network), + PRINTER_ATTRIBUTE_NETWORK, "Network", HFILL }}, + + { &hf_printer_attributes_hidden, + { "Hidden", "spoolss.printer_attributes.hidden", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_hidden), + PRINTER_ATTRIBUTE_HIDDEN, "Hidden", HFILL }}, + + { &hf_printer_attributes_local, + { "Local", "spoolss.printer_attributes.local", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_local), + PRINTER_ATTRIBUTE_LOCAL, "Local", HFILL }}, + + { &hf_printer_attributes_enable_devq, + { "Enable devq", "spoolss.printer_attributes.enable_devq", + FT_BOOLEAN, 32, TFS(&tfs_printer_attributes_enable_devq), + PRINTER_ATTRIBUTE_ENABLE_DEVQ, "Enable evq", HFILL }}, + + { &hf_printer_attributes_keep_printed_jobs, + { "Keep printed jobs", + "spoolss.printer_attributes.keep_printed_jobs", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_keep_printed_jobs), + PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, "Keep printed jobs", + HFILL }}, + + { &hf_printer_attributes_do_complete_first, + { "Do complete first", + "spoolss.printer_attributes.do_complete_first", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_do_complete_first), + PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST, "Do complete first", + HFILL }}, + + { &hf_printer_attributes_work_offline, + { "Work offline (9x/ME only)", + "spoolss.printer_attributes.work_offline", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_work_offline), + PRINTER_ATTRIBUTE_WORK_OFFLINE, "Work offline", HFILL }}, + + { &hf_printer_attributes_enable_bidi, + { "Enable bidi (9x/ME only)", + "spoolss.printer_attributes.enable_bidi", FT_BOOLEAN, + 32, TFS(&tfs_printer_attributes_enable_bidi), + PRINTER_ATTRIBUTE_ENABLE_BIDI, "Enable bidi", HFILL }}, + + { &hf_printer_attributes_raw_only, + { "Raw only", "spoolss.printer_attributes.raw_only", + FT_BOOLEAN, 32, TFS(&tfs_printer_attributes_raw_only), + PRINTER_ATTRIBUTE_RAW_ONLY, "Raw only", HFILL }}, + + { &hf_printer_attributes_published, + { "Published", "spoolss.printer_attributes.published", + FT_BOOLEAN, 32, TFS(&tfs_printer_attributes_published), + PRINTER_ATTRIBUTE_PUBLISHED, "Published", HFILL }}, + + /* Timestamps */ + + { &hf_time_year, + { "Year", "spoolss.time.year", FT_UINT32, BASE_DEC, + NULL, 0x0, "Year", HFILL }}, + + { &hf_time_month, + { "Month", "spoolss.time.month", FT_UINT32, BASE_DEC, + NULL, 0x0, "Month", HFILL }}, + + { &hf_time_dow, + { "Day of week", "spoolss.time.dow", FT_UINT32, BASE_DEC, + NULL, 0x0, "Day of week", HFILL }}, + + { &hf_time_day, + { "Day", "spoolss.time.day", FT_UINT32, BASE_DEC, + NULL, 0x0, "Day", HFILL }}, + + { &hf_time_hour, + { "Hour", "spoolss.time.hour", FT_UINT32, BASE_DEC, + NULL, 0x0, "Hour", HFILL }}, + + { &hf_time_minute, + { "Minute", "spoolss.time.minute", FT_UINT32, BASE_DEC, + NULL, 0x0, "Minute", HFILL }}, + + { &hf_time_second, + { "Second", "spoolss.time.second", FT_UINT32, BASE_DEC, + NULL, 0x0, "Second", HFILL }}, + + { &hf_time_msec, + { "Millisecond", "spoolss.time.msec", FT_UINT32, BASE_DEC, + NULL, 0x0, "Millisecond", HFILL }}, + + /* Userlevel */ + + { &hf_userlevel_size, + { "Size", "spoolss.userlevel.size", + FT_UINT32, BASE_DEC, NULL, 0, "Size", HFILL }}, + + { &hf_userlevel_client, + { "Client", "spoolss.userlevel.client", FT_STRING, + BASE_NONE, NULL, 0, "Client", HFILL }}, + + { &hf_userlevel_user, + { "User", "spoolss.userlevel.user", FT_STRING, + BASE_NONE, NULL, 0, "User", HFILL }}, + + { &hf_userlevel_build, + { "Build", "spoolss.userlevel.build", + FT_UINT32, BASE_DEC, NULL, 0, "Build", HFILL }}, + + { &hf_userlevel_major, + { "Major", "spoolss.userlevel.major", + FT_UINT32, BASE_DEC, NULL, 0, "Major", HFILL }}, + + { &hf_userlevel_minor, + { "Minor", "spoolss.userlevel.minor", + FT_UINT32, BASE_DEC, NULL, 0, "Minor", HFILL }}, + + { &hf_userlevel_processor, + { "Processor", "spoolss.userlevel.processor", + FT_UINT32, BASE_DEC, NULL, 0, "Processor", HFILL }}, + + /* EnumprinterdataEx RPC */ + + { &hf_enumprinterdataex_num_values, + { "Num values", "spoolss.enumprinterdataex.num_values", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Number of values returned", HFILL }}, + + { &hf_enumprinterdataex_name_offset, + { "Name offset", "spoolss.enumprinterdataex.name_offset", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Name offset", HFILL }}, + + { &hf_enumprinterdataex_name_len, + { "Name len", "spoolss.enumprinterdataex.name_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Name len", HFILL }}, + + { &hf_enumprinterdataex_name, + { "Name", "spoolss.enumprinterdataex.name", + FT_STRING, BASE_NONE, NULL, 0, "Name", HFILL }}, + + { &hf_enumprinterdataex_val_type, + { "Value type", "spoolss.enumprinterdataex.value_type", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Value type", HFILL }}, + + { &hf_enumprinterdataex_val_offset, + { "Value offset", "spoolss.enumprinterdataex.value_offset", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Value offset", HFILL }}, + + { &hf_enumprinterdataex_val_len, + { "Value len", "spoolss.enumprinterdataex.value_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Value len", HFILL }}, + + { &hf_enumprinterdataex_val_dword_high, + { "DWORD value (high)", + "spoolss.enumprinterdataex.val_dword.high", + FT_UINT16, BASE_DEC, NULL, 0x0, + "DWORD value (high)", HFILL }}, + + { &hf_enumprinterdataex_val_dword_low, + { "DWORD value (low)", + "spoolss.enumprinterdataex.val_dword.low", + FT_UINT16, BASE_DEC, NULL, 0x0, + "DWORD value (low)", HFILL }}, + + { &hf_enumprinterdataex_val_sz, + { "SZ value", "spoolss.printerdata.val_sz", + FT_STRING, BASE_NONE, NULL, 0, "SZ value", HFILL }}, + + /* RouterReplyPrinter RPC */ + + { &hf_routerreplyprinter_condition, + { "Condition", "spoolss.routerreplyprinter.condition", + FT_UINT32, BASE_DEC, NULL, 0, "Condition", HFILL }}, + + { &hf_routerreplyprinter_unknown1, + { "Unknown1", "spoolss.routerreplyprinter.unknown1", + FT_UINT32, BASE_DEC, NULL, 0, "Unknown1", HFILL }}, + + { &hf_routerreplyprinter_changeid, + { "Change id", "spoolss.routerreplyprinter.changeid", + FT_UINT32, BASE_DEC, NULL, 0, "Change id", HFILL }}, + + /* EnumPrinterKey RPC */ + + { &hf_keybuffer_size, + { "Key Buffer size", "spoolss.keybuffer.size", FT_UINT32, + BASE_DEC, NULL, 0x0, "Size of buffer", HFILL }}, + + { &hf_keybuffer_data, + { "Key Buffer data", "spoolss.keybuffer.data", FT_BYTES, + BASE_HEX, NULL, 0x0, "Contents of buffer", HFILL }}, + + /* SetJob RPC */ + + { &hf_setjob_cmd, + { "Set job command", "spoolss.setjob.cmd", FT_UINT32, + BASE_DEC, VALS(setjob_commands), 0x0, "Printer data name", + HFILL }}, + + /* EnumJobs RPC */ + + { &hf_enumjobs_firstjob, + { "First job", "spoolss.enumjobs.firstjob", FT_UINT32, + BASE_DEC, NULL, 0x0, "Index of first job to return", + HFILL }}, + + { &hf_enumjobs_numjobs, + { "Num jobs", "spoolss.enumjobs.numjobs", FT_UINT32, + BASE_DEC, NULL, 0x0, "Number of jobs to return", HFILL }}, + + /* Security descriptor buffer */ + + { &hf_secdescbuf_maxlen, + { "Max len", "secdescbuf.max_len", + FT_UINT32, BASE_DEC, NULL, 0, "Max len", HFILL }}, + + { &hf_secdescbuf_undoc, + { "Undocumented", "secdescbuf.undoc", + FT_UINT32, BASE_DEC, NULL, 0, "Undocumented", HFILL }}, + + { &hf_secdescbuf_len, + { "Length", "secdescbuf.len", + FT_UINT32, BASE_DEC, NULL, 0, "Length", HFILL }}, + + /* Spool printer info */ + + { &hf_spool_printer_info_devmode_ptr, + { "Devmode pointer", "spoolprinterinfo.devmode_ptr", + FT_UINT32, BASE_HEX, NULL, 0, "Devmode pointer", HFILL }}, + + { &hf_spool_printer_info_secdesc_ptr, + { "Secdesc pointer", "spoolprinterinfo.secdesc_ptr", + FT_UINT32, BASE_HEX, NULL, 0, "Secdesc pointer", HFILL }}, + + /* WritePrinter RPC */ + + { &hf_writeprinter_numwritten, + { "Num written", "spoolss.writeprinter.numwritten", + FT_UINT32, BASE_DEC, NULL, 0x0, "Number of bytes written", + HFILL }}, + + /* Setprinterdataex RPC */ + + { &hf_setprinterdataex_max_len, + { "Max len", "setprinterdataex.max_len", + FT_UINT32, BASE_DEC, NULL, 0, "Max len", HFILL }}, + + { &hf_setprinterdataex_real_len, + { "Real len", "setprinterdataex.real_len", + FT_UINT32, BASE_DEC, NULL, 0, "Real len", HFILL }}, + + { &hf_setprinterdataex_data, + { "Data", "setprinterdataex.data", + FT_BYTES, BASE_HEX, NULL, 0, "Data", HFILL }}, + + /* Specific access rights */ + + { &hf_access_required, + { "Access required", "spoolss.access_required", + FT_UINT32, BASE_HEX, NULL, 0x0, "Access required", + HFILL }}, + + { &hf_server_access_admin, + { "Server admin", "spoolss.access_mask.server_admin", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + SERVER_ACCESS_ADMINISTER, "Server admin", HFILL }}, + + { &hf_server_access_enum, + { "Server enum", "spoolss.access_mask.server_enum", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + SERVER_ACCESS_ENUMERATE, "Server enum", HFILL }}, + + { &hf_printer_access_admin, + { "Printer admin", "spoolss.access_mask.printer_admin", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ACCESS_ADMINISTER, "Printer admin", HFILL }}, + + { &hf_printer_access_use, + { "Printer use", "spoolss.access_mask.printer_use", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + PRINTER_ACCESS_USE, "Printer use", HFILL }}, + + { &hf_job_access_admin, + { "Job admin", "spoolss.access_mask.job_admin", + FT_BOOLEAN, 32, TFS(&flags_set_truth), + JOB_ACCESS_ADMINISTER, "Job admin", HFILL }}, + + /* Printer information */ + + { &hf_printer_cjobs, + { "CJobs", "spoolss.printer.cjobs", FT_UINT32, + BASE_DEC, NULL, 0, "CJobs", HFILL }}, + + { &hf_printer_total_jobs, + { "Total jobs", "spoolss.printer.total_jobs", FT_UINT32, + BASE_DEC, NULL, 0, "Total jobs", HFILL }}, + + { &hf_printer_total_bytes, + { "Total bytes", "spoolss.printer.total_bytes", FT_UINT32, + BASE_DEC, NULL, 0, "Total bytes", HFILL }}, + + { &hf_printer_global_counter, + { "Global counter", "spoolss.printer.global_counter", + FT_UINT32, BASE_DEC, NULL, 0, "Global counter", HFILL }}, + + { &hf_printer_total_pages, + { "Total pages", "spoolss.printer.total_pages", FT_UINT32, + BASE_DEC, NULL, 0, "Total pages", HFILL }}, + + { &hf_printer_major_version, + { "Major version", "spoolss.printer.major_version", + FT_UINT16, BASE_DEC, NULL, 0, "Major version", HFILL }}, + + { &hf_printer_build_version, + { "Build version", "spoolss.printer.build_version", + FT_UINT16, BASE_DEC, NULL, 0, "Build version", HFILL }}, + + { &hf_printer_unk7, + { "Unknown 7", "spoolss.printer.unknown7", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 7", HFILL }}, + + { &hf_printer_unk8, + { "Unknown 8", "spoolss.printer.unknown8", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 8", HFILL }}, + + { &hf_printer_unk9, + { "Unknown 9", "spoolss.printer.unknown9", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 9", HFILL }}, + + { &hf_printer_session_ctr, + { "Session counter", "spoolss.printer.session_ctr", + FT_UINT32, BASE_DEC, NULL, 0, "Sessopm counter", HFILL }}, + + { &hf_printer_unk11, + { "Unknown 11", "spoolss.printer.unknown11", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 11", HFILL }}, + + { &hf_printer_printer_errors, + { "Printer errors", "spoolss.printer.printer_errors", + FT_UINT32, BASE_DEC, NULL, 0, "Printer errors", HFILL }}, + + { &hf_printer_unk13, + { "Unknown 13", "spoolss.printer.unknown13", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 13", HFILL }}, + + { &hf_printer_unk14, + { "Unknown 14", "spoolss.printer.unknown14", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 14", HFILL }}, + + { &hf_printer_unk15, + { "Unknown 15", "spoolss.printer.unknown15", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 15", HFILL }}, + + { &hf_printer_unk16, + { "Unknown 16", "spoolss.printer.unknown16", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 16", HFILL }}, + + { &hf_printer_changeid, + { "Change id", "spoolss.printer.changeid", FT_UINT32, + BASE_DEC, NULL, 0, "Change id", HFILL }}, + + { &hf_printer_unk18, + { "Unknown 18", "spoolss.printer.unknown18", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 18", HFILL }}, + + { &hf_printer_unk20, + { "Unknown 20", "spoolss.printer.unknown20", FT_UINT32, + BASE_DEC, NULL, 0, "Unknown 20", HFILL }}, + + { &hf_printer_c_setprinter, + { "Csetprinter", "spoolss.printer.c_setprinter", + FT_UINT32, BASE_DEC, NULL, 0, "Csetprinter", HFILL }}, + + { &hf_printer_unk22, + { "Unknown 22", "spoolss.printer.unknown22", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 22", HFILL }}, + + { &hf_printer_unk23, + { "Unknown 23", "spoolss.printer.unknown23", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 23", HFILL }}, + + { &hf_printer_unk24, + { "Unknown 24", "spoolss.printer.unknown24", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 24", HFILL }}, + + { &hf_printer_unk25, + { "Unknown 25", "spoolss.printer.unknown25", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 25", HFILL }}, + + { &hf_printer_unk26, + { "Unknown 26", "spoolss.printer.unknown26", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 26", HFILL }}, + + { &hf_printer_unk27, + { "Unknown 27", "spoolss.printer.unknown27", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 27", HFILL }}, + + { &hf_printer_unk28, + { "Unknown 28", "spoolss.printer.unknown28", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 28", HFILL }}, + + { &hf_printer_unk29, + { "Unknown 29", "spoolss.printer.unknown29", + FT_UINT16, BASE_DEC, NULL, 0, "Unknown 29", HFILL }}, + + { &hf_printer_flags, + { "Flags", "spoolss.printer.flags", + FT_UINT32, BASE_HEX, NULL, 0, "Flags", HFILL }}, + + { &hf_printer_guid, + { "GUID", "spoolss.printer.guid", FT_STRING, + BASE_NONE, NULL, 0, "GUID", HFILL }}, + + { &hf_printer_action, + { "Action", "spoolss.printer.action", FT_UINT32, BASE_DEC, + VALS(getprinter_action_vals), 0, "Action", HFILL }}, + }; + + static gint *ett[] = { + &ett_dcerpc_spoolss, + &ett_PRINTER_DATATYPE, + &ett_DEVMODE_CTR, + &ett_DEVMODE, + &ett_DEVMODE_fields, + &ett_USER_LEVEL_CTR, + &ett_USER_LEVEL_1, + &ett_BUFFER, + &ett_PRINTER_INFO, + &ett_SPOOL_PRINTER_INFO_LEVEL, + &ett_PRINTER_INFO_0, + &ett_PRINTER_INFO_1, + &ett_PRINTER_INFO_2, + &ett_PRINTER_INFO_3, + &ett_PRINTER_INFO_7, + &ett_RELSTR, + &ett_RELSTR_ARRAY, + &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, + &ett_printer_attributes, + &ett_job_status, + &ett_enumprinters_flags, + &ett_PRINTER_DATA_CTR, + &ett_printer_enumdataex_value, + }; + + 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, hf_opnum); +} |