Make the LDP dissectors new-style dissectors, so they can reject packets
[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.20 2002/04/24 03:08:49 tpot 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 /* 
42  * New system for handling pointers and buffers.  We act more like the NDR
43  * specification and have a list of deferred pointers which are processed
44  * after a structure has been parsed.  
45  *
46  * Each structure has a parse function which takes as an argument a GList.
47  * As pointers are processed, they are appended onto this list.  When the
48  * structure is complete, the pointers (referents) are processed by calling
49  * prs_referents().  In the case of function arguments, the
50  * prs_struct_and_referents() function is called as pointers are always
51  * processed immediately after the argument.
52  */
53
54 typedef int prs_fn(tvbuff_t *tvb, int offset, packet_info *pinfo,
55                    proto_tree *tree, GList **dp_list, void **data);
56
57 /* Deferred referent */
58
59 struct deferred_ptr {
60         prs_fn *fn;             /* Parse function to call */
61         proto_tree *tree;       /* Tree context */
62 };
63
64 /* A structure to hold needed ethereal state to pass to GList foreach
65    iterator. */
66
67 struct deferred_ptr_state {
68         tvbuff_t *tvb;
69         int *poffset;
70         packet_info *pinfo;
71         GList **dp_list;
72         void **ptr_data;
73 };
74
75 void defer_ptr(GList **list, prs_fn *fn, proto_tree *tree)
76 {
77         struct deferred_ptr *dr;
78
79         dr = g_malloc(sizeof(struct deferred_ptr));
80
81         dr->fn = fn;
82         dr->tree = tree;
83         
84         *list = g_list_append(*list, dr);
85 }
86
87 /* Parse a pointer */
88
89 static int prs_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
90                    proto_tree *tree, guint32 *data, char *name)
91 {
92         guint32 ptr;
93
94         offset = prs_uint32(tvb, offset, pinfo, tree, &ptr, NULL);
95
96         if (tree && name)
97                 proto_tree_add_text(tree, tvb, offset - 4, 4, 
98                                     "%s pointer: 0x%08x", name, ptr);
99
100         if (data)
101                 *data = ptr;
102
103         return offset;
104 }
105
106 /* Iterator function for prs_referents */
107
108 static void dr_iterator(gpointer data, gpointer user_data)
109 {
110         struct deferred_ptr *dp = (struct deferred_ptr *)data;
111         struct deferred_ptr_state *s = (struct deferred_ptr_state *)user_data;
112
113         /* Parse pointer */
114
115         *s->poffset = dp->fn(s->tvb, *s->poffset, s->pinfo, dp->tree, 
116                              s->dp_list, s->ptr_data);
117
118         if (s->ptr_data)
119                 s->ptr_data++;          /* Ready for next parse fn */
120 }
121
122 /* Call the parse function for each element in the deferred pointers list.
123    If there are any additional pointers in these structures they are pushed
124    onto parent_dp_list. */ 
125
126 int prs_referents(tvbuff_t *tvb, int offset, packet_info *pinfo,
127                   proto_tree *tree, GList **dp_list, GList **list,
128                   void ***ptr_data)
129 {
130         struct deferred_ptr_state s;
131         int new_offset = offset;
132
133         /* Create a list of void pointers to store return data */
134
135         if (ptr_data) {
136                 int len = g_list_length(*dp_list) * sizeof(void *);
137
138                 if (len > 0) {
139                         *ptr_data = malloc(len);
140                         memset(*ptr_data, 0, len);
141                 } else
142                         *ptr_data = NULL;
143         }
144
145         /* Set up iterator data */
146
147         s.tvb = tvb;
148         s.poffset = &new_offset;
149         s.pinfo = pinfo;
150         s.dp_list = dp_list;
151         s.ptr_data = ptr_data ? *ptr_data : NULL;
152
153         g_list_foreach(*list, dr_iterator, &s); 
154
155         *list = NULL;           /* XXX: free list */
156
157         return new_offset;
158 }
159
160 /* Parse a structure then clean up any deferred referants it creates. */
161
162 static int prs_struct_and_referents(tvbuff_t *tvb, int offset,
163                                     packet_info *pinfo, proto_tree *tree,
164                                     prs_fn *fn, void **data, void ***ptr_data)
165 {
166         GList *dp_list = NULL;
167
168         offset = fn(tvb, offset, pinfo, tree, &dp_list, data);
169
170         offset = prs_referents(tvb, offset, pinfo, tree, &dp_list,
171                                &dp_list, ptr_data);
172
173         return offset;
174 }
175
176 /* Parse a Win32 error, basically a DOS error.  The spoolss API doesn't
177    use NT status codes. */
178
179 static int prs_werror(tvbuff_t *tvb, int offset, packet_info *pinfo,
180                       proto_tree *tree, guint32 *data)
181 {
182         guint32 status;
183
184         offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
185
186         if (tree)
187                 proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
188                                     val_to_str(status, DOS_errors, 
189                                                "Unknown error"));
190
191         if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
192                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
193                                 val_to_str(status, DOS_errors, 
194                                            "Unknown error"));
195
196         if (data)
197                 *data = status;
198
199         return offset;
200 }
201
202 /* Display a policy handle in the protocol tree */
203
204 static gint ett_POLICY_HND = -1;
205
206 static void display_pol(proto_tree *tree, tvbuff_t *tvb, int offset, 
207                         const guint8 *policy_hnd)
208 {
209         proto_item *item;
210         char *pol_name = NULL;
211         int pol_open_frame = 0, pol_close_frame = 0;
212         proto_tree *subtree;
213
214         dcerpc_smb_fetch_pol(policy_hnd, &pol_name, &pol_open_frame,
215                              &pol_close_frame);
216
217         item = proto_tree_add_text(tree, tvb, offset, 20, 
218                                    "Policy handle%s%s", 
219                                    pol_name ? ": " : "", 
220                                    pol_name ? pol_name : "");
221
222         subtree = proto_item_add_subtree(item, ett_POLICY_HND);
223
224         if (pol_open_frame)
225                 proto_tree_add_text(subtree, tvb, offset, 0,
226                                     "Opened in frame %u", pol_open_frame);
227
228         if (pol_close_frame)
229                 proto_tree_add_text(subtree, tvb, offset, 0,
230                                     "Closed in frame %u", pol_close_frame);
231
232         proto_tree_add_text(subtree, tvb, offset, 20, "Policy Handle: %s",
233                             tvb_bytes_to_str(tvb, offset, 20));
234 }
235
236 /*
237  * SpoolssClosePrinter
238  */
239
240 static int SpoolssClosePrinter_q(tvbuff_t *tvb, int offset,
241                                  packet_info *pinfo, proto_tree *tree, 
242                                  char *drep)
243 {
244         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
245         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
246         const guint8 *policy_hnd;
247
248         /* Update informational fields */
249
250         if (check_col(pinfo->cinfo, COL_INFO))
251                 col_set_str(pinfo->cinfo, COL_INFO, "ClosePrinter request");
252
253         if (dcv->rep_frame != 0)
254                 proto_tree_add_text(tree, tvb, offset, 0, 
255                                     "Response in frame %u", dcv->rep_frame);
256         /* Parse packet */
257
258         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
259
260         dcerpc_smb_store_pol(policy_hnd, NULL, 0, pinfo->fd->num);
261
262         display_pol(tree, tvb, offset - 20, policy_hnd);
263
264         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
265
266         return offset;
267 }
268
269 static int SpoolssClosePrinter_r(tvbuff_t *tvb, int offset, 
270                                  packet_info *pinfo, proto_tree *tree, 
271                                  char *drep)
272 {
273         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
274         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
275         const guint8 *policy_hnd;
276
277         /* Update informational fields */
278
279         if (check_col(pinfo->cinfo, COL_INFO))
280                 col_set_str(pinfo->cinfo, COL_INFO, "ClosePrinter response");
281
282         if (dcv->req_frame != 0)
283                 proto_tree_add_text(tree, tvb, offset, 0, 
284                                     "Request in frame %u", dcv->req_frame);
285
286         /* Parse packet */
287
288         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
289
290         display_pol(tree, tvb, offset - 20, policy_hnd);
291
292         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
293
294         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
295
296         return offset;
297 }
298
299 /* Parse a UNISTR2 structure */
300
301 static gint ett_UNISTR2 = -1;
302
303 static int prs_UNISTR2_dp(tvbuff_t *tvb, int offset, packet_info *pinfo,
304                           proto_tree *tree, GList **dp_list, void **data)
305 {
306         proto_item *item;
307         proto_tree *subtree;
308         guint32 length, the_offset, max_len;
309         int old_offset = offset;
310         int data16_offset;
311         char *text;
312         
313         offset = prs_uint32(tvb, offset, pinfo, tree, &length, NULL);
314         offset = prs_uint32(tvb, offset, pinfo, tree, &the_offset, NULL);
315         offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, NULL);
316
317         offset = prs_uint16s(tvb, offset, pinfo, tree, max_len, &data16_offset,
318                              NULL);
319         
320         text = fake_unicode(tvb, data16_offset, max_len);
321
322         item = proto_tree_add_text(tree, tvb, old_offset, offset - old_offset,
323                                    "UNISTR2: %s", text);
324
325         subtree = proto_item_add_subtree(item, ett_UNISTR2);    
326
327         if (data)
328                 *data = text;
329         else
330                 g_free(text);
331
332         proto_tree_add_text(subtree, tvb, old_offset, 4, "Length: %u", length);
333
334         old_offset += 4;
335
336         proto_tree_add_text(subtree, tvb, old_offset, 4, "Offset: %u", 
337                             the_offset);
338
339         old_offset += 4;
340
341         proto_tree_add_text(subtree, tvb, old_offset, 4, "Max length: %u",
342                             max_len);
343
344         old_offset += 4;
345
346         proto_tree_add_text(subtree, tvb, old_offset, max_len * 2, "Data");
347
348         return offset;
349 }
350
351 /*
352  * SpoolssGetPrinterData
353  */
354
355 static int SpoolssGetPrinterData_q(tvbuff_t *tvb, int offset,
356                                    packet_info *pinfo, proto_tree *tree, 
357                                    char *drep)
358 {
359         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
360         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
361         char *value_name = NULL;
362         const guint8 *policy_hnd;
363
364         /* Update informational fields */
365
366         if (check_col(pinfo->cinfo, COL_INFO))
367                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinterData request");
368
369         if (dcv->rep_frame != 0)
370                 proto_tree_add_text(tree, tvb, offset, 0, 
371                                     "Response in frame %u", dcv->rep_frame);
372
373         /* Parse packet */
374
375         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
376
377         display_pol(tree, tvb, offset - 20, policy_hnd);
378
379         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
380                                           prs_UNISTR2_dp, (void **)&value_name,
381                                           NULL);
382
383         if (check_col(pinfo->cinfo, COL_INFO))
384                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
385
386         g_free(value_name);
387
388         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Size");
389
390         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
391
392         return offset;
393 }
394
395 static int SpoolssGetPrinterData_r(tvbuff_t *tvb, int offset,
396                                    packet_info *pinfo, proto_tree *tree, 
397                                    char *drep)
398 {
399         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
400         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
401         GList *dp_list = NULL;
402         guint32 size, type;
403
404         /* Update information fields */
405
406         if (check_col(pinfo->cinfo, COL_INFO))
407                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinterData response");
408
409         if (dcv->req_frame != 0)
410                 proto_tree_add_text(tree, tvb, offset, 0, 
411                                     "Request in frame %u", dcv->req_frame);
412
413         /* Parse packet */
414
415         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
416   
417         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
418                             val_to_str(type, reg_datatypes, "Unknown type"));
419
420         offset = prs_uint32(tvb, offset, pinfo, tree, &size, "Size");
421   
422         offset = prs_uint8s(tvb, offset, pinfo, tree, size, NULL, "Data");
423
424         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
425
426         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
427
428         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
429
430         return offset;
431 }
432
433 /*
434  * SpoolssGetPrinterDataEx
435  */
436
437 static int SpoolssGetPrinterDataEx_q(tvbuff_t *tvb, int offset,
438                                      packet_info *pinfo, proto_tree *tree, 
439                                      char *drep)
440 {
441         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
442         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
443         char *key_name, *value_name;
444         const guint8 *policy_hnd;
445
446         /* Update informational fields */
447
448         if (check_col(pinfo->cinfo, COL_INFO))
449                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinterDataEx request");
450
451         if (dcv->rep_frame != 0)
452                 proto_tree_add_text(tree, tvb, offset, 0, 
453                                     "Response in frame %u", dcv->rep_frame);
454
455         /* Parse packet */
456
457         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
458
459         display_pol(tree, tvb, offset - 20, policy_hnd);
460
461         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
462                                           prs_UNISTR2_dp, (void **)&key_name,
463                                           NULL);
464
465         /*
466          * Register a cleanup function in case on of our tvbuff accesses
467          * throws an exception. We need to clean up key_name.
468          */
469         CLEANUP_PUSH(g_free, key_name);
470
471         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
472                                           prs_UNISTR2_dp, (void **)&value_name,
473                                           NULL);
474
475         if (check_col(pinfo->cinfo, COL_INFO))
476                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s", 
477                                 key_name, value_name);
478
479         /*
480          * We're done with key_name, so we can call the cleanup handler to
481          * free it, and then pop the cleanup handler.
482          */
483         CLEANUP_CALL_AND_POP;
484
485         /*
486          * We're also done with value_name.
487          */
488         g_free(value_name);
489
490         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Size");
491
492         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
493
494         return offset;
495 }
496
497 static int SpoolssGetPrinterDataEx_r(tvbuff_t *tvb, int offset,
498                                      packet_info *pinfo, proto_tree *tree, 
499                                      char *drep)
500 {
501         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
502         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
503         guint32 size, type;
504
505         /* Update informational fields */
506
507         if (check_col(pinfo->cinfo, COL_INFO))
508                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinterDataEx response");
509
510         if (dcv->req_frame != 0)
511                 proto_tree_add_text(tree, tvb, offset, 0, 
512                                     "Request in frame %u", dcv->req_frame);
513
514         /* Parse packet */
515
516         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
517   
518         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
519                             val_to_str(type, reg_datatypes, "Unknown type"));
520
521         offset = prs_uint32(tvb, offset, pinfo, tree, &size, "Size");
522   
523         offset = prs_uint8s(tvb, offset, pinfo, tree, size, NULL, "Data");
524
525         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
526
527         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
528
529         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
530
531         return offset;
532 }
533
534 /*
535  * SpoolssSetPrinterData
536  */
537
538 static int SpoolssSetPrinterData_q(tvbuff_t *tvb, int offset,
539                                    packet_info *pinfo, proto_tree *tree, 
540                                    char *drep)
541 {
542         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
543         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
544         char *value_name = NULL;
545         guint32 type, max_len;
546         const guint8 *policy_hnd;
547
548         /* Update informational fields */
549
550         if (check_col(pinfo->cinfo, COL_INFO))
551                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinterData request");
552
553         if (dcv->rep_frame != 0)
554                 proto_tree_add_text(tree, tvb, offset, 0, 
555                                     "Response in frame %u", dcv->rep_frame);
556
557         /* Parse packet */
558
559         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
560
561         display_pol(tree, tvb, offset - 20, policy_hnd);
562
563         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
564                                           prs_UNISTR2_dp, (void **)&value_name,
565                                           NULL);
566
567         if (check_col(pinfo->cinfo, COL_INFO))
568                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", value_name);
569
570         g_free(value_name);
571
572         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
573
574         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
575                             val_to_str(type, reg_datatypes, "Unknown type"));
576
577         offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, "Max length");
578
579         offset = prs_uint8s(tvb, offset, pinfo, tree, max_len, NULL,
580                             "Data");
581
582         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real length");
583
584         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
585
586         return offset;
587 }
588
589 static int SpoolssSetPrinterData_r(tvbuff_t *tvb, int offset,
590                                    packet_info *pinfo, proto_tree *tree, 
591                                    char *drep)
592 {
593         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
594         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
595         GList *dp_list = NULL;
596
597         /* Update informational fields */
598
599         if (check_col(pinfo->cinfo, COL_INFO))
600                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinterData response");
601
602         if (dcv->req_frame != 0)
603                 proto_tree_add_text(tree, tvb, offset, 0, 
604                                     "Request in frame %u", dcv->req_frame);
605
606         /* Parse packet */
607
608         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
609
610         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
611
612         return offset;
613 }
614
615 /*
616  * SpoolssSetPrinterDataEx
617  */
618
619 static int SpoolssSetPrinterDataEx_q(tvbuff_t *tvb, int offset,
620                                      packet_info *pinfo, proto_tree *tree, 
621                                      char *drep)
622 {
623         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
624         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
625         GList *dp_list = NULL;
626         char *key_name, *value_name;
627         guint32 type, max_len;
628         const guint8 *policy_hnd;
629
630         /* Update informational fields */
631
632         if (check_col(pinfo->cinfo, COL_INFO))
633                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinterDataEx request");
634
635         if (dcv->rep_frame != 0)
636                 proto_tree_add_text(tree, tvb, offset, 0, 
637                                     "Response in frame %u", dcv->rep_frame);
638
639         /* Parse packet */
640
641         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
642
643         display_pol(tree, tvb, offset - 20, policy_hnd);
644
645         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
646                                           prs_UNISTR2_dp, (void **)&key_name,
647                                           NULL);
648
649         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
650                                           prs_UNISTR2_dp, (void **)&value_name,
651                                           NULL);
652
653         if (check_col(pinfo->cinfo, COL_INFO))
654                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s/%s",
655                                 key_name, value_name);
656
657         g_free(key_name);
658         g_free(value_name);
659
660         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
661
662         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
663                             val_to_str(type, reg_datatypes, "Unknown type"));
664
665         offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, "Max length");
666
667         offset = prs_uint8s(tvb, offset, pinfo, tree, max_len, NULL,
668                             "Data");
669
670         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real length");
671
672         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
673
674         return offset;
675 }
676
677 static int SpoolssSetPrinterDataEx_r(tvbuff_t *tvb, int offset,
678                                      packet_info *pinfo, proto_tree *tree, 
679                                      char *drep)
680 {
681         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
682         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
683         GList *dp_list = NULL;
684
685         /* Update informational fields */
686
687         if (check_col(pinfo->cinfo, COL_INFO))
688                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinterDataEx response");
689
690         if (dcv->req_frame != 0)
691                 proto_tree_add_text(tree, tvb, offset, 0, 
692                                     "Request in frame %u", dcv->req_frame);
693
694         /* Parse packet */
695
696         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
697
698         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
699
700         return offset;
701 }
702
703 /* Yet another way to represent a unicode string - sheesh. */
704
705 static int prs_uint16uni(tvbuff_t *tvb, int offset, packet_info *pinfo,
706                          proto_tree *tree, void **data, char *name)
707 {
708         gint len = 0, remaining, i;
709         char *text;
710
711         offset = prs_align(offset, 2);
712
713         /* Get remaining data in buffer as a string */
714
715         remaining = tvb_length_remaining(tvb, offset)/2;
716         text = fake_unicode(tvb, offset, remaining);
717         len = strlen(text);
718
719         if (name) 
720                 proto_tree_add_text(tree, tvb, offset, (len + 1) * 2, 
721                                     "%s: %s", name ? name : "UINT16UNI", 
722                                     text);
723
724         if (data)
725                 *data = text;
726         else
727                 g_free(text);
728
729         return offset + (len + 1) * 2;
730 }
731
732 /*
733  * DEVMODE
734  */
735
736 static gint ett_DEVMODE = -1;
737
738 static int prs_DEVMODE(tvbuff_t *tvb, int offset, packet_info *pinfo,
739                        proto_tree *tree, GList **dp_list, void **data)
740 {
741         proto_item *item;
742         proto_tree *subtree;
743         guint32 ptr = 0;
744         guint16 extra;
745
746         item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE");
747
748         subtree = proto_item_add_subtree(item, ett_DEVMODE);
749
750         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
751
752         /* The device name is stored in a 32-wchar buffer */
753
754         prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Devicename");
755         offset += 64;
756
757         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Spec version");
758         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Driver version");
759         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Size");
760         offset = prs_uint16(tvb, offset, pinfo, subtree, &extra, "Driver extra");
761
762         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Fields");
763
764         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Orientation");
765         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper size");
766         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper length");
767         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Paper width");
768         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Scale");
769         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Copies");
770         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Default source");
771         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Print quality");
772         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Color");
773         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Duplex");
774         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Y resolution");
775         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "TT option");
776         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Collate");
777
778         prs_uint16uni(tvb, offset, pinfo, subtree, NULL, "Form name");
779         offset += 64;
780
781         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Log pixels");
782
783         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Bits per pel");
784         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pels width");
785         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Pels height");
786         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Display flags");
787         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Display frequency");
788         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "ICM method");
789         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "ICM intent");
790         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Media type");
791         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Dither type");
792         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
793         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
794         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Panning width");
795         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Panning height");
796         
797         if (extra != 0)
798                 offset = prs_uint8s(tvb, offset, pinfo, subtree, extra, NULL,
799                                     "Private");
800
801         return offset;
802 }
803
804 /*
805  * Relative string given by offset into the current buffer.  Note that
806  * the offset for subsequent relstrs are against the structure start, not
807  * the point where the offset is parsed from.
808  */
809
810 static gint ett_RELSTR = -1;
811
812 static int prs_relstr(tvbuff_t *tvb, int offset, packet_info *pinfo,
813                       proto_tree *tree, GList **dp_list, int struct_start,
814                       void **data, char *name)
815 {
816         proto_item *item;
817         proto_tree *subtree;
818         guint32 relstr_offset, relstr_start, relstr_end;
819         guint16 *ptr;
820         char *text = strdup("NULL");
821         gint len = 0, remaining, i;
822
823         offset = prs_uint32(tvb, offset, pinfo, tree, &relstr_offset, NULL);
824
825         /* A relative offset of zero is a NULL string */
826
827         relstr_start = relstr_offset + struct_start;
828                
829         if (relstr_offset)
830                 relstr_end = prs_uint16uni(tvb, relstr_start, pinfo, tree, 
831                                            (void **)&text, NULL);
832         else
833                 relstr_end = offset;
834         
835         item = proto_tree_add_text(tree, tvb, relstr_start, 
836                                    relstr_end - relstr_start, "%s: %s", 
837                                    name ? name : "RELSTR", text);
838
839         subtree = proto_item_add_subtree(item, ett_RELSTR);
840
841         if (data)
842                 *data = text;
843         else
844                 g_free(text);
845
846         proto_tree_add_text(subtree, tvb, offset - 4, 4, 
847                             "Relative offset: %d", relstr_offset);
848
849         proto_tree_add_text(subtree, tvb, relstr_start, 
850                             relstr_end - relstr_start, "Data");
851
852         return offset;
853 }
854
855 /*
856  * PRINTER_INFO_0
857  */
858
859 static gint ett_PRINTER_INFO_0 = -1;
860
861 static int prs_PRINTER_INFO_0(tvbuff_t *tvb, int offset, packet_info *pinfo,
862                               proto_tree *tree, GList **dp_list, void **data)
863 {
864         int struct_start = offset;
865
866         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
867                             NULL, "Printer name");
868         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
869                             NULL, "Server name");
870
871         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "CJobs");
872         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total jobs");
873         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total bytes");
874
875         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Year");
876         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Month");
877         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Day of week");
878         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Day");
879         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Hour");
880         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Minute");
881         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Second");
882         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Milliseconds");
883
884         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Global counter");
885         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Total pages");
886
887         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Major version");
888         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Build version");
889
890         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
891         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
892         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
893         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Session counter");
894         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
895         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer errors");
896         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
897         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
898         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
899         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
900         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Change id");
901         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
902         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status");
903         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
904         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "C_setprinter");
905
906         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
907         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
908         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
909         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
910         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
911         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
912         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
913         offset = prs_uint16(tvb, offset, pinfo, tree, NULL, "Unknown");
914
915         return offset;
916 }
917
918 /*
919  * PRINTER_INFO_1
920  */
921
922 static gint ett_PRINTER_INFO_1 = -1;
923
924 static int prs_PRINTER_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
925                               proto_tree *tree, GList **dp_list, void **data)
926 {
927         int struct_start = offset;
928
929         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
930         
931         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
932                             NULL, "Description");
933         
934         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
935                             NULL, "Name");
936         
937         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
938                             NULL, "Comment");
939         
940         return offset;
941 }
942
943 /*
944  * PRINTER_INFO_2
945  */
946
947 static gint ett_PRINTER_INFO_2 = -1;
948
949 static int prs_PRINTER_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo,
950                               proto_tree *tree, int len, GList **dp_list, 
951                               void **data)
952 {
953         int struct_start = offset;
954         guint32 rel_offset;
955         
956         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
957                             NULL, "Server name");
958         
959         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
960                             NULL, "Printer name");
961         
962         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
963                             NULL, "Share name");
964         
965         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
966                            NULL, "Port name");
967         
968         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
969                             NULL, "Driver name");
970         
971         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
972                             NULL, "Comment");
973         
974         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
975                             NULL, "Location");
976
977         /* This is a relative devicemode */
978
979         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
980
981         prs_DEVMODE(tvb, struct_start + rel_offset - 4, pinfo, tree, 
982                     dp_list, NULL);
983         
984         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
985                             NULL, "Separator file");
986
987         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
988                             NULL, "Print processor");
989
990         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
991                             NULL, "Datatype");
992
993         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
994                             NULL, "Parameters");
995
996         /* This is a relative security descriptor */
997
998         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
999
1000         dissect_nt_sec_desc(tvb, pinfo, struct_start + rel_offset, tree, len);
1001         
1002         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Attributes");
1003
1004         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Priority");
1005
1006         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, 
1007                             "Default priority");
1008
1009         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Start time");
1010
1011         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "End time");
1012
1013         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status");
1014
1015         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Jobs");
1016
1017         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Average PPM");
1018
1019         return offset;
1020 }
1021
1022 /*
1023  * PRINTER_INFO_3
1024  */
1025
1026 static gint ett_PRINTER_INFO_3 = -1;
1027
1028 static int prs_PRINTER_INFO_3(tvbuff_t *tvb, int offset, packet_info *pinfo,
1029                               proto_tree *tree, int len, GList **dp_list, 
1030                               void **data)
1031 {
1032         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
1033
1034         offset = dissect_nt_sec_desc(tvb, pinfo, offset, tree, len);
1035
1036         return offset;
1037 }
1038
1039 /*
1040  * DEVMODE_CTR
1041  */
1042
1043 static gint ett_DEVMODE_CTR = -1;
1044
1045 static int prs_DEVMODE_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
1046                            proto_tree *tree, GList **dp_list, void **data)
1047 {
1048         proto_item *item;
1049         proto_tree *subtree;
1050         guint32 ptr = 0;
1051
1052         item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE_CTR");
1053
1054         subtree = proto_item_add_subtree(item, ett_DEVMODE_CTR);
1055
1056         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1057                 
1058         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Devicemode");
1059
1060         if (ptr)
1061                 offset = prs_DEVMODE(tvb, offset, pinfo, subtree, dp_list, 
1062                                      data);
1063
1064         return offset;
1065 }
1066
1067 /*
1068  * PRINTER_DEFAULT structure
1069  */
1070
1071 static gint ett_PRINTER_DEFAULT = -1;
1072
1073 static int prs_PRINTER_DEFAULT(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1074                                proto_tree *tree, GList **dp_list, void **data)
1075 {
1076         GList *child_dp_list = NULL;
1077         proto_item *item;
1078         proto_tree *subtree;
1079         guint32 ptr = 0, access;
1080
1081         item = proto_tree_add_text(tree, tvb, offset, 0, "PRINTER_DEFAULT");
1082
1083         subtree = proto_item_add_subtree(item, ett_PRINTER_DEFAULT);
1084
1085         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Datatype");
1086
1087         /* Not sure why this isn't a deferred pointer.  I think this may be
1088            two structures stuck together. */
1089
1090         if (ptr)
1091                 offset = prs_UNISTR2_dp(tvb, offset, pinfo, subtree, dp_list, 
1092                                         NULL);
1093
1094         offset = prs_DEVMODE_CTR(tvb, offset, pinfo, subtree,
1095                                  &child_dp_list, NULL);
1096                 
1097         offset = prs_uint32(tvb, offset, pinfo, subtree, &access, NULL);
1098
1099         proto_tree_add_text(subtree, tvb, offset - 4, 4, 
1100                             "Access required: 0x%08x", access);
1101
1102         offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
1103                                &child_dp_list, NULL);
1104
1105         return offset;
1106 }
1107
1108 /*
1109  * USER_LEVEL_1 structure
1110  */
1111
1112 static gint ett_USER_LEVEL_1 = -1;
1113
1114 static int prs_USER_LEVEL_1(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1115                             proto_tree *tree, GList **dp_list, void **data)
1116 {
1117         proto_item *item;
1118         proto_tree *subtree;
1119         guint32 ptr = 0;
1120
1121         item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL_1");
1122
1123         subtree = proto_item_add_subtree(item, ett_USER_LEVEL_1);
1124
1125         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1126
1127         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Client name");
1128
1129         if (ptr)
1130                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
1131
1132         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User name");
1133
1134         if (ptr)
1135                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
1136
1137         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Build");
1138
1139         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Major");
1140
1141         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Minor");
1142
1143         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Processor");
1144         
1145         return offset;
1146 }
1147
1148 /*
1149  * USER_LEVEL structure
1150  */
1151
1152 static gint ett_USER_LEVEL = -1;
1153
1154 static int prs_USER_LEVEL(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1155                           proto_tree *tree, GList **parent_dp_list,
1156                           void **data)
1157 {
1158         proto_item *item;
1159         proto_tree *subtree;
1160         guint32 ptr = 0;
1161         guint32 level;
1162
1163         item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL");
1164
1165         subtree = proto_item_add_subtree(item, ett_USER_LEVEL);
1166
1167         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Info level");
1168
1169         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User level");
1170
1171         if (ptr) {
1172                 switch (level) {
1173                 case 1:
1174                         defer_ptr(parent_dp_list, prs_USER_LEVEL_1, subtree);
1175                         break;
1176                 default:
1177                         proto_tree_add_text(
1178                                 tree, tvb, offset, 0, 
1179                                 "[GetPrinter level %d not decoded]", level);
1180                         break;
1181                 }
1182         }
1183
1184         return offset;
1185 }
1186
1187 /*
1188  * SpoolssOpenPrinterEx
1189  */
1190
1191 static int SpoolssOpenPrinterEx_q(tvbuff_t *tvb, int offset, 
1192                                   packet_info *pinfo, proto_tree *tree, 
1193                                   char *drep)
1194 {
1195         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1196         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1197         char *printer_name;
1198         guint32 ptr = 0;
1199
1200         /* Update informational fields */
1201
1202         if (check_col(pinfo->cinfo, COL_INFO))
1203                 col_set_str(pinfo->cinfo, COL_INFO, "OpenPrinterEx request");
1204
1205         if (dcv->rep_frame != 0)
1206                 proto_tree_add_text(tree, tvb, offset, 0, 
1207                                     "Response in frame %u", dcv->rep_frame);
1208
1209         /* Parse packet */
1210
1211         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Printer name");
1212
1213         if (ptr) {
1214                 char *printer_name;
1215
1216                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1217                                                   prs_UNISTR2_dp, 
1218                                                   (void **)&printer_name,
1219                                                   NULL); 
1220
1221                 if (check_col(pinfo->cinfo, COL_INFO))
1222                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1223                                         printer_name);
1224                 
1225                 /* Store printer name to match with response packet */
1226
1227                 dcv->private_data = printer_name;
1228         }
1229
1230         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1231                                           prs_PRINTER_DEFAULT, NULL, NULL);
1232
1233         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
1234
1235         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1236                                           prs_USER_LEVEL, NULL, NULL);
1237
1238         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1239
1240         return offset;
1241 }
1242
1243 static int SpoolssOpenPrinterEx_r(tvbuff_t *tvb, int offset,
1244                                   packet_info *pinfo, proto_tree *tree, 
1245                                   char *drep)
1246 {
1247         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1248         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1249         GList *dp_list = NULL;
1250         guint32 status;
1251         const guint8 *policy_hnd;
1252
1253         /* Display informational data */
1254
1255         if (check_col(pinfo->cinfo, COL_INFO))
1256                 col_set_str(pinfo->cinfo, COL_INFO, "OpenPrinterEx response");
1257
1258         if (dcv->req_frame != 0)
1259                 proto_tree_add_text(tree, tvb, offset, 0, 
1260                                     "Request in frame %u", dcv->req_frame);
1261
1262         /* Parse packet */
1263
1264         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1265
1266         display_pol(tree, tvb, offset - 20, policy_hnd);
1267
1268         offset = prs_werror(tvb, offset, pinfo, tree, &status);
1269
1270         if (status == 0) {
1271
1272                 /* Associate the returned printer handle with a name */
1273
1274                 if (dcv->private_data) {
1275                         dcerpc_smb_store_pol(policy_hnd, dcv->private_data,
1276                                              pinfo->fd->num, 0);
1277
1278                         g_free(dcv->private_data);
1279                         dcv->private_data = NULL;
1280                 }
1281         }
1282
1283         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1284
1285         return offset;
1286 }
1287
1288 /*
1289  * NOTIFY_OPTION_DATA structure
1290  */
1291
1292 static gint ett_NOTIFY_OPTION_DATA = -1;
1293
1294 static int prs_NOTIFY_OPTION_DATA(tvbuff_t *tvb, int offset, 
1295                                   packet_info *pinfo, proto_tree *tree,
1296                                   GList **parent_dp_list, void **data)
1297 {
1298         proto_item *item;
1299         proto_tree *subtree;
1300         guint32 count, i;
1301
1302         item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION_DATA");
1303
1304         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_DATA);
1305
1306         offset = prs_uint32(tvb, offset, pinfo, subtree, &count, "Count");
1307
1308         for (i = 0; i < count; i++)
1309                 offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, 
1310                                     "Field");
1311
1312         return offset;
1313 }
1314
1315 /*
1316  * NOTIFY_OPTION structure
1317  */
1318
1319 static gint ett_NOTIFY_OPTION = -1;
1320
1321 static int prs_NOTIFY_OPTION(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1322                              proto_tree *tree, GList **parent_dp_list,
1323                              void **data) 
1324 {
1325         proto_item *item;
1326         proto_tree *subtree;
1327         guint32 ptr = 0;
1328
1329         item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION");
1330
1331         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION);
1332
1333         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Type");
1334
1335         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Reserved");
1336
1337         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
1338
1339         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Reserved");
1340
1341         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Count");
1342
1343         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Fields");
1344
1345         if (ptr)
1346                 defer_ptr(parent_dp_list, prs_NOTIFY_OPTION_DATA, subtree);
1347
1348         return offset;
1349 }
1350
1351 /*
1352  * NOTIFY_OPTION_CTR structure
1353  */
1354
1355 static gint ett_NOTIFY_OPTION_CTR = -1;
1356
1357 static int prs_NOTIFY_OPTION_CTR(tvbuff_t *tvb, int offset, 
1358                                  packet_info *pinfo, proto_tree *tree,
1359                                  GList **dp_list, void **data)
1360 {
1361         GList *child_dp_list = NULL;
1362         proto_item *item;
1363         proto_tree *subtree;
1364         guint32 count, i, ptr;
1365
1366         item = proto_tree_add_text(tree, tvb, offset, 0, 
1367                                    "NOTIFY_OPTION_CTR");
1368
1369         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_CTR);
1370
1371         offset = prs_uint32(tvb, offset, pinfo, subtree, &count, "Count");
1372
1373         for (i = 0; i < count; i++)
1374                 offset = prs_NOTIFY_OPTION(tvb, offset, pinfo, subtree, 
1375                                            &child_dp_list, NULL);
1376
1377         offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
1378                                &child_dp_list, NULL);
1379
1380         return offset;
1381 }
1382
1383 /*
1384  * NOTIFY_OPTION structure
1385  */
1386
1387 gint ett_NOTIFY_OPTION_ARRAY = -1;
1388
1389 static int prs_NOTIFY_OPTION_ARRAY(tvbuff_t *tvb, int offset,
1390                                    packet_info *pinfo, proto_tree *tree,
1391                                    GList **dp_list, void **data)
1392 {
1393         proto_item *item;
1394         proto_tree *subtree;
1395         guint32 ptr = 0;
1396
1397         item = proto_tree_add_text(tree, tvb, offset, 0, 
1398                                    "NOTIFY_OPTION_ARRAY");
1399
1400         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_ARRAY);
1401
1402         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Version");
1403         
1404         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Flags");
1405         
1406         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Count");
1407         
1408         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Option type");
1409
1410         if (ptr)
1411                 defer_ptr(dp_list, prs_NOTIFY_OPTION_CTR, subtree);
1412
1413         return offset;
1414 }
1415
1416 /*
1417  * SpoolssRFFPCNEX
1418  */
1419
1420 static int SpoolssRFFPCNEX_q(tvbuff_t *tvb, int offset, 
1421                              packet_info *pinfo, proto_tree *tree, 
1422                              char *drep)
1423 {
1424         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1425         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1426         char *printer_name;
1427         guint32 ptr = 0;
1428         const guint8 *policy_hnd;
1429
1430         /* Update informational fields */
1431
1432         if (check_col(pinfo->cinfo, COL_INFO))
1433                 col_set_str(pinfo->cinfo, COL_INFO, "RFFPCNEX request");
1434
1435         if (dcv->rep_frame != 0)
1436                 proto_tree_add_text(tree, tvb, offset, 0, 
1437                                     "Response in frame %u", dcv->rep_frame);
1438
1439         /* Parse packet */
1440
1441         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1442
1443         display_pol(tree, tvb, offset - 20, policy_hnd);
1444
1445         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
1446         
1447         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Options");
1448         
1449         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Local machine");
1450
1451         if (ptr) {
1452                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1453                                                   prs_UNISTR2_dp,
1454                                                   (void *)&printer_name, NULL);
1455
1456                 if (check_col(pinfo->cinfo, COL_INFO))
1457                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1458                                         printer_name);
1459
1460                 g_free(printer_name);
1461         }
1462
1463         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer local");
1464         
1465         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Option");
1466         
1467         if (ptr) {
1468                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1469                                                   prs_NOTIFY_OPTION_ARRAY,
1470                                                   NULL, NULL);
1471         }
1472         
1473         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1474
1475         return offset;
1476 }
1477
1478 static int SpoolssRFFPCNEX_r(tvbuff_t *tvb, int offset,
1479                              packet_info *pinfo, proto_tree *tree, 
1480                              char *drep)
1481 {
1482         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1483         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1484
1485         /* Update informational fields */
1486
1487         if (check_col(pinfo->cinfo, COL_INFO))
1488                 col_set_str(pinfo->cinfo, COL_INFO, "RFFPCNEX response");
1489
1490         if (dcv->req_frame != 0)
1491                 proto_tree_add_text(tree, tvb, offset, 0, 
1492                                     "Request in frame %u", dcv->req_frame);
1493
1494         /* Parse packet */
1495
1496         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1497
1498         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1499
1500         return offset;
1501 }
1502
1503 /*
1504  * SpoolssReplyOpenPrinter
1505  */
1506
1507 static int SpoolssReplyOpenPrinter_q(tvbuff_t *tvb, int offset, 
1508                                      packet_info *pinfo, proto_tree *tree, 
1509                                      char *drep)
1510 {
1511         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1512         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1513         guint32 ptr = 0, type;
1514
1515         /* Update informational fields */
1516
1517         if (check_col(pinfo->cinfo, COL_INFO))
1518                 col_set_str(pinfo->cinfo, COL_INFO, "ReplyOpenPrinter request");
1519
1520         if (dcv->rep_frame != 0)
1521                 proto_tree_add_text(tree, tvb, offset, 0, 
1522                                     "Response in frame %u", dcv->rep_frame);
1523
1524         /* Parse packet */
1525
1526         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1527                                           prs_UNISTR2_dp, NULL, NULL);
1528
1529         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer");
1530
1531         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
1532
1533         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
1534                             val_to_str(type, reg_datatypes, "Unknown type"));
1535
1536         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1537
1538         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown"); 
1539
1540         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1541
1542         return offset;
1543 }       
1544
1545 static int SpoolssReplyOpenPrinter_r(tvbuff_t *tvb, int offset, 
1546                                      packet_info *pinfo, proto_tree *tree, 
1547                                      char *drep)
1548 {
1549         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1550         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1551         GList *dp_list = NULL;
1552         const guint8 *policy_hnd;
1553
1554         /* Update informational fields */
1555
1556         if (check_col(pinfo->cinfo, COL_INFO))
1557                 col_set_str(pinfo->cinfo, COL_INFO, "ReplyOpenPrinter response");
1558
1559         if (dcv->req_frame != 0)
1560                 proto_tree_add_text(tree, tvb, offset, 0, 
1561                                     "Request in frame %u", dcv->req_frame);
1562
1563         /* Parse packet */
1564
1565         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1566
1567         display_pol(tree, tvb, offset - 20, policy_hnd);
1568
1569         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1570
1571         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1572
1573         return offset;
1574 }       
1575
1576 /*
1577  * BUFFER_DATA
1578  */
1579
1580 static gint ett_BUFFER_DATA = -1;
1581 static gint ett_BUFFER_DATA_BUFFER = -1;
1582
1583 struct BUFFER_DATA {
1584         proto_item *item;       /* proto_item holding proto_tree */
1585         proto_tree *tree;       /* proto_tree holding buffer data */
1586         tvbuff_t *tvb;          
1587         int offset;             /* Offset where data starts in tvb*/
1588         int size;               /* Size of buffer data */
1589 };
1590
1591 static int prs_BUFFER_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo,
1592                            proto_tree *tree, GList **dp_list, void **data)
1593 {
1594         proto_item *item, *subitem;
1595         proto_tree *subtree, *subsubtree;
1596         guint32 ptr = 0, size;
1597         int data8_offset;
1598
1599         item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER_DATA");
1600
1601         subtree = proto_item_add_subtree(item, ett_BUFFER_DATA);
1602
1603         offset = prs_uint32(tvb, offset, pinfo, subtree, &size, "Size");
1604
1605         subitem = proto_tree_add_text(subtree, tvb, offset, size, "Data");
1606
1607         subsubtree = proto_item_add_subtree(subitem, ett_BUFFER_DATA_BUFFER);
1608
1609         offset = prs_uint8s(tvb, offset, pinfo, subsubtree, size,
1610                             &data8_offset, NULL);
1611
1612         /* Return some info which will help the caller "cast" the buffer
1613            data and dissect it further. */
1614
1615         if (data) {
1616                 struct BUFFER_DATA *bd;
1617
1618                 bd = (struct BUFFER_DATA *)malloc(sizeof(struct BUFFER_DATA));
1619
1620                 bd->item = subitem;
1621                 bd->tree = subsubtree;
1622                 bd->tvb = tvb;
1623                 bd->offset = data8_offset;
1624                 bd->size = size;
1625
1626                 *data = bd;
1627         }
1628
1629         return offset;
1630 }
1631
1632 /*
1633  * BUFFER
1634  */
1635
1636 static gint ett_BUFFER = -1;
1637
1638 static int prs_BUFFER(tvbuff_t *tvb, int offset, packet_info *pinfo,
1639                       proto_tree *tree, GList **dp_list, void **data)
1640 {
1641         proto_item *item;
1642         proto_tree *subtree;
1643         guint32 ptr = 0;
1644
1645         item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER");
1646
1647         subtree = proto_item_add_subtree(item, ett_BUFFER);
1648
1649         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Data");
1650
1651         if (ptr)
1652                 defer_ptr(dp_list, prs_BUFFER_DATA, subtree);
1653
1654         return offset;
1655 }
1656
1657 /*
1658  * SpoolssGetPrinter
1659  */
1660
1661 static int SpoolssGetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
1662                                proto_tree *tree, char *drep)
1663 {
1664         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1665         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1666         GList *dp_list = NULL;
1667         guint32 level;
1668         const guint8 *policy_hnd;
1669
1670         /* Update informational fields */
1671
1672         if (check_col(pinfo->cinfo, COL_INFO))
1673                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinter request");
1674
1675         if (dcv->rep_frame != 0)
1676                 proto_tree_add_text(tree, tvb, offset, 0, 
1677                                     "Response in frame %u", dcv->rep_frame);
1678
1679         /* Parse packet */
1680
1681         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1682
1683         display_pol(tree, tvb, offset - 20, policy_hnd);
1684
1685         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
1686
1687         if (check_col(pinfo->cinfo, COL_INFO))
1688                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1689
1690         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1691                                           prs_BUFFER, NULL, NULL);
1692
1693         dcv->private_data = (void *)level;
1694
1695         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
1696
1697         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1698
1699         return offset;
1700 }       
1701
1702 static int SpoolssGetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
1703                                 proto_tree *tree, char *drep)
1704 {
1705         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1706         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1707         GList *dp_list = NULL;
1708         void **data_list;
1709         struct BUFFER_DATA *bd = NULL;
1710         gint16 level = (guint32)dcv->private_data;
1711
1712         /* Update informational fields */
1713
1714         if (check_col(pinfo->cinfo, COL_INFO))
1715                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinter response");
1716
1717         if (dcv->req_frame != 0)
1718                 proto_tree_add_text(tree, tvb, offset, 0, 
1719                                     "Request in frame %u", dcv->req_frame);
1720
1721         if (check_col(pinfo->cinfo, COL_INFO))
1722                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1723
1724         /* Parse packet */
1725
1726         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1727                                           prs_BUFFER, NULL, &data_list);
1728
1729         if (data_list)
1730                 bd = (struct BUFFER_DATA *)data_list[0];
1731
1732         if (bd && bd->tree) {
1733                 proto_item_append_text(bd->item, ", PRINTER_INFO_%d", level);
1734
1735                 switch (level) {
1736                 case 0:
1737                         prs_PRINTER_INFO_0(bd->tvb, bd->offset, pinfo, 
1738                                            bd->tree, &dp_list, NULL);
1739                         break;
1740                         
1741                 case 1:
1742                         prs_PRINTER_INFO_1(bd->tvb, bd->offset, pinfo, 
1743                                            bd->tree, &dp_list, NULL);
1744                         break;
1745                         
1746                 case 2:
1747                         prs_PRINTER_INFO_2(bd->tvb, bd->offset, pinfo,
1748                                            bd->tree, bd->size, &dp_list, NULL);
1749                         break;
1750
1751                 case 3:
1752                         prs_PRINTER_INFO_3(bd->tvb, bd->offset, pinfo,
1753                                            bd->tree, bd->size, &dp_list, NULL);
1754                         break;
1755
1756                 default:
1757                         proto_tree_add_text(bd->tree, tvb, offset, 0,
1758                                             "[Unknown info level %d]", level);
1759                         break;
1760                 }
1761         }
1762
1763         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
1764
1765         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1766
1767         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1768
1769         return offset;
1770 }       
1771
1772 /*
1773  * SPOOL_PRINTER_INFO_LEVEL
1774  */
1775
1776 static gint ett_SPOOL_PRINTER_INFO_LEVEL = -1;
1777
1778 static int prs_SPOOL_PRINTER_INFO_LEVEL(tvbuff_t *tvb, int offset, 
1779                                         packet_info *pinfo, proto_tree *tree, 
1780                                         GList **dp_list, void **data)
1781 {
1782         proto_item *item;
1783         proto_tree *subtree;
1784         guint32 ptr = 0, level;
1785
1786         item = proto_tree_add_text(tree, tvb, offset, 0, 
1787                                    "SPOOL_PRINTER_INFO_LEVEL");
1788
1789         subtree = proto_item_add_subtree(item, ett_SPOOL_PRINTER_INFO_LEVEL);
1790
1791         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level");
1792
1793         /* ptr */
1794
1795         switch(level) {
1796         }
1797
1798         return offset;
1799 }
1800
1801 /*
1802  * SpoolssSetPrinter
1803  */
1804
1805 static int SpoolssSetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
1806                                proto_tree *tree, char *drep)
1807 {
1808         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1809         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1810         GList *dp_list = NULL;
1811         guint32 level;
1812         const guint8 *policy_hnd;
1813
1814         /* Update informational fields */
1815
1816         if (check_col(pinfo->cinfo, COL_INFO))
1817                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinter request");
1818
1819         if (dcv->rep_frame != 0)
1820                 proto_tree_add_text(tree, tvb, offset, 0, 
1821                                     "Response in frame %u", dcv->rep_frame);
1822
1823         /* Parse packet */
1824
1825         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1826
1827         display_pol(tree, tvb, offset - 20, policy_hnd);
1828
1829         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
1830
1831         if (check_col(pinfo->cinfo, COL_INFO))
1832                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1833
1834         /* printer_info_level */
1835
1836         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1837                                           prs_SPOOL_PRINTER_INFO_LEVEL,
1838                                           NULL, NULL);
1839
1840         /* devmode_ctr */
1841
1842
1843         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Command");
1844
1845         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1846
1847         return offset;
1848 }       
1849
1850 static int SpoolssSetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
1851                                 proto_tree *tree, char *drep)
1852 {
1853         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1854         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1855         GList *dp_list = NULL;
1856
1857         /* Update informational fields */
1858
1859         if (check_col(pinfo->cinfo, COL_INFO))
1860                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinter response");
1861
1862         if (dcv->req_frame != 0)
1863                 proto_tree_add_text(tree, tvb, offset, 0, 
1864                                     "Request in frame %u", dcv->req_frame);
1865
1866         /* Parse packet */
1867
1868         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1869
1870         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1871
1872         return offset;
1873 }       
1874
1875 /*
1876  * FORM_REL
1877  */
1878
1879 static const value_string form_type_vals[] =
1880 {
1881         { FORM_USER, "FORM_USER" },
1882         { FORM_BUILTIN, "FORM_BUILTIN" },
1883         { FORM_PRINTER, "FORM_PRINTER" },
1884         { 0, NULL }
1885 };
1886
1887 static gint ett_FORM_REL = -1;
1888
1889 static int prs_FORM_REL(tvbuff_t *tvb, int offset, packet_info *pinfo,
1890                         proto_tree *tree, int struct_start, GList **dp_list, 
1891                         void **data)
1892 {
1893         proto_item *item;
1894         proto_tree *subtree;
1895         guint32 flags;
1896
1897         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_REL");
1898
1899         subtree = proto_item_add_subtree(item, ett_FORM_REL);
1900
1901         offset = prs_uint32(tvb, offset, pinfo, subtree, &flags, NULL);
1902
1903         proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s",
1904                             val_to_str(flags, form_type_vals, "Unknown type"));
1905
1906         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list,
1907                             struct_start, NULL, "Name");
1908
1909         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Width");
1910
1911         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Height");
1912
1913         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1914                             "Left margin");
1915
1916         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1917                             "Top margin");
1918
1919         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1920                             "Horizontal imageable length");
1921
1922         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1923                             "Vertical imageable length");
1924
1925         return offset;
1926 }
1927
1928 /*
1929  * SpoolssEnumForms
1930  */
1931
1932 static int SpoolssEnumForms_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
1933                               proto_tree *tree, char *drep)
1934 {
1935         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1936         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1937         GList *dp_list = NULL;
1938         guint32 level;
1939         const guint8 *policy_hnd;
1940
1941         /* Update informational fields */
1942
1943         if (check_col(pinfo->cinfo, COL_INFO))
1944                 col_set_str(pinfo->cinfo, COL_INFO, "EnumForms request");
1945
1946         if (dcv->rep_frame != 0)
1947                 proto_tree_add_text(tree, tvb, offset, 0, 
1948                                     "Response in frame %u", dcv->rep_frame);
1949
1950         /* Parse packet */
1951
1952         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1953         
1954         display_pol(tree, tvb, offset - 20, policy_hnd);
1955
1956         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
1957
1958         dcv->private_data = (void *)level;
1959
1960         if (check_col(pinfo->cinfo, COL_INFO))
1961                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1962
1963         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1964                                           prs_BUFFER, NULL, NULL);
1965
1966         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
1967
1968         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1969
1970         return offset;
1971 }       
1972
1973 static int SpoolssEnumForms_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
1974                               proto_tree *tree, char *drep)
1975 {
1976         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1977         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1978         guint32 count;
1979         GList *dp_list = NULL;
1980         struct BUFFER_DATA *bd = NULL;
1981         void **data_list;
1982
1983         /* Update informational fields */
1984
1985         if (check_col(pinfo->cinfo, COL_INFO))
1986                 col_set_str(pinfo->cinfo, COL_INFO, "EnumForms response");
1987
1988         if (dcv->req_frame != 0)
1989                 proto_tree_add_text(tree, tvb, offset, 0, 
1990                                     "Request in frame %u", dcv->req_frame);
1991
1992         /* Parse packet */
1993
1994         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
1995                                            prs_BUFFER, NULL, &data_list);
1996
1997         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
1998
1999         offset = prs_uint32(tvb, offset, pinfo, tree, &count, "Num entries");
2000
2001         if (data_list)
2002                 bd = (struct BUFFER_DATA *)data_list[0];
2003
2004         CLEANUP_PUSH(g_free, bd);
2005
2006         if (bd && bd->tree) {
2007                 guint32 level = (guint32)dcv->private_data, i;
2008                 GList *child_dp_list = NULL;
2009
2010                 if (check_col(pinfo->cinfo, COL_INFO))
2011                         col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2012
2013                 proto_item_append_text(bd->item, ", FORM_%d", level);
2014
2015                 /* Unfortunately this array isn't in NDR format so we can't
2016                    use prs_array().  The other weird thing is the
2017                    struct_start being inside the loop rather than outside.
2018                    Very strange. */
2019
2020                 for (i = 0; i < count; i++) {
2021                         int struct_start = bd->offset;
2022
2023                         bd->offset = prs_FORM_REL(
2024                                 bd->tvb, bd->offset, pinfo, bd->tree, 
2025                                 struct_start, &child_dp_list, NULL);
2026                 }
2027
2028         }
2029
2030         CLEANUP_CALL_AND_POP;
2031
2032         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2033
2034         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2035
2036         return offset;
2037 }       
2038
2039 /*
2040  * SpoolssDeletePrinter
2041  */
2042
2043 static int SpoolssDeletePrinter_q(tvbuff_t *tvb, int offset, 
2044                                   packet_info *pinfo, proto_tree *tree, 
2045                                   char *drep)
2046 {
2047         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2048         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2049         const guint8 *policy_hnd;
2050
2051         /* Update informational fields */
2052
2053         if (check_col(pinfo->cinfo, COL_INFO))
2054                 col_set_str(pinfo->cinfo, COL_INFO, "DeletePrinter request");
2055         
2056         if (dcv->rep_frame != 0)
2057                 proto_tree_add_text(tree, tvb, offset, 0, 
2058                                     "Response in frame %u", dcv->rep_frame);
2059
2060         /* Parse packet */
2061
2062         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2063
2064         display_pol(tree, tvb, offset - 20, policy_hnd);
2065         
2066         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2067
2068         return offset;
2069 }       
2070
2071 static int SpoolssDeletePrinter_r(tvbuff_t *tvb, int offset, 
2072                                   packet_info *pinfo, proto_tree *tree, 
2073                                   char *drep)
2074 {
2075         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2076         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2077         const guint8 *policy_hnd;
2078
2079         /* Update informational fields */
2080
2081         if (check_col(pinfo->cinfo, COL_INFO))
2082                 col_set_str(pinfo->cinfo, COL_INFO, "DeletePrinter response");
2083
2084         if (dcv->req_frame != 0)
2085                 proto_tree_add_text(tree, tvb, offset, 0, 
2086                                     "Request in frame %u", dcv->req_frame);
2087
2088         /* Parse packet */
2089
2090         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2091
2092         display_pol(tree, tvb, offset - 20, policy_hnd);
2093
2094         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2095
2096         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2097
2098         return offset;
2099 }       
2100
2101 /*
2102  * AddPrinterEx
2103  */
2104
2105 static int SpoolssAddPrinterEx_q(tvbuff_t *tvb, int offset, 
2106                                  packet_info *pinfo, proto_tree *tree, 
2107                                  char *drep)
2108 {
2109         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2110         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2111         guint32 ptr;
2112         
2113         /* Update informational fields */
2114         
2115         if (check_col(pinfo->cinfo, COL_INFO))
2116                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterEx request");
2117         
2118         if (dcv->rep_frame != 0)
2119                 proto_tree_add_text(tree, tvb, offset, 0, 
2120                                     "Response in frame %u", dcv->rep_frame);
2121
2122         /* Parse packet */
2123         
2124         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Server name");
2125         
2126         if (ptr) {
2127                 char *printer_name;
2128
2129                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2130                                                   prs_UNISTR2_dp,
2131                                                   (void *)&printer_name, NULL);
2132
2133                 if (printer_name)
2134                         dcv->private_data = printer_name;
2135         }
2136         
2137         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Level");
2138         
2139         /* TODO: PRINTER INFO LEVEL */
2140         
2141         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2142         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2143         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2144         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2145         
2146         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
2147         
2148         /* TODO: USER LEVEL */
2149         
2150         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2151         
2152         return offset;
2153 }      
2154
2155 static int SpoolssAddPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2156                                  proto_tree *tree, char *drep)
2157 {
2158         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2159         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2160         guint32 status;
2161         const guint8 *policy_hnd;
2162
2163         /* Update informational fields */
2164
2165         if (check_col(pinfo->cinfo, COL_INFO))
2166                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterEx response");
2167
2168         if (dcv->req_frame != 0)
2169                 proto_tree_add_text(tree, tvb, offset, 0, 
2170                                     "Request in frame %u", dcv->req_frame);
2171
2172         /* Parse packet */
2173
2174         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2175
2176         display_pol(tree, tvb, offset - 20, policy_hnd);
2177
2178         offset = prs_werror(tvb, offset, pinfo, tree, &status); 
2179
2180         if (status == 0) {
2181
2182                 /* Associate the returned printer handle with a name */
2183
2184                 if (dcv->private_data) {
2185
2186                         if (check_col(pinfo->cinfo, COL_INFO))
2187                                 col_append_fstr(
2188                                         pinfo->cinfo, COL_INFO, ", %s", 
2189                                         (char *)dcv->private_data);
2190
2191                         dcerpc_smb_store_pol(
2192                                 policy_hnd, dcv->private_data, pinfo->fd->num, 0);
2193
2194                         g_free(dcv->private_data);
2195                         dcv->private_data = NULL;
2196                 }
2197         }
2198
2199         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2200
2201         return offset;
2202 }       
2203
2204 /*
2205  * SpoolssEnumPrinterData
2206  */
2207
2208 static int SpoolssEnumPrinterData_q(tvbuff_t *tvb, int offset, 
2209                                     packet_info *pinfo, proto_tree *tree, 
2210                                     char *drep)
2211 {
2212         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2213         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2214         const guint8 *policy_hnd;
2215
2216         /* Update informational fields */
2217
2218         if (check_col(pinfo->cinfo, COL_INFO))
2219                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinterData request");
2220
2221         if (dcv->rep_frame != 0)
2222                 proto_tree_add_text(tree, tvb, offset, 0, 
2223                                     "Response in frame %u", dcv->rep_frame);
2224
2225         /* Parse packet */
2226
2227         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2228
2229         display_pol(tree, tvb, offset - 20, policy_hnd);
2230         
2231         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Index");
2232
2233         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Value size");
2234
2235         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Data size");
2236
2237         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2238
2239         return offset;
2240 }       
2241
2242 static int SpoolssEnumPrinterData_r(tvbuff_t *tvb, int offset, 
2243                                     packet_info *pinfo, proto_tree *tree, 
2244                                     char *drep)
2245 {
2246         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2247         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2248         guint32 data_size, type, value_size;
2249         int uint16s_offset;
2250         char *text;
2251
2252         /* Update informational fields */
2253
2254         if (check_col(pinfo->cinfo, COL_INFO))
2255                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinterData response");
2256
2257         if (dcv->req_frame != 0)
2258                 proto_tree_add_text(tree, tvb, offset, 0, 
2259                                     "Request in frame %u", dcv->req_frame);
2260
2261         /* Parse packet */
2262
2263         offset = prs_uint32(tvb, offset, pinfo, tree, &value_size, 
2264                             "Value size");
2265         
2266         offset = prs_uint16s(tvb, offset, pinfo, tree, value_size,
2267                              &uint16s_offset, NULL);
2268         
2269         text = fake_unicode(tvb, uint16s_offset, value_size);
2270         
2271         proto_tree_add_text(tree, tvb, uint16s_offset,
2272                             value_size * 2, "Value: %s", text);
2273        
2274         if (text[0] && check_col(pinfo->cinfo, COL_INFO))
2275                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", text);
2276         
2277         g_free(text);
2278
2279         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real value size");
2280
2281         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
2282
2283         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
2284                             val_to_str(type, reg_datatypes, "Unknown type"));
2285
2286         offset = prs_uint32(tvb, offset, pinfo, tree, &data_size, "Data size");
2287
2288         offset = prs_uint8s(tvb, offset, pinfo, tree, data_size, NULL,
2289                             "Data");
2290
2291         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real data size");
2292
2293         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2294         
2295         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2296
2297         return offset;
2298 }       
2299
2300 /*
2301  * SpoolssEnumPrinters
2302  */
2303
2304 static int SpoolssEnumPrinters_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2305                                  proto_tree *tree, char *drep)
2306 {
2307         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2308         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2309         guint32 ptr, level;
2310
2311         /* Update informational fields */
2312
2313         if (check_col(pinfo->cinfo, COL_INFO))
2314                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinters request");
2315
2316         if (dcv->rep_frame != 0)
2317                 proto_tree_add_text(tree, tvb, offset, 0, 
2318                                     "Response in frame %u", dcv->rep_frame);
2319
2320         /* Parse packet */
2321
2322         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
2323
2324         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Devicemode");
2325
2326         if (ptr)
2327                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2328                                                   prs_UNISTR2_dp, NULL, NULL);
2329
2330         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2331         
2332         if (check_col(pinfo->cinfo, COL_INFO))
2333                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level, %d", level);
2334         
2335         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2336                                           prs_BUFFER, NULL, NULL);
2337
2338         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
2339
2340         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2341
2342         return offset;
2343 }       
2344
2345 static int SpoolssEnumPrinters_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2346                                  proto_tree *tree, char *drep)
2347 {
2348         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2349         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2350
2351         /* Update informational fields */
2352
2353         if (check_col(pinfo->cinfo, COL_INFO))
2354                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinters response");
2355
2356         if (dcv->req_frame != 0)
2357                 proto_tree_add_text(tree, tvb, offset, 0, 
2358                                     "Request in frame %u", dcv->req_frame);
2359
2360         /* Parse packet */
2361
2362         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2363                                           prs_BUFFER, NULL, NULL);
2364
2365         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
2366
2367         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Returned");
2368
2369         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2370
2371         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2372
2373         return offset;
2374 }       
2375
2376 /*
2377  * AddPrinterDriver
2378  */
2379
2380 static int SpoolssAddPrinterDriver_q(tvbuff_t *tvb, int offset, 
2381                                      packet_info *pinfo, proto_tree *tree, 
2382                                      char *drep)
2383 {
2384         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2385         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2386
2387         /* Update informational fields */
2388
2389         if (check_col(pinfo->cinfo, COL_INFO))
2390                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterDriver request");
2391
2392         if (dcv->rep_frame != 0)
2393                 proto_tree_add_text(tree, tvb, offset, 0, 
2394                                     "Response in frame %u", dcv->rep_frame);
2395
2396         /* Parse packet */
2397
2398         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2399
2400         return offset;
2401 }      
2402
2403 static int SpoolssAddPrinterDriver_r(tvbuff_t *tvb, int offset, 
2404                                      packet_info *pinfo, proto_tree *tree, 
2405                                      char *drep)
2406 {
2407         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2408         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2409
2410         /* Update informational fields */
2411
2412         if (check_col(pinfo->cinfo, COL_INFO))
2413                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterDriver response");
2414
2415         if (dcv->req_frame != 0)
2416                 proto_tree_add_text(tree, tvb, offset, 0, 
2417                                     "Request in frame %u", dcv->req_frame);
2418
2419         /* Parse packet */
2420
2421         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2422
2423         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2424
2425         return offset;
2426 }      
2427
2428 /*
2429  * FORM_1
2430  */
2431
2432 static gint ett_FORM_1 = -1;
2433
2434 static int prs_FORM_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
2435                       proto_tree *tree, GList **dp_list, void **data)
2436 {
2437         proto_item *item;
2438         proto_tree *subtree;
2439         guint32 ptr = 0, flags;
2440
2441         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_1");
2442
2443         subtree = proto_item_add_subtree(item, ett_FORM_1);
2444
2445         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Name");
2446
2447         if (ptr)
2448                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
2449
2450         offset = prs_uint32(tvb, offset, pinfo, subtree, &flags, NULL);
2451
2452         proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s",
2453                             val_to_str(flags, form_type_vals, "Unknown type"));
2454
2455         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Unknown");
2456
2457         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Width");
2458
2459         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Height");
2460
2461         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2462                             "Left margin");
2463
2464         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2465                             "Top margin");
2466
2467         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2468                             "Horizontal imageable length");
2469
2470         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2471                             "Vertical imageable length");
2472
2473         return offset;
2474 }
2475
2476 /*
2477  * FORM_CTR
2478  */
2479
2480 static gint ett_FORM_CTR = -1;
2481
2482 static int prs_FORM_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
2483                     proto_tree *tree, GList **dp_list, void **data)
2484 {
2485         proto_item *item;
2486         proto_tree *subtree;
2487         guint32 level;
2488
2489         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_CTR");
2490
2491         subtree = proto_item_add_subtree(item, ett_FORM_CTR);
2492
2493         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level");
2494
2495         switch(level) {
2496         case 1:
2497                 offset = prs_struct_and_referents(tvb, offset, pinfo, subtree,
2498                                                   prs_FORM_1, NULL, NULL);
2499                 break;
2500         default:
2501                 proto_tree_add_text(subtree, tvb, offset, 0,
2502                                     "[Unknown info level %d]", level);
2503                 break;
2504         }
2505
2506         return offset;
2507 }
2508
2509 /*
2510  * AddForm
2511  */
2512
2513 static int SpoolssAddForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2514                             proto_tree *tree, char *drep)
2515 {
2516         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2517         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2518         const guint8 *policy_hnd;
2519         guint32 level;
2520
2521         /* Update informational fields */
2522
2523         if (check_col(pinfo->cinfo, COL_INFO))
2524                 col_set_str(pinfo->cinfo, COL_INFO, "AddForm request");
2525
2526         if (dcv->rep_frame != 0)
2527                 proto_tree_add_text(tree, tvb, offset, 0, 
2528                                     "Response in frame %u", dcv->rep_frame);
2529
2530         /* Parse packet */
2531
2532         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2533
2534         display_pol(tree, tvb, offset - 20, policy_hnd);
2535
2536         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); 
2537
2538         if (check_col(pinfo->cinfo, COL_INFO))
2539                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2540
2541         /* Store info level to match with response packet */
2542
2543         dcv->private_data = (void *)level;
2544
2545         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2546                                           prs_FORM_CTR, NULL, NULL);
2547
2548         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2549
2550         return offset;
2551 }       
2552
2553 static int SpoolssAddForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2554                             proto_tree *tree, char *drep)
2555 {
2556         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2557         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2558
2559         /* Update informational fields */
2560
2561         if (check_col(pinfo->cinfo, COL_INFO))
2562                 col_set_str(pinfo->cinfo, COL_INFO, "AddForm response");
2563
2564         if (dcv->req_frame != 0)
2565                 proto_tree_add_text(tree, tvb, offset, 0, 
2566                                     "Request in frame %u", dcv->req_frame);
2567
2568         /* Parse packet */
2569
2570         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2571
2572         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2573
2574         return offset;
2575 }      
2576
2577 /*
2578  * DeleteForm
2579  */
2580
2581 static int SpoolssDeleteForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2582                                proto_tree *tree, char *drep)
2583 {
2584         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2585         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2586         const guint8 *policy_hnd;
2587         char *form_name;
2588
2589         /* Update informational fields */
2590
2591         if (check_col(pinfo->cinfo, COL_INFO))
2592                 col_set_str(pinfo->cinfo, COL_INFO, "DeleteForm request");
2593
2594         if (dcv->rep_frame != 0)
2595                 proto_tree_add_text(tree, tvb, offset, 0, 
2596                                     "Response in frame %u", dcv->rep_frame);
2597
2598         /* Parse packet */
2599
2600         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2601
2602         display_pol(tree, tvb, offset - 20, policy_hnd);
2603
2604         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2605                                           prs_UNISTR2_dp, (void **)&form_name,
2606                                           NULL);
2607
2608         if (check_col(pinfo->cinfo, COL_INFO))
2609                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", form_name);
2610
2611         g_free(form_name);
2612
2613         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2614
2615         return offset;
2616 }       
2617
2618 static int SpoolssDeleteForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2619                             proto_tree *tree, char *drep)
2620 {
2621         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2622         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2623
2624         /* Update informational fields */
2625
2626         if (check_col(pinfo->cinfo, COL_INFO))
2627                 col_set_str(pinfo->cinfo, COL_INFO, "DeleteForm response");
2628
2629         if (dcv->req_frame != 0)
2630                 proto_tree_add_text(tree, tvb, offset, 0, 
2631                                     "Request in frame %u", dcv->req_frame);
2632
2633         /* Parse packet */
2634
2635         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2636
2637         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2638
2639         return offset;
2640 }       
2641
2642 /*
2643  * SetForm
2644  */
2645
2646 static int SpoolssSetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2647                             proto_tree *tree, char *drep)
2648 {
2649         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2650         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2651         const guint8 *policy_hnd;
2652         guint32 level;
2653         char *form_name;
2654
2655         /* Update informational fields */
2656
2657         if (check_col(pinfo->cinfo, COL_INFO))
2658                 col_set_str(pinfo->cinfo, COL_INFO, "SetForm request");
2659
2660         if (dcv->rep_frame != 0)
2661                 proto_tree_add_text(tree, tvb, offset, 0, 
2662                                     "Response in frame %u", dcv->rep_frame);
2663
2664         /* Parse packet */
2665
2666         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2667
2668         display_pol(tree, tvb, offset - 20, policy_hnd);
2669
2670         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2671                                           prs_UNISTR2_dp, (void **)&form_name,
2672                                           NULL);        
2673
2674         CLEANUP_PUSH(g_free, form_name);
2675
2676         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); 
2677
2678         if (check_col(pinfo->cinfo, COL_INFO))
2679                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, level %d", 
2680                                 form_name, level);
2681
2682         CLEANUP_CALL_AND_POP;
2683
2684         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2685                                           prs_FORM_CTR, NULL, NULL);
2686
2687         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2688
2689         return offset;
2690 }       
2691
2692 static int SpoolssSetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2693                             proto_tree *tree, char *drep)
2694 {
2695         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2696         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2697         proto_item *info_item;
2698
2699         /* Update informational fields */
2700
2701         if (check_col(pinfo->cinfo, COL_INFO))
2702                 col_set_str(pinfo->cinfo, COL_INFO, "SetForm response");
2703
2704         if (dcv->req_frame != 0)
2705                 proto_tree_add_text(tree, tvb, offset, 0, 
2706                                     "Request in frame %u", dcv->req_frame);
2707
2708         /* Parse packet */
2709
2710         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2711
2712         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2713
2714         return offset;
2715 }      
2716
2717 /*
2718  * GetForm
2719  */
2720
2721 static int SpoolssGetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2722                             proto_tree *tree, char *drep)
2723 {
2724         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2725         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2726         guint32 level;
2727         const guint8 *policy_hnd;
2728         char *form_name;
2729
2730         /* Update informational fields */
2731
2732         if (check_col(pinfo->cinfo, COL_INFO))
2733                 col_set_str(pinfo->cinfo, COL_INFO, "GetForm request");
2734
2735         if (dcv->rep_frame != 0)
2736                 proto_tree_add_text(tree, tvb, offset, 0, 
2737                                     "Response in frame %u", dcv->rep_frame);
2738
2739         /* Parse packet */
2740
2741         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2742
2743         display_pol(tree, tvb, offset - 20, policy_hnd);
2744
2745         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2746                                           prs_UNISTR2_dp, (void **)&form_name,
2747                                           NULL);        
2748
2749         CLEANUP_PUSH(g_free, form_name);
2750
2751         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2752
2753         dcv->private_data = (void *)level;
2754
2755         if (check_col(pinfo->cinfo, COL_INFO))
2756                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, level %d",
2757                                 form_name, level);
2758
2759         CLEANUP_CALL_AND_POP;
2760
2761         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2762                                           prs_BUFFER, NULL, NULL);
2763
2764         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
2765
2766         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2767
2768         return offset;
2769 }       
2770
2771 static int SpoolssGetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2772                             proto_tree *tree, char *drep)
2773 {
2774         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2775         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2776         void **data_list;
2777         struct BUFFER_DATA *bd = NULL;
2778
2779         /* Update informational fields */
2780
2781         if (check_col(pinfo->cinfo, COL_INFO))
2782                 col_set_str(pinfo->cinfo, COL_INFO, "GetForm response");
2783
2784         if (dcv->req_frame != 0)
2785                 proto_tree_add_text(tree, tvb, offset, 0, 
2786                                     "Request in frame %u", dcv->req_frame);
2787
2788         /* Parse packet */
2789
2790         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2791                                           prs_BUFFER, NULL, &data_list);
2792
2793         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
2794
2795         if (data_list)
2796                 bd = (struct BUFFER_DATA *)data_list[0];
2797
2798         CLEANUP_PUSH(g_free, bd);
2799
2800         if (bd && bd->tree) {
2801                 guint32 level = (guint32)dcv->private_data;
2802
2803                 switch(level) {
2804                 case 1: {
2805                         int struct_start = bd->offset;
2806                         GList *dp_list = NULL;
2807
2808                         bd->offset = prs_FORM_REL(
2809                                 bd->tvb, bd->offset, pinfo, bd->tree, 
2810                                 struct_start, &dp_list, NULL);
2811                         break;
2812                 }
2813                 default:
2814                         proto_tree_add_text(
2815                                 bd->tree, bd->tvb, bd->offset, 0, 
2816                                 "[Unknown info level %d]", level);
2817                         break;
2818                 }
2819
2820         }
2821
2822         CLEANUP_CALL_AND_POP;
2823
2824         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2825
2826         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2827
2828         return offset;
2829 }       
2830
2831 /* A generic reply function that just parses the status code.  Useful for
2832    unimplemented dissectors so the status code can be inserted into the
2833    INFO column. */
2834
2835 static int SpoolssGeneric_r(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2836                             proto_tree *tree, char *drep)
2837 {
2838         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2839         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2840         int len = tvb_length(tvb);
2841
2842         proto_tree_add_text(tree, tvb, offset, 0, 
2843                             "[Unimplemented dissector: SPOOLSS]");
2844
2845         if (dcv->req_frame != 0)
2846                 proto_tree_add_text(tree, tvb, offset, 0, 
2847                                     "Request in frame %u", dcv->req_frame);
2848
2849         prs_werror(tvb, len - 4, pinfo, tree, NULL);
2850
2851         return offset;
2852 }
2853
2854 /*
2855  * JOB_INFO_1
2856  */
2857
2858 static gint ett_JOB_INFO_1;
2859
2860 static int prs_JOB_INFO_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
2861                           proto_tree *tree, GList **dp_list, void **data)
2862 {
2863         proto_item *item;
2864         proto_tree *subtree;
2865         guint32 level;
2866
2867         item = proto_tree_add_text(tree, tvb, offset, 0, "JOB_INFO_1");
2868
2869         subtree = proto_item_add_subtree(item, ett_FORM_CTR);
2870
2871         return offset;
2872 }
2873
2874 /*
2875  * JOB_INFO_2
2876  */
2877
2878 static gint ett_JOB_INFO_2;
2879
2880 static int prs_JOB_INFO_2(tvbuff_t *tvb, int offset, packet_info *pinfo,
2881                           proto_tree *tree, GList **dp_list, void **data)
2882 {
2883         proto_item *item;
2884         proto_tree *subtree;
2885         guint32 level;
2886
2887         item = proto_tree_add_text(tree, tvb, offset, 0, "JOB_INFO_2");
2888
2889         subtree = proto_item_add_subtree(item, ett_FORM_CTR);
2890
2891         return offset;
2892 }
2893
2894 /*
2895  * EnumJobs
2896  */
2897
2898 static int SpoolssEnumJobs_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2899                              proto_tree *tree, char *drep)
2900 {
2901         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2902         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2903         const guint8 *policy_hnd;
2904         guint32 level;
2905
2906         /* Update informational fields */
2907
2908         if (check_col(pinfo->cinfo, COL_INFO))
2909                 col_set_str(pinfo->cinfo, COL_INFO, "EnumJobs request");
2910
2911         if (dcv->rep_frame != 0)
2912                 proto_tree_add_text(tree, tvb, offset, 0, 
2913                                     "Response in frame %d", dcv->rep_frame);
2914
2915         /* Parse packet */
2916
2917         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2918
2919         display_pol(tree, tvb, offset - 20, policy_hnd);
2920
2921         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "First job");
2922
2923         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Num jobs");
2924
2925         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2926
2927         dcv->private_data = (void *)level;
2928
2929         if (check_col(pinfo->cinfo, COL_INFO))
2930                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2931
2932         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2933                                           prs_BUFFER, NULL, NULL);
2934
2935         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
2936
2937         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2938
2939         return offset;
2940 }       
2941
2942 static int SpoolssEnumJobs_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2943                              proto_tree *tree, char *drep)
2944 {
2945         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2946         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2947         void **data_list;
2948         struct BUFFER_DATA *bd = NULL;
2949         gint16 level = (guint32)dcv->private_data;
2950
2951         /* Update informational fields */
2952
2953         if (check_col(pinfo->cinfo, COL_INFO))
2954                 col_set_str(pinfo->cinfo, COL_INFO, "EnumJobs response");
2955
2956         if (dcv->req_frame != 0)
2957                 proto_tree_add_text(tree, tvb, offset, 0, 
2958                                     "Request in frame %d", dcv->req_frame);
2959
2960         /* Parse packet */
2961
2962         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2963                                            prs_BUFFER, NULL, &data_list);
2964
2965         if (data_list)
2966                 bd = (struct BUFFER_DATA *)data_list[0];
2967
2968         if (bd && bd->tree) {
2969                 proto_item_append_text(bd->item, ", JOB_INFO_%d", level);
2970
2971                 switch (level) {
2972                 default:
2973                         proto_tree_add_text(
2974                                 bd->tree, tvb, offset, 0,
2975                                 "[Unknown info level %d]", level);
2976                         break;
2977                 }
2978         }
2979
2980         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
2981
2982         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Returned");
2983
2984         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2985
2986         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2987
2988         return offset;
2989 }       
2990
2991 #if 0
2992
2993 /* Templates for new subdissectors */
2994
2995 /*
2996  * FOO
2997  */
2998
2999 static int SpoolssFoo_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
3000                         proto_tree *tree, char *drep)
3001 {
3002         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3003         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3004
3005         /* Update informational fields */
3006
3007         if (check_col(pinfo->cinfo, COL_INFO))
3008                 col_set_str(pinfo->cinfo, COL_INFO, "Foo request");
3009
3010         if (dcv->rep_frame != 0)
3011                 proto_tree_add_text(tree, tvb, offset, 0, 
3012                                     "Response in frame %u", dcv->rep_frame);
3013
3014         /* Parse packet */
3015
3016         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3017
3018         return offset;
3019 }       
3020
3021 static int SpoolssFoo_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
3022                         proto_tree *tree, char *drep)
3023 {
3024         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
3025         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
3026
3027         /* Update informational fields */
3028
3029         if (check_col(pinfo->cinfo, COL_INFO))
3030                 col_set_str(pinfo->cinfo, COL_INFO, "Foo response");
3031
3032         if (dcv->req_frame != 0)
3033                 proto_tree_add_text(tree, tvb, offset, 0, 
3034                                     "Request in frame %u", dcv->req_frame);
3035
3036         /* Parse packet */
3037
3038         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
3039
3040         return offset;
3041 }       
3042
3043 #endif
3044
3045 /*
3046  * List of subdissectors for this pipe.
3047  */
3048
3049 static dcerpc_sub_dissector dcerpc_spoolss_dissectors[] = {
3050         { SPOOLSS_ENUMPRINTERS, "SPOOLSS_ENUMPRINTERS", 
3051           SpoolssEnumPrinters_q, SpoolssEnumPrinters_r },
3052         { SPOOLSS_OPENPRINTER, "SPOOLSS_OPENPRINTER", NULL, SpoolssGeneric_r },
3053         { SPOOLSS_SETJOB, "SPOOLSS_SETJOB", NULL, SpoolssGeneric_r },
3054         { SPOOLSS_GETJOB, "SPOOLSS_GETJOB", NULL, SpoolssGeneric_r },
3055         { SPOOLSS_ENUMJOBS, "SPOOLSS_ENUMJOBS", 
3056           SpoolssEnumJobs_q, SpoolssEnumJobs_r },
3057         { SPOOLSS_ADDPRINTER, "SPOOLSS_ADDPRINTER", NULL, SpoolssGeneric_r },
3058         { SPOOLSS_DELETEPRINTER, "SPOOLSS_DELETEPRINTER", 
3059           SpoolssDeletePrinter_q, SpoolssDeletePrinter_r },
3060         { SPOOLSS_SETPRINTER, "SPOOLSS_SETPRINTER", 
3061           SpoolssSetPrinter_q, SpoolssSetPrinter_r },
3062         { SPOOLSS_GETPRINTER, "SPOOLSS_GETPRINTER", 
3063           SpoolssGetPrinter_q, SpoolssGetPrinter_r },
3064         { SPOOLSS_ADDPRINTERDRIVER, "SPOOLSS_ADDPRINTERDRIVER", 
3065           NULL, SpoolssAddPrinterDriver_r },
3066         { SPOOLSS_ENUMPRINTERDRIVERS, "SPOOLSS_ENUMPRINTERDRIVERS", NULL, 
3067           SpoolssGeneric_r },
3068         { SPOOLSS_GETPRINTERDRIVER, "SPOOLSS_GETPRINTERDRIVER", NULL, 
3069           SpoolssGeneric_r },
3070         { SPOOLSS_GETPRINTERDRIVERDIRECTORY, 
3071           "SPOOLSS_GETPRINTERDRIVERDIRECTORY", NULL, SpoolssGeneric_r },
3072         { SPOOLSS_DELETEPRINTERDRIVER, "SPOOLSS_DELETEPRINTERDRIVER", NULL, 
3073           SpoolssGeneric_r },
3074         { SPOOLSS_ADDPRINTPROCESSOR, "SPOOLSS_ADDPRINTPROCESSOR", NULL, 
3075           SpoolssGeneric_r },
3076         { SPOOLSS_ENUMPRINTPROCESSORS, "SPOOLSS_ENUMPRINTPROCESSORS", NULL, 
3077           SpoolssGeneric_r },
3078         { SPOOLSS_GETPRINTPROCESSORDIRECTORY,
3079           "SPOOLSS_GETPRINTPROCESSORDIRECTORY", NULL, SpoolssGeneric_r },
3080         { SPOOLSS_STARTDOCPRINTER, "SPOOLSS_STARTDOCPRINTER", NULL, 
3081           SpoolssGeneric_r },
3082         { SPOOLSS_STARTPAGEPRINTER, "SPOOLSS_STARTPAGEPRINTER", NULL, 
3083           SpoolssGeneric_r },
3084         { SPOOLSS_WRITEPRINTER, "SPOOLSS_WRITEPRINTER", NULL, 
3085           SpoolssGeneric_r },
3086         { SPOOLSS_ENDPAGEPRINTER, "SPOOLSS_ENDPAGEPRINTER", NULL, 
3087           SpoolssGeneric_r },
3088         { SPOOLSS_ABORTPRINTER, "SPOOLSS_ABORTPRINTER", NULL, 
3089           SpoolssGeneric_r },
3090         { SPOOLSS_READPRINTER,"SPOOLSS_READPRINTER", NULL, SpoolssGeneric_r },
3091         { SPOOLSS_ENDDOCPRINTER, "SPOOLSS_ENDDOCPRINTER", NULL, 
3092           SpoolssGeneric_r },
3093         { SPOOLSS_ADDJOB, "SPOOLSS_ADDJOB", NULL, SpoolssGeneric_r },
3094         { SPOOLSS_SCHEDULEJOB, "SPOOLSS_SCHEDULEJOB", NULL, SpoolssGeneric_r },
3095         { SPOOLSS_GETPRINTERDATA, "SPOOLSS_GETPRINTERDATA", 
3096           SpoolssGetPrinterData_q, SpoolssGetPrinterData_r },   
3097         { SPOOLSS_SETPRINTERDATA, "SPOOLSS_SETPRINTERDATA", 
3098           SpoolssSetPrinterData_q, SpoolssSetPrinterData_r },
3099         { SPOOLSS_WAITFORPRINTERCHANGE,"SPOOLSS_WAITFORPRINTERCHANGE", NULL, 
3100           SpoolssGeneric_r },
3101         { SPOOLSS_CLOSEPRINTER, "SPOOLSS_CLOSEPRINTER", 
3102           SpoolssClosePrinter_q, SpoolssClosePrinter_r },
3103         { SPOOLSS_ADDFORM, "SPOOLSS_ADDFORM", 
3104           SpoolssAddForm_q, SpoolssAddForm_r },
3105         { SPOOLSS_DELETEFORM, "SPOOLSS_DELETEFORM", 
3106           SpoolssDeleteForm_q, SpoolssDeleteForm_r },
3107         { SPOOLSS_GETFORM, "SPOOLSS_GETFORM", 
3108           SpoolssGetForm_q, SpoolssGetForm_r },
3109         { SPOOLSS_SETFORM, "SPOOLSS_SETFORM", 
3110           SpoolssSetForm_q, SpoolssSetForm_r },
3111         { SPOOLSS_ENUMFORMS, "SPOOLSS_ENUMFORMS", 
3112           SpoolssEnumForms_q, SpoolssEnumForms_r },
3113         { SPOOLSS_ENUMPORTS, "SPOOLSS_ENUMPORTS", NULL, SpoolssGeneric_r },
3114         { SPOOLSS_ENUMMONITORS, "SPOOLSS_ENUMMONITORS", NULL, 
3115           SpoolssGeneric_r },
3116         { SPOOLSS_ADDPORT,"SPOOLSS_ADDPORT", NULL, SpoolssGeneric_r },
3117         { SPOOLSS_CONFIGUREPORT,"SPOOLSS_CONFIGUREPORT", NULL, 
3118           SpoolssGeneric_r },
3119         { SPOOLSS_DELETEPORT,"SPOOLSS_DELETEPORT", NULL, SpoolssGeneric_r },
3120         { SPOOLSS_CREATEPRINTERIC,"SPOOLSS_CREATEPRINTERIC", NULL, 
3121           SpoolssGeneric_r },
3122         { SPOOLSS_PLAYGDISCRIPTONPRINTERIC, "SPOOLSS_PLAYGDISCRIPTONPRINTERIC",
3123           NULL, SpoolssGeneric_r },
3124         { SPOOLSS_DELETEPRINTERIC,"SPOOLSS_DELETEPRINTERIC", NULL, 
3125           SpoolssGeneric_r },
3126         { SPOOLSS_ADDPRINTERCONNECTION,"SPOOLSS_ADDPRINTERCONNECTION", NULL, 
3127           SpoolssGeneric_r },
3128         { SPOOLSS_DELETEPRINTERCONNECTION,"SPOOLSS_DELETEPRINTERCONNECTION", 
3129           NULL, SpoolssGeneric_r },
3130         { SPOOLSS_PRINTERMESSAGEBOX,"SPOOLSS_PRINTERMESSAGEBOX", NULL, 
3131           SpoolssGeneric_r },
3132         { SPOOLSS_ADDMONITOR,"SPOOLSS_ADDMONITOR", NULL, 
3133           SpoolssGeneric_r },
3134         { SPOOLSS_DELETEMONITOR,"SPOOLSS_DELETEMONITOR", NULL, 
3135           SpoolssGeneric_r },
3136         { SPOOLSS_DELETEPRINTPROCESSOR,"SPOOLSS_DELETEPRINTPROCESSOR", NULL, 
3137           SpoolssGeneric_r },
3138         { SPOOLSS_ADDPRINTPROVIDOR,"SPOOLSS_ADDPRINTPROVIDER", NULL, 
3139           SpoolssGeneric_r },
3140         { SPOOLSS_DELETEPRINTPROVIDOR,"SPOOLSS_DELETEPRINTPROVIDER", NULL, 
3141           SpoolssGeneric_r },
3142         { SPOOLSS_ENUMPRINTPROCDATATYPES, "SPOOLSS_ENUMPRINTPROCDATATYPES", 
3143           NULL, SpoolssGeneric_r },
3144         { SPOOLSS_RESETPRINTER,"SPOOLSS_RESETPRINTER", NULL, 
3145           SpoolssGeneric_r },
3146         { SPOOLSS_GETPRINTERDRIVER2, "SPOOLSS_GETPRINTERDRIVER2", NULL, 
3147           SpoolssGeneric_r },
3148         { SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION,
3149           "SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION", NULL, 
3150           SpoolssGeneric_r },
3151         { SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION,
3152           "SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION", NULL, 
3153           SpoolssGeneric_r },
3154         { SPOOLSS_FCPN, "SPOOLSS_FCPN", NULL, SpoolssGeneric_r },
3155         { SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD,
3156           "SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD", NULL, 
3157           SpoolssGeneric_r },
3158         { SPOOLSS_REPLYOPENPRINTER, "SPOOLSS_REPLYOPENPRINTER",
3159           SpoolssReplyOpenPrinter_q, SpoolssReplyOpenPrinter_r },
3160         { SPOOLSS_ROUTERREPLYPRINTER,"SPOOLSS_ROUTERREPLYPRINTER", NULL, 
3161           SpoolssGeneric_r },
3162         { SPOOLSS_REPLYCLOSEPRINTER, "SPOOLSS_REPLYCLOSEPRINTER", NULL, 
3163           SpoolssGeneric_r },
3164         { SPOOLSS_ADDPORTEX,"SPOOLSS_ADDPORTEX", NULL, SpoolssGeneric_r },
3165         { SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION,
3166           "SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION", NULL, 
3167           SpoolssGeneric_r },
3168         { SPOOLSS_SPOOLERINIT,"SPOOLSS_SPOOLERINIT", NULL, SpoolssGeneric_r },
3169         { SPOOLSS_RESETPRINTEREX,"SPOOLSS_RESETPRINTEREX", NULL, 
3170           SpoolssGeneric_r },
3171         { SPOOLSS_RFFPCNEX, "SPOOLSS_RFFPCNEX",
3172           SpoolssRFFPCNEX_q, SpoolssRFFPCNEX_r },
3173         { SPOOLSS_RRPCN, "SPOOLSS_RRPCN", NULL, SpoolssGeneric_r },
3174         { SPOOLSS_RFNPCNEX, "SPOOLSS_RFNPCNEX", NULL, SpoolssGeneric_r },
3175         { SPOOLSS_OPENPRINTEREX, "SPOOLSS_OPENPRINTEREX", 
3176           SpoolssOpenPrinterEx_q, SpoolssOpenPrinterEx_r },
3177         { SPOOLSS_ADDPRINTEREX, "SPOOLSS_ADDPRINTEREX", 
3178           NULL, SpoolssAddPrinterEx_r },
3179         { SPOOLSS_ENUMPRINTERDATA, "SPOOLSS_ENUMPRINTERDATA", 
3180           SpoolssEnumPrinterData_q, SpoolssEnumPrinterData_r },
3181         { SPOOLSS_DELETEPRINTERDATA, "SPOOLSS_DELETEPRINTERDATA", NULL, 
3182           SpoolssGeneric_r },
3183         { SPOOLSS_GETPRINTERDATAEX, "SPOOLSS_GETPRINTERDATAEX", 
3184           SpoolssGetPrinterDataEx_q, SpoolssGetPrinterDataEx_r },
3185         { SPOOLSS_SETPRINTERDATAEX, "SPOOLSS_SETPRINTERDATAEX", 
3186           SpoolssSetPrinterDataEx_q, SpoolssSetPrinterDataEx_r },
3187         { SPOOLSS_ENUMPRINTERDATAEX,"SPOOLSS_ENUMPRINTERDATAEX", NULL, 
3188           SpoolssGeneric_r },
3189         { SPOOLSS_ENUMPRINTERKEY,"SPOOLSS_ENUMPRINTERKEY", NULL, 
3190           SpoolssGeneric_r },
3191         { SPOOLSS_DELETEPRINTERDATAEX,"SPOOLSS_DELETEPRINTERDATAEX", NULL, 
3192           SpoolssGeneric_r },
3193         { SPOOLSS_DELETEPRINTERDRIVEREX,"SPOOLSS_DELETEPRINTERDRIVEREX", NULL,
3194           SpoolssGeneric_r },
3195         { SPOOLSS_ADDPRINTERDRIVEREX,"SPOOLSS_ADDPRINTERDRIVEREX", NULL, 
3196           SpoolssGeneric_r },
3197
3198         { 0, NULL, NULL, NULL },
3199 };
3200
3201 /*
3202  * Dissector initialisation function
3203  */
3204
3205 /* Protocol registration */
3206
3207 static int proto_dcerpc_spoolss = -1;
3208 static gint ett_dcerpc_spoolss = -1;
3209
3210 void 
3211 proto_register_dcerpc_spoolss(void)
3212 {
3213         static gint *ett[] = {
3214                 &ett_dcerpc_spoolss,
3215                 &ett_NOTIFY_OPTION_ARRAY,
3216                 &ett_NOTIFY_OPTION_CTR,
3217                 &ett_NOTIFY_OPTION,
3218                 &ett_NOTIFY_OPTION_DATA,
3219                 &ett_PRINTER_DEFAULT,
3220                 &ett_DEVMODE_CTR,
3221                 &ett_DEVMODE,
3222                 &ett_USER_LEVEL,
3223                 &ett_USER_LEVEL_1,
3224                 &ett_BUFFER,
3225                 &ett_BUFFER_DATA,
3226                 &ett_BUFFER_DATA_BUFFER,
3227                 &ett_UNISTR2,
3228                 &ett_SPOOL_PRINTER_INFO_LEVEL,
3229                 &ett_PRINTER_INFO_0,
3230                 &ett_PRINTER_INFO_1,
3231                 &ett_PRINTER_INFO_2,
3232                 &ett_PRINTER_INFO_3,
3233                 &ett_RELSTR,
3234                 &ett_POLICY_HND,
3235                 &ett_FORM_REL,
3236                 &ett_FORM_CTR,
3237                 &ett_FORM_1,
3238                 &ett_JOB_INFO_1,
3239                 &ett_JOB_INFO_2,
3240         };
3241
3242         proto_dcerpc_spoolss = proto_register_protocol(
3243                 "Microsoft Spool Subsystem", "SPOOLSS", "spoolss");
3244
3245         proto_register_subtree_array(ett, array_length(ett));
3246 }
3247
3248 /* Protocol handoff */
3249
3250 static e_uuid_t uuid_dcerpc_spoolss = {
3251         0x12345678, 0x1234, 0xabcd,
3252         { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
3253 };
3254
3255 static guint16 ver_dcerpc_spoolss = 1;
3256
3257 void
3258 proto_reg_handoff_dcerpc_spoolss(void)
3259 {
3260         /* Register protocol as dcerpc */
3261
3262         dcerpc_init_uuid(proto_dcerpc_spoolss, ett_dcerpc_spoolss, 
3263                          &uuid_dcerpc_spoolss, ver_dcerpc_spoolss, 
3264                          dcerpc_spoolss_dissectors);
3265 }