New tap for tethereal: io statistics that provides frames/bytes counts for frames...
[obnox/wireshark/wip.git] / packet-dcerpc-spoolss.c
1 /* packet-dcerpc-spoolss.c
2  * Routines for SMB \PIPE\spoolss packet disassembly
3  * Copyright 2001-2002, Tim Potter <tpot@samba.org>
4  *
5  * $Id: packet-dcerpc-spoolss.c,v 1.53 2002/08/29 19:05:40 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <string.h>
32
33 #include <epan/packet.h>
34 #include "packet-dcerpc.h"
35 #include "packet-dcerpc-nt.h"
36 #include "packet-dcerpc-spoolss.h"
37 #include "packet-dcerpc-reg.h"
38 #include "smb.h"
39 #include "packet-smb-common.h"
40
41 /* Global objects */
42
43 static int hf_spoolss_opnum = -1;
44
45 static const value_string spoolss_opnum_vals[] = {
46         { SPOOLSS_ENUMPRINTERS, "EnumPrinters" },
47         { SPOOLSS_OPENPRINTER, "OpenPrinter" },
48         { SPOOLSS_SETJOB, "SetJob" },
49         { SPOOLSS_GETJOB, "GetJob" },
50         { SPOOLSS_ENUMJOBS, "EnumJobs" },
51         { SPOOLSS_ADDPRINTER, "AddPrinter" },
52         { SPOOLSS_DELETEPRINTER, "DeletePrinter" },
53         { SPOOLSS_SETPRINTER, "SetPrinter" },
54         { SPOOLSS_GETPRINTER, "GetPrinter" },
55         { SPOOLSS_ADDPRINTERDRIVER, "AddPrinterDriver" },
56         { SPOOLSS_ENUMPRINTERDRIVERS, "EnumPrinterDrivers" },
57         { SPOOLSS_GETPRINTERDRIVER, "GetPrinterDriver" },
58         { SPOOLSS_GETPRINTERDRIVERDIRECTORY, "GetPrinterDriverDirectory" },
59         { SPOOLSS_DELETEPRINTERDRIVER, "DeletePrinterDriver" },
60         { SPOOLSS_ADDPRINTPROCESSOR, "AddPrintProcessor" },
61         { SPOOLSS_ENUMPRINTPROCESSORS, "EnumPrintProcessor" },
62         { SPOOLSS_GETPRINTPROCESSORDIRECTORY, "GetPrintProcessorDirectory" },
63         { SPOOLSS_STARTDOCPRINTER, "StartDocPrinter" },
64         { SPOOLSS_STARTPAGEPRINTER, "StartPagePrinter" },
65         { SPOOLSS_WRITEPRINTER, "WritePrinter" },
66         { SPOOLSS_ENDPAGEPRINTER, "EndPagePrinter" },
67         { SPOOLSS_ABORTPRINTER, "AbortPrinter" },
68         { SPOOLSS_READPRINTER, "ReadPrinter" },
69         { SPOOLSS_ENDDOCPRINTER, "EndDocPrinter" },
70         { SPOOLSS_ADDJOB, "AddJob" },
71         { SPOOLSS_SCHEDULEJOB, "ScheduleJob" },
72         { SPOOLSS_GETPRINTERDATA, "GetPrinterData" },
73         { SPOOLSS_SETPRINTERDATA, "SetPrinterData" },
74         { SPOOLSS_WAITFORPRINTERCHANGE, "WaitForPrinterChange" },
75         { SPOOLSS_CLOSEPRINTER, "ClosePrinter" },
76         { SPOOLSS_ADDFORM, "AddForm" },
77         { SPOOLSS_DELETEFORM, "DeleteForm" },
78         { SPOOLSS_GETFORM, "GetForm" },
79         { SPOOLSS_SETFORM, "SetForm" },
80         { SPOOLSS_ENUMFORMS, "EnumForms" },
81         { SPOOLSS_ENUMPORTS, "EnumPorts" },
82         { SPOOLSS_ENUMMONITORS, "EnumMonitors" },
83         { SPOOLSS_ADDPORT, "AddPort" },
84         { SPOOLSS_CONFIGUREPORT, "ConfigurePort" },
85         { SPOOLSS_DELETEPORT, "DeletePort" },
86         { SPOOLSS_CREATEPRINTERIC, "CreatePrinterIC" },
87         { SPOOLSS_PLAYGDISCRIPTONPRINTERIC, "PlayDiscriptOnPrinterIC" },
88         { SPOOLSS_DELETEPRINTERIC, "DeletePrinterIC" },
89         { SPOOLSS_ADDPRINTERCONNECTION, "AddPrinterConnection" },
90         { SPOOLSS_DELETEPRINTERCONNECTION, "DeletePrinterConnection" },
91         { SPOOLSS_PRINTERMESSAGEBOX, "PrinterMessageBox" },
92         { SPOOLSS_ADDMONITOR, "AddMonitor" },
93         { SPOOLSS_DELETEMONITOR, "DeleteMonitor" },
94         { SPOOLSS_DELETEPRINTPROCESSOR, "DeletePrintProcessor" },
95         { SPOOLSS_ADDPRINTPROVIDER, "AddPrintProvider" },
96         { SPOOLSS_DELETEPRINTPROVIDER, "DeletePrintProvider" },
97         { SPOOLSS_ENUMPRINTPROCDATATYPES, "EnumPrintProcDataTypes" },
98         { SPOOLSS_RESETPRINTER, "ResetPrinter" },
99         { SPOOLSS_GETPRINTERDRIVER2, "GetPrinterDriver2" },
100         { SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION, "FindNextPrinterChangeNotification" },
101         { SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION, "FindNextPrinterChangeNotification" },
102         { SPOOLSS_FCPN, "FCPN" },
103         { SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD, "RouterFindFirstPrinterNotificationOld" },
104         { SPOOLSS_REPLYOPENPRINTER, "ReplyOpenPrinter" },
105         { SPOOLSS_ROUTERREPLYPRINTER, "RouterReplyPrinter" },
106         { SPOOLSS_REPLYCLOSEPRINTER, "ReplyClosePrinter" },
107         { SPOOLSS_ADDPORTEX, "AddPortEx" },
108         { SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION, "RemoteFindFirstPrinterChangeNotification" },
109         { SPOOLSS_SPOOLERINIT, "SpoolerInit" },
110         { SPOOLSS_RESETPRINTEREX, "ResetPrinterEx" },
111         { SPOOLSS_RFFPCNEX, "RFFPCNEX" },
112         { SPOOLSS_RRPCN, "RRPCN" },
113         { SPOOLSS_RFNPCNEX, "RFNPCNEX" },
114         { SPOOLSS_OPENPRINTEREX, "OpenPrinterEx" },
115         { SPOOLSS_ADDPRINTEREX, "AddPrinterEx" },
116         { SPOOLSS_ENUMPRINTERDATA, "EnumPrinterData" },
117         { SPOOLSS_DELETEPRINTERDATA, "DeletePrinterData" },
118         { SPOOLSS_GETPRINTERDATAEX, "GetPrinterDataEx" },
119         { SPOOLSS_SETPRINTERDATAEX, "SetPrinterDataEx" },
120         { SPOOLSS_ENUMPRINTERDATAEX, "EnumPrinterDataEx" },
121         { SPOOLSS_ENUMPRINTERKEY, "EnumPrinterKey" },
122         { SPOOLSS_DELETEPRINTERDATAEX, "DeletePrinterDataEx" },
123         { SPOOLSS_DELETEPRINTERDRIVEREX, "DeletePrinterDriverEx" },
124         { SPOOLSS_ADDPRINTERDRIVEREX, "AddPrinterDriverEx" },
125         { 0, NULL }
126 };
127
128 static int hf_spoolss_hnd = -1;
129 static int hf_spoolss_rc = -1;
130 static int hf_spoolss_offered = -1;
131 static int hf_spoolss_needed = -1;
132 static int hf_spoolss_returned = -1;
133 static int hf_spoolss_buffer_size = -1;
134 static int hf_spoolss_buffer_data = -1;
135 static int hf_spoolss_relstr_offset = -1;
136 static int hf_spoolss_printername = -1;
137 static int hf_spoolss_servername = -1;
138 static int hf_spoolss_drivername = -1;
139 static int hf_spoolss_architecture = -1;
140 static int hf_spoolss_username = -1;
141 static int hf_spoolss_documentname = -1;
142 static int hf_spoolss_outputfile = -1;
143 static int hf_spoolss_datatype = -1;
144 static int hf_spoolss_textstatus = -1;
145 static int hf_spoolss_level = -1;
146 static int hf_access_required = -1;
147
148 /* Print job */
149
150 static int hf_spoolss_jobid = -1;
151 static int hf_spoolss_jobpriority = -1;
152 static int hf_spoolss_jobposition = -1;
153 static int hf_spoolss_jobtotalpages = -1;
154 static int hf_spoolss_jobpagesprinted = -1;
155 static int hf_spoolss_enumjobs_firstjob = -1;
156 static int hf_spoolss_enumjobs_numjobs = -1;
157
158 /* SYSTEM_TIME */
159
160 static int hf_spoolss_time_year = -1;
161 static int hf_spoolss_time_month = -1;
162 static int hf_spoolss_time_dow = -1;
163 static int hf_spoolss_time_day = -1;
164 static int hf_spoolss_time_hour = -1;
165 static int hf_spoolss_time_minute = -1;
166 static int hf_spoolss_time_second = -1;
167 static int hf_spoolss_time_msec = -1;
168
169 /* Printer data */
170
171 static int hf_spoolss_printerdata_value = -1;
172 static int hf_spoolss_printerdata_type = -1;
173
174 /* enumprinterdata */
175
176 static int hf_spoolss_enumprinterdata_index = -1;
177 static int hf_spoolss_enumprinterdata_value_offered = -1;
178 static int hf_spoolss_enumprinterdata_data_offered = -1;
179 static int hf_spoolss_enumprinterdata_value_needed = -1;
180 static int hf_spoolss_enumprinterdata_data_needed = -1;
181
182 /* SetJob */
183
184 static int hf_spoolss_setjob_cmd = -1;
185
186 /* WritePrinter */
187
188 static int hf_spoolss_writeprinter_numwritten = -1;
189
190 /* GetPrinterDriver2 */
191
192 static int hf_spoolss_clientmajorversion = -1;
193 static int hf_spoolss_clientminorversion = -1;
194 static int hf_spoolss_servermajorversion = -1;
195 static int hf_spoolss_serverminorversion = -1;
196 static int hf_spoolss_driverpath = -1;
197 static int hf_spoolss_datafile = -1;
198 static int hf_spoolss_configfile = -1;
199 static int hf_spoolss_helpfile = -1;
200 static int hf_spoolss_monitorname = -1;
201 static int hf_spoolss_defaultdatatype = -1;
202 static int hf_spoolss_driverinfo_cversion = -1;
203 static int hf_spoolss_dependentfiles = -1;
204 static int hf_spoolss_printer_status = -1;
205
206 /* rffpcnex */
207
208 static int hf_spoolss_rffpcnex_flags = -1;
209 static int hf_spoolss_rffpcnex_options = -1;
210 static int hf_spoolss_printerlocal = -1;
211 static int hf_spoolss_notify_options_version = -1;
212 static int hf_spoolss_notify_options_flags = -1;
213 static int hf_spoolss_notify_options_flags_refresh = -1;
214 static int hf_spoolss_notify_options_count = -1;
215 static int hf_spoolss_notify_option_type = -1;
216 static int hf_spoolss_notify_option_reserved1 = -1;
217 static int hf_spoolss_notify_option_reserved2 = -1;
218 static int hf_spoolss_notify_option_reserved3 = -1;
219 static int hf_spoolss_notify_option_count = -1;
220 static int hf_spoolss_notify_option_data_count = -1;
221 static int hf_spoolss_notify_info_count = -1;
222 static int hf_spoolss_notify_info_version = -1;
223 static int hf_spoolss_notify_info_flags = -1;
224 static int hf_spoolss_notify_info_data_type = -1;
225 static int hf_spoolss_notify_info_data_count = -1;
226 static int hf_spoolss_notify_info_data_id = -1;
227 static int hf_spoolss_notify_info_data_value1 = -1;
228 static int hf_spoolss_notify_info_data_value2 = -1;
229 static int hf_spoolss_notify_info_data_bufsize = -1;
230 static int hf_spoolss_notify_info_data_buffer = -1;
231 static int hf_spoolss_notify_info_data_buffer_len = -1;
232 static int hf_spoolss_notify_info_data_buffer_data = -1;
233
234 static int hf_spoolss_notify_field = -1;
235
236 static int hf_spoolss_rrpcn_changelow = -1;
237 static int hf_spoolss_rrpcn_changehigh = -1;
238 static int hf_spoolss_rrpcn_unk0 = -1;
239 static int hf_spoolss_rrpcn_unk1 = -1;
240
241 static int hf_spoolss_replyopenprinter_unk0 = -1;
242 static int hf_spoolss_replyopenprinter_unk1 = -1;
243
244 static const value_string printer_status_vals[] =
245 {
246         { PRINTER_STATUS_OK, "OK" },
247         { PRINTER_STATUS_PAUSED, "Paused" },
248         { PRINTER_STATUS_ERROR, "Error" },
249         { PRINTER_STATUS_PENDING_DELETION, "Pending deletion" },
250         { PRINTER_STATUS_PAPER_JAM, "Paper jam" },
251         { PRINTER_STATUS_PAPER_OUT, "Paper out" },
252         { PRINTER_STATUS_MANUAL_FEED, "Manual feed" },
253         { PRINTER_STATUS_PAPER_PROBLEM, "Paper problem" },
254         { PRINTER_STATUS_OFFLINE, "Offline" },
255         { PRINTER_STATUS_IO_ACTIVE, "IO active" },
256         { PRINTER_STATUS_BUSY, "Busy" },
257         { PRINTER_STATUS_PRINTING, "Printing" },
258         { PRINTER_STATUS_OUTPUT_BIN_FULL, "Output bin full" },
259         { PRINTER_STATUS_NOT_AVAILABLE, "Not available" },
260         { PRINTER_STATUS_WAITING, "Waiting" },
261         { PRINTER_STATUS_PROCESSING, "Processing" },
262         { PRINTER_STATUS_INITIALIZING, "Initialising" },
263         { PRINTER_STATUS_WARMING_UP, "Warming up" },
264         { PRINTER_STATUS_TONER_LOW, "Toner low" },
265         { PRINTER_STATUS_NO_TONER, "No toner" },
266         { PRINTER_STATUS_PAGE_PUNT, "Page punt" },
267         { PRINTER_STATUS_USER_INTERVENTION, "User intervention" },
268         { PRINTER_STATUS_OUT_OF_MEMORY, "Out of memory" },
269         { PRINTER_STATUS_DOOR_OPEN, "Door open" },
270         { PRINTER_STATUS_SERVER_UNKNOWN, "Server unknown" },
271         { PRINTER_STATUS_POWER_SAVE, "Power save" },
272         { 0, NULL }
273 };
274
275 /* Printer attributes */
276
277 static int hf_spoolss_printer_attributes = -1;
278 static int hf_spoolss_printer_attributes_queued = -1;
279 static int hf_spoolss_printer_attributes_direct = -1;
280 static int hf_spoolss_printer_attributes_default = -1;
281 static int hf_spoolss_printer_attributes_shared = -1;
282 static int hf_spoolss_printer_attributes_network = -1;
283 static int hf_spoolss_printer_attributes_hidden = -1;
284 static int hf_spoolss_printer_attributes_local = -1;
285 static int hf_spoolss_printer_attributes_enable_devq = -1;
286 static int hf_spoolss_printer_attributes_keep_printed_jobs = -1;
287 static int hf_spoolss_printer_attributes_do_complete_first = -1;
288 static int hf_spoolss_printer_attributes_work_offline = -1;
289 static int hf_spoolss_printer_attributes_enable_bidi = -1;
290 static int hf_spoolss_printer_attributes_raw_only = -1;
291 static int hf_spoolss_printer_attributes_published = -1;
292
293 static const true_false_string tfs_printer_attributes_queued = {
294         "Printer starts printing after last page spooled",
295         "Printer starts printing while spooling"
296 };
297
298 static const true_false_string tfs_printer_attributes_direct = {
299         "Jobs sent directly to printer",
300         "Jobs are spooled to printer before printing"
301 };
302
303 static const true_false_string tfs_printer_attributes_default = {
304         "Printer is the default printer",
305         "Printer is not the default printer"
306 };
307
308 static const true_false_string tfs_printer_attributes_shared = {
309         "Printer is shared",
310         "Printer is not shared"
311 };
312
313 static const true_false_string tfs_printer_attributes_network = {
314         "Printer is a network printer connection",
315         "Printer is not a network printer connection"
316 };
317
318 static const true_false_string tfs_printer_attributes_hidden = {
319         "Reserved",
320         "Reserved"
321 };
322
323 static const true_false_string tfs_printer_attributes_local = {
324         "Printer is a local printer",
325         "Printer is not a local printer"
326 };
327
328 static const true_false_string tfs_printer_attributes_enable_devq = {
329         "Call DevQueryPrint",
330         "Do not call DevQueryPrint"
331 };
332
333 static const true_false_string tfs_printer_attributes_keep_printed_jobs = {
334         "Jobs are kept after they are printed",
335         "Jobs are deleted after printing"
336 };
337
338 static const true_false_string tfs_printer_attributes_do_complete_first = {
339         "Jobs that have completed spooling are scheduled before still spooling jobs",
340         "Jobs are scheduled in the order they start spooling"
341 };
342
343 static const true_false_string tfs_printer_attributes_work_offline = {
344         "The printer is currently connected",
345         "The printer is currently not connected"
346 };
347
348 static const true_false_string tfs_printer_attributes_enable_bidi = {
349         "Bidirectional communications are supported",
350         "Bidirectional communications are not supported"
351 };
352
353 static const true_false_string tfs_printer_attributes_raw_only = {
354         "Only raw data type print jobs can be spooled",
355         "All data type print jobs can be spooled"
356 };
357
358 static const true_false_string tfs_printer_attributes_published = {
359         "Printer is published in the directory",
360         "Printer is not published in the directory"
361 };
362
363 static int hf_spoolss_job_status = -1;
364 static int hf_spoolss_job_status_paused = -1;
365 static int hf_spoolss_job_status_error = -1;
366 static int hf_spoolss_job_status_deleting = -1;
367 static int hf_spoolss_job_status_spooling = -1;
368 static int hf_spoolss_job_status_printing = -1;
369 static int hf_spoolss_job_status_offline = -1;
370 static int hf_spoolss_job_status_paperout = -1;
371 static int hf_spoolss_job_status_printed = -1;
372 static int hf_spoolss_job_status_deleted = -1;
373 static int hf_spoolss_job_status_blocked = -1;
374 static int hf_spoolss_job_status_user_intervention = -1;
375
376 static const true_false_string tfs_job_status_paused = {
377         "Job is paused",
378         "Job is not paused"
379 };
380
381 static const true_false_string tfs_job_status_error = {
382         "Job has an error",
383         "Job is OK"
384 };
385
386 static const true_false_string tfs_job_status_deleting = {
387         "Job is being deleted",
388         "Job is not being deleted"
389 };
390
391 static const true_false_string tfs_job_status_spooling = {
392         "Job is being spooled",
393         "Job is not being spooled"
394 };
395
396 static const true_false_string tfs_job_status_printing = {
397         "Job is being printed",
398         "Job is not being printed"
399 };
400
401 static const true_false_string tfs_job_status_offline = {
402         "Job is offline",
403         "Job is not offline"
404 };
405
406 static const true_false_string tfs_job_status_paperout = {
407         "Job is out of paper",
408         "Job is not out of paper"
409 };
410
411 static const true_false_string tfs_job_status_printed = {
412         "Job has completed printing",
413         "Job has not completed printing"
414 };
415
416 static const true_false_string tfs_job_status_deleted = {
417         "Job has been deleted",
418         "Job has not been deleted"
419 };
420
421 static const true_false_string tfs_job_status_blocked = {
422         "Job has been blocked",
423         "Job has not been blocked"
424 };
425
426 static const true_false_string tfs_job_status_user_intervention = {
427         "User intervention required",
428         "User intervention not required"
429 };
430
431 /* Setprinter RPC */
432
433 static int hf_spoolss_setprinter_cmd = -1;
434
435 static const value_string setprinter_cmd_vals[] = {
436         { SPOOLSS_PRINTER_CONTROL_UNPAUSE, "Unpause" },
437         { SPOOLSS_PRINTER_CONTROL_PAUSE, "Pause" },
438         { SPOOLSS_PRINTER_CONTROL_RESUME, "Resume" },
439         { SPOOLSS_PRINTER_CONTROL_PURGE, "Purge" },
440         { SPOOLSS_PRINTER_CONTROL_SET_STATUS, "Set status" },
441         { 0, NULL }
442 };
443
444 /* RouterReplyPrinter RPC */
445
446 static int hf_spoolss_routerreplyprinter_condition = -1;
447 static int hf_spoolss_routerreplyprinter_unknown1 = -1;
448 static int hf_spoolss_routerreplyprinter_changeid = -1;
449
450 /* Forms */
451
452 static int hf_spoolss_form_level = -1;
453 static int hf_spoolss_form_name = -1;
454 static int hf_spoolss_form_flags = -1;
455 static int hf_spoolss_form_unknown = -1;
456 static int hf_spoolss_form_width = -1;
457 static int hf_spoolss_form_height = -1;
458 static int hf_spoolss_form_left_margin = -1;
459 static int hf_spoolss_form_top_margin = -1;
460 static int hf_spoolss_form_horiz_len = -1;
461 static int hf_spoolss_form_vert_len = -1;
462
463 /* AddForm RPC */
464
465 static int hf_spoolss_addform_level = -1;
466
467 /* GetForm RPC */
468
469 static int hf_spoolss_getform_level = -1;
470
471 /* SetForm RPC */
472
473 static int hf_spoolss_setform_level = -1;
474
475 /* EnumForms RPC */
476
477 static int hf_spoolss_enumforms_num = -1;
478
479 /* Printerdata */
480
481 static int hf_spoolss_printerdata_size = -1;
482 static int hf_spoolss_printerdata_data = -1;
483
484 /*
485  * Dissect SPOOLSS specific access rights
486  */
487
488 static int hf_server_access_admin = -1;
489 static int hf_server_access_enum = -1;
490 static int hf_printer_access_admin = -1;
491 static int hf_printer_access_use = -1;
492 static int hf_job_access_admin = -1;
493
494 static void
495 spoolss_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree,
496                         guint32 access)
497 {
498         proto_tree_add_boolean(
499                 tree, hf_job_access_admin,
500                 tvb, offset, 4, access);
501
502         proto_tree_add_boolean(
503                 tree, hf_printer_access_use,
504                 tvb, offset, 4, access);
505
506         proto_tree_add_boolean(
507                 tree, hf_printer_access_admin,
508                 tvb, offset, 4, access);
509
510         proto_tree_add_boolean(
511                 tree, hf_server_access_enum,
512                 tvb, offset, 4, access);
513
514         proto_tree_add_boolean(
515                 tree, hf_server_access_admin,
516                 tvb, offset, 4, access);
517 }
518
519 /*
520  * Routines to dissect a spoolss BUFFER
521  */
522
523 typedef struct {
524         guint32 size;           /* Size of buffer */
525         guint8 *data;           /* Contents of buffer */
526         int offset;             /* Offset to start of buffer */
527         proto_item *tree;       /* Proto tree buffer located in */
528 } BUFFER;
529
530 static int
531 dissect_spoolss_buffer_data(tvbuff_t *tvb, int offset, packet_info *pinfo,
532                             proto_tree *tree, char *drep)
533 {
534         dcerpc_info *di = pinfo->private_data;
535         BUFFER *b = (BUFFER *)di->private_data;
536         guint32 size;
537         guint8 *data;
538
539         if (di->conformant_run)
540                 return offset;
541
542         /* Dissect size and data */
543
544         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
545                                     hf_spoolss_buffer_size, &size);
546
547         offset = dissect_ndr_uint8s(tvb, offset, pinfo, tree, drep,
548                                     hf_spoolss_buffer_data, size, &data);
549
550         /* Return buffer info */
551
552         if (b) {
553                 b->size = size;
554                 b->data = data;
555                 b->offset = offset - size;
556                 b->tree = tree;
557         }
558
559         return offset;
560 }
561
562 /* Dissect a spoolss buffer and return buffer data */
563
564 static int
565 dissect_spoolss_buffer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
566                        proto_tree *tree, char *drep, BUFFER *b)
567 {
568         dcerpc_info *di = pinfo->private_data;
569
570         if (b)
571                 memset(b, 0, sizeof(BUFFER));
572
573         di->private_data = b;
574
575         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
576                                      dissect_spoolss_buffer_data,
577                                      NDR_POINTER_UNIQUE, "Buffer",
578                                      -1, 0);
579
580         return offset;
581 }
582
583 /*
584  * New system for handling pointers and buffers.  We act more like the NDR
585  * specification and have a list of deferred pointers which are processed
586  * after a structure has been parsed.
587  *
588  * Each structure has a parse function which takes as an argument a GList.
589  * As pointers are processed, they are appended onto this list.  When the
590  * structure is complete, the pointers (referents) are processed by calling
591  * prs_referents().  In the case of function arguments, the
592  * prs_struct_and_referents() function is called as pointers are always
593  * processed immediately after the argument.
594  */
595
596 typedef int prs_fn(tvbuff_t *tvb, int offset, packet_info *pinfo,
597                    proto_tree *tree, GList **dp_list, void **data);
598
599 /* Deferred referent */
600
601 struct deferred_ptr {
602         prs_fn *fn;             /* Parse function to call */
603         proto_tree *tree;       /* Tree context */
604 };
605
606 /* A structure to hold needed ethereal state to pass to GList foreach
607    iterator. */
608
609 struct deferred_ptr_state {
610         tvbuff_t *tvb;
611         int *poffset;
612         packet_info *pinfo;
613         GList **dp_list;
614         void **ptr_data;
615 };
616
617 static void defer_ptr(GList **list, prs_fn *fn, proto_tree *tree)
618 {
619         struct deferred_ptr *dr;
620
621         dr = g_malloc(sizeof(struct deferred_ptr));
622
623         dr->fn = fn;
624         dr->tree = tree;
625
626         *list = g_list_append(*list, dr);
627 }
628
629 /* Parse a pointer */
630
631 static int prs_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
632                    proto_tree *tree, guint32 *data, char *name)
633 {
634         guint32 ptr;
635
636         offset = prs_uint32(tvb, offset, pinfo, tree, &ptr, NULL);
637
638         if (tree && name)
639                 proto_tree_add_text(tree, tvb, offset - 4, 4,
640                                     "%s pointer: 0x%08x", name, ptr);
641
642         if (data)
643                 *data = ptr;
644
645         return offset;
646 }
647
648 /* Iterator function for prs_referents */
649
650 static void dr_iterator(gpointer data, gpointer user_data)
651 {
652         struct deferred_ptr *dp = (struct deferred_ptr *)data;
653         struct deferred_ptr_state *s = (struct deferred_ptr_state *)user_data;
654
655         /* Parse pointer */
656
657         *s->poffset = dp->fn(s->tvb, *s->poffset, s->pinfo, dp->tree,
658                              s->dp_list, s->ptr_data);
659
660         if (s->ptr_data)
661                 s->ptr_data++;          /* Ready for next parse fn */
662 }
663
664 /* Call the parse function for each element in the deferred pointers list.
665    If there are any additional pointers in these structures they are pushed
666    onto parent_dp_list. */
667
668 static int prs_referents(tvbuff_t *tvb, int offset, packet_info *pinfo,
669                   proto_tree *tree _U_, GList **dp_list, GList **list,
670                   void ***ptr_data)
671 {
672         struct deferred_ptr_state s;
673         int new_offset = offset;
674
675         /* Create a list of void pointers to store return data */
676
677         if (ptr_data) {
678                 int len = g_list_length(*dp_list) * sizeof(void *);
679
680                 if (len > 0) {
681                         *ptr_data = malloc(len);
682                         memset(*ptr_data, 0, len);
683                 } else
684                         *ptr_data = NULL;
685         }
686
687         /* Set up iterator data */
688
689         s.tvb = tvb;
690         s.poffset = &new_offset;
691         s.pinfo = pinfo;
692         s.dp_list = dp_list;
693         s.ptr_data = ptr_data ? *ptr_data : NULL;
694
695         g_list_foreach(*list, dr_iterator, &s);
696
697         *list = NULL;           /* XXX: free list */
698
699         return new_offset;
700 }
701
702 /* Parse a structure then clean up any deferred referants it creates. */
703
704 static int prs_struct_and_referents(tvbuff_t *tvb, int offset,
705                                     packet_info *pinfo, proto_tree *tree,
706                                     prs_fn *fn, void **data, void ***ptr_data)
707 {
708         GList *dp_list = NULL;
709
710         offset = fn(tvb, offset, pinfo, tree, &dp_list, data);
711
712         offset = prs_referents(tvb, offset, pinfo, tree, &dp_list,
713                                &dp_list, ptr_data);
714
715         return offset;
716 }
717
718 /*
719  * SpoolssClosePrinter
720  */
721
722 static int SpoolssClosePrinter_q(tvbuff_t *tvb, int offset,
723                                  packet_info *pinfo, proto_tree *tree,
724                                  char *drep _U_)
725 {
726         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
727         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
728         e_ctx_hnd policy_hnd;
729         char *pol_name;
730
731         if (dcv->rep_frame != 0)
732                 proto_tree_add_text(tree, tvb, offset, 0,
733                                     "Reply in frame %u", dcv->rep_frame);
734         /* Parse packet */
735
736         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
737                                        hf_spoolss_hnd, &policy_hnd,
738                                        FALSE, TRUE);
739
740         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
741
742         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
743                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
744                                 pol_name);
745
746         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
747
748         return offset;
749 }
750
751 static int SpoolssClosePrinter_r(tvbuff_t *tvb, int offset,
752                                  packet_info *pinfo, proto_tree *tree,
753                                  char *drep _U_)
754 {
755         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
756         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
757
758         if (dcv->req_frame != 0)
759                 proto_tree_add_text(tree, tvb, offset, 0,
760                                     "Request in frame %u", dcv->req_frame);
761
762         /* Parse packet */
763
764         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
765                                        hf_spoolss_hnd, NULL,
766                                        FALSE, FALSE);
767
768
769         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
770                                   hf_spoolss_rc, NULL);
771
772         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
773
774         return offset;
775 }
776
777 /* Parse a UNISTR2 structure */
778
779 static gint ett_UNISTR2 = -1;
780
781 static int prs_UNISTR2_dp(tvbuff_t *tvb, int offset, packet_info *pinfo,
782                           proto_tree *tree, GList **dp_list _U_, void **data)
783 {
784         proto_item *item;
785         proto_tree *subtree;
786         guint32 length, the_offset, max_len;
787         int old_offset = offset;
788         int data16_offset;
789         char *text;
790
791         offset = prs_uint32(tvb, offset, pinfo, tree, &length, NULL);
792         offset = prs_uint32(tvb, offset, pinfo, tree, &the_offset, NULL);
793         offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, NULL);
794
795         offset = prs_uint16s(tvb, offset, pinfo, tree, max_len, &data16_offset,
796                              NULL);
797
798         text = fake_unicode(tvb, data16_offset, max_len);
799
800         item = proto_tree_add_text(tree, tvb, old_offset, offset - old_offset,
801                                    "UNISTR2: %s", text);
802
803         subtree = proto_item_add_subtree(item, ett_UNISTR2);
804
805         if (data)
806                 *data = text;
807         else
808                 g_free(text);
809
810         proto_tree_add_text(subtree, tvb, old_offset, 4, "Length: %u", length);
811
812         old_offset += 4;
813
814         proto_tree_add_text(subtree, tvb, old_offset, 4, "Offset: %u",
815                             the_offset);
816
817         old_offset += 4;
818
819         proto_tree_add_text(subtree, tvb, old_offset, 4, "Max length: %u",
820                             max_len);
821
822         old_offset += 4;
823
824         proto_tree_add_text(subtree, tvb, old_offset, max_len * 2, "Data");
825
826         return offset;
827 }
828
829 /* Dissect some printer data.  The get/set/enum printerdata routines all
830    store value/data in a uint8 array.  We could use the ndr routines for
831    this but that would result in one item for each byte in the printer
832    data. */
833
834 static gint ett_printerdata_data = -1;
835 static gint ett_printerdata_value = -1;
836
837 static int dissect_printerdata_data(tvbuff_t *tvb, int offset,
838                                     packet_info *pinfo, proto_tree *tree,
839                                     char *drep _U_)
840 {
841         proto_item *item;
842         proto_tree *subtree;
843         guint32 size;
844
845         item = proto_tree_add_text(tree, tvb, offset, 0, "Printer data");
846         subtree = proto_item_add_subtree(item, ett_printerdata_data);
847
848         offset = dissect_ndr_uint32(
849                 tvb, offset, pinfo, subtree, drep,
850                 hf_spoolss_printerdata_size, &size);
851
852         offset = dissect_ndr_uint8s(
853                 tvb, offset, pinfo, subtree, drep,
854                 hf_spoolss_printerdata_data, size, NULL);
855
856         proto_item_set_len(item, size + 4);
857
858         return offset;
859 }
860
861 /*
862  * SpoolssGetPrinterData
863  */
864
865 static int SpoolssGetPrinterData_q(tvbuff_t *tvb, int offset,
866                                    packet_info *pinfo, proto_tree *tree,
867                                    char *drep _U_)
868 {
869         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
870         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
871         char *value_name = NULL;
872
873         if (dcv->rep_frame != 0)
874                 proto_tree_add_text(tree, tvb, offset, 0,
875                                     "Reply in frame %u", dcv->rep_frame);
876
877         /* Parse packet */
878
879         offset = dissect_nt_policy_hnd(
880                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
881                 FALSE, FALSE);
882
883         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
884                                           prs_UNISTR2_dp, (void **)&value_name,
885                                           NULL);
886
887         if (check_col(pinfo->cinfo, COL_INFO))
888                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
889
890         g_free(value_name);
891
892         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
893                                     hf_spoolss_offered, NULL);
894
895         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
896
897         return offset;
898 }
899
900 static int SpoolssGetPrinterData_r(tvbuff_t *tvb, int offset,
901                                    packet_info *pinfo, proto_tree *tree,
902                                    char *drep _U_)
903 {
904         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
905         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
906
907         if (dcv->req_frame != 0)
908                 proto_tree_add_text(tree, tvb, offset, 0,
909                                     "Request in frame %u", dcv->req_frame);
910
911         /* Parse packet */
912
913         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
914                                     hf_spoolss_printerdata_type, NULL);
915
916         offset = dissect_printerdata_data(tvb, offset, pinfo, tree, drep);
917
918         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
919
920         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
921                                   hf_spoolss_rc, NULL);
922
923         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
924
925         return offset;
926 }
927
928 /*
929  * SpoolssGetPrinterDataEx
930  */
931
932 static int SpoolssGetPrinterDataEx_q(tvbuff_t *tvb, int offset,
933                                      packet_info *pinfo, proto_tree *tree,
934                                      char *drep _U_)
935 {
936         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
937         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
938         char *key_name, *value_name;
939
940         if (dcv->rep_frame != 0)
941                 proto_tree_add_text(tree, tvb, offset, 0,
942                                     "Reply in frame %u", dcv->rep_frame);
943
944         /* Parse packet */
945
946         offset = dissect_nt_policy_hnd(
947                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
948                 FALSE, FALSE);
949
950         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
951                                           prs_UNISTR2_dp, (void **)&key_name,
952                                           NULL);
953
954         /*
955          * Register a cleanup function in case on of our tvbuff accesses
956          * throws an exception. We need to clean up key_name.
957          */
958         CLEANUP_PUSH(g_free, key_name);
959
960         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
961                                           prs_UNISTR2_dp, (void **)&value_name,
962                                           NULL);
963
964         if (check_col(pinfo->cinfo, COL_INFO))
965                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s",
966                                 key_name, value_name);
967
968         /*
969          * We're done with key_name, so we can call the cleanup handler to
970          * free it, and then pop the cleanup handler.
971          */
972         CLEANUP_CALL_AND_POP;
973
974         /*
975          * We're also done with value_name.
976          */
977         g_free(value_name);
978
979         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Size");
980
981         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
982
983         return offset;
984 }
985
986 static int SpoolssGetPrinterDataEx_r(tvbuff_t *tvb, int offset,
987                                      packet_info *pinfo, proto_tree *tree,
988                                      char *drep _U_)
989 {
990         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
991         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
992         guint32 size;
993
994         if (dcv->req_frame != 0)
995                 proto_tree_add_text(tree, tvb, offset, 0,
996                                     "Request in frame %u", dcv->req_frame);
997
998         /* Parse packet */
999
1000         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1001                                     hf_spoolss_printerdata_type, NULL);
1002
1003         offset = prs_uint32(tvb, offset, pinfo, tree, &size, "Size");
1004
1005         offset = prs_uint8s(tvb, offset, pinfo, tree, size, NULL, "Data");
1006
1007         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
1008
1009         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
1010                                   hf_spoolss_rc, NULL);
1011
1012         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1013
1014         return offset;
1015 }
1016
1017 /*
1018  * SpoolssSetPrinterData
1019  */
1020
1021 static int SpoolssSetPrinterData_q(tvbuff_t *tvb, int offset,
1022                                    packet_info *pinfo, proto_tree *tree,
1023                                    char *drep _U_)
1024 {
1025         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1026         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1027         char *value_name = NULL;
1028
1029         if (dcv->rep_frame != 0)
1030                 proto_tree_add_text(tree, tvb, offset, 0,
1031                                     "Reply in frame %u", dcv->rep_frame);
1032
1033         /* Parse packet */
1034
1035         offset = dissect_nt_policy_hnd(
1036                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
1037                 FALSE, FALSE);
1038
1039         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1040                                           prs_UNISTR2_dp, (void **)&value_name,
1041                                           NULL);
1042
1043         if (check_col(pinfo->cinfo, COL_INFO))
1044                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
1045
1046         g_free(value_name);
1047
1048         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1049                                     hf_spoolss_printerdata_type, NULL);
1050
1051         offset = dissect_printerdata_data(tvb, offset, pinfo, tree, drep);
1052
1053         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
1054
1055         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1056
1057         return offset;
1058 }
1059
1060 static int SpoolssSetPrinterData_r(tvbuff_t *tvb, int offset,
1061                                    packet_info *pinfo, proto_tree *tree,
1062                                    char *drep _U_)
1063 {
1064         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1065         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1066
1067         if (dcv->req_frame != 0)
1068                 proto_tree_add_text(tree, tvb, offset, 0,
1069                                     "Request in frame %u", dcv->req_frame);
1070
1071         /* Parse packet */
1072
1073         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
1074                                   hf_spoolss_rc, NULL);
1075
1076         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1077
1078         return offset;
1079 }
1080
1081 /*
1082  * SpoolssSetPrinterDataEx
1083  */
1084
1085 static int SpoolssSetPrinterDataEx_q(tvbuff_t *tvb, int offset,
1086                                      packet_info *pinfo, proto_tree *tree,
1087                                      char *drep _U_)
1088 {
1089         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1090         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1091         char *key_name, *value_name;
1092         guint32 max_len;
1093
1094         if (dcv->rep_frame != 0)
1095                 proto_tree_add_text(tree, tvb, offset, 0,
1096                                     "Reply in frame %u", dcv->rep_frame);
1097
1098         /* Parse packet */
1099
1100         offset = dissect_nt_policy_hnd(
1101                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
1102                 FALSE, FALSE);
1103
1104         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1105                                           prs_UNISTR2_dp, (void **)&key_name,
1106                                           NULL);
1107
1108         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1109                                           prs_UNISTR2_dp, (void **)&value_name,
1110                                           NULL);
1111
1112         if (check_col(pinfo->cinfo, COL_INFO))
1113                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s",
1114                                 key_name, value_name);
1115
1116         g_free(key_name);
1117         g_free(value_name);
1118
1119         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1120                                     hf_spoolss_printerdata_type, NULL);
1121
1122         offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, "Max length");
1123
1124         offset = prs_uint8s(tvb, offset, pinfo, tree, max_len, NULL,
1125                             "Data");
1126
1127         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real length");
1128
1129         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1130
1131         return offset;
1132 }
1133
1134 static int SpoolssSetPrinterDataEx_r(tvbuff_t *tvb, int offset,
1135                                      packet_info *pinfo, proto_tree *tree,
1136                                      char *drep _U_)
1137 {
1138         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1139         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1140
1141         if (dcv->req_frame != 0)
1142                 proto_tree_add_text(tree, tvb, offset, 0,
1143                                     "Request in frame %u", dcv->req_frame);
1144
1145         /* Parse packet */
1146
1147         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
1148                                   hf_spoolss_rc, NULL);
1149
1150         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1151
1152         return offset;
1153 }
1154
1155 /* Yet another way to represent a unicode string - sheesh. This function
1156    dissects a NULL terminate unicode string at the current offset and
1157    returns the (char *) equivalent.  This really should return UTF8 or
1158    something but we use fake_unicode() instead. */
1159
1160 static int
1161 dissect_spoolss_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1162                           proto_tree *tree, char *drep _U_, char **data)
1163 {
1164         gint len, remaining;
1165         char *text;
1166
1167         if (offset % 2)
1168                 offset += 2 - (offset % 2);
1169
1170         /* Get remaining data in buffer as a string */
1171
1172         remaining = tvb_length_remaining(tvb, offset) / 2;
1173         text = fake_unicode(tvb, offset, remaining);
1174         len = strlen(text);
1175
1176         proto_tree_add_text(tree, tvb, offset, len * 2, "%s: %s",
1177                             "UINT16UNI", tvb_bytes_to_str(tvb, offset, len * 2));
1178
1179         if (data)
1180                 *data = text;
1181         else
1182                 g_free(text);
1183
1184         return offset + (len + 1) * 2;
1185 }
1186
1187 static int prs_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1188                          proto_tree *tree, void **data, char *name)
1189 {
1190         gint len = 0, remaining;
1191         char *text;
1192
1193         offset = prs_align(offset, 2);
1194
1195         /* Get remaining data in buffer as a string */
1196
1197         remaining = tvb_length_remaining(tvb, offset)/2;
1198         text = fake_unicode(tvb, offset, remaining);
1199         len = strlen(text);
1200
1201         if (name)
1202                 proto_tree_add_text(tree, tvb, offset, (len + 1) * 2,
1203                                     "%s: %s", name ? name : "UINT16UNI",
1204                                     text);
1205
1206         if (data)
1207                 *data = text;
1208         else
1209                 g_free(text);
1210
1211         return offset + (len + 1) * 2;
1212 }
1213
1214 /*
1215  * DEVMODE
1216  */
1217
1218 static gint ett_DEVMODE = -1;
1219
1220 static int prs_DEVMODE(tvbuff_t *tvb, int offset, packet_info *pinfo,
1221                        proto_tree *tree, GList **dp_list _U_, void **data _U_)
1222 {
1223         proto_item *item;
1224         proto_tree *subtree;
1225         guint16 extra;
1226
1227         item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE");
1228
1229         subtree = proto_item_add_subtree(item, ett_DEVMODE);
1230
1231         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1232
1233         /* The device name is stored in a 32-wchar buffer */
1234
1235         prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Devicename");
1236         offset += 64;
1237
1238         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Spec version");
1239         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Driver version");
1240         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Size");
1241         offset = prs_uint16(tvb, offset, pinfo, subtree, &extra, "Driver extra");
1242
1243         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Fields");
1244
1245         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Orientation");
1246         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper size");
1247         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper length");
1248         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper width");
1249         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Scale");
1250         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Copies");
1251         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Default source");
1252         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Print quality");
1253         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Color");
1254         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Duplex");
1255         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Y resolution");
1256         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "TT option");
1257         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Collate");
1258
1259         prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Form name");
1260         offset += 64;
1261
1262         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Log pixels");
1263
1264         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Bits per pel");
1265         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pels width");
1266         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pels height");
1267         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Display flags");
1268         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Display frequency");
1269         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "ICM method");
1270         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "ICM intent");
1271         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Media type");
1272         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Dither type");
1273         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
1274         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
1275         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Panning width");
1276         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Panning height");
1277
1278         if (extra != 0)
1279                 offset = prs_uint8s(tvb, offset, pinfo, subtree, extra, NULL,
1280                                     "Private");
1281
1282         return offset;
1283 }
1284
1285 /*
1286  * Relative string given by offset into the current buffer.  Note that
1287  * the offset for subsequent relstrs are against the structure start, not
1288  * the point where the offset is parsed from.
1289  */
1290
1291 static gint ett_RELSTR = -1;
1292
1293 static int
1294 dissect_spoolss_relstr(tvbuff_t *tvb, int offset, packet_info *pinfo,
1295                        proto_tree *tree, char *drep, int hf_index,
1296                        int struct_start, char **data)
1297 {
1298         proto_item *item;
1299         proto_tree *subtree;
1300         guint32 relstr_offset, relstr_start, relstr_end, relstr_len;
1301         char *text;
1302
1303         item = proto_tree_add_string(tree, hf_index, tvb, offset, 4, "");
1304
1305         subtree = proto_item_add_subtree(item, ett_RELSTR);
1306
1307         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
1308                                     hf_spoolss_relstr_offset,
1309                                     &relstr_offset);
1310
1311         /* A relative offset of zero is a NULL string */
1312
1313         relstr_start = relstr_offset + struct_start;
1314
1315         if (relstr_offset)
1316                 relstr_end = dissect_spoolss_uint16uni(
1317                         tvb, relstr_start, pinfo, subtree, drep, &text);
1318         else {
1319                 text = g_strdup("NULL");
1320                 relstr_end = offset;
1321         }
1322
1323         relstr_len = relstr_end - relstr_start;
1324
1325         proto_item_append_text(item, text);
1326
1327         if (data)
1328                 *data = text;
1329         else
1330                 g_free(text);
1331
1332         return offset;
1333 }
1334
1335 /* An array of relative strings.  This is currently just a copy of the
1336    dissect_spoolss_relstr() function as I can't find an example driver that
1337    has more than one dependent file. */
1338
1339 static gint ett_RELSTR_ARRAY = -1;
1340
1341 static int
1342 dissect_spoolss_relstrarray(tvbuff_t *tvb, int offset, packet_info *pinfo,
1343                             proto_tree *tree, char *drep, int hf_index,
1344                             int struct_start, char **data)
1345 {
1346         proto_item *item;
1347         proto_tree *subtree;
1348         guint32 relstr_offset, relstr_start, relstr_end, relstr_len;
1349         char *text;
1350
1351         item = proto_tree_add_string(tree, hf_index, tvb, offset, 4, "");
1352
1353         subtree = proto_item_add_subtree(item, ett_RELSTR_ARRAY);
1354
1355         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
1356                                     hf_spoolss_relstr_offset,
1357                                     &relstr_offset);
1358
1359         /* A relative offset of zero is a NULL string */
1360
1361         relstr_start = relstr_offset + struct_start;
1362
1363         if (relstr_offset)
1364                 relstr_end = dissect_spoolss_uint16uni(
1365                         tvb, relstr_start, pinfo, subtree, drep, &text);
1366         else {
1367                 text = g_strdup("NULL");
1368                 relstr_end = offset;
1369         }
1370
1371         relstr_len = relstr_end - relstr_start;
1372
1373         proto_item_append_text(item, text);
1374
1375         if (data)
1376                 *data = text;
1377         else
1378                 g_free(text);
1379
1380         return offset;
1381 }
1382
1383 static int prs_relstr(tvbuff_t *tvb, int offset, packet_info *pinfo,
1384                       proto_tree *tree, GList **dp_list _U_, int struct_start,
1385                       void **data, char *name)
1386 {
1387         proto_item *item;
1388         proto_tree *subtree;
1389         guint32 relstr_offset, relstr_start, relstr_end;
1390         char *text = strdup("NULL");
1391
1392         offset = prs_uint32(tvb, offset, pinfo, tree, &relstr_offset, NULL);
1393
1394         /* A relative offset of zero is a NULL string */
1395
1396         relstr_start = relstr_offset + struct_start;
1397
1398         if (relstr_offset)
1399                 relstr_end = prs_uint16uni(tvb, relstr_start, pinfo, tree,
1400                                            (void **)&text, NULL);
1401         else
1402                 relstr_end = offset;
1403
1404         item = proto_tree_add_text(tree, tvb, relstr_start,
1405                                    relstr_end - relstr_start, "%s: %s",
1406                                    name ? name : "RELSTR", text);
1407
1408         subtree = proto_item_add_subtree(item, ett_RELSTR);
1409
1410         if (data)
1411                 *data = text;
1412         else
1413                 g_free(text);
1414
1415         proto_tree_add_text(subtree, tvb, offset - 4, 4,
1416                             "Relative offset: %d", relstr_offset);
1417
1418         proto_tree_add_text(subtree, tvb, relstr_start,
1419                             relstr_end - relstr_start, "Data");
1420
1421         return offset;
1422 }
1423
1424 /*
1425  * PRINTER_INFO_0
1426  */
1427
1428 static gint ett_PRINTER_INFO_0 = -1;
1429
1430 static int prs_PRINTER_INFO_0(tvbuff_t *tvb, int offset, packet_info *pinfo,
1431                               proto_tree *tree, GList **dp_list,
1432                               void **data _U_)
1433 {
1434         int struct_start = offset;
1435
1436         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1437                             NULL, "Printer name");
1438         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1439                             NULL, "Server name");
1440
1441         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "CJobs");
1442         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total jobs");
1443         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total bytes");
1444
1445         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Year");
1446         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Month");
1447         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Day of week");
1448         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Day");
1449         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Hour");
1450         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Minute");
1451         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Second");
1452         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Milliseconds");
1453
1454         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Global counter");
1455         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total pages");
1456
1457         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Major version");
1458         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Build version");
1459
1460         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1461         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1462         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1463         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Session counter");
1464         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1465         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer errors");
1466         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1467         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1468         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1469         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1470         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Change id");
1471         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1472         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status");
1473         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1474         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "C_setprinter");
1475
1476         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1477         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1478         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1479         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1480         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1481         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1482         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1483         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
1484
1485         return offset;
1486 }
1487
1488 /*
1489  * PRINTER_INFO_1
1490  */
1491
1492 static gint ett_PRINTER_INFO_1 = -1;
1493
1494 static int prs_PRINTER_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
1495                               proto_tree *tree, GList **dp_list,
1496                               void **data _U_)
1497 {
1498         int struct_start = offset;
1499
1500         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
1501
1502         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1503                             NULL, "Description");
1504
1505         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1506                             NULL, "Name");
1507
1508         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1509                             NULL, "Comment");
1510
1511         return offset;
1512 }
1513
1514 /* Job status */
1515
1516 static gint ett_job_status = -1;
1517
1518 static int
1519 dissect_job_status(tvbuff_t *tvb, int offset, packet_info *pinfo,
1520                    proto_tree *tree, char *drep)
1521 {
1522         proto_item *item;
1523         proto_tree *subtree;
1524         guint32 status;
1525
1526         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
1527                                     hf_spoolss_job_status, &status);
1528
1529         item = proto_tree_add_text(tree, tvb, offset - 4, 4,
1530                                    "Status: 0x%08x", status);
1531
1532         subtree = proto_item_add_subtree(item, ett_job_status);
1533
1534         proto_tree_add_boolean(
1535                 subtree, hf_spoolss_job_status_user_intervention,
1536                 tvb, offset - 4, 4, status);
1537
1538         proto_tree_add_boolean(
1539                 subtree, hf_spoolss_job_status_blocked,
1540                 tvb, offset - 4, 4, status);
1541
1542         proto_tree_add_boolean(
1543                 subtree, hf_spoolss_job_status_deleted,
1544                 tvb, offset - 4, 4, status);
1545
1546         proto_tree_add_boolean(
1547                 subtree, hf_spoolss_job_status_printed,
1548                 tvb, offset - 4, 4, status);
1549
1550         proto_tree_add_boolean(
1551                 subtree, hf_spoolss_job_status_paperout,
1552                 tvb, offset - 4, 4, status);
1553
1554         proto_tree_add_boolean(
1555                 subtree, hf_spoolss_job_status_offline,
1556                 tvb, offset - 4, 4, status);
1557
1558         proto_tree_add_boolean(
1559                 subtree, hf_spoolss_job_status_printing,
1560                 tvb, offset - 4, 4, status);
1561
1562         proto_tree_add_boolean(
1563                 subtree, hf_spoolss_job_status_spooling,
1564                 tvb, offset - 4, 4, status);
1565
1566         proto_tree_add_boolean(
1567                 subtree, hf_spoolss_job_status_deleting,
1568                 tvb, offset - 4, 4, status);
1569
1570         proto_tree_add_boolean(
1571                 subtree, hf_spoolss_job_status_error,
1572                 tvb, offset - 4, 4, status);
1573
1574         proto_tree_add_boolean(
1575                 subtree, hf_spoolss_job_status_paused,
1576                 tvb, offset - 4, 4, status);
1577
1578         return offset;
1579 }
1580
1581 /* Printer attributes */
1582
1583 static gint ett_printer_attributes = -1;
1584
1585 static int
1586 dissect_printer_attributes(tvbuff_t *tvb, int offset, packet_info *pinfo,
1587                            proto_tree *tree, char *drep)
1588 {
1589         proto_item *item;
1590         proto_tree *subtree;
1591         guint32 attributes;
1592
1593         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
1594                                     hf_spoolss_printer_attributes,
1595                                     &attributes);
1596
1597         item = proto_tree_add_text(tree, tvb, offset - 4, 4,
1598                                    "Attributes: 0x%08x", attributes);
1599
1600         subtree = proto_item_add_subtree(item, ett_printer_attributes);
1601
1602         proto_tree_add_boolean(
1603                 subtree, hf_spoolss_printer_attributes_published,
1604                 tvb, offset - 4, 4, attributes);
1605
1606         proto_tree_add_boolean(
1607                 subtree, hf_spoolss_printer_attributes_raw_only,
1608                 tvb, offset - 4, 4, attributes);
1609
1610         proto_tree_add_boolean(
1611                 subtree, hf_spoolss_printer_attributes_enable_bidi,
1612                 tvb, offset - 4, 4, attributes);
1613
1614         proto_tree_add_boolean(
1615                 subtree, hf_spoolss_printer_attributes_work_offline,
1616                 tvb, offset - 4, 4, attributes);
1617
1618         proto_tree_add_boolean(
1619                 subtree, hf_spoolss_printer_attributes_do_complete_first,
1620                 tvb, offset - 4, 4, attributes);
1621
1622         proto_tree_add_boolean(
1623                 subtree, hf_spoolss_printer_attributes_keep_printed_jobs,
1624                 tvb, offset - 4, 4, attributes);
1625
1626         proto_tree_add_boolean(
1627                 subtree, hf_spoolss_printer_attributes_enable_devq,
1628                 tvb, offset - 4, 4, attributes);
1629
1630         proto_tree_add_boolean(
1631                 subtree, hf_spoolss_printer_attributes_local,
1632                 tvb, offset - 4, 4, attributes);
1633
1634         proto_tree_add_boolean(
1635                 subtree, hf_spoolss_printer_attributes_hidden,
1636                 tvb, offset - 4, 4, attributes);
1637
1638         proto_tree_add_boolean(
1639                 subtree, hf_spoolss_printer_attributes_network,
1640                 tvb, offset - 4, 4, attributes);
1641
1642         proto_tree_add_boolean(
1643                 subtree, hf_spoolss_printer_attributes_shared,
1644                 tvb, offset - 4, 4, attributes);
1645
1646         proto_tree_add_boolean(
1647                 subtree, hf_spoolss_printer_attributes_default,
1648                 tvb, offset - 4, 4, attributes);
1649
1650         proto_tree_add_boolean(
1651                 subtree, hf_spoolss_printer_attributes_direct,
1652                 tvb, offset - 4, 4, attributes);
1653
1654         proto_tree_add_boolean(
1655                 subtree, hf_spoolss_printer_attributes_queued,
1656                 tvb, offset - 4, 4, attributes);
1657
1658         return offset;
1659 }
1660
1661 /*
1662  * PRINTER_INFO_2
1663  */
1664
1665 static gint ett_PRINTER_INFO_2 = -1;
1666
1667 static int prs_PRINTER_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo,
1668                               proto_tree *tree, int len, GList **dp_list,
1669                               void **data _U_)
1670 {
1671         int struct_start = offset;
1672         guint32 rel_offset;
1673
1674         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1675                             NULL, "Server name");
1676
1677         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1678                             NULL, "Printer name");
1679
1680         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1681                             NULL, "Share name");
1682
1683         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1684                            NULL, "Port name");
1685
1686         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1687                             NULL, "Driver name");
1688
1689         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1690                             NULL, "Comment");
1691
1692         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1693                             NULL, "Location");
1694
1695         /* This is a relative devicemode */
1696
1697         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
1698
1699         prs_DEVMODE(tvb, struct_start + rel_offset - 4, pinfo, tree,
1700                     dp_list, NULL);
1701
1702         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1703                             NULL, "Separator file");
1704
1705         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1706                             NULL, "Print processor");
1707
1708         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1709                             NULL, "Datatype");
1710
1711         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
1712                             NULL, "Parameters");
1713
1714         /* This is a relative security descriptor */
1715
1716         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
1717
1718         /*
1719          * XXX - what *is* the length of this security descriptor?
1720          * "prs_PRINTER_INFO_2()" is passed to "defer_ptr()", but
1721          * "defer_ptr" takes, as an argument, a function with a
1722          * different calling sequence from "prs_PRINTER_INFO_2()",
1723          * lacking the "len" argument, so that won't work.
1724          */
1725         dissect_nt_sec_desc(tvb, struct_start + rel_offset, tree, len);
1726
1727 /*      offset = dissect_printer_attributes(tvb, offset, pinfo, tree, drep); */
1728
1729         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Attributes");
1730
1731         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Priority");
1732
1733         offset = prs_uint32(tvb, offset, pinfo, tree, NULL,
1734                             "Default priority");
1735
1736         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Start time");
1737
1738         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "End time");
1739
1740         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status");
1741
1742         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Jobs");
1743
1744         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Average PPM");
1745
1746         return offset;
1747 }
1748
1749 /*
1750  * PRINTER_INFO_3
1751  */
1752
1753 static gint ett_PRINTER_INFO_3 = -1;
1754
1755 static int prs_PRINTER_INFO_3(tvbuff_t *tvb, int offset, packet_info *pinfo,
1756                               proto_tree *tree, int len, GList **dp_list _U_,
1757                               void **data _U_)
1758 {
1759         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
1760
1761         offset = dissect_nt_sec_desc(tvb, offset, tree, len);
1762
1763         return offset;
1764 }
1765
1766 /*
1767  * DEVMODE_CTR
1768  */
1769
1770 static gint ett_DEVMODE_CTR = -1;
1771
1772 static int prs_DEVMODE_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
1773                            proto_tree *tree, GList **dp_list, void **data)
1774 {
1775         proto_item *item;
1776         proto_tree *subtree;
1777         guint32 ptr = 0;
1778
1779         item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE_CTR");
1780
1781         subtree = proto_item_add_subtree(item, ett_DEVMODE_CTR);
1782
1783         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1784
1785         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Devicemode");
1786
1787         if (ptr)
1788                 offset = prs_DEVMODE(tvb, offset, pinfo, subtree, dp_list,
1789                                      data);
1790
1791         return offset;
1792 }
1793
1794 /*
1795  * PRINTER_DEFAULT structure
1796  */
1797
1798 static gint ett_PRINTER_DEFAULT = -1;
1799
1800 static int prs_PRINTER_DEFAULT(tvbuff_t *tvb, int offset, packet_info *pinfo,
1801                                proto_tree *tree, GList **dp_list,
1802                                void **data _U_)
1803 {
1804         GList *child_dp_list = NULL;
1805         proto_item *item;
1806         proto_tree *subtree;
1807         guint32 ptr = 0;
1808         char drep = 0x10;
1809
1810         item = proto_tree_add_text(tree, tvb, offset, 0, "PRINTER_DEFAULT");
1811
1812         subtree = proto_item_add_subtree(item, ett_PRINTER_DEFAULT);
1813
1814         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Datatype");
1815
1816         /* Not sure why this isn't a deferred pointer.  I think this may be
1817            two structures stuck together. */
1818
1819         if (ptr)
1820                 offset = prs_UNISTR2_dp(tvb, offset, pinfo, subtree, dp_list,
1821                                         NULL);
1822
1823         offset = prs_DEVMODE_CTR(tvb, offset, pinfo, subtree,
1824                                  &child_dp_list, NULL);
1825
1826         offset = dissect_nt_access_mask(
1827                 tvb, offset, pinfo, subtree, &drep, hf_access_required,
1828                 spoolss_specific_rights);
1829
1830         offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
1831                                &child_dp_list, NULL);
1832
1833         return offset;
1834 }
1835
1836 /*
1837  * USER_LEVEL_1 structure
1838  */
1839
1840 static gint ett_USER_LEVEL_1 = -1;
1841
1842 static int prs_USER_LEVEL_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
1843                             proto_tree *tree, GList **dp_list,
1844                             void **data _U_)
1845 {
1846         proto_item *item;
1847         proto_tree *subtree;
1848         guint32 ptr = 0;
1849
1850         item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL_1");
1851
1852         subtree = proto_item_add_subtree(item, ett_USER_LEVEL_1);
1853
1854         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1855
1856         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Client name");
1857
1858         if (ptr)
1859                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
1860
1861         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User name");
1862
1863         if (ptr)
1864                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
1865
1866         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Build");
1867
1868         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Major");
1869
1870         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Minor");
1871
1872         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Processor");
1873
1874         return offset;
1875 }
1876
1877 /*
1878  * USER_LEVEL structure
1879  */
1880
1881 static gint ett_USER_LEVEL = -1;
1882
1883 static int prs_USER_LEVEL(tvbuff_t *tvb, int offset, packet_info *pinfo,
1884                           proto_tree *tree, GList **parent_dp_list,
1885                           void **data _U_)
1886 {
1887         proto_item *item;
1888         proto_tree *subtree;
1889         guint32 ptr = 0;
1890         guint32 level;
1891
1892         item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL");
1893
1894         subtree = proto_item_add_subtree(item, ett_USER_LEVEL);
1895
1896         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Info level");
1897
1898         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User level");
1899
1900         if (ptr) {
1901                 switch (level) {
1902                 case 1:
1903                         defer_ptr(parent_dp_list, prs_USER_LEVEL_1, subtree);
1904                         break;
1905                 default:
1906                         proto_tree_add_text(
1907                                 tree, tvb, offset, 0,
1908                                 "[GetPrinter level %d not decoded]", level);
1909                         break;
1910                 }
1911         }
1912
1913         return offset;
1914 }
1915
1916 /*
1917  * SpoolssOpenPrinterEx
1918  */
1919
1920 static int SpoolssOpenPrinterEx_q(tvbuff_t *tvb, int offset,
1921                                   packet_info *pinfo, proto_tree *tree,
1922                                   char *drep _U_)
1923 {
1924         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1925         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1926         guint32 ptr = 0;
1927
1928         if (dcv->rep_frame != 0)
1929                 proto_tree_add_text(tree, tvb, offset, 0,
1930                                     "Reply in frame %u", dcv->rep_frame);
1931
1932         /* Parse packet */
1933
1934         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Printer name");
1935
1936         if (ptr) {
1937                 char *printer_name;
1938
1939                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1940                                                   prs_UNISTR2_dp,
1941                                                   (void **)&printer_name,
1942                                                   NULL);
1943
1944                 if (check_col(pinfo->cinfo, COL_INFO))
1945                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1946                                         printer_name);
1947
1948                 /* Store printer name to match with reply packet */
1949
1950                 dcv->private_data = printer_name;
1951         }
1952
1953         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1954                                           prs_PRINTER_DEFAULT, NULL, NULL);
1955
1956         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
1957
1958         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1959                                           prs_USER_LEVEL, NULL, NULL);
1960
1961         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1962
1963         return offset;
1964 }
1965
1966 static int SpoolssOpenPrinterEx_r(tvbuff_t *tvb, int offset,
1967                                   packet_info *pinfo, proto_tree *tree,
1968                                   char *drep _U_)
1969 {
1970         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1971         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1972         e_ctx_hnd policy_hnd;
1973         guint32 status;
1974         int start_offset = offset;
1975
1976         if (dcv->req_frame != 0)
1977                 proto_tree_add_text(tree, tvb, offset, 0,
1978                                     "Request in frame %u", dcv->req_frame);
1979
1980         /* We need the value of the policy handle and status before we
1981            can retrieve the policy handle name.  Then we can insert
1982            the policy handle with the name in the proto tree. */
1983
1984         offset = dissect_nt_policy_hnd(
1985                 tvb, offset, pinfo, NULL, drep, hf_spoolss_hnd, &policy_hnd,
1986                 TRUE, FALSE);
1987
1988         offset = dissect_doserror(tvb, offset, pinfo, NULL, drep,
1989                                   hf_spoolss_rc, &status);
1990
1991         if (status == 0) {
1992
1993                 /* Associate the returned printer handle with a name */
1994
1995                 if (dcv->private_data) {
1996                         dcerpc_smb_store_pol_name(
1997                                 &policy_hnd, dcv->private_data);
1998
1999                         g_free(dcv->private_data);
2000                         dcv->private_data = NULL;
2001                 }
2002         }
2003
2004         /* Parse packet */
2005
2006         offset = start_offset;
2007
2008         offset = dissect_nt_policy_hnd(
2009                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd,
2010                 TRUE, FALSE);
2011
2012         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
2013                                   hf_spoolss_rc, &status);
2014
2015         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2016
2017         return offset;
2018 }
2019
2020 static const value_string printer_notify_option_data_vals[] = {
2021         { PRINTER_NOTIFY_SERVER_NAME, "Server name" },
2022         { PRINTER_NOTIFY_PRINTER_NAME, "Printer name" },
2023         { PRINTER_NOTIFY_SHARE_NAME, "Share name" },
2024         { PRINTER_NOTIFY_PORT_NAME, "Port name" },
2025         { PRINTER_NOTIFY_DRIVER_NAME, "Driver name" },
2026         { PRINTER_NOTIFY_COMMENT, "Comment" },
2027         { PRINTER_NOTIFY_LOCATION, "Location" },
2028         { PRINTER_NOTIFY_DEVMODE, "Devmode" },
2029         { PRINTER_NOTIFY_SEPFILE, "Sepfile" },
2030         { PRINTER_NOTIFY_PRINT_PROCESSOR, "Print processor" },
2031         { PRINTER_NOTIFY_PARAMETERS, "Parameters" },
2032         { PRINTER_NOTIFY_DATATYPE, "Datatype" },
2033         { PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "Security descriptor" },
2034         { PRINTER_NOTIFY_ATTRIBUTES, "Attributes" },
2035         { PRINTER_NOTIFY_PRIORITY, "Priority" },
2036         { PRINTER_NOTIFY_DEFAULT_PRIORITY, "Default priority" },
2037         { PRINTER_NOTIFY_START_TIME, "Start time" },
2038         { PRINTER_NOTIFY_UNTIL_TIME, "Until time" },
2039         { PRINTER_NOTIFY_STATUS, "Status" },
2040         { PRINTER_NOTIFY_STATUS_STRING, "Status string" },
2041         { PRINTER_NOTIFY_CJOBS, "Cjobs" },
2042         { PRINTER_NOTIFY_AVERAGE_PPM, "Average PPM" },
2043         { PRINTER_NOTIFY_TOTAL_PAGES, "Total pages" },
2044         { PRINTER_NOTIFY_PAGES_PRINTED, "Pages printed" },
2045         { PRINTER_NOTIFY_TOTAL_BYTES, "Total bytes" },
2046         { PRINTER_NOTIFY_BYTES_PRINTED, "Bytes printed" },
2047         { 0, NULL}
2048 };
2049
2050 static const value_string job_notify_option_data_vals[] = {
2051         { JOB_NOTIFY_PRINTER_NAME, "Printer name" },
2052         { JOB_NOTIFY_MACHINE_NAME, "Machine name" },
2053         { JOB_NOTIFY_PORT_NAME, "Port name" },
2054         { JOB_NOTIFY_USER_NAME, "User name" },
2055         { JOB_NOTIFY_NOTIFY_NAME, "Notify name" },
2056         { JOB_NOTIFY_DATATYPE, "Data type" },
2057         { JOB_NOTIFY_PRINT_PROCESSOR, "Print processor" },
2058         { JOB_NOTIFY_PARAMETERS, "Parameters" },
2059         { JOB_NOTIFY_DRIVER_NAME, "Driver name" },
2060         { JOB_NOTIFY_DEVMODE, "Devmode" },
2061         { JOB_NOTIFY_STATUS, "Status" },
2062         { JOB_NOTIFY_STATUS_STRING, "Status string" },
2063         { JOB_NOTIFY_SECURITY_DESCRIPTOR, "Security descriptor" },
2064         { JOB_NOTIFY_DOCUMENT, "Document" },
2065         { JOB_NOTIFY_PRIORITY, "Priority" },
2066         { JOB_NOTIFY_POSITION, "Position" },
2067         { JOB_NOTIFY_SUBMITTED, "Submitted" },
2068         { JOB_NOTIFY_START_TIME, "Start time" },
2069         { JOB_NOTIFY_UNTIL_TIME, "Until time" },
2070         { JOB_NOTIFY_TIME, "Time" },
2071         { JOB_NOTIFY_TOTAL_PAGES, "Total pages" },
2072         { JOB_NOTIFY_PAGES_PRINTED, "Pages printed" },
2073         { JOB_NOTIFY_TOTAL_BYTES, "Total bytes" },
2074         { JOB_NOTIFY_BYTES_PRINTED, "Bytes printed" },
2075         { 0, NULL}
2076 };
2077
2078 static int
2079 dissect_notify_field(tvbuff_t *tvb, int offset, packet_info *pinfo,
2080                      proto_tree *tree, char *drep, guint16 type,
2081                      guint16 *data)
2082 {
2083         guint16 field;
2084         char *str;
2085
2086         offset = dissect_ndr_uint16(
2087                 tvb, offset, pinfo, NULL, drep,
2088                 hf_spoolss_notify_field, &field);
2089
2090         switch(type) {
2091         case PRINTER_NOTIFY_TYPE:
2092                 str = val_to_str(field, printer_notify_option_data_vals,
2093                                  "Unknown");
2094                 break;
2095         case JOB_NOTIFY_TYPE:
2096                 str = val_to_str(field, job_notify_option_data_vals,
2097                                  "Unknown");
2098                 break;
2099         default:
2100                 str = "Unknown notify type";
2101                 break;
2102         }
2103
2104         proto_tree_add_text(tree, tvb, offset - 2, 2,
2105                             "Field: %s (%d)", str, field);
2106
2107         if (data)
2108                 *data = field;
2109
2110         return offset;
2111 }
2112
2113 static int
2114 dissect_NOTIFY_OPTION_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo,
2115                            proto_tree *tree, char *drep)
2116 {
2117         dcerpc_info *di = pinfo->private_data;
2118         guint32 count, i;
2119         guint16 type;
2120
2121         if (di->conformant_run)
2122                 return offset;
2123
2124         type = di->levels;
2125
2126         offset = dissect_ndr_uint32(
2127                 tvb, offset, pinfo, tree, drep,
2128                 hf_spoolss_notify_option_data_count, &count);
2129
2130         for (i = 0; i < count; i++)
2131                 offset = dissect_notify_field(
2132                         tvb, offset, pinfo, tree, drep, type, NULL);
2133
2134         return offset;
2135 }
2136
2137 static const value_string printer_notify_types[] =
2138 {
2139         { PRINTER_NOTIFY_TYPE, "Printer notify" },
2140         { JOB_NOTIFY_TYPE, "Job notify" },
2141         { 0, NULL }
2142 };
2143
2144 static gint ett_NOTIFY_OPTION = -1;
2145
2146 static int
2147 dissect_NOTIFY_OPTION(tvbuff_t *tvb, int offset, packet_info *pinfo,
2148                       proto_tree *tree, char *drep)
2149 {
2150         proto_item *item;
2151         proto_tree *subtree;
2152         guint16 type;
2153
2154         item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION");
2155
2156         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION);
2157
2158         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep,
2159                                     hf_spoolss_notify_option_type, &type);
2160
2161         proto_item_append_text(item, ": %s",
2162                                val_to_str(type, printer_notify_types, "Unknown (%d)"));
2163
2164         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep,
2165                                     hf_spoolss_notify_option_reserved1, NULL);
2166
2167         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
2168                                     hf_spoolss_notify_option_reserved2, NULL);
2169
2170         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
2171                                     hf_spoolss_notify_option_reserved3, NULL);
2172
2173         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
2174                                     hf_spoolss_notify_option_count, NULL);
2175
2176         offset = dissect_ndr_pointer(
2177                 tvb, offset, pinfo, subtree, drep,
2178                 dissect_NOTIFY_OPTION_DATA, NDR_POINTER_UNIQUE,
2179                 "NOTIFY_OPTION_DATA", -1, type);
2180
2181         return offset;
2182 }
2183
2184 static int
2185 dissect_NOTIFY_OPTIONS_ARRAY(tvbuff_t *tvb, int offset,
2186                              packet_info *pinfo, proto_tree *tree,
2187                              char *drep)
2188 {
2189         /* Why is a check for di->conformant_run not required here? */
2190
2191         offset = dissect_ndr_ucarray(
2192                 tvb, offset, pinfo, tree, drep, dissect_NOTIFY_OPTION);
2193
2194         return offset;
2195 }
2196
2197 static gint ett_notify_options_flags = -1;
2198
2199 static const true_false_string tfs_notify_options_flags_refresh = {
2200         "Data for all monitored fields is present",
2201         "Data for all monitored fields not present"
2202 };
2203
2204 static int
2205 dissect_notify_options_flags(tvbuff_t *tvb, int offset, packet_info *pinfo,
2206                              proto_tree *tree, char *drep)
2207 {
2208         proto_item *item;
2209         proto_tree *subtree;
2210         guint32 flags;
2211
2212         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
2213                                     hf_spoolss_notify_options_flags,
2214                                     &flags);
2215
2216         item = proto_tree_add_text(tree, tvb, offset - 4, 4,
2217                                    "Flags: 0x%08x", flags);
2218
2219         subtree = proto_item_add_subtree(item, ett_notify_options_flags);
2220
2221         proto_tree_add_boolean(
2222                 subtree, hf_spoolss_notify_options_flags_refresh,
2223                 tvb, offset, 4, flags);
2224
2225         return offset;
2226 }
2227
2228 static int
2229 dissect_NOTIFY_OPTIONS_ARRAY_CTR(tvbuff_t *tvb, int offset,
2230                                  packet_info *pinfo, proto_tree *tree,
2231                                  char *drep)
2232 {
2233         dcerpc_info *di = pinfo->private_data;
2234
2235         if (di->conformant_run)
2236                 return offset;
2237
2238         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2239                                     hf_spoolss_notify_options_version, NULL);
2240
2241         offset = dissect_notify_options_flags(tvb, offset, pinfo, tree, drep);
2242
2243         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2244                                     hf_spoolss_notify_options_count, NULL);
2245
2246         offset = dissect_ndr_pointer(
2247                 tvb, offset, pinfo, tree, drep,
2248                 dissect_NOTIFY_OPTIONS_ARRAY, NDR_POINTER_UNIQUE,
2249                 "NOTIFY_OPTIONS", -1, 0);
2250
2251         return offset;
2252 }
2253
2254 /*
2255  * SpoolssRFFPCNEX
2256  */
2257
2258 static gint ett_rffpcnex_flags = -1;
2259
2260 static int hf_spoolss_rffpcnex_flags_add_printer = -1;
2261 static int hf_spoolss_rffpcnex_flags_set_printer = -1;
2262 static int hf_spoolss_rffpcnex_flags_delete_printer = -1;
2263 static int hf_spoolss_rffpcnex_flags_failed_printer_connection = -1;
2264
2265 static const true_false_string tfs_rffpcnex_flags_add_printer = {
2266         "Notify on add printer",
2267         "Don't notify on add printer"
2268 };
2269
2270 static const true_false_string tfs_rffpcnex_flags_set_printer = {
2271         "Notify on set printer",
2272         "Don't notify on set printer"
2273 };
2274
2275 static const true_false_string tfs_rffpcnex_flags_delete_printer = {
2276         "Notify on delete printer",
2277         "Don't notify on delete printer"
2278 };
2279
2280 static const true_false_string tfs_rffpcnex_flags_failed_connection_printer = {
2281         "Notify on failed printer connection",
2282         "Don't notify on failed printer connection"
2283 };
2284
2285 static int hf_spoolss_rffpcnex_flags_add_job = -1;
2286 static int hf_spoolss_rffpcnex_flags_set_job = -1;
2287 static int hf_spoolss_rffpcnex_flags_delete_job = -1;
2288 static int hf_spoolss_rffpcnex_flags_write_job = -1;
2289
2290 static const true_false_string tfs_rffpcnex_flags_add_job = {
2291         "Notify on add job",
2292         "Don't notify on add job"
2293 };
2294
2295 static const true_false_string tfs_rffpcnex_flags_set_job = {
2296         "Notify on set job",
2297         "Don't notify on set job"
2298 };
2299
2300 static const true_false_string tfs_rffpcnex_flags_delete_job = {
2301         "Notify on delete job",
2302         "Don't notify on delete job"
2303 };
2304
2305 static const true_false_string tfs_rffpcnex_flags_write_job = {
2306         "Notify on writejob",
2307         "Don't notify on write job"
2308 };
2309
2310 static int hf_spoolss_rffpcnex_flags_add_form = -1;
2311 static int hf_spoolss_rffpcnex_flags_set_form = -1;
2312 static int hf_spoolss_rffpcnex_flags_delete_form = -1;
2313
2314 static const true_false_string tfs_rffpcnex_flags_add_form = {
2315         "Notify on add form",
2316         "Don't notify on add form"
2317 };
2318
2319 static const true_false_string tfs_rffpcnex_flags_set_form = {
2320         "Notify on set form",
2321         "Don't notify on set form"
2322 };
2323
2324 static const true_false_string tfs_rffpcnex_flags_delete_form = {
2325         "Notify on delete form",
2326         "Don't notify on delete form"
2327 };
2328
2329 static int hf_spoolss_rffpcnex_flags_add_port = -1;
2330 static int hf_spoolss_rffpcnex_flags_configure_port = -1;
2331 static int hf_spoolss_rffpcnex_flags_delete_port = -1;
2332
2333 static const true_false_string tfs_rffpcnex_flags_add_port = {
2334         "Notify on add port",
2335         "Don't notify on add port"
2336 };
2337
2338 static const true_false_string tfs_rffpcnex_flags_configure_port = {
2339         "Notify on configure port",
2340         "Don't notify on configure port"
2341 };
2342
2343 static const true_false_string tfs_rffpcnex_flags_delete_port = {
2344         "Notify on delete port",
2345         "Don't notify on delete port"
2346 };
2347
2348 static int hf_spoolss_rffpcnex_flags_add_print_processor = -1;
2349 static int hf_spoolss_rffpcnex_flags_delete_print_processor = -1;
2350
2351 static const true_false_string tfs_rffpcnex_flags_add_print_processor = {
2352         "Notify on add driver",
2353         "Don't notify on add driver"
2354 };
2355
2356 static const true_false_string tfs_rffpcnex_flags_delete_print_processor = {
2357         "Notify on add driver",
2358         "Don't notify on add driver"
2359 };
2360
2361 static int hf_spoolss_rffpcnex_flags_add_driver = -1;
2362 static int hf_spoolss_rffpcnex_flags_set_driver = -1;
2363 static int hf_spoolss_rffpcnex_flags_delete_driver = -1;
2364
2365 static const true_false_string tfs_rffpcnex_flags_add_driver = {
2366         "Notify on add driver",
2367         "Don't notify on add driver"
2368 };
2369
2370 static const true_false_string tfs_rffpcnex_flags_set_driver = {
2371         "Notify on set driver",
2372         "Don't notify on set driver"
2373 };
2374
2375 static const true_false_string tfs_rffpcnex_flags_delete_driver = {
2376         "Notify on delete driver",
2377         "Don't notify on delete driver"
2378 };
2379
2380 static int hf_spoolss_rffpcnex_flags_timeout = -1;
2381
2382 static const true_false_string tfs_rffpcnex_flags_timeout = {
2383         "Notify on timeout",
2384         "Don't notify on timeout"
2385 };
2386
2387 static int SpoolssRFFPCNEX_q(tvbuff_t *tvb, int offset,
2388                              packet_info *pinfo, proto_tree *tree,
2389                              char *drep _U_)
2390 {
2391         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2392         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2393         guint32 flags;
2394         proto_item *flags_item;
2395         proto_tree *flags_subtree;
2396
2397         if (dcv->rep_frame != 0)
2398                 proto_tree_add_text(tree, tvb, offset, 0,
2399                                     "Reply in frame %u", dcv->rep_frame);
2400
2401         /* Parse packet */
2402
2403         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
2404                                        hf_spoolss_hnd, NULL, FALSE, FALSE);
2405
2406         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
2407                                     hf_spoolss_rffpcnex_flags, &flags);
2408
2409         flags_item = proto_tree_add_text(tree, tvb, offset - 4, 4,
2410                                          "Flags: 0x%08x", flags);
2411
2412         flags_subtree = proto_item_add_subtree(flags_item, ett_rffpcnex_flags);
2413
2414         proto_tree_add_boolean(
2415                 flags_subtree, hf_spoolss_rffpcnex_flags_timeout, tvb,
2416                 offset - 4, 4, flags);
2417
2418         proto_tree_add_boolean(
2419                 flags_subtree, hf_spoolss_rffpcnex_flags_delete_driver, tvb,
2420                 offset - 4, 4, flags);
2421
2422         proto_tree_add_boolean(
2423                 flags_subtree, hf_spoolss_rffpcnex_flags_set_driver, tvb,
2424                 offset - 4, 4, flags);
2425
2426         proto_tree_add_boolean(
2427                 flags_subtree, hf_spoolss_rffpcnex_flags_add_driver, tvb,
2428                 offset - 4, 4, flags);
2429
2430         proto_tree_add_boolean(
2431                 flags_subtree,
2432                 hf_spoolss_rffpcnex_flags_delete_print_processor, tvb,
2433                 offset - 4, 4, flags);
2434
2435         proto_tree_add_boolean(
2436                 flags_subtree, hf_spoolss_rffpcnex_flags_add_print_processor,
2437                 tvb, offset - 4, 4, flags);
2438
2439         proto_tree_add_boolean(
2440                 flags_subtree, hf_spoolss_rffpcnex_flags_delete_port, tvb,
2441                 offset - 4, 4, flags);
2442
2443         proto_tree_add_boolean(
2444                 flags_subtree, hf_spoolss_rffpcnex_flags_configure_port, tvb,
2445                 offset - 4, 4, flags);
2446
2447         proto_tree_add_boolean(
2448                 flags_subtree, hf_spoolss_rffpcnex_flags_add_port, tvb,
2449                 offset - 4, 4, flags);
2450
2451         proto_tree_add_boolean(
2452                 flags_subtree, hf_spoolss_rffpcnex_flags_delete_form, tvb,
2453                 offset - 4, 4, flags);
2454
2455         proto_tree_add_boolean(
2456                 flags_subtree, hf_spoolss_rffpcnex_flags_set_form, tvb,
2457                 offset - 4, 4, flags);
2458
2459         proto_tree_add_boolean(
2460                 flags_subtree, hf_spoolss_rffpcnex_flags_add_form, tvb,
2461                 offset - 4, 4, flags);
2462
2463         proto_tree_add_boolean(
2464                 flags_subtree, hf_spoolss_rffpcnex_flags_write_job, tvb,
2465                 offset - 4, 4, flags);
2466
2467         proto_tree_add_boolean(
2468                 flags_subtree, hf_spoolss_rffpcnex_flags_delete_job, tvb,
2469                 offset - 4, 4, flags);
2470
2471         proto_tree_add_boolean(
2472                 flags_subtree, hf_spoolss_rffpcnex_flags_set_job, tvb,
2473                 offset - 4, 4, flags);
2474
2475         proto_tree_add_boolean(
2476                 flags_subtree, hf_spoolss_rffpcnex_flags_add_job, tvb,
2477                 offset - 4, 4, flags);
2478
2479         proto_tree_add_boolean(
2480                 flags_subtree,
2481                 hf_spoolss_rffpcnex_flags_failed_printer_connection, tvb,
2482                 offset - 4, 4, flags);
2483
2484         proto_tree_add_boolean(
2485                 flags_subtree, hf_spoolss_rffpcnex_flags_delete_printer, tvb,
2486                 offset - 4, 4, flags);
2487
2488         proto_tree_add_boolean(
2489                 flags_subtree, hf_spoolss_rffpcnex_flags_set_printer, tvb,
2490                 offset - 4, 4, flags);
2491
2492         proto_tree_add_boolean(
2493                 flags_subtree, hf_spoolss_rffpcnex_flags_add_printer, tvb,
2494                 offset - 4, 4, flags);
2495
2496         if (flags & SPOOLSS_PRINTER_CHANGE_PRINTER)
2497                 proto_item_append_text(flags_item, ", change printer");
2498
2499         if (flags & SPOOLSS_PRINTER_CHANGE_JOB)
2500                 proto_item_append_text(flags_item, ", change job");
2501
2502         if (flags & SPOOLSS_PRINTER_CHANGE_FORM)
2503                 proto_item_append_text(flags_item, ", change form");
2504
2505         if (flags & SPOOLSS_PRINTER_CHANGE_PORT)
2506                 proto_item_append_text(flags_item, ", change port");
2507
2508         if (flags & SPOOLSS_PRINTER_CHANGE_PRINTER_DRIVER)
2509                 proto_item_append_text(flags_item, ", change printer driver");
2510
2511         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2512                                     hf_spoolss_rffpcnex_options, NULL);
2513
2514         offset = dissect_ndr_pointer(
2515                 tvb, offset, pinfo, tree, drep,
2516                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
2517                 "Server", hf_spoolss_servername, 0);
2518
2519         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2520                                     hf_spoolss_printerlocal, NULL);
2521
2522         offset = dissect_ndr_pointer(
2523                 tvb, offset, pinfo, tree, drep,
2524                 dissect_NOTIFY_OPTIONS_ARRAY_CTR, NDR_POINTER_UNIQUE,
2525                 "NOTIFY_OPTIONS_CTR", -1, 0);
2526
2527         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2528
2529         return offset;
2530 }
2531
2532 static int SpoolssRFFPCNEX_r(tvbuff_t *tvb, int offset,
2533                              packet_info *pinfo, proto_tree *tree,
2534                              char *drep _U_)
2535 {
2536         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2537         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2538
2539         if (dcv->req_frame != 0)
2540                 proto_tree_add_text(tree, tvb, offset, 0,
2541                                     "Request in frame %u", dcv->req_frame);
2542
2543         /* Parse packet */
2544
2545         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
2546                                   hf_spoolss_rc, NULL);
2547
2548         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2549
2550         return offset;
2551 }
2552
2553 /*
2554  * SpoolssReplyOpenPrinter
2555  */
2556
2557 static int SpoolssReplyOpenPrinter_q(tvbuff_t *tvb, int offset,
2558                                      packet_info *pinfo, proto_tree *tree,
2559                                      char *drep _U_)
2560 {
2561         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2562         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2563         guint32 printerlocal;
2564
2565         if (dcv->rep_frame != 0)
2566                 proto_tree_add_text(tree, tvb, offset, 0,
2567                                     "Reply in frame %u", dcv->rep_frame);
2568
2569         /* Parse packet */
2570
2571         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2572                                           prs_UNISTR2_dp, NULL, NULL);
2573
2574         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2575                                     hf_spoolss_printerlocal, &printerlocal);
2576
2577         dcv->private_data = (void *)printerlocal;
2578
2579         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2580                                     hf_spoolss_printerdata_type, NULL);
2581
2582         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2583                                     hf_spoolss_replyopenprinter_unk0, NULL);
2584
2585         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
2586                                     hf_spoolss_replyopenprinter_unk1, NULL);
2587
2588         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2589
2590         return offset;
2591 }
2592
2593 static int SpoolssReplyOpenPrinter_r(tvbuff_t *tvb, int offset,
2594                                      packet_info *pinfo, proto_tree *tree,
2595                                      char *drep _U_)
2596 {
2597         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2598         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2599         e_ctx_hnd policy_hnd;
2600
2601         if (dcv->req_frame != 0)
2602                 proto_tree_add_text(tree, tvb, offset, 0,
2603                                     "Request in frame %u", dcv->req_frame);
2604
2605         /* Parse packet */
2606
2607         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
2608                                        hf_spoolss_hnd, &policy_hnd,
2609                                        TRUE, FALSE);
2610
2611         dcerpc_smb_store_pol_name(&policy_hnd, "ReplyOpenPrinter handle");
2612
2613         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
2614                                   hf_spoolss_rc, NULL);
2615
2616         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2617
2618         return offset;
2619 }
2620
2621 /*
2622  * BUFFER_DATA
2623  */
2624
2625 static gint ett_BUFFER_DATA = -1;
2626 static gint ett_BUFFER_DATA_BUFFER = -1;
2627
2628 struct BUFFER_DATA {
2629         proto_item *item;       /* proto_item holding proto_tree */
2630         proto_tree *tree;       /* proto_tree holding buffer data */
2631         tvbuff_t *tvb;
2632         int offset;             /* Offset where data starts in tvb*/
2633         int size;               /* Size of buffer data */
2634 };
2635
2636 static int prs_BUFFER_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo,
2637                            proto_tree *tree, GList **dp_list _U_, void **data)
2638 {
2639         proto_item *item, *subitem;
2640         proto_tree *subtree, *subsubtree;
2641         guint32 size;
2642         int data8_offset;
2643
2644         item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER_DATA");
2645
2646         subtree = proto_item_add_subtree(item, ett_BUFFER_DATA);
2647
2648         offset = prs_uint32(tvb, offset, pinfo, subtree, &size, "Size");
2649
2650         subitem = proto_tree_add_text(subtree, tvb, offset, size, "Data");
2651
2652         subsubtree = proto_item_add_subtree(subitem, ett_BUFFER_DATA_BUFFER);
2653
2654         offset = prs_uint8s(tvb, offset, pinfo, subsubtree, size,
2655                             &data8_offset, NULL);
2656
2657         /* Return some info which will help the caller "cast" the buffer
2658            data and dissect it further. */
2659
2660         if (data) {
2661                 struct BUFFER_DATA *bd;
2662
2663                 bd = (struct BUFFER_DATA *)malloc(sizeof(struct BUFFER_DATA));
2664
2665                 bd->item = subitem;
2666                 bd->tree = subsubtree;
2667                 bd->tvb = tvb;
2668                 bd->offset = data8_offset;
2669                 bd->size = size;
2670
2671                 *data = bd;
2672         }
2673
2674         return offset;
2675 }
2676
2677 /*
2678  * BUFFER
2679  */
2680
2681 static gint ett_BUFFER = -1;
2682
2683 static int prs_BUFFER(tvbuff_t *tvb, int offset, packet_info *pinfo,
2684                       proto_tree *tree, GList **dp_list, void **data _U_)
2685 {
2686         proto_item *item;
2687         proto_tree *subtree;
2688         guint32 ptr = 0;
2689
2690         item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER");
2691
2692         subtree = proto_item_add_subtree(item, ett_BUFFER);
2693
2694         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Data");
2695
2696         if (ptr)
2697                 defer_ptr(dp_list, prs_BUFFER_DATA, subtree);
2698
2699         return offset;
2700 }
2701
2702 /*
2703  * SpoolssGetPrinter
2704  */
2705
2706 static int SpoolssGetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2707                                proto_tree *tree, char *drep _U_)
2708 {
2709         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2710         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2711         guint32 level;
2712
2713         if (dcv->rep_frame != 0)
2714                 proto_tree_add_text(tree, tvb, offset, 0,
2715                                     "Reply in frame %u", dcv->rep_frame);
2716
2717         /* Parse packet */
2718
2719         offset = dissect_nt_policy_hnd(
2720                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
2721                 FALSE, FALSE);
2722
2723         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2724
2725         if (check_col(pinfo->cinfo, COL_INFO))
2726                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2727
2728         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2729                                           prs_BUFFER, NULL, NULL);
2730
2731         dcv->private_data = (void *)level;
2732
2733         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
2734
2735         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2736
2737         return offset;
2738 }
2739
2740 static int SpoolssGetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2741                                 proto_tree *tree, char *drep _U_)
2742 {
2743         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2744         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2745         GList *dp_list = NULL;
2746         void **data_list;
2747         struct BUFFER_DATA *bd = NULL;
2748         gint16 level = (guint32)dcv->private_data;
2749
2750         if (dcv->req_frame != 0)
2751                 proto_tree_add_text(tree, tvb, offset, 0,
2752                                     "Request in frame %u", dcv->req_frame);
2753
2754         if (check_col(pinfo->cinfo, COL_INFO))
2755                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2756
2757         /* Parse packet */
2758
2759         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2760                                           prs_BUFFER, NULL, &data_list);
2761
2762         if (data_list)
2763                 bd = (struct BUFFER_DATA *)data_list[0];
2764
2765         if (bd && bd->tree) {
2766                 proto_item_append_text(bd->item, ", PRINTER_INFO_%d", level);
2767
2768                 switch (level) {
2769                 case 0:
2770                         prs_PRINTER_INFO_0(bd->tvb, bd->offset, pinfo,
2771                                            bd->tree, &dp_list, NULL);
2772                         break;
2773
2774                 case 1:
2775                         prs_PRINTER_INFO_1(bd->tvb, bd->offset, pinfo,
2776                                            bd->tree, &dp_list, NULL);
2777                         break;
2778
2779                 case 2:
2780                         prs_PRINTER_INFO_2(bd->tvb, bd->offset, pinfo,
2781                                            bd->tree, bd->size, &dp_list, NULL);
2782                         break;
2783
2784                 case 3:
2785                         prs_PRINTER_INFO_3(bd->tvb, bd->offset, pinfo,
2786                                            bd->tree, bd->size, &dp_list, NULL);
2787                         break;
2788
2789                 default:
2790                         proto_tree_add_text(bd->tree, tvb, offset, 0,
2791                                             "[Unknown info level %d]", level);
2792                         break;
2793                 }
2794         }
2795
2796         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
2797
2798         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
2799                                   hf_spoolss_rc, NULL);
2800
2801         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2802
2803         return offset;
2804 }
2805
2806 /*
2807  * SEC_DESC_BUF
2808  */
2809
2810 static gint ett_SEC_DESC_BUF = -1;
2811
2812 static int prs_SEC_DESC_BUF(tvbuff_t *tvb, int offset, packet_info *pinfo,
2813                             proto_tree *tree, GList **dp_list _U_,
2814                             void **Data _U_)
2815 {
2816         proto_item *item;
2817         proto_tree *subtree;
2818         guint32 len;
2819
2820         item = proto_tree_add_text(tree, tvb, offset, 0, "SEC_DESC_BUF");
2821
2822         subtree = proto_item_add_subtree(item, ett_SEC_DESC_BUF);
2823
2824         offset = prs_uint32(tvb, offset, pinfo, subtree, &len, "Max length");
2825         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Undocumented");
2826         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Length");
2827
2828         dissect_nt_sec_desc(tvb, offset, subtree, len);
2829
2830         offset += len;
2831
2832         return offset;
2833 }
2834
2835 /*
2836  * SPOOL_PRINTER_INFO_LEVEL
2837  */
2838
2839 static gint ett_SPOOL_PRINTER_INFO_LEVEL = -1;
2840
2841 static int prs_SPOOL_PRINTER_INFO_LEVEL(tvbuff_t *tvb, int offset,
2842                                         packet_info *pinfo, proto_tree *tree,
2843                                         GList **dp_list, void **data _U_)
2844 {
2845         proto_item *item;
2846         proto_tree *subtree;
2847         guint32 level;
2848
2849         item = proto_tree_add_text(tree, tvb, offset, 0,
2850                                    "SPOOL_PRINTER_INFO_LEVEL");
2851
2852         subtree = proto_item_add_subtree(item, ett_SPOOL_PRINTER_INFO_LEVEL);
2853
2854         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level");
2855
2856         switch(level) {
2857         case 3: {
2858                 guint32 ptr;
2859
2860                 offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr,
2861                                  "Devicemode container");
2862
2863                 if (ptr)
2864                         defer_ptr(dp_list, prs_DEVMODE_CTR, subtree);
2865
2866                 offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr,
2867                                  "Security descriptor");
2868
2869                 if (ptr)
2870                         defer_ptr(dp_list, prs_SEC_DESC_BUF, subtree);
2871
2872                 break;
2873         }
2874         case 2: {
2875                 guint32 ptr;
2876
2877                 offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Info");
2878
2879                 /* Sigh - dissecting a PRINTER_INFO_2 is currently
2880                    broken.  Hopefully this will be fixed when these
2881                    routines are converted to the NDR parsing functions
2882                    used by all the other DCERPC dissectors. */
2883
2884 #if 0
2885                 if (ptr)
2886                         defer_ptr(dp_list, prs_PRINTER_INFO_2, subtree);
2887 #endif
2888
2889                 break;
2890         }
2891         default:
2892                 proto_tree_add_text(subtree, tvb, offset, 0,
2893                                     "[Unknown info level %d]", level);
2894                 break;
2895         }
2896
2897         return offset;
2898 }
2899
2900 /*
2901  * SpoolssSetPrinter
2902  */
2903
2904 static int SpoolssSetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2905                                proto_tree *tree, char *drep _U_)
2906 {
2907         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2908         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2909         guint32 level;
2910
2911         if (dcv->rep_frame != 0)
2912                 proto_tree_add_text(tree, tvb, offset, 0,
2913                                     "Reply in frame %u", dcv->rep_frame);
2914
2915         /* Parse packet */
2916
2917         offset = dissect_nt_policy_hnd(
2918                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
2919                 FALSE, FALSE);
2920
2921         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2922
2923         if (check_col(pinfo->cinfo, COL_INFO))
2924                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2925
2926         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2927                                           prs_SPOOL_PRINTER_INFO_LEVEL,
2928                                           NULL, NULL);
2929
2930         offset = dissect_ndr_uint32(
2931                 tvb, offset, pinfo, tree, drep,
2932                 hf_spoolss_setprinter_cmd, NULL);
2933
2934         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2935
2936         return offset;
2937 }
2938
2939 static int SpoolssSetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2940                                 proto_tree *tree, char *drep _U_)
2941 {
2942         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2943         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2944
2945         if (dcv->req_frame != 0)
2946                 proto_tree_add_text(tree, tvb, offset, 0,
2947                                     "Request in frame %u", dcv->req_frame);
2948
2949         /* Parse packet */
2950
2951         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
2952                                   hf_spoolss_rc, NULL);
2953
2954         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2955
2956         return offset;
2957 }
2958
2959 /*
2960  * FORM_REL
2961  */
2962
2963 static const value_string form_type_vals[] =
2964 {
2965         { SPOOLSS_FORM_USER, "User" },
2966         { SPOOLSS_FORM_BUILTIN, "Builtin" },
2967         { SPOOLSS_FORM_PRINTER, "Printer" },
2968         { 0, NULL }
2969 };
2970
2971 static gint ett_FORM_REL = -1;
2972
2973 static int dissect_FORM_REL(tvbuff_t *tvb, int offset, packet_info *pinfo,
2974                             proto_tree *tree, char *drep, int struct_start)
2975 {
2976         proto_item *item;
2977         proto_tree *subtree;
2978         guint32 flags;
2979         int item_start = offset;
2980
2981         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_REL");
2982
2983         subtree = proto_item_add_subtree(item, ett_FORM_REL);
2984
2985         offset = dissect_ndr_uint32(
2986                 tvb, offset, pinfo, NULL, drep,
2987                 hf_spoolss_form_flags, &flags);
2988
2989         proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s",
2990                             val_to_str(flags, form_type_vals, "Unknown (%d)"));
2991
2992         offset = dissect_spoolss_relstr(
2993                 tvb, offset, pinfo, subtree, drep, hf_spoolss_form_name,
2994                 struct_start, NULL);
2995
2996         offset = dissect_ndr_uint32(
2997                 tvb, offset, pinfo, subtree, drep,
2998                 hf_spoolss_form_width, NULL);
2999
3000         offset = dissect_ndr_uint32(
3001                 tvb, offset, pinfo, subtree, drep,
3002                 hf_spoolss_form_height, NULL);
3003
3004         offset = dissect_ndr_uint32(
3005                 tvb, offset, pinfo, subtree, drep,
3006                 hf_spoolss_form_left_margin, NULL);
3007
3008         offset = dissect_ndr_uint32(
3009                 tvb, offset, pinfo, subtree, drep,
3010                 hf_spoolss_form_top_margin, NULL);
3011
3012         offset = dissect_ndr_uint32(
3013                 tvb, offset, pinfo, subtree, drep,
3014                 hf_spoolss_form_horiz_len, NULL);
3015
3016         offset = dissect_ndr_uint32(
3017                 tvb, offset, pinfo, subtree, drep,
3018                 hf_spoolss_form_vert_len, NULL);
3019
3020         proto_item_set_len(item, offset - item_start);
3021
3022         return offset;
3023 }
3024
3025 /*
3026  * SpoolssEnumForms
3027  */
3028
3029 static int SpoolssEnumForms_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3030                               proto_tree *tree, char *drep _U_)
3031 {
3032         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3033         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3034         guint32 level;
3035
3036         if (dcv->rep_frame != 0)
3037                 proto_tree_add_text(tree, tvb, offset, 0,
3038                                     "Reply in frame %u", dcv->rep_frame);
3039
3040         /* Parse packet */
3041
3042         offset = dissect_nt_policy_hnd(
3043                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3044                 FALSE, FALSE);
3045
3046         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
3047
3048         dcv->private_data = (void *)level;
3049
3050         if (check_col(pinfo->cinfo, COL_INFO))
3051                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
3052
3053         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
3054                                           prs_BUFFER, NULL, NULL);
3055
3056         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
3057
3058         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3059
3060         return offset;
3061 }
3062
3063 static int SpoolssEnumForms_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3064                               proto_tree *tree, char *drep _U_)
3065 {
3066         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3067         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3068         BUFFER buffer;
3069         guint32 level = (guint32)dcv->private_data, i, count;
3070         int buffer_offset;
3071
3072         if (dcv->req_frame != 0)
3073                 proto_tree_add_text(tree, tvb, offset, 0,
3074                                     "Request in frame %u", dcv->req_frame);
3075
3076         /* Parse packet */
3077
3078         offset = dissect_spoolss_buffer(
3079                 tvb, offset, pinfo, tree, drep, &buffer);
3080
3081         offset = dissect_ndr_uint32(
3082                 tvb, offset, pinfo, tree, drep,
3083                 hf_spoolss_needed, NULL);
3084
3085         if (check_col(pinfo->cinfo, COL_INFO))
3086                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
3087
3088         offset = dissect_ndr_uint32(
3089                 tvb, offset, pinfo, tree, drep,
3090                 hf_spoolss_enumforms_num, &count);
3091
3092         /* Unfortunately this array isn't in NDR format so we can't
3093            use prs_array().  The other weird thing is the
3094            struct_start being inside the loop rather than outside.
3095            Very strange. */
3096
3097         buffer_offset = buffer.offset;
3098
3099         for (i = 0; i < count; i++) {
3100                 int struct_start = buffer.offset;
3101
3102                 buffer_offset = dissect_FORM_REL(
3103                         tvb, buffer_offset, pinfo, buffer.tree, drep,
3104                         struct_start);
3105         }
3106
3107         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3108                                   hf_spoolss_rc, NULL);
3109
3110         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3111
3112         return offset;
3113 }
3114
3115 /*
3116  * SpoolssDeletePrinter
3117  */
3118
3119 static int SpoolssDeletePrinter_q(tvbuff_t *tvb, int offset,
3120                                   packet_info *pinfo, proto_tree *tree,
3121                                   char *drep _U_)
3122 {
3123         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3124         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3125
3126         if (dcv->rep_frame != 0)
3127                 proto_tree_add_text(tree, tvb, offset, 0,
3128                                     "Reply in frame %u", dcv->rep_frame);
3129
3130         /* Parse packet */
3131
3132         offset = dissect_nt_policy_hnd(
3133                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3134                 FALSE, FALSE);
3135
3136         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3137
3138         return offset;
3139 }
3140
3141 static int SpoolssDeletePrinter_r(tvbuff_t *tvb, int offset,
3142                                   packet_info *pinfo, proto_tree *tree,
3143                                   char *drep _U_)
3144 {
3145         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3146         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3147
3148         if (dcv->req_frame != 0)
3149                 proto_tree_add_text(tree, tvb, offset, 0,
3150                                     "Request in frame %u", dcv->req_frame);
3151
3152         /* Parse packet */
3153
3154         offset = dissect_nt_policy_hnd(
3155                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3156                 FALSE, FALSE);
3157
3158         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3159                                   hf_spoolss_rc, NULL);
3160
3161         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3162
3163         return offset;
3164 }
3165
3166 /*
3167  * AddPrinterEx
3168  */
3169 #if 0
3170 static int SpoolssAddPrinterEx_q(tvbuff_t *tvb, int offset,
3171                                  packet_info *pinfo, proto_tree *tree,
3172                                  char *drep)
3173 {
3174         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3175         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3176         guint32 ptr;
3177
3178         if (dcv->rep_frame != 0)
3179                 proto_tree_add_text(tree, tvb, offset, 0,
3180                                     "Reply in frame %u", dcv->rep_frame);
3181
3182         /* Parse packet */
3183
3184         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Server name");
3185
3186         if (ptr) {
3187                 char *printer_name;
3188
3189                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
3190                                                   prs_UNISTR2_dp,
3191                                                   (void *)&printer_name, NULL);
3192
3193                 if (printer_name)
3194                         dcv->private_data = printer_name;
3195         }
3196
3197         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Level");
3198
3199         /* TODO: PRINTER INFO LEVEL */
3200
3201         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
3202         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
3203         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
3204         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
3205
3206         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
3207
3208         /* TODO: USER LEVEL */
3209
3210         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3211
3212         return offset;
3213 }
3214 #endif
3215 static int SpoolssAddPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3216                                  proto_tree *tree, char *drep _U_)
3217 {
3218         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3219         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3220         e_ctx_hnd policy_hnd;
3221         guint32 status;
3222
3223         if (dcv->req_frame != 0)
3224                 proto_tree_add_text(tree, tvb, offset, 0,
3225                                     "Request in frame %u", dcv->req_frame);
3226
3227         /* Parse packet */
3228
3229         offset = dissect_nt_policy_hnd(
3230                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd,
3231                 TRUE, FALSE);
3232
3233         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3234                                   hf_spoolss_rc, &status);
3235
3236         if (status == 0) {
3237
3238                 /* Associate the returned printer handle with a name */
3239
3240                 if (dcv->private_data) {
3241
3242                         if (check_col(pinfo->cinfo, COL_INFO))
3243                                 col_append_fstr(
3244                                         pinfo->cinfo, COL_INFO, ", %s",
3245                                         (char *)dcv->private_data);
3246
3247                         dcerpc_smb_store_pol_name(
3248                                 &policy_hnd, dcv->private_data);
3249
3250                         g_free(dcv->private_data);
3251                         dcv->private_data = NULL;
3252                 }
3253         }
3254
3255         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3256
3257         return offset;
3258 }
3259
3260 /*
3261  * SpoolssEnumPrinterData
3262  */
3263
3264 static int SpoolssEnumPrinterData_q(tvbuff_t *tvb, int offset,
3265                                     packet_info *pinfo, proto_tree *tree,
3266                                     char *drep _U_)
3267 {
3268         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3269         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3270         guint32 ndx;
3271
3272         if (dcv->rep_frame != 0)
3273                 proto_tree_add_text(tree, tvb, offset, 0,
3274                                     "Reply in frame %u", dcv->rep_frame);
3275
3276         /* Parse packet */
3277
3278         offset = dissect_nt_policy_hnd(
3279                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3280                 FALSE, FALSE);
3281
3282         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
3283                                     hf_spoolss_enumprinterdata_index, &ndx);
3284
3285         if (check_col(pinfo->cinfo, COL_INFO))
3286                 col_append_fstr(pinfo->cinfo, COL_INFO, ", index %d", ndx);
3287
3288         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
3289                                     hf_spoolss_enumprinterdata_value_offered, NULL);
3290
3291         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
3292                                     hf_spoolss_enumprinterdata_data_offered, NULL);
3293
3294         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3295
3296         return offset;
3297 }
3298
3299 static int SpoolssEnumPrinterData_r(tvbuff_t *tvb, int offset,
3300                                     packet_info *pinfo, proto_tree *tree,
3301                                     char *drep _U_)
3302 {
3303         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3304         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3305         guint32 value_size;
3306         proto_item *value_item;
3307         proto_tree *value_subtree;
3308         int uint16s_offset;
3309
3310         if (dcv->req_frame != 0)
3311                 proto_tree_add_text(tree, tvb, offset, 0,
3312                                     "Request in frame %u", dcv->req_frame);
3313
3314         /* Parse packet */
3315
3316         value_item = proto_tree_add_text(tree, tvb, offset, 0, "Value");
3317
3318         value_subtree = proto_item_add_subtree(value_item, ett_printerdata_value);
3319
3320         offset = prs_uint32(tvb, offset, pinfo, value_subtree, &value_size,
3321                             "Value size");
3322
3323         offset = prs_uint16s(tvb, offset, pinfo, value_subtree, value_size,
3324                              &uint16s_offset, NULL);
3325
3326         if (value_size) {
3327                 char *text = fake_unicode(tvb, uint16s_offset, value_size);
3328
3329                 proto_tree_add_text(value_subtree, tvb, uint16s_offset,
3330                                     value_size * 2, "Value: %s", text);
3331
3332                 proto_item_append_text(value_item, ": %s", text);
3333
3334                 if (text[0] && check_col(pinfo->cinfo, COL_INFO))
3335                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", text);
3336
3337                 g_free(text);
3338         }
3339
3340         proto_item_set_len(value_item, value_size * 2 + 4);
3341
3342         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
3343                                     hf_spoolss_enumprinterdata_value_needed, NULL);
3344
3345         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
3346                                     hf_spoolss_printerdata_type, NULL);
3347
3348         offset = dissect_printerdata_data(tvb, offset, pinfo, tree, drep);
3349
3350         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
3351                                     hf_spoolss_enumprinterdata_data_needed, NULL);
3352
3353         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3354                                   hf_spoolss_rc, NULL);
3355
3356         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3357
3358         return offset;
3359 }
3360
3361 /*
3362  * SpoolssEnumPrinters
3363  */
3364
3365 static gint ett_enumprinters_flags = -1;
3366
3367 static int hf_enumprinters_flags_local = -1;
3368 static int hf_enumprinters_flags_name = -1;
3369 static int hf_enumprinters_flags_shared = -1;
3370 static int hf_enumprinters_flags_default = -1;
3371 static int hf_enumprinters_flags_connections = -1;
3372 static int hf_enumprinters_flags_network = -1;
3373 static int hf_enumprinters_flags_remote = -1;
3374
3375 static int SpoolssEnumPrinters_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3376                                  proto_tree *tree, char *drep _U_)
3377 {
3378         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3379         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3380         guint32 ptr, level, flags;
3381         proto_tree *flags_subtree;
3382         proto_item *flags_item;
3383
3384         if (dcv->rep_frame != 0)
3385                 proto_tree_add_text(tree, tvb, offset, 0,
3386                                     "Reply in frame %u", dcv->rep_frame);
3387
3388         /* Parse packet */
3389
3390         offset = prs_uint32(tvb, offset, pinfo, NULL, &flags, "Flags");
3391
3392         flags_item = proto_tree_add_text(tree, tvb, offset - 4, 4,
3393                                          "Flags: 0x%08x", flags);
3394
3395         flags_subtree = proto_item_add_subtree(
3396                 flags_item, ett_enumprinters_flags);
3397
3398         proto_tree_add_boolean(
3399                 flags_subtree, hf_enumprinters_flags_network, tvb,
3400                 offset - 4, 4, flags);
3401
3402         proto_tree_add_boolean(
3403                 flags_subtree, hf_enumprinters_flags_shared, tvb,
3404                 offset - 4, 4, flags);
3405
3406         proto_tree_add_boolean(
3407                 flags_subtree, hf_enumprinters_flags_remote, tvb,
3408                 offset - 4, 4, flags);
3409
3410         proto_tree_add_boolean(
3411                 flags_subtree, hf_enumprinters_flags_name, tvb,
3412                 offset - 4, 4, flags);
3413
3414         proto_tree_add_boolean(
3415                 flags_subtree, hf_enumprinters_flags_connections, tvb,
3416                 offset - 4, 4, flags);
3417
3418         proto_tree_add_boolean(
3419                 flags_subtree, hf_enumprinters_flags_local, tvb,
3420                 offset - 4, 4, flags);
3421
3422         proto_tree_add_boolean(
3423                 flags_subtree, hf_enumprinters_flags_default, tvb,
3424                 offset - 4, 4, flags);
3425
3426         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Name");
3427
3428         if (ptr)
3429                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
3430                                                   prs_UNISTR2_dp, NULL, NULL);
3431
3432         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
3433
3434         if (check_col(pinfo->cinfo, COL_INFO))
3435                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level, %d", level);
3436
3437         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
3438                                           prs_BUFFER, NULL, NULL);
3439
3440         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
3441
3442         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3443
3444         return offset;
3445 }
3446
3447 static int SpoolssEnumPrinters_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3448                                  proto_tree *tree, char *drep _U_)
3449 {
3450         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3451         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3452
3453         if (dcv->req_frame != 0)
3454                 proto_tree_add_text(tree, tvb, offset, 0,
3455                                     "Request in frame %u", dcv->req_frame);
3456
3457         /* Parse packet */
3458
3459         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
3460                                           prs_BUFFER, NULL, NULL);
3461
3462         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
3463
3464         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Returned");
3465
3466         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3467                                   hf_spoolss_rc, NULL);
3468
3469         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3470
3471         return offset;
3472 }
3473
3474 /*
3475  * AddPrinterDriver
3476  */
3477 #if 0
3478 static int SpoolssAddPrinterDriver_q(tvbuff_t *tvb, int offset,
3479                                      packet_info *pinfo, proto_tree *tree,
3480                                      char *drep)
3481 {
3482         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3483         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3484
3485         if (dcv->rep_frame != 0)
3486                 proto_tree_add_text(tree, tvb, offset, 0,
3487                                     "Reply in frame %u", dcv->rep_frame);
3488
3489         /* Parse packet */
3490
3491         offset = dissect_ndr_pointer(
3492                 tvb, offset, pinfo, tree, drep,
3493                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
3494                 "Server", hf_spoolss_servername, 0);
3495
3496         offset = dissect_spoolss_DRIVER_INFO_CTR(
3497                 tvb, offset, pinfo, tree, drep);
3498
3499         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3500
3501         return offset;
3502 }
3503 #endif
3504 static int SpoolssAddPrinterDriver_r(tvbuff_t *tvb, int offset,
3505                                      packet_info *pinfo, proto_tree *tree,
3506                                      char *drep _U_)
3507 {
3508         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3509         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3510
3511         if (dcv->req_frame != 0)
3512                 proto_tree_add_text(tree, tvb, offset, 0,
3513                                     "Request in frame %u", dcv->req_frame);
3514
3515         /* Parse packet */
3516
3517         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3518                                   hf_spoolss_rc, NULL);
3519
3520         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3521
3522         return offset;
3523 }
3524
3525 /*
3526  * FORM_1
3527  */
3528
3529 static gint ett_FORM_1 = -1;
3530
3531 static int dissect_FORM_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
3532                           proto_tree *tree, char *drep)
3533 {
3534         proto_item *item;
3535         proto_tree *subtree;
3536         guint32 flags;
3537
3538         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_1");
3539
3540         subtree = proto_item_add_subtree(item, ett_FORM_1);
3541
3542         offset = dissect_ndr_pointer(
3543                 tvb, offset, pinfo, subtree, drep,
3544                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
3545                 "Name", hf_spoolss_form_name, 0);
3546
3547         /* Eek - we need to know whether this pointer was NULL or not.
3548            Currently there is not any way to do this. */
3549
3550         if (tvb_length_remaining(tvb, offset) == 0)
3551                 goto done;
3552
3553         offset = dissect_ndr_uint32(
3554                 tvb, offset, pinfo, NULL, drep,
3555                 hf_spoolss_form_flags, &flags);
3556
3557         proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s",
3558                             val_to_str(flags, form_type_vals, "Unknown (%d)"));
3559
3560         offset = dissect_ndr_uint32(
3561                 tvb, offset, pinfo, subtree, drep,
3562                 hf_spoolss_form_unknown, NULL);
3563
3564         offset = dissect_ndr_uint32(
3565                 tvb, offset, pinfo, subtree, drep,
3566                 hf_spoolss_form_width, NULL);
3567
3568         offset = dissect_ndr_uint32(
3569                 tvb, offset, pinfo, subtree, drep,
3570                 hf_spoolss_form_height, NULL);
3571
3572         offset = dissect_ndr_uint32(
3573                 tvb, offset, pinfo, subtree, drep,
3574                 hf_spoolss_form_left_margin, NULL);
3575
3576         offset = dissect_ndr_uint32(
3577                 tvb, offset, pinfo, subtree, drep,
3578                 hf_spoolss_form_top_margin, NULL);
3579
3580         offset = dissect_ndr_uint32(
3581                 tvb, offset, pinfo, subtree, drep,
3582                 hf_spoolss_form_horiz_len, NULL);
3583
3584         offset = dissect_ndr_uint32(
3585                 tvb, offset, pinfo, subtree, drep,
3586                 hf_spoolss_form_vert_len, NULL);
3587
3588  done:
3589         return offset;
3590 }
3591
3592 /*
3593  * FORM_CTR
3594  */
3595
3596 static gint ett_FORM_CTR = -1;
3597
3598 static int dissect_FORM_CTR(tvbuff_t *tvb, int offset,
3599                             packet_info *pinfo, proto_tree *tree,
3600                             char *drep)
3601 {
3602         proto_item *item;
3603         proto_tree *subtree;
3604         guint32 level;
3605
3606         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_CTR");
3607
3608         subtree = proto_item_add_subtree(item, ett_FORM_CTR);
3609
3610         offset = dissect_ndr_uint32(
3611                 tvb, offset, pinfo, subtree, drep,
3612                 hf_spoolss_form_level, &level);
3613
3614         switch(level) {
3615         case 1:
3616                 offset = dissect_FORM_1(tvb, offset, pinfo, subtree, drep);
3617                 break;
3618
3619         default:
3620                 proto_tree_add_text(subtree, tvb, offset, 0,
3621                                     "[Unknown info level %d]", level);
3622                 break;
3623         }
3624
3625         return offset;
3626 }
3627
3628 /* Form name - this is actually a unistr2 without the pointer */
3629
3630 static int dissect_form_name(tvbuff_t *tvb, int offset, packet_info *pinfo,
3631                              proto_tree *tree, char *drep)
3632 {
3633         extern int hf_nt_str_len;
3634         extern int hf_nt_str_off;
3635         extern int hf_nt_str_max_len;
3636         guint32 len;
3637
3638         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
3639                         hf_nt_str_max_len, NULL);
3640
3641         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
3642                         hf_nt_str_off, NULL);
3643
3644         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
3645                         hf_nt_str_len, &len);
3646
3647         offset = dissect_ndr_uint16s(
3648                 tvb, offset, pinfo, tree, drep,
3649                 hf_spoolss_form_name, len, NULL);
3650
3651         return offset;
3652 }
3653
3654
3655 /*
3656  * AddForm
3657  */
3658
3659 static int SpoolssAddForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3660                             proto_tree *tree, char *drep _U_)
3661 {
3662         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3663         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3664         guint32 level;
3665
3666         if (dcv->rep_frame != 0)
3667                 proto_tree_add_text(tree, tvb, offset, 0,
3668                                     "Reply in frame %u", dcv->rep_frame);
3669
3670         /* Parse packet */
3671
3672         offset = dissect_nt_policy_hnd(
3673                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3674                 FALSE, FALSE);
3675
3676         offset = dissect_ndr_uint32(
3677                 tvb, offset, pinfo, tree, drep,
3678                 hf_spoolss_addform_level, &level);
3679
3680         if (check_col(pinfo->cinfo, COL_INFO))
3681                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
3682
3683         /* Store info level to match with reply packet */
3684
3685         dcv->private_data = (void *)level;
3686
3687         offset = dissect_FORM_CTR(tvb, offset, pinfo, tree, drep);
3688
3689         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3690
3691         return offset;
3692 }
3693
3694 static int SpoolssAddForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3695                             proto_tree *tree, char *drep _U_)
3696 {
3697         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3698         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3699
3700         if (dcv->req_frame != 0)
3701                 proto_tree_add_text(tree, tvb, offset, 0,
3702                                     "Request in frame %u", dcv->req_frame);
3703
3704         /* Parse packet */
3705
3706         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3707                                   hf_spoolss_rc, NULL);
3708
3709         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3710
3711         return offset;
3712 }
3713
3714 /*
3715  * DeleteForm
3716  */
3717
3718 static int SpoolssDeleteForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3719                                proto_tree *tree, char *drep _U_)
3720 {
3721         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3722         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3723
3724         if (dcv->rep_frame != 0)
3725                 proto_tree_add_text(tree, tvb, offset, 0,
3726                                     "Reply in frame %u", dcv->rep_frame);
3727
3728         /* Parse packet */
3729
3730         offset = dissect_nt_policy_hnd(
3731                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3732                 FALSE, FALSE);
3733
3734         offset = dissect_form_name(
3735                 tvb, offset, pinfo, tree, drep);
3736
3737         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3738
3739         return offset;
3740 }
3741
3742 static int SpoolssDeleteForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3743                             proto_tree *tree, char *drep _U_)
3744 {
3745         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3746         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3747
3748         if (dcv->req_frame != 0)
3749                 proto_tree_add_text(tree, tvb, offset, 0,
3750                                     "Request in frame %u", dcv->req_frame);
3751
3752         /* Parse packet */
3753
3754         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3755                                   hf_spoolss_rc, NULL);
3756
3757         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3758
3759         return offset;
3760 }
3761
3762 /*
3763  * SetForm
3764  */
3765
3766 static int SpoolssSetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3767                             proto_tree *tree, char *drep _U_)
3768 {
3769         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3770         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3771         guint32 level;
3772
3773         if (dcv->rep_frame != 0)
3774                 proto_tree_add_text(tree, tvb, offset, 0,
3775                                     "Reply in frame %u", dcv->rep_frame);
3776
3777         /* Parse packet */
3778
3779         offset = dissect_nt_policy_hnd(
3780                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3781                 FALSE, FALSE);
3782
3783         offset = dissect_form_name(
3784                 tvb, offset, pinfo, tree, drep);
3785
3786         offset = dissect_ndr_uint32(
3787                 tvb, offset, pinfo, tree, drep,
3788                 hf_spoolss_setform_level, &level);
3789
3790         if (check_col(pinfo->cinfo, COL_INFO))
3791                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
3792
3793         offset = dissect_FORM_CTR(tvb, offset, pinfo, tree, drep);
3794
3795         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3796
3797         return offset;
3798 }
3799
3800 static int SpoolssSetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3801                             proto_tree *tree, char *drep _U_)
3802 {
3803         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3804         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3805
3806         if (dcv->req_frame != 0)
3807                 proto_tree_add_text(tree, tvb, offset, 0,
3808                                     "Request in frame %u", dcv->req_frame);
3809
3810         /* Parse packet */
3811
3812         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3813                                   hf_spoolss_rc, NULL);
3814
3815         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3816
3817         return offset;
3818 }
3819
3820 /*
3821  * GetForm
3822  */
3823
3824 static int SpoolssGetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3825                             proto_tree *tree, char *drep _U_)
3826 {
3827         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3828         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3829         guint32 level;
3830
3831         if (dcv->rep_frame != 0)
3832                 proto_tree_add_text(tree, tvb, offset, 0,
3833                                     "Reply in frame %u", dcv->rep_frame);
3834
3835         /* Parse packet */
3836
3837         offset = dissect_nt_policy_hnd(
3838                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
3839                 FALSE, FALSE);
3840
3841         offset = dissect_form_name(
3842                 tvb, offset, pinfo, tree, drep);
3843
3844         offset = dissect_ndr_uint32(
3845                 tvb, offset, pinfo, tree, drep,
3846                 hf_spoolss_getform_level, &level);
3847
3848         dcv->private_data = (void *)level;
3849
3850         if (check_col(pinfo->cinfo, COL_INFO))
3851                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d",
3852                                 level);
3853
3854         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL);
3855
3856         offset = dissect_ndr_uint32(
3857                 tvb, offset, pinfo, tree, drep,
3858                 hf_spoolss_offered, NULL);
3859
3860         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3861
3862         return offset;
3863 }
3864
3865 static int SpoolssGetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3866                             proto_tree *tree, char *drep _U_)
3867 {
3868         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3869         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3870         BUFFER buffer;
3871         int buffer_offset;
3872         guint32 level = (guint32)dcv->private_data;
3873
3874         if (dcv->req_frame != 0)
3875                 proto_tree_add_text(tree, tvb, offset, 0,
3876                                     "Request in frame %u", dcv->req_frame);
3877
3878         /* Parse packet */
3879
3880         offset = dissect_spoolss_buffer(
3881                 tvb, offset, pinfo, tree, drep, &buffer);
3882
3883         offset = dissect_ndr_uint32(
3884                 tvb, offset, pinfo, tree, drep,
3885                 hf_spoolss_needed, NULL);
3886
3887         if (check_col(pinfo->cinfo, COL_INFO))
3888                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
3889
3890         if (!buffer.size)
3891                 goto done;
3892
3893         buffer_offset = buffer.offset;
3894
3895         switch(level) {
3896         case 1: {
3897                 int struct_start = buffer.offset;
3898
3899                 buffer_offset = dissect_FORM_REL(
3900                         tvb, buffer_offset, pinfo, tree, drep, struct_start);
3901                 break;
3902         }
3903
3904         default:
3905                 proto_tree_add_text(
3906                         buffer.tree, tvb, buffer_offset, buffer.size,
3907                         "[Unknown info level %d]", level);
3908                 goto done;
3909         }
3910
3911  done:
3912         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
3913                                   hf_spoolss_rc, NULL);
3914
3915         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3916
3917         return offset;
3918 }
3919
3920 /* A generic reply function that just parses the status code.  Useful for
3921    unimplemented dissectors so the status code can be inserted into the
3922    INFO column. */
3923
3924 static int SpoolssGeneric_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3925                             proto_tree *tree, char *drep _U_)
3926 {
3927         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3928         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3929         int len = tvb_length(tvb);
3930
3931         proto_tree_add_text(tree, tvb, offset, 0,
3932                             "[Unimplemented dissector: SPOOLSS]");
3933
3934         if (dcv->req_frame != 0)
3935                 proto_tree_add_text(tree, tvb, offset, 0,
3936                                     "Request in frame %u", dcv->req_frame);
3937
3938         offset = dissect_doserror(tvb, len - 4, pinfo, tree, drep,
3939                                   hf_spoolss_rc, NULL);
3940
3941         return offset;
3942 }
3943
3944 /*
3945  * SYSTEM_TIME
3946  */
3947
3948 static gint ett_SYSTEM_TIME;
3949
3950 static int
3951 dissect_SYSTEM_TIME(tvbuff_t *tvb, int offset, packet_info *pinfo,
3952                     proto_tree *tree, char *drep)
3953 {
3954         proto_item *item;
3955         proto_tree *subtree;
3956         guint16 year, month, day, hour, minute, second;
3957
3958         item = proto_tree_add_text(tree, tvb, offset, 16, "SYSTEM_TIME: ");
3959
3960         subtree = proto_item_add_subtree(item, ett_SYSTEM_TIME);
3961
3962         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3963                                      hf_spoolss_time_year, &year);
3964
3965         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3966                                      hf_spoolss_time_month, &month);
3967
3968         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3969                                      hf_spoolss_time_dow, NULL);
3970
3971         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3972                                      hf_spoolss_time_day, &day);
3973
3974         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3975                                      hf_spoolss_time_hour, &hour);
3976
3977         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3978                                      hf_spoolss_time_minute, &minute);
3979
3980         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3981                                      hf_spoolss_time_second, &second);
3982
3983         offset = dissect_ndr_uint16 (tvb, offset, pinfo, subtree, drep,
3984                                      hf_spoolss_time_msec, NULL);
3985
3986         proto_item_append_text(item, "%d/%02d/%02d %02d:%02d:%02d", year,
3987                                month, day, hour, minute, second);
3988
3989         return offset;
3990 }
3991
3992 /*
3993  * JOB_INFO_1
3994  */
3995
3996 static gint ett_JOB_INFO_1;
3997
3998 static int
3999 dissect_spoolss_JOB_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
4000                            proto_tree *tree, char *drep)
4001 {
4002         proto_item *item;
4003         proto_tree *subtree;
4004         int struct_start = offset;
4005         char *document_name;
4006
4007         item = proto_tree_add_text(tree, tvb, offset, 0, "JOB_INFO_1");
4008
4009         subtree = proto_item_add_subtree(item, ett_JOB_INFO_1);
4010
4011         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4012                                     hf_spoolss_jobid, NULL);
4013
4014         offset = dissect_spoolss_relstr(
4015                 tvb, offset, pinfo, subtree, drep, hf_spoolss_printername,
4016                 struct_start, NULL);
4017
4018         offset = dissect_spoolss_relstr(
4019                 tvb, offset, pinfo, subtree, drep, hf_spoolss_servername,
4020                 struct_start, NULL);
4021
4022         offset = dissect_spoolss_relstr(
4023                 tvb, offset, pinfo, subtree, drep, hf_spoolss_username,
4024                 struct_start, NULL);
4025
4026         offset = dissect_spoolss_relstr(
4027                 tvb, offset, pinfo, subtree, drep, hf_spoolss_documentname,
4028                 struct_start, &document_name);
4029
4030         proto_item_append_text(item, ": %s", document_name);
4031         g_free(document_name);
4032
4033         offset = dissect_spoolss_relstr(
4034                 tvb, offset, pinfo, subtree, drep, hf_spoolss_datatype,
4035                 struct_start, NULL);
4036
4037         offset = dissect_spoolss_relstr(
4038                 tvb, offset, pinfo, subtree, drep, hf_spoolss_textstatus,
4039                 struct_start, NULL);
4040
4041         offset = dissect_job_status(tvb, offset, pinfo, subtree, drep);
4042
4043         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4044                                     hf_spoolss_jobpriority, NULL);
4045
4046         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4047                                     hf_spoolss_jobposition, NULL);
4048
4049         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4050                                     hf_spoolss_jobtotalpages, NULL);
4051
4052         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4053                                     hf_spoolss_jobpagesprinted, NULL);
4054
4055         offset = dissect_SYSTEM_TIME(tvb, offset, pinfo, subtree, drep);
4056
4057         proto_item_set_len(item, offset - struct_start);
4058
4059         return offset;
4060 }
4061
4062 /*
4063  * JOB_INFO_2
4064  */
4065
4066 static gint ett_JOB_INFO_2;
4067
4068 #if 0
4069
4070 static int prs_JOB_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo,
4071                           proto_tree *tree, GList **dp_list, void **data)
4072 {
4073         proto_item *item;
4074         proto_tree *subtree;
4075         int struct_start = offset;
4076         guint32 rel_offset;
4077
4078         item = proto_tree_add_text(tree, tvb, offset, 0, "JOB_INFO_2");
4079
4080         subtree = proto_item_add_subtree(item, ett_FORM_CTR);
4081
4082         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Job ID");
4083
4084         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4085                             NULL, "Printer name");
4086
4087         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4088                             NULL, "Machine name");
4089
4090         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4091                             NULL, "User name");
4092
4093         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4094                             NULL, "Document");
4095
4096         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4097                             NULL, "Notify name");
4098
4099         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4100                             NULL, "Data type");
4101
4102         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4103                             NULL, "Print processor");
4104
4105         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4106                             NULL, "Parameters");
4107
4108         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list, struct_start,
4109                             NULL, "Driver name");
4110
4111         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
4112
4113         prs_DEVMODE(tvb, struct_start + rel_offset - 4, pinfo, tree,
4114                     dp_list, NULL);
4115
4116         /* XXX security descriptor */
4117
4118         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Security descriptor");
4119
4120         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Status");
4121
4122         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Priority");
4123
4124         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Position");
4125
4126         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Start time");
4127
4128         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Until time");
4129
4130         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Total pages");
4131
4132         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
4133
4134         offset = prs_struct_and_referents(tvb, offset, pinfo, subtree,
4135                                           prs_SYSTEM_TIME, NULL, NULL);
4136
4137         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Time elapsed");
4138
4139         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pages printed");
4140
4141         return offset;
4142 }
4143
4144 #endif
4145
4146 /*
4147  * EnumJobs
4148  */
4149
4150 static int SpoolssEnumJobs_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
4151                              proto_tree *tree, char *drep _U_)
4152 {
4153         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4154         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4155         guint32 level;
4156
4157         if (dcv->rep_frame != 0)
4158                 proto_tree_add_text(tree, tvb, offset, 0,
4159                                     "Reply in frame %d", dcv->rep_frame);
4160
4161         /* Parse packet */
4162
4163         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4164                                        hf_spoolss_hnd, NULL,
4165                                        FALSE, FALSE);
4166
4167         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4168                                     hf_spoolss_enumjobs_firstjob, NULL);
4169
4170         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4171                                     hf_spoolss_enumjobs_numjobs, NULL);
4172
4173         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4174                                     hf_spoolss_level, &level);
4175
4176         dcv->private_data = (void *)level;
4177
4178         if (check_col(pinfo->cinfo, COL_INFO))
4179                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
4180
4181         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL);
4182
4183         offset = dissect_ndr_uint32(
4184                 tvb, offset, pinfo, tree, drep,
4185                 hf_spoolss_offered, NULL);
4186
4187         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4188
4189         return offset;
4190 }
4191
4192 static int SpoolssEnumJobs_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
4193                              proto_tree *tree, char *drep _U_)
4194 {
4195         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4196         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4197         gint16 level = (guint32)dcv->private_data;
4198         BUFFER buffer;
4199         guint32 num_jobs, i;
4200         int buffer_offset;
4201
4202         if (dcv->req_frame != 0)
4203                 proto_tree_add_text(tree, tvb, offset, 0,
4204                                     "Request in frame %d", dcv->req_frame);
4205
4206         /* Parse packet */
4207
4208         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep,
4209                                         &buffer);
4210
4211         offset = dissect_ndr_uint32(
4212                 tvb, offset, pinfo, tree, drep,
4213                 hf_spoolss_needed, NULL);
4214
4215         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4216                                     hf_spoolss_enumjobs_numjobs, &num_jobs);
4217
4218         buffer_offset = buffer.offset;
4219
4220         for (i = 0; i < num_jobs; i++) {
4221                 switch(level) {
4222                 case 1:
4223                         buffer_offset = dissect_spoolss_JOB_INFO_1(
4224                                 tvb, buffer_offset, pinfo, buffer.tree, drep);
4225                         break;
4226                 case 2:
4227                 default:
4228                         proto_tree_add_text(
4229                                 buffer.tree, tvb, buffer_offset, buffer.size,
4230                                 "[Unknown info level %d]", level);
4231                         goto done;
4232                 }
4233
4234         }
4235
4236 done:
4237         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4238                                   hf_spoolss_rc, NULL);
4239
4240         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4241
4242         return offset;
4243 }
4244
4245 /*
4246  * SetJob
4247  */
4248
4249 /* Set job command values */
4250
4251 #define JOB_CONTROL_PAUSE              1
4252 #define JOB_CONTROL_RESUME             2
4253 #define JOB_CONTROL_CANCEL             3
4254 #define JOB_CONTROL_RESTART            4
4255 #define JOB_CONTROL_DELETE             5
4256
4257 static const value_string setjob_commands[] = {
4258         { JOB_CONTROL_PAUSE, "Pause" },
4259         { JOB_CONTROL_RESUME, "Resume" },
4260         { JOB_CONTROL_CANCEL, "Cancel" },
4261         { JOB_CONTROL_RESTART, "Restart" },
4262         { JOB_CONTROL_DELETE, "Delete" },
4263         { 0, NULL }
4264 };
4265
4266 static int SpoolssSetJob_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
4267                            proto_tree *tree, char *drep)
4268 {
4269         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4270         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4271         guint32 jobid, cmd;
4272
4273         if (dcv->rep_frame != 0)
4274                 proto_tree_add_text(tree, tvb, offset, 0,
4275                                     "Reply in frame %u", dcv->rep_frame);
4276
4277         /* Parse packet */
4278
4279         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4280                                        hf_spoolss_hnd, NULL,
4281                                        FALSE, FALSE);
4282
4283         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4284                                     hf_spoolss_jobid, &jobid);
4285
4286         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4287                                     hf_spoolss_level, NULL);
4288
4289         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4290                                     hf_spoolss_setjob_cmd, &cmd);
4291
4292         if (check_col(pinfo->cinfo, COL_INFO))
4293                 col_append_fstr(
4294                         pinfo->cinfo, COL_INFO, ", %s jobid %d",
4295                         val_to_str(cmd, setjob_commands, "Unknown (%d)"),
4296                         jobid);
4297
4298         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4299
4300         return offset;
4301 }
4302
4303 static int SpoolssSetJob_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
4304                            proto_tree *tree, char *drep)
4305 {
4306         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4307         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4308
4309         if (dcv->req_frame != 0)
4310                 proto_tree_add_text(tree, tvb, offset, 0,
4311                                     "Request in frame %u", dcv->req_frame);
4312
4313         /* Parse packet */
4314
4315         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4316                                   hf_spoolss_rc, NULL);
4317
4318         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4319
4320         return offset;
4321 }
4322
4323 /*
4324  * GetJob
4325  */
4326
4327 static int SpoolssGetJob_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
4328                            proto_tree *tree, char *drep)
4329 {
4330         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4331         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4332         guint32 level, jobid;
4333
4334         if (dcv->rep_frame != 0)
4335                 proto_tree_add_text(tree, tvb, offset, 0,
4336                                     "Reply in frame %u", dcv->rep_frame);
4337
4338         /* Parse packet */
4339
4340         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4341                                        hf_spoolss_hnd, NULL,
4342                                        FALSE, FALSE);
4343
4344         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4345                                     hf_spoolss_jobid, &jobid);
4346
4347         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4348                                     hf_spoolss_level, &level);
4349
4350         dcv->private_data = (void *)level;
4351
4352         if (check_col(pinfo->cinfo, COL_INFO))
4353                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d, jobid %d",
4354                                 level, jobid);
4355
4356         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL);
4357
4358         offset = dissect_ndr_uint32(
4359                 tvb, offset, pinfo, tree, drep,
4360                 hf_spoolss_offered, NULL);
4361
4362         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4363
4364         return offset;
4365 }
4366
4367 static int SpoolssGetJob_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
4368                         proto_tree *tree, char *drep)
4369 {
4370         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4371         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4372         gint32 level = (guint32)dcv->private_data;
4373         BUFFER buffer;
4374         int buffer_offset;
4375
4376         if (dcv->req_frame != 0)
4377                 proto_tree_add_text(tree, tvb, offset, 0,
4378                                     "Request in frame %u", dcv->req_frame);
4379
4380         /* Parse packet */
4381
4382         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep,
4383                                         &buffer);
4384
4385         if (!buffer.size)
4386                 goto done;
4387
4388         buffer_offset = buffer.offset;
4389
4390         switch(level) {
4391         case 1:
4392                 buffer_offset = dissect_spoolss_JOB_INFO_1(
4393                         tvb, buffer_offset, pinfo, buffer.tree, drep);
4394                 break;
4395         case 2:
4396         default:
4397                 proto_tree_add_text(
4398                         buffer.tree, tvb, buffer_offset, buffer.size,
4399                         "[Unknown info level %d]", level);
4400                 goto done;
4401         }
4402
4403 done:
4404         offset = dissect_ndr_uint32(
4405                 tvb, offset, pinfo, tree, drep,
4406                 hf_spoolss_needed, NULL);
4407
4408         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4409                                   hf_spoolss_rc, NULL);
4410
4411         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4412
4413         return offset;
4414 }
4415
4416 /*
4417  * StartPagePrinter
4418  */
4419
4420 static int SpoolssStartPagePrinter_q(tvbuff_t *tvb, int offset,
4421                                      packet_info *pinfo, proto_tree *tree,
4422                                      char *drep)
4423 {
4424         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4425         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4426         e_ctx_hnd policy_hnd;
4427         char *pol_name;
4428
4429         if (dcv->rep_frame != 0)
4430                 proto_tree_add_text(tree, tvb, offset, 0,
4431                                     "Reply in frame %u", dcv->rep_frame);
4432
4433         /* Parse packet */
4434
4435         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4436                                        hf_spoolss_hnd, &policy_hnd,
4437                                        FALSE, FALSE);
4438
4439         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
4440
4441         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
4442                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
4443                                 pol_name);
4444
4445         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4446
4447         return offset;
4448 }
4449
4450 static int SpoolssStartPagePrinter_r(tvbuff_t *tvb, int offset,
4451                                      packet_info *pinfo, proto_tree *tree,
4452                                      char *drep)
4453 {
4454         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4455         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4456
4457         if (dcv->req_frame != 0)
4458                 proto_tree_add_text(tree, tvb, offset, 0,
4459                                     "Request in frame %u", dcv->req_frame);
4460
4461         /* Parse packet */
4462
4463         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4464                                   hf_spoolss_rc, NULL);
4465
4466         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4467
4468         return offset;
4469 }
4470
4471 /*
4472  * EndPagePrinter
4473  */
4474
4475 static int SpoolssEndPagePrinter_q(tvbuff_t *tvb, int offset,
4476                                    packet_info *pinfo, proto_tree *tree,
4477                                    char *drep)
4478 {
4479         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4480         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4481         e_ctx_hnd policy_hnd;
4482         char *pol_name;
4483
4484         if (dcv->rep_frame != 0)
4485                 proto_tree_add_text(tree, tvb, offset, 0,
4486                                     "Reply in frame %u", dcv->rep_frame);
4487
4488         /* Parse packet */
4489
4490         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4491                                        hf_spoolss_hnd, &policy_hnd,
4492                                        FALSE, FALSE);
4493
4494         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
4495
4496         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
4497                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
4498                                 pol_name);
4499
4500         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4501
4502         return offset;
4503 }
4504
4505 static int SpoolssEndPagePrinter_r(tvbuff_t *tvb, int offset,
4506                                    packet_info *pinfo, proto_tree *tree,
4507                                    char *drep)
4508 {
4509         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4510         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4511
4512         if (dcv->req_frame != 0)
4513                 proto_tree_add_text(tree, tvb, offset, 0,
4514                                     "Request in frame %u", dcv->req_frame);
4515
4516         /* Parse packet */
4517
4518         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4519                                   hf_spoolss_rc, NULL);
4520
4521         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4522
4523         return offset;
4524 }
4525
4526 /*
4527  * DOC_INFO_1
4528  */
4529
4530 static gint ett_DOC_INFO_1 = -1;
4531
4532 static int
4533 dissect_spoolss_doc_info_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
4534                            proto_tree *tree, char *drep)
4535 {
4536         proto_item *item;
4537         proto_tree *subtree;
4538
4539         item = proto_tree_add_text(tree, tvb, offset, 0, "DOC_INFO_1");
4540
4541         subtree = proto_item_add_subtree(item, ett_DOC_INFO_1);
4542
4543         offset = dissect_ndr_pointer(
4544                 tvb, offset, pinfo, subtree, drep,
4545                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
4546                 "Document name", hf_spoolss_documentname, 0);
4547
4548         offset = dissect_ndr_pointer(
4549                 tvb, offset, pinfo, subtree, drep,
4550                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
4551                 "Output file", hf_spoolss_outputfile, 0);
4552
4553         offset = dissect_ndr_pointer(
4554                 tvb, offset, pinfo, subtree, drep,
4555                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
4556                 "Data type", hf_spoolss_datatype, 0);
4557
4558         return offset;
4559 }
4560
4561 static int
4562 dissect_spoolss_doc_info_data(tvbuff_t *tvb, int offset, packet_info *pinfo,
4563                               proto_tree *tree, char *drep)
4564 {
4565         dcerpc_info *di = pinfo->private_data;
4566
4567         if (di->conformant_run)
4568                 return offset;
4569
4570         switch(di->levels) {
4571         case 1:
4572                 offset = dissect_spoolss_doc_info_1(
4573                         tvb, offset, pinfo, tree, drep);
4574                 break;
4575         default:
4576                 proto_tree_add_text(tree, tvb, offset, 0,
4577                                     "[Unknown info level %d]", di->levels);
4578                 break;
4579         }
4580
4581         return offset;
4582 }
4583
4584 /*
4585  * DOC_INFO
4586  */
4587
4588 static gint ett_DOC_INFO = -1;
4589
4590 static int
4591 dissect_spoolss_doc_info(tvbuff_t *tvb, int offset, packet_info *pinfo,
4592                          proto_tree *tree, char *drep)
4593 {
4594         proto_item *item;
4595         proto_tree *subtree;
4596         guint32 level;
4597
4598         item = proto_tree_add_text(tree, tvb, offset, 0, "DOC_INFO");
4599
4600         subtree = proto_item_add_subtree(item, ett_DOC_INFO);
4601
4602         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4603                                     hf_spoolss_level, &level);
4604
4605         offset = dissect_ndr_pointer(tvb, offset, pinfo, subtree, drep,
4606                                      dissect_spoolss_doc_info_data,
4607                                      NDR_POINTER_UNIQUE, "Document info",
4608                                      -1, level);
4609         return offset;
4610 }
4611
4612 /*
4613  * DOC_INFO_CTR
4614  */
4615
4616 static gint ett_DOC_INFO_CTR = -1;
4617
4618 static int
4619 dissect_spoolss_doc_info_ctr(tvbuff_t *tvb, int offset, packet_info *pinfo,
4620                              proto_tree *tree, char *drep)
4621 {
4622         proto_item *item;
4623         proto_tree *subtree;
4624
4625         item = proto_tree_add_text(tree, tvb, offset, 0, "DOC_INFO_CTR");
4626
4627         subtree = proto_item_add_subtree(item, ett_DOC_INFO_CTR);
4628
4629         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4630                                     hf_spoolss_level, NULL);
4631
4632         offset = dissect_spoolss_doc_info(
4633                 tvb, offset, pinfo, subtree, drep);
4634
4635         return offset;
4636 }
4637
4638 /*
4639  * StartDocPrinter
4640  */
4641
4642 static int SpoolssStartDocPrinter_q(tvbuff_t *tvb, int offset,
4643                                     packet_info *pinfo, proto_tree *tree,
4644                                     char *drep)
4645 {
4646         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4647         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4648         e_ctx_hnd policy_hnd;
4649         char *pol_name;
4650
4651         if (dcv->rep_frame != 0)
4652                 proto_tree_add_text(tree, tvb, offset, 0,
4653                                     "Reply in frame %u", dcv->rep_frame);
4654
4655         /* Parse packet */
4656
4657         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4658                                        hf_spoolss_hnd, &policy_hnd,
4659                                        FALSE, FALSE);
4660
4661         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
4662
4663         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
4664                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
4665                                 pol_name);
4666
4667         offset = dissect_spoolss_doc_info_ctr(tvb, offset, pinfo, tree, drep);
4668
4669         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4670
4671         return offset;
4672 }
4673
4674 static int SpoolssStartDocPrinter_r(tvbuff_t *tvb, int offset,
4675                                     packet_info *pinfo, proto_tree *tree,
4676                                     char *drep)
4677 {
4678         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4679         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4680
4681         if (dcv->req_frame != 0)
4682                 proto_tree_add_text(tree, tvb, offset, 0,
4683                                     "Request in frame %u", dcv->req_frame);
4684
4685         /* Parse packet */
4686
4687         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4688                                     hf_spoolss_jobid, NULL);
4689
4690         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4691                                   hf_spoolss_rc, NULL);
4692
4693         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4694
4695         return offset;
4696 }
4697
4698 /*
4699  * EndDocPrinter
4700  */
4701
4702 static int SpoolssEndDocPrinter_q(tvbuff_t *tvb, int offset,
4703                                   packet_info *pinfo, proto_tree *tree,
4704                                   char *drep)
4705 {
4706         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4707         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4708         e_ctx_hnd policy_hnd;
4709         char *pol_name;
4710
4711         if (dcv->rep_frame != 0)
4712                 proto_tree_add_text(tree, tvb, offset, 0,
4713                                     "Reply in frame %u", dcv->rep_frame);
4714
4715         /* Parse packet */
4716
4717         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4718                                        hf_spoolss_hnd, &policy_hnd,
4719                                        FALSE, FALSE);
4720
4721         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
4722
4723         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
4724                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
4725                                 pol_name);
4726
4727         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4728
4729         return offset;
4730 }
4731
4732 static int SpoolssEndDocPrinter_r(tvbuff_t *tvb, int offset,
4733                                   packet_info *pinfo, proto_tree *tree,
4734                                   char *drep)
4735 {
4736         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4737         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4738
4739         if (dcv->req_frame != 0)
4740                 proto_tree_add_text(tree, tvb, offset, 0,
4741                                     "Request in frame %u", dcv->req_frame);
4742
4743         /* Parse packet */
4744
4745         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4746                                   hf_spoolss_rc, NULL);
4747
4748         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4749
4750         return offset;
4751 }
4752
4753 /*
4754  * WritePrinter
4755  */
4756
4757 static gint ett_writeprinter_buffer = -1;
4758
4759 static int SpoolssWritePrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
4760                                  proto_tree *tree, char *drep)
4761 {
4762         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4763         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4764         e_ctx_hnd policy_hnd;
4765         char *pol_name;
4766         guint32 size;
4767         proto_item *item;
4768         proto_tree *subtree;
4769
4770         if (dcv->rep_frame != 0)
4771                 proto_tree_add_text(tree, tvb, offset, 0,
4772                                     "Reply in frame %u", dcv->rep_frame);
4773
4774         /* Parse packet */
4775
4776         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
4777                                        hf_spoolss_hnd, &policy_hnd,
4778                                        FALSE, FALSE);
4779
4780         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
4781
4782         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
4783                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
4784                                 pol_name);
4785
4786         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4787                                     hf_spoolss_buffer_size, &size);
4788
4789         item = proto_tree_add_text(tree, tvb, offset, 0, "Buffer");
4790
4791         subtree = proto_item_add_subtree(item, ett_writeprinter_buffer);
4792
4793         offset = dissect_ndr_uint8s(tvb, offset, pinfo, subtree, drep,
4794                                     hf_spoolss_buffer_data, size, NULL);
4795
4796         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4797                                     hf_spoolss_buffer_size, NULL);
4798
4799         proto_item_set_len(item, size + 4);
4800
4801         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4802
4803         return offset;
4804 }
4805
4806 static int SpoolssWritePrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
4807                                  proto_tree *tree, char *drep)
4808 {
4809         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4810         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4811
4812         if (dcv->req_frame != 0)
4813                 proto_tree_add_text(tree, tvb, offset, 0,
4814                                     "Request in frame %u", dcv->req_frame);
4815
4816         /* Parse packet */
4817
4818         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
4819                                     hf_spoolss_writeprinter_numwritten, NULL);
4820
4821         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4822                                   hf_spoolss_rc, NULL);
4823
4824         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4825
4826         return offset;
4827 }
4828
4829 /*
4830  * DeletePrinterData
4831  */
4832
4833 static int SpoolssDeletePrinterData_q(tvbuff_t *tvb, int offset,
4834                                       packet_info *pinfo, proto_tree *tree,
4835                                       char *drep)
4836 {
4837         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4838         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4839         char *value_name;
4840
4841         if (dcv->rep_frame != 0)
4842                 proto_tree_add_text(tree, tvb, offset, 0,
4843                                     "Reply in frame %u", dcv->rep_frame);
4844
4845         /* Parse packet */
4846
4847         offset = dissect_nt_policy_hnd(
4848                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
4849                 FALSE, FALSE);
4850
4851         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
4852                                           prs_UNISTR2_dp, (void **)&value_name,
4853                                           NULL);
4854
4855         if (check_col(pinfo->cinfo, COL_INFO))
4856                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
4857
4858         g_free(value_name);
4859
4860         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4861
4862         return offset;
4863 }
4864
4865 static int SpoolssDeletePrinterData_r(tvbuff_t *tvb, int offset,
4866                                       packet_info *pinfo, proto_tree *tree,
4867                                       char *drep)
4868 {
4869         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4870         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4871
4872         if (dcv->req_frame != 0)
4873                 proto_tree_add_text(tree, tvb, offset, 0,
4874                                     "Request in frame %u", dcv->req_frame);
4875
4876         /* Parse packet */
4877
4878         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
4879                                   hf_spoolss_rc, NULL);
4880
4881         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
4882
4883         return offset;
4884 }
4885
4886
4887 /*
4888  * DRIVER_INFO_1
4889  */
4890
4891 static gint ett_DRIVER_INFO_1 = -1;
4892
4893 static int dissect_DRIVER_INFO_1(tvbuff_t *tvb, int offset,
4894                                  packet_info *pinfo, proto_tree *tree,
4895                                  char *drep)
4896 {
4897         proto_item *item;
4898         proto_tree *subtree;
4899         int struct_start = offset;
4900
4901         item = proto_tree_add_text(tree, tvb, offset, 0, "DRIVER_INFO_1");
4902
4903         subtree = proto_item_add_subtree(item, ett_DRIVER_INFO_1);
4904
4905         offset = dissect_spoolss_relstr(
4906                 tvb, offset, pinfo, subtree, drep, hf_spoolss_drivername,
4907                 struct_start, NULL);
4908
4909         return offset;
4910 }
4911
4912 /*
4913  * DRIVER_INFO_3
4914  */
4915
4916 static const value_string driverinfo_cversion_vals[] =
4917 {
4918         { 0, "Windows 95/98/Me" },
4919         { 2, "Windows NT 4.0" },
4920         { 3, "Windows 2000/XP" },
4921         { 0, NULL }
4922 };
4923
4924 static gint ett_DRIVER_INFO_3 = -1;
4925
4926 static int dissect_DRIVER_INFO_3(tvbuff_t *tvb, int offset,
4927                                  packet_info *pinfo, proto_tree *tree,
4928                                  char *drep)
4929 {
4930         proto_item *item;
4931         proto_tree *subtree;
4932         int struct_start = offset;
4933
4934         item = proto_tree_add_text(tree, tvb, offset, 0, "DRIVER_INFO_3");
4935
4936         subtree = proto_item_add_subtree(item, ett_DRIVER_INFO_3);
4937
4938         offset = dissect_ndr_uint32(tvb, offset, pinfo, subtree, drep,
4939                                     hf_spoolss_driverinfo_cversion, NULL);
4940
4941         offset = dissect_spoolss_relstr(
4942                 tvb, offset, pinfo, subtree, drep, hf_spoolss_drivername,
4943                 struct_start, NULL);
4944
4945         offset = dissect_spoolss_relstr(
4946                 tvb, offset, pinfo, subtree, drep, hf_spoolss_architecture,
4947                 struct_start, NULL);
4948
4949         offset = dissect_spoolss_relstr(
4950                 tvb, offset, pinfo, subtree, drep, hf_spoolss_driverpath,
4951                 struct_start, NULL);
4952
4953         offset = dissect_spoolss_relstr(
4954                 tvb, offset, pinfo, subtree, drep, hf_spoolss_datafile,
4955                 struct_start, NULL);
4956
4957         offset = dissect_spoolss_relstr(
4958                 tvb, offset, pinfo, subtree, drep, hf_spoolss_configfile,
4959                 struct_start, NULL);
4960
4961         offset = dissect_spoolss_relstr(
4962                 tvb, offset, pinfo, subtree, drep, hf_spoolss_helpfile,
4963                 struct_start, NULL);
4964
4965         offset = dissect_spoolss_relstrarray(
4966                 tvb, offset, pinfo, subtree, drep, hf_spoolss_dependentfiles,
4967                 struct_start, NULL);
4968
4969         offset = dissect_spoolss_relstr(
4970                 tvb, offset, pinfo, subtree, drep, hf_spoolss_monitorname,
4971                 struct_start, NULL);
4972
4973         offset = dissect_spoolss_relstr(
4974                 tvb, offset, pinfo, subtree, drep, hf_spoolss_defaultdatatype,
4975                 struct_start, NULL);
4976
4977         return offset;
4978 }
4979
4980 /*
4981  * EnumPrinterDrivers
4982  */
4983
4984 static int SpoolssEnumPrinterDrivers_q(tvbuff_t *tvb, int offset,
4985                                        packet_info *pinfo, proto_tree *tree,
4986                                        char *drep)
4987 {
4988         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
4989         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
4990         guint32 level;
4991
4992         if (dcv->rep_frame != 0)
4993                 proto_tree_add_text(tree, tvb, offset, 0,
4994                                     "Reply in frame %u", dcv->rep_frame);
4995
4996         /* Parse packet */
4997
4998         offset = dissect_ndr_pointer(
4999                 tvb, offset, pinfo, tree, drep,
5000                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
5001                 "Name", hf_spoolss_servername, 0);
5002
5003         offset = dissect_ndr_pointer(
5004                 tvb, offset, pinfo, tree, drep,
5005                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
5006                 "Environment", hf_spoolss_servername, 0);
5007
5008         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5009                                     hf_spoolss_level, &level);
5010
5011         dcv->private_data = (void *)level;
5012
5013         if (check_col(pinfo->cinfo, COL_INFO))
5014                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
5015
5016         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL);
5017
5018         offset = dissect_ndr_uint32(
5019                 tvb, offset, pinfo, tree, drep,
5020                 hf_spoolss_offered, NULL);
5021
5022         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5023
5024         return offset;
5025 }
5026
5027 static int SpoolssEnumPrinterDrivers_r(tvbuff_t *tvb, int offset,
5028                                        packet_info *pinfo, proto_tree *tree,
5029                                        char *drep)
5030 {
5031         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5032         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5033         guint32 level = (guint32)dcv->private_data, num_drivers, i;
5034         int buffer_offset;
5035         BUFFER buffer;
5036
5037         if (dcv->req_frame != 0)
5038                 proto_tree_add_text(tree, tvb, offset, 0,
5039                                     "Request in frame %u", dcv->req_frame);
5040
5041         /* Parse packet */
5042
5043         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep,
5044                                         &buffer);
5045
5046         offset = dissect_ndr_uint32(
5047                 tvb, offset, pinfo, tree, drep,
5048                 hf_spoolss_needed, NULL);
5049
5050         offset = dissect_ndr_uint32(
5051                 tvb, offset, pinfo, tree, drep,
5052                 hf_spoolss_returned, &num_drivers);
5053
5054         buffer_offset = buffer.offset;
5055
5056         for (i = 0; i < num_drivers; i++) {
5057                 switch(level) {
5058                 case 1:
5059                         buffer_offset = dissect_DRIVER_INFO_1(
5060                                 tvb, buffer_offset, pinfo, buffer.tree, drep);
5061                         break;
5062                 case 3:
5063                         buffer_offset = dissect_DRIVER_INFO_3(
5064                                 tvb, buffer_offset, pinfo, buffer.tree, drep);
5065                         break;
5066                 default:
5067                         proto_tree_add_text(
5068                                 buffer.tree, tvb, buffer_offset, buffer.size,
5069                                 "[Unknown info level %d]", level);
5070                         goto done;
5071                 }
5072         }
5073
5074 done:
5075         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5076                                   hf_spoolss_rc, NULL);
5077
5078         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5079
5080         return offset;
5081 }
5082
5083 /*
5084  * GetPrinterDriver2
5085  */
5086
5087 static int SpoolssGetPrinterDriver2_q(tvbuff_t *tvb, int offset,
5088                                       packet_info *pinfo, proto_tree *tree,
5089                                       char *drep)
5090 {
5091         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5092         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5093         e_ctx_hnd policy_hnd;
5094         char *pol_name;
5095         guint32 level;
5096
5097         if (dcv->rep_frame != 0)
5098                 proto_tree_add_text(tree, tvb, offset, 0,
5099                                     "Reply in frame %u", dcv->rep_frame);
5100
5101         /* Parse packet */
5102
5103         offset = dissect_nt_policy_hnd(
5104                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, &policy_hnd,
5105                 FALSE, FALSE);
5106
5107         dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL);
5108
5109         if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
5110                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
5111                                 pol_name);
5112
5113         offset = dissect_ndr_pointer(
5114                 tvb, offset, pinfo, tree, drep,
5115                 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
5116                 "Architecture", hf_spoolss_architecture, 0);
5117
5118         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5119                                     hf_spoolss_level, &level);
5120
5121         dcv->private_data = (void *)level;
5122
5123         if (check_col(pinfo->cinfo, COL_INFO))
5124                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
5125
5126         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep, NULL);
5127
5128         offset = dissect_ndr_uint32(
5129                 tvb, offset, pinfo, tree, drep,
5130                 hf_spoolss_offered, NULL);
5131
5132         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5133                                     hf_spoolss_clientmajorversion, NULL);
5134
5135         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5136                                     hf_spoolss_clientminorversion, NULL);
5137
5138         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5139
5140         return offset;
5141 }
5142
5143 static int SpoolssGetPrinterDriver2_r(tvbuff_t *tvb, int offset,
5144                                       packet_info *pinfo, proto_tree *tree,
5145                                       char *drep)
5146 {
5147         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5148         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5149         guint32 level = (guint32)dcv->private_data;
5150         BUFFER buffer;
5151
5152         if (dcv->req_frame != 0)
5153                 proto_tree_add_text(tree, tvb, offset, 0,
5154                                     "Request in frame %u", dcv->req_frame);
5155
5156         /* Parse packet */
5157
5158         offset = dissect_spoolss_buffer(tvb, offset, pinfo, tree, drep,
5159                                         &buffer);
5160
5161         switch(level) {
5162         case 1:
5163                 dissect_DRIVER_INFO_1(
5164                         tvb, buffer.offset, pinfo, buffer.tree, drep);
5165                 break;
5166         case 3:
5167                 dissect_DRIVER_INFO_3(
5168                         tvb, buffer.offset, pinfo, buffer.tree, drep);
5169                 break;
5170         default:
5171                 proto_tree_add_text(
5172                         buffer.tree, tvb, buffer.offset, buffer.size,
5173                         "[Unknown info level %d]", level);
5174                 break;
5175         }
5176
5177         offset = dissect_ndr_uint32(
5178                 tvb, offset, pinfo, tree, drep,
5179                 hf_spoolss_needed, NULL);
5180
5181         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5182                                     hf_spoolss_servermajorversion, NULL);
5183
5184         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5185                                     hf_spoolss_serverminorversion, NULL);
5186
5187         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5188                                   hf_spoolss_rc, NULL);
5189
5190         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5191
5192         return offset;
5193 }
5194
5195 static int
5196 dissect_notify_info_data_buffer(tvbuff_t *tvb, int offset, packet_info *pinfo,
5197                                 proto_tree *tree, char *drep)
5198 {
5199         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5200         guint32 len = di->levels;
5201
5202         offset = dissect_ndr_uint32(
5203                 tvb, offset, pinfo, tree, drep,
5204                 hf_spoolss_notify_info_data_buffer_len, NULL);
5205
5206         offset = dissect_ndr_uint16s(
5207                 tvb, offset, pinfo, tree, drep,
5208                 hf_spoolss_notify_info_data_buffer_data, len, NULL);
5209
5210         return offset;
5211 }
5212
5213 static int
5214 dissect_NOTIFY_INFO_DATA_printer(tvbuff_t *tvb, int offset, packet_info *pinfo,
5215                                  proto_tree *tree, char *drep, guint16 field)
5216 {
5217         guint32 value1;
5218
5219         switch (field) {
5220
5221                 /* String notify data */
5222
5223         case PRINTER_NOTIFY_SERVER_NAME:
5224         case PRINTER_NOTIFY_PRINTER_NAME:
5225         case PRINTER_NOTIFY_SHARE_NAME:
5226         case PRINTER_NOTIFY_DRIVER_NAME:
5227         case PRINTER_NOTIFY_COMMENT:
5228         case PRINTER_NOTIFY_LOCATION:
5229         case PRINTER_NOTIFY_SEPFILE:
5230         case PRINTER_NOTIFY_PRINT_PROCESSOR:
5231         case PRINTER_NOTIFY_PARAMETERS:
5232         case PRINTER_NOTIFY_DATATYPE:
5233         case PRINTER_NOTIFY_PORT_NAME:
5234
5235                 offset = dissect_ndr_uint32(
5236                         tvb, offset, pinfo, tree, drep,
5237                         hf_spoolss_notify_info_data_bufsize, &value1);
5238
5239                 offset = dissect_ndr_pointer(
5240                         tvb, offset, pinfo, tree, drep,
5241                         dissect_notify_info_data_buffer,
5242                         NDR_POINTER_UNIQUE, "String",
5243                         hf_spoolss_notify_info_data_buffer, value1 / 2);
5244
5245                 break;
5246
5247         case PRINTER_NOTIFY_ATTRIBUTES:
5248
5249                 /* Value 1 is the printer attributes */
5250
5251                 offset = dissect_printer_attributes(
5252                         tvb, offset, pinfo, tree, drep);
5253
5254                 offset = dissect_ndr_uint32(
5255                         tvb, offset, pinfo, NULL, drep,
5256                         hf_spoolss_notify_info_data_value2, NULL);
5257
5258                 break;
5259
5260         case PRINTER_NOTIFY_STATUS:
5261
5262                 /* Value 1 is the printer status */
5263
5264                 offset = dissect_ndr_uint32(
5265                         tvb, offset, pinfo, tree, drep,
5266                         hf_spoolss_printer_status, NULL);
5267
5268                 offset = dissect_ndr_uint32(
5269                         tvb, offset, pinfo, NULL, drep,
5270                         hf_spoolss_notify_info_data_value2, NULL);
5271
5272                 break;
5273
5274                 /* Unknown notify data */
5275
5276         case PRINTER_NOTIFY_SECURITY_DESCRIPTOR: /* Secdesc */
5277         case PRINTER_NOTIFY_DEVMODE: /* Device mode */
5278
5279                 offset = dissect_ndr_uint32(
5280                         tvb, offset, pinfo, tree, drep,
5281                         hf_spoolss_notify_info_data_bufsize, &value1);
5282
5283                 offset = dissect_ndr_pointer(
5284                         tvb, offset, pinfo, tree, drep,
5285                         dissect_notify_info_data_buffer,
5286                         NDR_POINTER_UNIQUE, "Buffer",
5287                         hf_spoolss_notify_info_data_buffer, value1 / 2);
5288
5289                 break;
5290
5291         default:
5292                 offset = dissect_ndr_uint32(
5293                         tvb, offset, pinfo, tree, drep,
5294                         hf_spoolss_notify_info_data_value1, NULL);
5295
5296                 offset = dissect_ndr_uint32(
5297                         tvb, offset, pinfo, tree, drep,
5298                         hf_spoolss_notify_info_data_value2, NULL);
5299
5300                 break;
5301         }
5302         return offset;
5303 }
5304
5305 static int
5306 dissect_NOTIFY_INFO_DATA_job(tvbuff_t *tvb, int offset, packet_info *pinfo,
5307                              proto_tree *tree, char *drep, guint16 field)
5308 {
5309         guint32 value1;
5310
5311         switch (field) {
5312
5313                 /* String notify data */
5314
5315         case JOB_NOTIFY_PRINTER_NAME:
5316         case JOB_NOTIFY_MACHINE_NAME:
5317         case JOB_NOTIFY_PORT_NAME:
5318         case JOB_NOTIFY_USER_NAME:
5319         case JOB_NOTIFY_NOTIFY_NAME:
5320         case JOB_NOTIFY_DATATYPE:
5321         case JOB_NOTIFY_PRINT_PROCESSOR:
5322         case JOB_NOTIFY_PARAMETERS:
5323         case JOB_NOTIFY_DRIVER_NAME:
5324         case JOB_NOTIFY_STATUS_STRING:
5325         case JOB_NOTIFY_DOCUMENT:
5326
5327                 offset = dissect_ndr_uint32(
5328                         tvb, offset, pinfo, tree, drep,
5329                         hf_spoolss_notify_info_data_bufsize, &value1);
5330
5331                 offset = dissect_ndr_pointer(
5332                         tvb, offset, pinfo, tree, drep,
5333                         dissect_notify_info_data_buffer,
5334                         NDR_POINTER_UNIQUE, "String",
5335                         hf_spoolss_notify_info_data_buffer, value1 / 2);
5336
5337                 break;
5338
5339         case JOB_NOTIFY_STATUS:
5340
5341                 offset = dissect_job_status(
5342                         tvb, offset, pinfo, tree, drep);
5343
5344                 offset = dissect_ndr_uint32(
5345                         tvb, offset, pinfo, NULL, drep,
5346                         hf_spoolss_notify_info_data_value2, NULL);
5347
5348                 break;
5349
5350         case JOB_NOTIFY_SUBMITTED:
5351
5352                 /* SYSTEM_TIME */
5353
5354                 offset = dissect_ndr_uint32(
5355                         tvb, offset, pinfo, tree, drep,
5356                         hf_spoolss_notify_info_data_buffer_len, NULL);
5357
5358                 offset = dissect_ndr_pointer(
5359                         tvb, offset, pinfo, tree, drep,
5360                         dissect_SYSTEM_TIME, NDR_POINTER_UNIQUE,
5361                         "SYSTEM_TIME", -1, 0);
5362
5363                 break;
5364
5365                 /* Unknown notify data */
5366
5367         case JOB_NOTIFY_DEVMODE:
5368
5369                 offset = dissect_ndr_uint32(
5370                         tvb, offset, pinfo, tree, drep,
5371                         hf_spoolss_notify_info_data_bufsize, &value1);
5372
5373                 offset = dissect_ndr_pointer(
5374                         tvb, offset, pinfo, tree, drep,
5375                         dissect_notify_info_data_buffer,
5376                         NDR_POINTER_UNIQUE, "Buffer",
5377                         hf_spoolss_notify_info_data_buffer, value1 / 2);
5378
5379                 break;
5380
5381         default:
5382                 offset = dissect_ndr_uint32(
5383                         tvb, offset, pinfo, tree, drep,
5384                         hf_spoolss_notify_info_data_value1, NULL);
5385
5386                 offset = dissect_ndr_uint32(
5387                         tvb, offset, pinfo, tree, drep,
5388                         hf_spoolss_notify_info_data_value2, NULL);
5389         }
5390         return offset;
5391 }
5392
5393 static gint ett_NOTIFY_INFO_DATA;
5394
5395 static int
5396 dissect_NOTIFY_INFO_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo,
5397                          proto_tree *tree, char *drep)
5398 {
5399         proto_item *item;
5400         proto_tree *subtree;
5401         guint32 count;
5402         guint16 type, field;
5403         char *field_string;
5404
5405         item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_INFO_DATA");
5406
5407         subtree = proto_item_add_subtree(item, ett_NOTIFY_INFO_DATA);
5408
5409         offset = dissect_ndr_uint16(
5410                 tvb, offset, pinfo, subtree, drep,
5411                 hf_spoolss_notify_info_data_type, &type);
5412
5413         offset = dissect_notify_field(
5414                 tvb, offset, pinfo, subtree, drep, type, &field);
5415
5416         switch(type) {
5417         case PRINTER_NOTIFY_TYPE:
5418                 field_string = val_to_str(
5419                         field, printer_notify_option_data_vals, "Unknown (%d)");
5420                 break;
5421         case JOB_NOTIFY_TYPE:
5422                 field_string = val_to_str(
5423                         field, job_notify_option_data_vals, "Unknown (%d)");
5424                 break;
5425         default:
5426                 field_string = "Unknown field";
5427                 break;
5428         }
5429
5430         proto_item_append_text(
5431                 item, ": %s, %s",
5432                 val_to_str(type, printer_notify_types, "Unknown (%d)"),
5433                 field_string);
5434
5435         offset = dissect_ndr_uint32(
5436                 tvb, offset, pinfo, subtree, drep,
5437                 hf_spoolss_notify_info_data_count, &count);
5438
5439         offset = dissect_ndr_uint32(
5440                 tvb, offset, pinfo, subtree, drep,
5441                 hf_spoolss_notify_info_data_id, NULL);
5442
5443         offset = dissect_ndr_uint32(
5444                 tvb, offset, pinfo, subtree, drep,
5445                 hf_spoolss_notify_info_data_count, NULL);
5446
5447         /* The value here depends on (type, field) */
5448
5449         switch (type) {
5450         case PRINTER_NOTIFY_TYPE:
5451                 offset = dissect_NOTIFY_INFO_DATA_printer(
5452                         tvb, offset, pinfo, subtree, drep,
5453                         field);
5454                 break;
5455         case JOB_NOTIFY_TYPE:
5456                 offset = dissect_NOTIFY_INFO_DATA_job(
5457                         tvb, offset, pinfo, subtree, drep,
5458                         field);
5459                 break;
5460         default:
5461                 proto_tree_add_text(
5462                         tree, tvb, offset, 0,
5463                         "[Unknown notify type %d]", type);
5464                 break;
5465         }
5466
5467         return offset;
5468 }
5469
5470 static int
5471 dissect_NOTIFY_INFO(tvbuff_t *tvb, int offset, packet_info *pinfo,
5472                     proto_tree *tree, char *drep)
5473 {
5474         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5475                                     hf_spoolss_notify_info_version, NULL);
5476
5477         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5478                                     hf_spoolss_notify_info_flags, NULL);
5479
5480         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5481                                     hf_spoolss_notify_info_count, NULL);
5482
5483         offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, drep,
5484                                      dissect_NOTIFY_INFO_DATA);
5485
5486         return offset;
5487 }
5488
5489 /*
5490  * RFNPCNEX
5491  */
5492
5493 static int SpoolssRFNPCNEX_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
5494                              proto_tree *tree, char *drep)
5495 {
5496         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5497         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5498
5499         if (dcv->rep_frame != 0)
5500                 proto_tree_add_text(tree, tvb, offset, 0,
5501                                     "Reply in frame %u", dcv->rep_frame);
5502
5503         /* Parse packet */
5504
5505         offset = dissect_nt_policy_hnd(
5506                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
5507                 FALSE, FALSE);
5508
5509         offset = dissect_ndr_uint32(
5510                 tvb, offset, pinfo, tree, drep,
5511                 hf_spoolss_rrpcn_changelow, NULL);
5512
5513         offset = dissect_ndr_pointer(
5514                 tvb, offset, pinfo, tree, drep,
5515                 dissect_NOTIFY_OPTIONS_ARRAY_CTR, NDR_POINTER_UNIQUE,
5516                 "NOTIFY_OPTIONS_ARRAY_CTR", -1, 0);
5517
5518         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5519
5520         return offset;
5521 }
5522
5523 static int SpoolssRFNPCNEX_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
5524                              proto_tree *tree, char *drep)
5525 {
5526         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5527         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5528
5529         if (dcv->req_frame != 0)
5530                 proto_tree_add_text(tree, tvb, offset, 0,
5531                                     "Request in frame %u", dcv->req_frame);
5532
5533         /* Parse packet */
5534
5535         offset = dissect_ndr_pointer(
5536                 tvb, offset, pinfo, tree, drep,
5537                 dissect_NOTIFY_INFO, NDR_POINTER_UNIQUE,
5538                 "NOTIFY_INFO", -1, 0);
5539
5540         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5541                                   hf_spoolss_rc, NULL);
5542
5543         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5544
5545         return offset;
5546 }
5547
5548 /*
5549  * RRPCN
5550  */
5551
5552 static int SpoolssRRPCN_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
5553                           proto_tree *tree, char *drep)
5554 {
5555         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5556         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5557
5558         if (dcv->rep_frame != 0)
5559                 proto_tree_add_text(tree, tvb, offset, 0,
5560                                     "Reply in frame %u", dcv->rep_frame);
5561
5562         /* Parse packet */
5563
5564         offset = dissect_nt_policy_hnd(
5565                 tvb, offset, pinfo, tree, drep, hf_spoolss_hnd, NULL,
5566                 FALSE, FALSE);
5567
5568         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5569                                     hf_spoolss_rrpcn_changelow, NULL);
5570
5571         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5572                                     hf_spoolss_rrpcn_changehigh, NULL);
5573
5574         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5575                                     hf_spoolss_rrpcn_unk0, NULL);
5576
5577         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5578                                     hf_spoolss_rrpcn_unk1, NULL);
5579
5580         offset = dissect_ndr_pointer(
5581                 tvb, offset, pinfo, tree, drep,
5582                 dissect_NOTIFY_INFO, NDR_POINTER_UNIQUE,
5583                 "NOTIFY_INFO", -1, 0);
5584
5585         /* Notify info */
5586
5587         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5588
5589         return offset;
5590 }
5591
5592 static int SpoolssRRPCN_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
5593                           proto_tree *tree, char *drep)
5594 {
5595         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5596         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5597
5598         if (dcv->req_frame != 0)
5599                 proto_tree_add_text(tree, tvb, offset, 0,
5600                                     "Request in frame %u", dcv->req_frame);
5601
5602         /* Parse packet */
5603
5604         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
5605                                     hf_spoolss_rrpcn_unk0, NULL);
5606
5607         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5608                                   hf_spoolss_rc, NULL);
5609
5610         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5611
5612         return offset;
5613 }
5614
5615 /*
5616  * ReplyClosePrinter
5617  */
5618
5619 static int SpoolssReplyClosePrinter_q(tvbuff_t *tvb, int offset,
5620                                       packet_info *pinfo, proto_tree *tree,
5621                                       char *drep)
5622 {
5623         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5624         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5625
5626         if (dcv->rep_frame != 0)
5627                 proto_tree_add_text(tree, tvb, offset, 0,
5628                                     "Reply in frame %u", dcv->rep_frame);
5629
5630         /* Parse packet */
5631
5632         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
5633                                        hf_spoolss_hnd, NULL,
5634                                        FALSE, TRUE);
5635
5636         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5637
5638         return offset;
5639 }
5640
5641 static int SpoolssReplyClosePrinter_r(tvbuff_t *tvb, int offset,
5642                                       packet_info *pinfo, proto_tree *tree,
5643                                       char *drep)
5644 {
5645         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5646         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5647
5648         if (dcv->req_frame != 0)
5649                 proto_tree_add_text(tree, tvb, offset, 0,
5650                                     "Request in frame %u", dcv->req_frame);
5651
5652         /* Parse packet */
5653
5654         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
5655                                        hf_spoolss_hnd, NULL,
5656                                        FALSE, FALSE);
5657
5658         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5659                                   hf_spoolss_rc, NULL);
5660
5661         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5662
5663         return offset;
5664 }
5665
5666 /*
5667  * FCPN
5668  */
5669
5670 static int SpoolssFCPN_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
5671                         proto_tree *tree, char *drep)
5672 {
5673         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5674         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5675
5676         if (dcv->rep_frame != 0)
5677                 proto_tree_add_text(tree, tvb, offset, 0,
5678                                     "Reply in frame %u", dcv->rep_frame);
5679
5680         /* Parse packet */
5681
5682         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
5683                                        hf_spoolss_hnd, NULL,
5684                                        FALSE, FALSE);
5685
5686         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5687
5688         return offset;
5689 }
5690
5691 static int SpoolssFCPN_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
5692                         proto_tree *tree, char *drep)
5693 {
5694         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5695         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5696
5697         if (dcv->req_frame != 0)
5698                 proto_tree_add_text(tree, tvb, offset, 0,
5699                                     "Request in frame %u", dcv->req_frame);
5700
5701         /* Parse packet */
5702
5703         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5704                                   hf_spoolss_rc, NULL);
5705
5706         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5707
5708         return offset;
5709 }
5710
5711 /*
5712  * RouterReplyPrinter
5713  */
5714
5715 static int SpoolssRouterReplyPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
5716                                        proto_tree *tree, char *drep)
5717 {
5718         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5719         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5720
5721         if (dcv->rep_frame != 0)
5722                 proto_tree_add_text(tree, tvb, offset, 0,
5723                                     "Reply in frame %u", dcv->rep_frame);
5724
5725         /* Parse packet */
5726
5727         offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
5728                                        hf_spoolss_hnd, NULL,
5729                                        FALSE, FALSE);
5730
5731         offset = dissect_ndr_uint32(
5732                 tvb, offset, pinfo, tree, drep,
5733                 hf_spoolss_routerreplyprinter_condition, NULL);
5734
5735         offset = dissect_ndr_uint32(
5736                 tvb, offset, pinfo, tree, drep,
5737                 hf_spoolss_routerreplyprinter_unknown1, NULL);
5738
5739         offset = dissect_ndr_uint32(
5740                 tvb, offset, pinfo, tree, drep,
5741                 hf_spoolss_routerreplyprinter_changeid, NULL);
5742
5743         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5744
5745         return offset;
5746 }
5747
5748 static int SpoolssRouterReplyPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
5749                                        proto_tree *tree, char *drep)
5750 {
5751         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5752         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5753
5754         if (dcv->req_frame != 0)
5755                 proto_tree_add_text(tree, tvb, offset, 0,
5756                                     "Request in frame %u", dcv->req_frame);
5757
5758         /* Parse packet */
5759
5760         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5761                                   hf_spoolss_rc, NULL);
5762
5763         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5764
5765         return offset;
5766 }
5767
5768 #if 0
5769
5770 /* Templates for new subdissectors */
5771
5772 /*
5773  * FOO
5774  */
5775
5776 static int SpoolssFoo_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
5777                         proto_tree *tree, char *drep)
5778 {
5779         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5780         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5781
5782         if (dcv->rep_frame != 0)
5783                 proto_tree_add_text(tree, tvb, offset, 0,
5784                                     "Reply in frame %u", dcv->rep_frame);
5785
5786         /* Parse packet */
5787
5788         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5789
5790         return offset;
5791 }
5792
5793 static int SpoolssFoo_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
5794                         proto_tree *tree, char *drep)
5795 {
5796         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
5797         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
5798
5799         if (dcv->req_frame != 0)
5800                 proto_tree_add_text(tree, tvb, offset, 0,
5801                                     "Request in frame %u", dcv->req_frame);
5802
5803         /* Parse packet */
5804
5805         offset = dissect_doserror(tvb, offset, pinfo, tree, drep,
5806                                   hf_spoolss_rc, NULL);
5807
5808         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
5809
5810         return offset;
5811 }
5812
5813 #endif
5814
5815 /*
5816  * List of subdissectors for this pipe.
5817  */
5818
5819 static dcerpc_sub_dissector dcerpc_spoolss_dissectors[] = {
5820         { SPOOLSS_ENUMPRINTERS, "EnumPrinters",
5821           SpoolssEnumPrinters_q, SpoolssEnumPrinters_r },
5822         { SPOOLSS_OPENPRINTER, "OpenPrinter",
5823           NULL, SpoolssGeneric_r },
5824         { SPOOLSS_SETJOB, "SetJob",
5825           SpoolssSetJob_q, SpoolssSetJob_r },
5826         { SPOOLSS_GETJOB, "GetJob",
5827           SpoolssGetJob_q, SpoolssGetJob_r },
5828         { SPOOLSS_ENUMJOBS, "EnumJobs",
5829           SpoolssEnumJobs_q, SpoolssEnumJobs_r },
5830         { SPOOLSS_ADDPRINTER, "AddPrinter",
5831           NULL, SpoolssGeneric_r },
5832         { SPOOLSS_DELETEPRINTER, "DeletePrinter",
5833           SpoolssDeletePrinter_q, SpoolssDeletePrinter_r },
5834         { SPOOLSS_SETPRINTER, "SetPrinter",
5835           SpoolssSetPrinter_q, SpoolssSetPrinter_r },
5836         { SPOOLSS_GETPRINTER, "GetPrinter",
5837           SpoolssGetPrinter_q, SpoolssGetPrinter_r },
5838         { SPOOLSS_ADDPRINTERDRIVER, "AddPrinterDriver",
5839           NULL, SpoolssAddPrinterDriver_r },
5840         { SPOOLSS_ENUMPRINTERDRIVERS, "EnumPrinterDrivers",
5841           SpoolssEnumPrinterDrivers_q, SpoolssEnumPrinterDrivers_r },
5842         { SPOOLSS_GETPRINTERDRIVER, "GetPrinterDriver",
5843           NULL, SpoolssGeneric_r },
5844         { SPOOLSS_GETPRINTERDRIVERDIRECTORY, "GetPrinterDriverDirectory",
5845           NULL, SpoolssGeneric_r },
5846         { SPOOLSS_DELETEPRINTERDRIVER, "DeletePrinterDriver",
5847           NULL, SpoolssGeneric_r },
5848         { SPOOLSS_ADDPRINTPROCESSOR, "AddPrintProcessor",
5849           NULL, SpoolssGeneric_r },
5850         { SPOOLSS_ENUMPRINTPROCESSORS, "EnumPrintProcessor",
5851           NULL, SpoolssGeneric_r },
5852         { SPOOLSS_GETPRINTPROCESSORDIRECTORY, "GetPrintProcessorDirectory",
5853           NULL, SpoolssGeneric_r },
5854         { SPOOLSS_STARTDOCPRINTER, "StartDocPrinter",
5855           SpoolssStartDocPrinter_q, SpoolssStartDocPrinter_r },
5856         { SPOOLSS_STARTPAGEPRINTER, "StartPagePrinter",
5857           SpoolssStartPagePrinter_q, SpoolssStartPagePrinter_r },
5858         { SPOOLSS_WRITEPRINTER, "WritePrinter",
5859           SpoolssWritePrinter_q, SpoolssWritePrinter_r },
5860         { SPOOLSS_ENDPAGEPRINTER, "EndPagePrinter",
5861           SpoolssEndPagePrinter_q, SpoolssEndPagePrinter_r },
5862         { SPOOLSS_ABORTPRINTER, "AbortPrinter",
5863           NULL, SpoolssGeneric_r },
5864         { SPOOLSS_READPRINTER, "ReadPrinter",
5865           NULL, SpoolssGeneric_r },
5866         { SPOOLSS_ENDDOCPRINTER, "EndDocPrinter",
5867           SpoolssEndDocPrinter_q, SpoolssEndDocPrinter_r },
5868         { SPOOLSS_ADDJOB, "AddJob",
5869           NULL, SpoolssGeneric_r },
5870         { SPOOLSS_SCHEDULEJOB, "ScheduleJob",
5871           NULL, SpoolssGeneric_r },
5872         { SPOOLSS_GETPRINTERDATA, "GetPrinterData",
5873           SpoolssGetPrinterData_q, SpoolssGetPrinterData_r },
5874         { SPOOLSS_SETPRINTERDATA, "SetPrinterData",
5875           SpoolssSetPrinterData_q, SpoolssSetPrinterData_r },
5876         { SPOOLSS_WAITFORPRINTERCHANGE, "WaitForPrinterChange",
5877           NULL, SpoolssGeneric_r },
5878         { SPOOLSS_CLOSEPRINTER, "ClosePrinter",
5879           SpoolssClosePrinter_q, SpoolssClosePrinter_r },
5880         { SPOOLSS_ADDFORM, "AddForm",
5881           SpoolssAddForm_q, SpoolssAddForm_r },
5882         { SPOOLSS_DELETEFORM, "DeleteForm",
5883           SpoolssDeleteForm_q, SpoolssDeleteForm_r },
5884         { SPOOLSS_GETFORM, "GetForm",
5885           SpoolssGetForm_q, SpoolssGetForm_r },
5886         { SPOOLSS_SETFORM, "SetForm",
5887           SpoolssSetForm_q, SpoolssSetForm_r },
5888         { SPOOLSS_ENUMFORMS, "EnumForms",
5889           SpoolssEnumForms_q, SpoolssEnumForms_r },
5890         { SPOOLSS_ENUMPORTS, "EnumPorts",
5891           NULL, SpoolssGeneric_r },
5892         { SPOOLSS_ENUMMONITORS, "EnumMonitors",
5893           NULL, SpoolssGeneric_r },
5894         { SPOOLSS_ADDPORT, "AddPort",
5895           NULL, SpoolssGeneric_r },
5896         { SPOOLSS_CONFIGUREPORT, "ConfigurePort",
5897           NULL, SpoolssGeneric_r },
5898         { SPOOLSS_DELETEPORT, "DeletePort",
5899           NULL, SpoolssGeneric_r },
5900         { SPOOLSS_CREATEPRINTERIC, "CreatePrinterIC",
5901           NULL, SpoolssGeneric_r },
5902         { SPOOLSS_PLAYGDISCRIPTONPRINTERIC, "PlayDiscriptOnPrinterIC",
5903           NULL, SpoolssGeneric_r },
5904         { SPOOLSS_DELETEPRINTERIC, "DeletePrinterIC",
5905           NULL, SpoolssGeneric_r },
5906         { SPOOLSS_ADDPRINTERCONNECTION, "AddPrinterConnection",
5907           NULL, SpoolssGeneric_r },
5908         { SPOOLSS_DELETEPRINTERCONNECTION, "DeletePrinterConnection",
5909           NULL, SpoolssGeneric_r },
5910         { SPOOLSS_PRINTERMESSAGEBOX, "PrinterMessageBox",
5911           NULL, SpoolssGeneric_r },
5912         { SPOOLSS_ADDMONITOR, "AddMonitor",
5913           NULL, SpoolssGeneric_r },
5914         { SPOOLSS_DELETEMONITOR, "DeleteMonitor",
5915           NULL, SpoolssGeneric_r },
5916         { SPOOLSS_DELETEPRINTPROCESSOR, "DeletePrintProcessor",
5917           NULL, SpoolssGeneric_r },
5918         { SPOOLSS_ADDPRINTPROVIDER, "AddPrintProvider",
5919           NULL, SpoolssGeneric_r },
5920         { SPOOLSS_DELETEPRINTPROVIDER, "DeletePrintProvider",
5921           NULL, SpoolssGeneric_r },
5922         { SPOOLSS_ENUMPRINTPROCDATATYPES, "EnumPrintProcDataTypes",
5923           NULL, SpoolssGeneric_r },
5924         { SPOOLSS_RESETPRINTER, "ResetPrinter",
5925           NULL, SpoolssGeneric_r },
5926         { SPOOLSS_GETPRINTERDRIVER2, "GetPrinterDriver2",
5927           SpoolssGetPrinterDriver2_q, SpoolssGetPrinterDriver2_r },
5928         { SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION,
5929           "FindFirstPrinterChangeNotification",
5930           NULL, SpoolssGeneric_r },
5931         { SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION,
5932           "FindNextPrinterChangeNotification",
5933           NULL, SpoolssGeneric_r },
5934         { SPOOLSS_FCPN, "FCPN",
5935           SpoolssFCPN_q, SpoolssFCPN_r },
5936         { SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD,
5937           "RouterFindFirstPrinterNotificationOld",
5938           NULL, SpoolssGeneric_r },
5939         { SPOOLSS_REPLYOPENPRINTER, "ReplyOpenPrinter",
5940           SpoolssReplyOpenPrinter_q, SpoolssReplyOpenPrinter_r },
5941         { SPOOLSS_ROUTERREPLYPRINTER, "RouterReplyPrinter",
5942           SpoolssRouterReplyPrinter_q, SpoolssRouterReplyPrinter_r },
5943         { SPOOLSS_REPLYCLOSEPRINTER, "ReplyClosePrinter",
5944           SpoolssReplyClosePrinter_q, SpoolssReplyClosePrinter_r },
5945         { SPOOLSS_ADDPORTEX, "AddPortEx",
5946           NULL, SpoolssGeneric_r },
5947         { SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION,
5948           "RemoteFindFirstPrinterChangeNotification",
5949           NULL, SpoolssGeneric_r },
5950         { SPOOLSS_SPOOLERINIT, "SpoolerInit",
5951           NULL, SpoolssGeneric_r },
5952         { SPOOLSS_RESETPRINTEREX, "ResetPrinterEx",
5953           NULL, SpoolssGeneric_r },
5954         { SPOOLSS_RFFPCNEX, "RFFPCNEX",
5955           SpoolssRFFPCNEX_q, SpoolssRFFPCNEX_r },
5956         { SPOOLSS_RRPCN, "RRPCN",
5957           SpoolssRRPCN_q, SpoolssRRPCN_r },
5958         { SPOOLSS_RFNPCNEX, "RFNPCNEX",
5959           SpoolssRFNPCNEX_q, SpoolssRFNPCNEX_r },
5960         { SPOOLSS_OPENPRINTEREX, "OpenPrinterEx",
5961           SpoolssOpenPrinterEx_q, SpoolssOpenPrinterEx_r },
5962         { SPOOLSS_ADDPRINTEREX, "AddPrinterEx",
5963           NULL, SpoolssAddPrinterEx_r },
5964         { SPOOLSS_ENUMPRINTERDATA, "EnumPrinterData",
5965           SpoolssEnumPrinterData_q, SpoolssEnumPrinterData_r },
5966         { SPOOLSS_DELETEPRINTERDATA, "DeletePrinterData",
5967           SpoolssDeletePrinterData_q, SpoolssDeletePrinterData_r },
5968         { SPOOLSS_GETPRINTERDATAEX, "GetPrinterDataEx",
5969           SpoolssGetPrinterDataEx_q, SpoolssGetPrinterDataEx_r },
5970         { SPOOLSS_SETPRINTERDATAEX, "SetPrinterDataEx",
5971           SpoolssSetPrinterDataEx_q, SpoolssSetPrinterDataEx_r },
5972         { SPOOLSS_ENUMPRINTERDATAEX, "EnumPrinterDataEx",
5973           NULL, SpoolssGeneric_r },
5974         { SPOOLSS_ENUMPRINTERKEY, "EnumPrinterKey",
5975           NULL, SpoolssGeneric_r },
5976         { SPOOLSS_DELETEPRINTERDATAEX, "DeletePrinterDataEx",
5977           NULL, SpoolssGeneric_r },
5978         { SPOOLSS_DELETEPRINTERDRIVEREX, "DeletePrinterDriverEx",
5979           NULL, SpoolssGeneric_r },
5980         { SPOOLSS_ADDPRINTERDRIVEREX, "AddPrinterDriverEx",
5981           NULL, SpoolssGeneric_r },
5982
5983         { 0, NULL, NULL, NULL },
5984 };
5985
5986 /*
5987  * Dissector initialisation function
5988  */
5989
5990 /* Protocol registration */
5991
5992 static int proto_dcerpc_spoolss = -1;
5993 static gint ett_dcerpc_spoolss = -1;
5994
5995 void
5996 proto_register_dcerpc_spoolss(void)
5997 {
5998         static hf_register_info hf[] = {
5999
6000                 /* Opnum */
6001
6002                 { &hf_spoolss_opnum,
6003                   { "Operation", "spoolss.opnum", FT_UINT16, BASE_DEC,
6004                     VALS(spoolss_opnum_vals), 0x0, "Operation", HFILL }},
6005
6006                 { &hf_spoolss_hnd,
6007                   { "Context handle", "spoolss.hnd", FT_BYTES, BASE_NONE,
6008                     NULL, 0x0, "SPOOLSS policy handle", HFILL }},
6009                 { &hf_spoolss_rc,
6010                   { "Return code", "spoolss.rc", FT_UINT32, BASE_HEX,
6011                     VALS(DOS_errors), 0x0, "SPOOLSS return code", HFILL }},
6012                 { &hf_spoolss_offered,
6013                   { "Offered", "spoolss.offered", FT_UINT32, BASE_DEC,
6014                     NULL, 0x0, "Size of buffer offered in this request", HFILL }},
6015                 { &hf_spoolss_needed,
6016                   { "Needed", "spoolss.needed", FT_UINT32, BASE_DEC,
6017                     NULL, 0x0, "Size of buffer required for request", HFILL }},
6018                 { &hf_spoolss_returned,
6019                   { "Returned", "spoolss.returned", FT_UINT32, BASE_DEC,
6020                     NULL, 0x0, "Number of items returned", HFILL }},
6021                 { &hf_spoolss_relstr_offset,
6022                   { "Relative string offset", "spoolss.relstr.offset", FT_UINT32, BASE_DEC,
6023                     NULL, 0x0, "Offset of relative string data", HFILL }},
6024                 { &hf_spoolss_printername,
6025                   { "Printer name", "spoolss.printername", FT_STRING, BASE_NONE,
6026                     NULL, 0, "Printer name", HFILL }},
6027                 { &hf_spoolss_servername,
6028                   { "Server name", "spoolss.servername", FT_STRING, BASE_NONE,
6029                     NULL, 0, "Server name", HFILL }},
6030                 { &hf_spoolss_architecture,
6031                   { "Architecture name", "spoolss.architecture", FT_STRING, BASE_NONE,
6032                     NULL, 0, "Architecture name", HFILL }},
6033                 { &hf_spoolss_drivername,
6034                   { "Driver name", "spoolss.drivername", FT_STRING, BASE_NONE,
6035                     NULL, 0, "Driver name", HFILL }},
6036                 { &hf_spoolss_username,
6037                   { "User name", "spoolss.username", FT_STRING, BASE_NONE,
6038                     NULL, 0, "User name", HFILL }},
6039                 { &hf_spoolss_documentname,
6040                   { "Document name", "spoolss.document", FT_STRING, BASE_NONE,
6041                     NULL, 0, "Document name", HFILL }},
6042                 { &hf_spoolss_outputfile,
6043                   { "Output file", "spoolss.outputfile", FT_STRING, BASE_NONE,
6044                     NULL, 0, "Output File", HFILL }},
6045                 { &hf_spoolss_datatype,
6046                   { "Datatype", "spoolss.Datatype", FT_STRING, BASE_NONE,
6047                     NULL, 0, "Datatype", HFILL }},
6048                 { &hf_spoolss_textstatus,
6049                   { "Text status", "spoolss.textstatus", FT_STRING, BASE_NONE,
6050                     NULL, 0, "Text status", HFILL }},
6051                 { &hf_spoolss_buffer_size,
6052                   { "Buffer size", "spoolss.buffer.size", FT_UINT32, BASE_DEC,
6053                     NULL, 0x0, "Size of buffer", HFILL }},
6054                 { &hf_spoolss_buffer_data,
6055                   { "Buffer data", "spoolss.buffer.data", FT_BYTES, BASE_HEX,
6056                     NULL, 0x0, "Contents of buffer", HFILL }},
6057                 { &hf_spoolss_enumjobs_firstjob,
6058                   { "First job", "spoolss.enumjobs.firstjob", FT_UINT32, BASE_DEC,
6059                     NULL, 0x0, "Index of first job to return", HFILL }},
6060                 { &hf_spoolss_enumjobs_numjobs,
6061                   { "Num jobs", "spoolss.enumjobs.numjobs", FT_UINT32, BASE_DEC,
6062                     NULL, 0x0, "Number of jobs to return", HFILL }},
6063                 { &hf_spoolss_level,
6064                   { "Info level", "spoolss.enumjobs.level", FT_UINT32, BASE_DEC,
6065                     NULL, 0x0, "Info level", HFILL }},
6066
6067                 /* Print jobs */
6068
6069                 { &hf_spoolss_jobid,
6070                   { "Job ID", "spoolss.job.id", FT_UINT32, BASE_DEC,
6071                     NULL, 0x0, "Job identification number", HFILL }},
6072
6073                 { &hf_spoolss_job_status,
6074                   { "Job status", "spoolss.job.status", FT_UINT32, BASE_DEC,
6075                     NULL, 0x0, "Job status", HFILL }},
6076
6077                 { &hf_spoolss_job_status_paused,
6078                   { "Paused", "spoolss.job.status.paused", FT_BOOLEAN, 32,
6079                     TFS(&tfs_job_status_paused), JOB_STATUS_PAUSED,
6080                     "Paused", HFILL }},
6081
6082                 { &hf_spoolss_job_status_error,
6083                   { "Error", "spoolss.job.status.error", FT_BOOLEAN, 32,
6084                     TFS(&tfs_job_status_error), JOB_STATUS_ERROR,
6085                     "Error", HFILL }},
6086
6087                 { &hf_spoolss_job_status_deleting,
6088                   { "Deleting", "spoolss.job.status.deleting", FT_BOOLEAN, 32,
6089                     TFS(&tfs_job_status_deleting), JOB_STATUS_DELETING,
6090                     "Deleting", HFILL }},
6091
6092                 { &hf_spoolss_job_status_spooling,
6093                   { "Spooling", "spoolss.job.status.spooling", FT_BOOLEAN, 32,
6094                     TFS(&tfs_job_status_spooling), JOB_STATUS_SPOOLING,
6095                     "Spooling", HFILL }},
6096
6097                 { &hf_spoolss_job_status_printing,
6098                   { "Printing", "spoolss.job.status.printing", FT_BOOLEAN, 32,
6099                     TFS(&tfs_job_status_printing), JOB_STATUS_PRINTING,
6100                     "Printing", HFILL }},
6101
6102                 { &hf_spoolss_job_status_offline,
6103                   { "Offline", "spoolss.job.status.offline", FT_BOOLEAN, 32,
6104                     TFS(&tfs_job_status_offline), JOB_STATUS_OFFLINE,
6105                     "Offline", HFILL }},
6106
6107                 { &hf_spoolss_job_status_paperout,
6108                   { "Paperout", "spoolss.job.status.paperout", FT_BOOLEAN, 32,
6109                     TFS(&tfs_job_status_paperout), JOB_STATUS_PAPEROUT,
6110                     "Paperout", HFILL }},
6111
6112                 { &hf_spoolss_job_status_printed,
6113                   { "Printed", "spoolss.job.status.printed", FT_BOOLEAN, 32,
6114                     TFS(&tfs_job_status_printed), JOB_STATUS_PRINTED,
6115                     "Printed", HFILL }},
6116
6117                 { &hf_spoolss_job_status_deleted,
6118                   { "Deleted", "spoolss.job.status.deleted", FT_BOOLEAN, 32,
6119                     TFS(&tfs_job_status_deleted), JOB_STATUS_DELETED,
6120                     "Deleted", HFILL }},
6121
6122                 { &hf_spoolss_job_status_blocked,
6123                   { "Blocked", "spoolss.job.status.blocked", FT_BOOLEAN, 32,
6124                     TFS(&tfs_job_status_blocked), JOB_STATUS_BLOCKED,
6125                     "Blocked", HFILL }},
6126
6127                 { &hf_spoolss_job_status_user_intervention,
6128                   { "User intervention", "spoolss.job.status.user_intervention", FT_BOOLEAN, 32,
6129                     TFS(&tfs_job_status_user_intervention), JOB_STATUS_USER_INTERVENTION,
6130                     "User intervention", HFILL }},
6131
6132                 { &hf_spoolss_jobpriority,
6133                   { "Job priority", "spoolss.job.priority", FT_UINT32, BASE_DEC,
6134                     NULL, 0x0, "Job priority", HFILL }},
6135                 { &hf_spoolss_jobposition,
6136                   { "Job position", "spoolss.job.position", FT_UINT32, BASE_DEC,
6137                     NULL, 0x0, "Job position", HFILL }},
6138                 { &hf_spoolss_jobtotalpages,
6139                   { "Job total pages", "spoolss.job.totalpages", FT_UINT32, BASE_DEC,
6140                     NULL, 0x0, "Job total pages", HFILL }},
6141                 { &hf_spoolss_jobpagesprinted,
6142                   { "Job pages printed", "spoolss.job.pagesprinted", FT_UINT32, BASE_DEC,
6143                     NULL, 0x0, "Job identification number", HFILL }},
6144
6145                 /* SYSTEM_TIME */
6146
6147                 { &hf_spoolss_time_year,
6148                   { "Year", "spoolss.time.year", FT_UINT32, BASE_DEC,
6149                     NULL, 0x0, "Year", HFILL }},
6150                 { &hf_spoolss_time_month,
6151                   { "Month", "spoolss.time.month", FT_UINT32, BASE_DEC,
6152                     NULL, 0x0, "Month", HFILL }},
6153                 { &hf_spoolss_time_dow,
6154                   { "Day of week", "spoolss.time.dow", FT_UINT32, BASE_DEC,
6155                     NULL, 0x0, "Day of week", HFILL }},
6156                 { &hf_spoolss_time_day,
6157                   { "Day", "spoolss.time.day", FT_UINT32, BASE_DEC,
6158                     NULL, 0x0, "Day", HFILL }},
6159                 { &hf_spoolss_time_hour,
6160                   { "Hour", "spoolss.time.hour", FT_UINT32, BASE_DEC,
6161                     NULL, 0x0, "Hour", HFILL }},
6162                 { &hf_spoolss_time_minute,
6163                   { "Minute", "spoolss.time.minute", FT_UINT32, BASE_DEC,
6164                     NULL, 0x0, "Minute", HFILL }},
6165                 { &hf_spoolss_time_second,
6166                   { "Second", "spoolss.time.second", FT_UINT32, BASE_DEC,
6167                     NULL, 0x0, "Second", HFILL }},
6168                 { &hf_spoolss_time_msec,
6169                   { "Millisecond", "spoolss.time.msec", FT_UINT32, BASE_DEC,
6170                     NULL, 0x0, "Millisecond", HFILL }},
6171
6172                 /* Printer data */
6173
6174                 { &hf_spoolss_printerdata_value,
6175                   { "Printer data value", "spoolss.printerdata.value", FT_STRING, BASE_NONE,
6176                     NULL, 0, "Printer data value", HFILL }},
6177
6178                 { &hf_spoolss_printerdata_type,
6179                   { "Printer data type", "spoolss.printerdata.type", FT_UINT32, BASE_DEC,
6180                     VALS(reg_datatypes), 0, "Printer data type", HFILL }},
6181
6182                 /* SetJob RPC */
6183
6184                 { &hf_spoolss_setjob_cmd,
6185                   { "Set job command", "spoolss.setjob.cmd", FT_UINT32, BASE_DEC,
6186                     VALS(setjob_commands), 0x0, "Printer data name", HFILL }},
6187
6188                 /* WritePrinter */
6189
6190                 { &hf_spoolss_writeprinter_numwritten,
6191                   { "Num written", "spoolss.writeprinter.numwritten", FT_UINT32, BASE_DEC,
6192                     NULL, 0x0, "Number of bytes written", HFILL }},
6193
6194                 /* EnumPrinterData */
6195
6196                 { &hf_spoolss_enumprinterdata_index,
6197                   { "Enum index", "spoolss.enumprinterdata.index", FT_UINT32, BASE_DEC,
6198                     NULL, 0x0, "Index for start of enumeration", HFILL }},
6199
6200                 { &hf_spoolss_enumprinterdata_value_offered,
6201                   { "Value size offered", "spoolss.enumprinterdata.value_offered", FT_UINT32, BASE_DEC,
6202                     NULL, 0x0, "Buffer size offered for printerdata value", HFILL }},
6203
6204                 { &hf_spoolss_enumprinterdata_data_offered,
6205                   { "Data size offered", "spoolss.enumprinterdata.data_offered", FT_UINT32, BASE_DEC,
6206                     NULL, 0x0, "Buffer size offered for printerdata data", HFILL }},
6207
6208                 { &hf_spoolss_enumprinterdata_value_needed,
6209                   { "Value size needed", "spoolss.enumprinterdata.value_needed", FT_UINT32, BASE_DEC,
6210                     NULL, 0x0, "Buffer size needed for printerdata value", HFILL }},
6211
6212                 { &hf_spoolss_enumprinterdata_data_needed,
6213                   { "Data size needed", "spoolss.enumprinterdata.data_needed", FT_UINT32, BASE_DEC,
6214                     NULL, 0x0, "Buffer size needed for printerdata data", HFILL }},
6215
6216                 /* GetPrinterDriver2 */
6217
6218                 { &hf_spoolss_clientmajorversion,
6219                   { "Client major version", "spoolss.clientmajorversion", FT_UINT32, BASE_DEC,
6220                     NULL, 0x0, "Client printer driver major version", HFILL }},
6221                 { &hf_spoolss_clientminorversion,
6222                   { "Client minor version", "spoolss.clientminorversion", FT_UINT32, BASE_DEC,
6223                     NULL, 0x0, "Client printer driver minor version", HFILL }},
6224                 { &hf_spoolss_servermajorversion,
6225                   { "Server major version", "spoolss.servermajorversion", FT_UINT32, BASE_DEC,
6226                     NULL, 0x0, "Server printer driver major version", HFILL }},
6227                 { &hf_spoolss_serverminorversion,
6228                   { "Server minor version", "spoolss.serverminorversion", FT_UINT32, BASE_DEC,
6229                     NULL, 0x0, "Server printer driver minor version", HFILL }},
6230                 { &hf_spoolss_driverpath,
6231                   { "Driver path", "spoolss.driverpath", FT_STRING, BASE_NONE,
6232                     NULL, 0, "Driver path", HFILL }},
6233                 { &hf_spoolss_datafile,
6234                   { "Data file", "spoolss.datafile", FT_STRING, BASE_NONE,
6235                     NULL, 0, "Data file", HFILL }},
6236                 { &hf_spoolss_configfile,
6237                   { "Config file", "spoolss.configfile", FT_STRING, BASE_NONE,
6238                     NULL, 0, "Printer name", HFILL }},
6239                 { &hf_spoolss_helpfile,
6240                   { "Help file", "spoolss.helpfile", FT_STRING, BASE_NONE,
6241                     NULL, 0, "Help file", HFILL }},
6242                 { &hf_spoolss_monitorname,
6243                   { "Monitor name", "spoolss.monitorname", FT_STRING, BASE_NONE,
6244                     NULL, 0, "Monitor name", HFILL }},
6245                 { &hf_spoolss_defaultdatatype,
6246                   { "Default data type", "spoolss.defaultdatatype", FT_STRING, BASE_NONE,
6247                     NULL, 0, "Default data type", HFILL }},
6248                 { &hf_spoolss_driverinfo_cversion,
6249                   { "Driver version", "spoolss.driverversion", FT_UINT32, BASE_DEC,
6250                     VALS(driverinfo_cversion_vals), 0, "Printer name", HFILL }},
6251                 { &hf_spoolss_dependentfiles,
6252                   { "Dependent files", "spoolss.dependentfiles", FT_STRING, BASE_NONE,
6253                     NULL, 0, "Dependent files", HFILL }},
6254
6255                 /* rffpcnex */
6256
6257                 { &hf_spoolss_rffpcnex_options,
6258                   { "Options", "spoolss.rffpcnex.options", FT_UINT32, BASE_DEC,
6259                     NULL, 0, "RFFPCNEX options", HFILL }},
6260
6261                 { &hf_spoolss_printerlocal,
6262                   { "Printer local", "spoolss.printer_local", FT_UINT32, BASE_DEC,
6263                     NULL, 0, "Printer local", HFILL }},
6264
6265                 { &hf_spoolss_rffpcnex_flags,
6266                   { "RFFPCNEX flags", "spoolss.rffpcnex.flags", FT_UINT32, BASE_DEC,
6267                     NULL, 0, "RFFPCNEX flags", HFILL }},
6268
6269                 { &hf_spoolss_rffpcnex_flags_add_printer,
6270                   { "Add printer", "spoolss.rffpcnex.flags.add_printer",
6271                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_printer),
6272                     SPOOLSS_PRINTER_CHANGE_ADD_PRINTER, "Add printer", HFILL }},
6273
6274                 { &hf_spoolss_rffpcnex_flags_set_printer,
6275                   { "Set printer", "spoolss.rffpcnex.flags.set_printer",
6276                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_printer),
6277                     SPOOLSS_PRINTER_CHANGE_SET_PRINTER, "Set printer", HFILL }},
6278
6279                 { &hf_spoolss_rffpcnex_flags_delete_printer,
6280                   { "Delete printer", "spoolss.rffpcnex.flags.delete_printer",
6281                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_printer),
6282                     SPOOLSS_PRINTER_CHANGE_DELETE_PRINTER, "Delete printer", HFILL }},
6283
6284                 { &hf_spoolss_rffpcnex_flags_add_job,
6285                   { "Add job", "spoolss.rffpcnex.flags.add_job",
6286                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_job),
6287                     SPOOLSS_PRINTER_CHANGE_ADD_JOB, "Add job", HFILL }},
6288
6289                 { &hf_spoolss_rffpcnex_flags_set_job,
6290                   { "Set job", "spoolss.rffpcnex.flags.set_job",
6291                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_job),
6292                     SPOOLSS_PRINTER_CHANGE_SET_JOB, "Set job", HFILL }},
6293
6294                 { &hf_spoolss_rffpcnex_flags_delete_job,
6295                   { "Delete job", "spoolss.rffpcnex.flags.delete_job",
6296                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_job),
6297                     SPOOLSS_PRINTER_CHANGE_DELETE_JOB, "Delete job", HFILL }},
6298
6299                 { &hf_spoolss_rffpcnex_flags_write_job,
6300                   { "Write job", "spoolss.rffpcnex.flags.write_job",
6301                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_write_job),
6302                     SPOOLSS_PRINTER_CHANGE_WRITE_JOB, "Write job", HFILL }},
6303
6304                 { &hf_spoolss_rffpcnex_flags_add_form,
6305                   { "Add form", "spoolss.rffpcnex.flags.add_form",
6306                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_form),
6307                     SPOOLSS_PRINTER_CHANGE_ADD_FORM, "Add form", HFILL }},
6308
6309                 { &hf_spoolss_rffpcnex_flags_set_form,
6310                   { "Set form", "spoolss.rffpcnex.flags.set_form",
6311                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_form),
6312                     SPOOLSS_PRINTER_CHANGE_SET_FORM, "Set form", HFILL }},
6313
6314                 { &hf_spoolss_rffpcnex_flags_delete_form,
6315                   { "Delete form", "spoolss.rffpcnex.flags.delete_form",
6316                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_form),
6317                     SPOOLSS_PRINTER_CHANGE_DELETE_FORM, "Delete form", HFILL }},
6318
6319                 { &hf_spoolss_rffpcnex_flags_add_port,
6320                   { "Add port", "spoolss.rffpcnex.flags.add_port",
6321                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_port),
6322                     SPOOLSS_PRINTER_CHANGE_ADD_PORT, "Add port", HFILL }},
6323
6324                 { &hf_spoolss_rffpcnex_flags_configure_port,
6325                   { "Configure port", "spoolss.rffpcnex.flags.configure_port",
6326                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_configure_port),
6327                     SPOOLSS_PRINTER_CHANGE_CONFIGURE_PORT, "Configure port", HFILL }},
6328
6329                 { &hf_spoolss_rffpcnex_flags_delete_port,
6330                   { "Delete port", "spoolss.rffpcnex.flags.delete_port",
6331                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_port),
6332                     SPOOLSS_PRINTER_CHANGE_DELETE_PORT, "Delete port", HFILL }},
6333
6334
6335                 { &hf_spoolss_rffpcnex_flags_add_print_processor,
6336                   { "Add processor", "spoolss.rffpcnex.flags.add_processor",
6337                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_print_processor),
6338                     SPOOLSS_PRINTER_CHANGE_ADD_PRINT_PROCESSOR, "Add processor", HFILL }},
6339
6340                 { &hf_spoolss_rffpcnex_flags_delete_print_processor,
6341                   { "Delete processor", "spoolss.rffpcnex.flags.delete_processor",
6342                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_print_processor),
6343                     SPOOLSS_PRINTER_CHANGE_DELETE_PRINT_PROCESSOR, "Delete processor", HFILL }},
6344
6345                 { &hf_spoolss_rffpcnex_flags_add_driver,
6346                   { "Add driver", "spoolss.rffpcnex.flags.add_driver",
6347                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_add_driver),
6348                     SPOOLSS_PRINTER_CHANGE_ADD_PRINTER_DRIVER, "Add driver", HFILL }},
6349
6350                 { &hf_spoolss_rffpcnex_flags_set_driver,
6351                   { "Set driver", "spoolss.rffpcnex.flags.set_driver",
6352                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_set_driver),
6353                     SPOOLSS_PRINTER_CHANGE_SET_PRINTER_DRIVER, "Set driver", HFILL }},
6354
6355                 { &hf_spoolss_rffpcnex_flags_delete_driver,
6356                   { "Delete driver", "spoolss.rffpcnex.flags.delete_driver",
6357                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_delete_driver),
6358                     SPOOLSS_PRINTER_CHANGE_DELETE_PRINTER_DRIVER, "Delete driver", HFILL }},
6359
6360                 { &hf_spoolss_rffpcnex_flags_timeout,
6361                   { "Timeout", "spoolss.rffpcnex.flags.timeout",
6362                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_timeout),
6363                     SPOOLSS_PRINTER_CHANGE_TIMEOUT, "Timeout", HFILL }},
6364
6365                 { &hf_spoolss_rffpcnex_flags_failed_printer_connection,
6366                   { "Failed printer connection", "spoolss.rffpcnex.flags.failed_connection_printer",
6367                     FT_BOOLEAN, 32, TFS(&tfs_rffpcnex_flags_failed_connection_printer),
6368                     SPOOLSS_PRINTER_CHANGE_FAILED_CONNECTION_PRINTER, "Failed printer connection", HFILL }},
6369
6370                 { &hf_spoolss_notify_options_version,
6371                   { "Version", "spoolss.notify_options.version", FT_UINT32, BASE_DEC,
6372                     NULL, 0, "Version", HFILL }},
6373
6374                 { &hf_spoolss_notify_options_flags,
6375                   { "Flags", "spoolss.notify_options.flags", FT_UINT32, BASE_DEC,
6376                     NULL, 0, "Flags", HFILL }},
6377
6378                 { &hf_spoolss_notify_options_count,
6379                   { "Count", "spoolss.notify_options.count", FT_UINT32, BASE_DEC,
6380                     NULL, 0, "Count", HFILL }},
6381
6382                 { &hf_spoolss_notify_option_type,
6383                   { "Type", "spoolss.notify_option.type", FT_UINT16, BASE_DEC,
6384                     VALS(printer_notify_types), 0, "Type", HFILL }},
6385                 { &hf_spoolss_notify_option_reserved1,
6386                   { "Reserved1", "spoolss.notify_option.reserved1", FT_UINT16, BASE_DEC,
6387                     NULL, 0, "Reserved1", HFILL }},
6388                 { &hf_spoolss_notify_option_reserved2,
6389                   { "Reserved2", "spoolss.notify_option.reserved2", FT_UINT32, BASE_DEC,
6390                     NULL, 0, "Reserved2", HFILL }},
6391                 { &hf_spoolss_notify_option_reserved3,
6392                   { "Reserved3", "spoolss.notify_option.reserved3", FT_UINT32, BASE_DEC,
6393                     NULL, 0, "Reserved3", HFILL }},
6394                 { &hf_spoolss_notify_option_count,
6395                   { "Count", "spoolss.notify_option.count", FT_UINT32, BASE_DEC,
6396                     NULL, 0, "Count", HFILL }},
6397                 { &hf_spoolss_notify_option_data_count,
6398                   { "Count", "spoolss.notify_option_data.count", FT_UINT32, BASE_DEC,
6399                     NULL, 0, "Count", HFILL }},
6400                 { &hf_spoolss_notify_options_flags_refresh,
6401                   { "Refresh", "spoolss.notify_options.flags", FT_BOOLEAN, 32,
6402                     TFS(&tfs_notify_options_flags_refresh), PRINTER_NOTIFY_OPTIONS_REFRESH,
6403                     "Refresh", HFILL }},
6404                 { &hf_spoolss_notify_info_count,
6405                   { "Count", "spoolss.notify_info.count", FT_UINT32, BASE_DEC,
6406                     NULL, 0, "Count", HFILL }},
6407                 { &hf_spoolss_notify_info_version,
6408                   { "Version", "spoolss.notify_info.version", FT_UINT32, BASE_DEC,
6409                     NULL, 0, "Version", HFILL }},
6410                 { &hf_spoolss_notify_info_flags,
6411                   { "Flags", "spoolss.notify_info.flags", FT_UINT32, BASE_HEX,
6412                     NULL, 0, "Flags", HFILL }},
6413                 { &hf_spoolss_notify_info_data_type,
6414                   { "Type", "spoolss.notify_info_data.type", FT_UINT16, BASE_DEC,
6415                     VALS(printer_notify_types), 0, "Type", HFILL }},
6416                 { &hf_spoolss_notify_field,
6417                   { "Field", "spoolss.notify_field", FT_UINT16, BASE_DEC,
6418                     NULL, 0, "Field", HFILL }},
6419                 { &hf_spoolss_notify_info_data_count,
6420                   { "Count", "spoolss.notify_info_data.count", FT_UINT32, BASE_DEC,
6421                     NULL, 0, "Count", HFILL }},
6422                 { &hf_spoolss_notify_info_data_id,
6423                   { "Job Id", "spoolss.notify_info_data.jobid", FT_UINT32, BASE_DEC,
6424                     NULL, 0, "Job Id", HFILL }},
6425                 { &hf_spoolss_notify_info_data_value1,
6426                   { "Value1", "spoolss.notify_info_data.value1", FT_UINT32, BASE_HEX,
6427                     NULL, 0, "Value1", HFILL }},
6428                 { &hf_spoolss_notify_info_data_value2,
6429                   { "Value2", "spoolss.notify_info_data.value2", FT_UINT32, BASE_HEX,
6430                     NULL, 0, "Value2", HFILL }},
6431                 { &hf_spoolss_notify_info_data_bufsize,
6432                   { "Buffer size", "spoolss.notify_info_data.bufsize", FT_UINT32, BASE_DEC,
6433                     NULL, 0, "Buffer size", HFILL }},
6434                 { &hf_spoolss_notify_info_data_buffer,
6435                   { "Buffer", "spoolss.notify_info_data.buffer", FT_UINT32, BASE_HEX,
6436                     NULL, 0, "Buffer", HFILL }},
6437                 { &hf_spoolss_notify_info_data_buffer_len,
6438                   { "Buffer length", "spoolss.notify_info_data.buffer.len", FT_UINT32, BASE_HEX,
6439                     NULL, 0, "Buffer length", HFILL }},
6440                 { &hf_spoolss_notify_info_data_buffer_data,
6441                   { "Buffer data", "spoolss.notify_info_data.buffer.data", FT_BYTES, BASE_HEX,
6442                     NULL, 0, "Buffer data", HFILL }},
6443
6444                 { &hf_spoolss_rrpcn_changelow,
6445                   { "Change low", "spoolss.rrpcn.changelow", FT_UINT32, BASE_DEC,
6446                     NULL, 0, "Change low", HFILL }},
6447                 { &hf_spoolss_rrpcn_changehigh,
6448                   { "Change high", "spoolss.rrpcn.changehigh", FT_UINT32, BASE_DEC,
6449                     NULL, 0, "Change high", HFILL }},
6450                 { &hf_spoolss_rrpcn_unk0,
6451                   { "Unknown 0", "spoolss.rrpcn.unk0", FT_UINT32, BASE_DEC,
6452                     NULL, 0, "Unknown 0", HFILL }},
6453                 { &hf_spoolss_rrpcn_unk1,
6454                   { "Unknown 1", "spoolss.rrpcn.unk1", FT_UINT32, BASE_DEC,
6455                     NULL, 0, "Unknown 1", HFILL }},
6456                 { &hf_spoolss_replyopenprinter_unk0,
6457                   { "Unknown 0", "spoolss.replyopenprinter.unk0", FT_UINT32, BASE_DEC,
6458                     NULL, 0, "Unknown 0", HFILL }},
6459                 { &hf_spoolss_replyopenprinter_unk1,
6460                   { "Unknown 1", "spoolss.replyopenprinter.unk1", FT_UINT32, BASE_DEC,
6461                     NULL, 0, "Unknown 1", HFILL }},
6462
6463                 { &hf_spoolss_printer_status,
6464                   { "Status", "spoolss.printer_status", FT_UINT32, BASE_DEC,
6465                    VALS(printer_status_vals), 0, "Status", HFILL }},
6466
6467                 /* Printer attributes */
6468
6469                 { &hf_spoolss_printer_attributes,
6470                   { "Attributes", "spoolss.printer_attributes", FT_UINT32,
6471                     BASE_HEX, NULL, 0, "Attributes", HFILL }},
6472
6473                 { &hf_spoolss_printer_attributes_queued,
6474                   { "Queued", "spoolss.printer_attributes.queued", FT_BOOLEAN,
6475                     32, TFS(&tfs_printer_attributes_queued),
6476                     PRINTER_ATTRIBUTE_QUEUED, "Queued", HFILL }},
6477
6478                 { &hf_spoolss_printer_attributes_direct,
6479                   { "Direct", "spoolss.printer_attributes.direct", FT_BOOLEAN,
6480                     32, TFS(&tfs_printer_attributes_direct),
6481                     PRINTER_ATTRIBUTE_DIRECT, "Direct", HFILL }},
6482
6483                 { &hf_spoolss_printer_attributes_default,
6484                   { "Default (9x/ME only)", "spoolss.printer_attributes.default",FT_BOOLEAN,
6485                     32, TFS(&tfs_printer_attributes_default),
6486                     PRINTER_ATTRIBUTE_DEFAULT, "Default", HFILL }},
6487
6488                 { &hf_spoolss_printer_attributes_shared,
6489                   { "Shared", "spoolss.printer_attributes.shared", FT_BOOLEAN,
6490                     32, TFS(&tfs_printer_attributes_shared),
6491                     PRINTER_ATTRIBUTE_SHARED, "Shared", HFILL }},
6492
6493                 { &hf_spoolss_printer_attributes_network,
6494                   { "Network", "spoolss.printer_attributes.network", FT_BOOLEAN,
6495                     32, TFS(&tfs_printer_attributes_network),
6496                     PRINTER_ATTRIBUTE_NETWORK, "Network", HFILL }},
6497
6498                 { &hf_spoolss_printer_attributes_hidden,
6499                   { "Hidden", "spoolss.printer_attributes.hidden", FT_BOOLEAN,
6500                     32, TFS(&tfs_printer_attributes_hidden),
6501                     PRINTER_ATTRIBUTE_HIDDEN, "Hidden", HFILL }},
6502
6503                 { &hf_spoolss_printer_attributes_local,
6504                   { "Local", "spoolss.printer_attributes.local", FT_BOOLEAN,
6505                     32, TFS(&tfs_printer_attributes_local),
6506                     PRINTER_ATTRIBUTE_LOCAL, "Local", HFILL }},
6507
6508                 { &hf_spoolss_printer_attributes_enable_devq,
6509                   { "Enable devq", "spoolss.printer_attributes.enable_devq", FT_BOOLEAN,
6510                     32, TFS(&tfs_printer_attributes_enable_devq),
6511                     PRINTER_ATTRIBUTE_ENABLE_DEVQ, "Enable evq", HFILL }},
6512
6513                 { &hf_spoolss_printer_attributes_keep_printed_jobs,
6514                   { "Keep printed jobs", "spoolss.printer_attributes.keep_printed_jobs", FT_BOOLEAN,
6515                     32, TFS(&tfs_printer_attributes_keep_printed_jobs),
6516                     PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, "Keep printed jobs", HFILL }},
6517
6518                 { &hf_spoolss_printer_attributes_do_complete_first,
6519                   { "Do complete first", "spoolss.printer_attributes.do_complete_first", FT_BOOLEAN,
6520                     32, TFS(&tfs_printer_attributes_do_complete_first),
6521                     PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST, "Do complete first", HFILL }},
6522
6523                 { &hf_spoolss_printer_attributes_work_offline,
6524                   { "Work offline (9x/ME only)", "spoolss.printer_attributes.work_offline", FT_BOOLEAN,
6525                     32, TFS(&tfs_printer_attributes_work_offline),
6526                     PRINTER_ATTRIBUTE_WORK_OFFLINE, "Work offline", HFILL }},
6527
6528                 { &hf_spoolss_printer_attributes_enable_bidi,
6529                   { "Enable bidi (9x/ME only)", "spoolss.printer_attributes.enable_bidi", FT_BOOLEAN,
6530                     32, TFS(&tfs_printer_attributes_enable_bidi),
6531                     PRINTER_ATTRIBUTE_ENABLE_BIDI, "Enable bidi", HFILL }},
6532
6533                 { &hf_spoolss_printer_attributes_raw_only,
6534                   { "Raw only", "spoolss.printer_attributes.raw_only", FT_BOOLEAN,
6535                     32, TFS(&tfs_printer_attributes_raw_only),
6536                     PRINTER_ATTRIBUTE_RAW_ONLY, "Raw only", HFILL }},
6537
6538                 { &hf_spoolss_printer_attributes_published,
6539                   { "Published", "spoolss.printer_attributes.published", FT_BOOLEAN,
6540                     32, TFS(&tfs_printer_attributes_published),
6541                     PRINTER_ATTRIBUTE_PUBLISHED, "Published", HFILL }},
6542
6543                 /* Setprinter RPC */
6544
6545                 { &hf_spoolss_setprinter_cmd,
6546                   { "Command", "spoolss.setprinter_cmd", FT_UINT32, BASE_DEC,
6547                    VALS(setprinter_cmd_vals), 0, "Command", HFILL }},
6548
6549                 /* RouterReplyPrinter RPC */
6550
6551                 { &hf_spoolss_routerreplyprinter_condition,
6552                   { "Condition", "spoolss.routerreplyprinter.condition", FT_UINT32,
6553                     BASE_DEC, NULL, 0, "Condition", HFILL }},
6554
6555                 { &hf_spoolss_routerreplyprinter_unknown1,
6556                   { "Unknown1", "spoolss.routerreplyprinter.unknown1", FT_UINT32,
6557                     BASE_DEC, NULL, 0, "Unknown1", HFILL }},
6558
6559                 { &hf_spoolss_routerreplyprinter_changeid,
6560                   { "Change id", "spoolss.routerreplyprinter.changeid", FT_UINT32,
6561                     BASE_DEC, NULL, 0, "Change id", HFILL }},
6562
6563                 /* Forms */
6564
6565                 { &hf_spoolss_form_level,
6566                   { "Level", "spoolss.form.level", FT_UINT32,
6567                     BASE_DEC, NULL, 0, "Level", HFILL }},
6568
6569                 { &hf_spoolss_form_name,
6570                   { "Name", "spoolss.form.name", FT_STRING, BASE_NONE,
6571                     NULL, 0, "Name", HFILL }},
6572
6573                 { &hf_spoolss_form_flags,
6574                   { "Flags", "spoolss.form.flags", FT_UINT32,
6575                     BASE_DEC, NULL, 0, "Flags", HFILL }},
6576
6577                 { &hf_spoolss_form_unknown,
6578                   { "Unknown", "spoolss.form.unknown", FT_UINT32,
6579                     BASE_HEX, NULL, 0, "Unknown", HFILL }},
6580
6581                 { &hf_spoolss_form_width,
6582                   { "Width", "spoolss.form.width", FT_UINT32,
6583                     BASE_DEC, NULL, 0, "Width", HFILL }},
6584
6585                 { &hf_spoolss_form_height,
6586                   { "Height", "spoolss.form.height", FT_UINT32,
6587                     BASE_DEC, NULL, 0, "Height", HFILL }},
6588
6589                 { &hf_spoolss_form_left_margin,
6590                   { "Left margin", "spoolss.form.left", FT_UINT32,
6591                     BASE_DEC, NULL, 0, "Left", HFILL }},
6592
6593                 { &hf_spoolss_form_top_margin,
6594                   { "Top", "spoolss.form.top", FT_UINT32,
6595                     BASE_DEC, NULL, 0, "Top", HFILL }},
6596
6597                 { &hf_spoolss_form_horiz_len,
6598                   { "Horizontal", "spoolss.form.horiz", FT_UINT32,
6599                     BASE_DEC, NULL, 0, "Horizontal", HFILL }},
6600
6601                 { &hf_spoolss_form_vert_len,
6602                   { "Vertical", "spoolss.form.vert", FT_UINT32,
6603                     BASE_DEC, NULL, 0, "Vertical", HFILL }},
6604
6605                 /* GetForm RPC */
6606
6607                 { &hf_spoolss_getform_level,
6608                   { "Level", "spoolss.getform.level", FT_UINT32,
6609                     BASE_DEC, NULL, 0, "Level", HFILL }},
6610
6611                 /* SetForm RPC */
6612
6613                 { &hf_spoolss_setform_level,
6614                   { "Level", "spoolss.setform.level", FT_UINT32,
6615                     BASE_DEC, NULL, 0, "Level", HFILL }},
6616
6617                 /* AddForm RPC */
6618
6619                 { &hf_spoolss_addform_level,
6620                   { "Level", "spoolss.addform.level", FT_UINT32,
6621                     BASE_DEC, NULL, 0, "Level", HFILL }},
6622
6623                 /* EnumForms RPC */
6624
6625                 { &hf_spoolss_enumforms_num,
6626                   { "Num", "spoolss.enumforms.num", FT_UINT32,
6627                     BASE_DEC, NULL, 0, "Num", HFILL }},
6628
6629                 /* Printerdata */
6630
6631                 { &hf_spoolss_printerdata_size,
6632                   { "Size", "spoolss.printerdata.size", FT_UINT32,
6633                     BASE_DEC, NULL, 0, "Size", HFILL }},
6634
6635                 { &hf_spoolss_printerdata_data,
6636                   { "Data", "spoolss.printerdata.data", FT_BYTES,
6637                     BASE_HEX, NULL, 0, "Data", HFILL }},
6638
6639                 /* Specific access rights */
6640
6641                 { &hf_access_required,
6642                   { "Access required", "spoolss.access_required",
6643                     FT_UINT32, BASE_HEX, NULL, 0x0, "Access REQUIRED",
6644                     HFILL }},
6645
6646                 { &hf_server_access_admin,
6647                   { "Server admin", "spoolss.access_mask.server_admin",
6648                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6649                     SERVER_ACCESS_ADMINISTER, "Server admin", HFILL }},
6650
6651                 { &hf_server_access_enum,
6652                   { "Server enum", "spoolss.access_mask.server_enum",
6653                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6654                     SERVER_ACCESS_ENUMERATE, "Server enum", HFILL }},
6655
6656                 { &hf_printer_access_admin,
6657                   { "Printer admin", "spoolss.access_mask.printer_admin",
6658                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6659                     PRINTER_ACCESS_ADMINISTER, "Printer admin", HFILL }},
6660
6661                 { &hf_printer_access_use,
6662                   { "Printer use", "spoolss.access_mask.printer_use",
6663                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6664                     PRINTER_ACCESS_USE, "Printer use", HFILL }},
6665
6666                 { &hf_job_access_admin,
6667                   { "Job admin", "spoolss.access_mask.job_admin",
6668                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6669                     JOB_ACCESS_ADMINISTER, "Job admin", HFILL }},
6670
6671                 /* Enumprinters */
6672
6673                 { &hf_enumprinters_flags_local,
6674                   { "Enum local", "spoolss.enumprinters.flags.enum_local",
6675                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6676                     PRINTER_ENUM_LOCAL, "Enum local", HFILL }},
6677
6678                 { &hf_enumprinters_flags_name,
6679                   { "Enum name", "spoolss.enumprinters.flags.enum_name",
6680                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6681                     PRINTER_ENUM_NAME, "Enum name", HFILL }},
6682
6683                 { &hf_enumprinters_flags_shared,
6684                   { "Enum shared", "spoolss.enumprinters.flags.enum_shared",
6685                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6686                     PRINTER_ENUM_SHARED, "Enum shared", HFILL }},
6687
6688                 { &hf_enumprinters_flags_default,
6689                   { "Enum default", "spoolss.enumprinters.flags.enum_default",
6690                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6691                     PRINTER_ENUM_DEFAULT, "Enum default", HFILL }},
6692
6693                 { &hf_enumprinters_flags_connections,
6694                   { "Enum connections", "spoolss.enumprinters.flags.enum_connections",
6695                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6696                     PRINTER_ENUM_CONNECTIONS, "Enum connections", HFILL }},
6697
6698                 { &hf_enumprinters_flags_network,
6699                   { "Enum network", "spoolss.enumprinters.flags.enum_network",
6700                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6701                     PRINTER_ENUM_NETWORK, "Enum network", HFILL }},
6702
6703                 { &hf_enumprinters_flags_remote,
6704                   { "Enum remote", "spoolss.enumprinters.flags.enum_remote",
6705                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
6706                     PRINTER_ENUM_REMOTE, "Enum remote", HFILL }}
6707         };
6708
6709         static gint *ett[] = {
6710                 &ett_dcerpc_spoolss,
6711                 &ett_PRINTER_DEFAULT,
6712                 &ett_DEVMODE_CTR,
6713                 &ett_DEVMODE,
6714                 &ett_USER_LEVEL,
6715                 &ett_USER_LEVEL_1,
6716                 &ett_BUFFER,
6717                 &ett_BUFFER_DATA,
6718                 &ett_BUFFER_DATA_BUFFER,
6719                 &ett_UNISTR2,
6720                 &ett_SPOOL_PRINTER_INFO_LEVEL,
6721                 &ett_PRINTER_INFO_0,
6722                 &ett_PRINTER_INFO_1,
6723                 &ett_PRINTER_INFO_2,
6724                 &ett_PRINTER_INFO_3,
6725                 &ett_RELSTR,
6726                 &ett_RELSTR_ARRAY,
6727                 &ett_FORM_REL,
6728                 &ett_FORM_CTR,
6729                 &ett_FORM_1,
6730                 &ett_JOB_INFO_1,
6731                 &ett_JOB_INFO_2,
6732                 &ett_SEC_DESC_BUF,
6733                 &ett_SYSTEM_TIME,
6734                 &ett_DOC_INFO_1,
6735                 &ett_DOC_INFO,
6736                 &ett_DOC_INFO_CTR,
6737                 &ett_printerdata_value,
6738                 &ett_printerdata_data,
6739                 &ett_writeprinter_buffer,
6740                 &ett_DRIVER_INFO_1,
6741                 &ett_DRIVER_INFO_3,
6742                 &ett_rffpcnex_flags,
6743                 &ett_notify_options_flags,
6744                 &ett_NOTIFY_INFO_DATA,
6745                 &ett_NOTIFY_OPTION,
6746                 &ett_printer_attributes,
6747                 &ett_job_status,
6748                 &ett_enumprinters_flags,
6749         };
6750
6751         proto_dcerpc_spoolss = proto_register_protocol(
6752                 "Microsoft Spool Subsystem", "SPOOLSS", "spoolss");
6753
6754         proto_register_field_array(proto_dcerpc_spoolss, hf, array_length(hf));
6755
6756         proto_register_subtree_array(ett, array_length(ett));
6757 }
6758
6759 /* Protocol handoff */
6760
6761 static e_uuid_t uuid_dcerpc_spoolss = {
6762         0x12345678, 0x1234, 0xabcd,
6763         { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
6764 };
6765
6766 static guint16 ver_dcerpc_spoolss = 1;
6767
6768 void
6769 proto_reg_handoff_dcerpc_spoolss(void)
6770 {
6771         /* Register protocol as dcerpc */
6772
6773         dcerpc_init_uuid(proto_dcerpc_spoolss, ett_dcerpc_spoolss,
6774                          &uuid_dcerpc_spoolss, ver_dcerpc_spoolss,
6775                          dcerpc_spoolss_dissectors, hf_spoolss_opnum);
6776 }