proto_registrar_get_nth(hfinfo->id) == hfinfo, so use the latter rather
[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.17 2002/04/18 00:29:17 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <string.h>
32
33 #include <epan/packet.h>
34 #include "packet-dcerpc.h"
35 #include "packet-dcerpc-nt.h"
36 #include "packet-dcerpc-spoolss.h"
37 #include "packet-dcerpc-reg.h"
38 #include "smb.h"
39 #include "packet-smb-common.h"
40
41 /* 
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 %d", pol_open_frame);
227
228         if (pol_close_frame)
229                 proto_tree_add_text(subtree, tvb, offset, 0,
230                                     "Closed in frame %d", 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 != -1)
254                 proto_tree_add_text(tree, tvb, offset, 0, 
255                                     "Response in frame %d", 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 != -1)
283                 proto_tree_add_text(tree, tvb, offset, 0, 
284                                     "Request in frame %d", 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 != -1)
370                 proto_tree_add_text(tree, tvb, offset, 0, 
371                                     "Response in frame %d", 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 != -1)
410                 proto_tree_add_text(tree, tvb, offset, 0, 
411                                     "Request in frame %d", 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 != -1)
452                 proto_tree_add_text(tree, tvb, offset, 0, 
453                                     "Response in frame %d", 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 != -1)
511                 proto_tree_add_text(tree, tvb, offset, 0, 
512                                     "Request in frame %d", 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 != -1)
554                 proto_tree_add_text(tree, tvb, offset, 0, 
555                                     "Response in frame %d", 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 != -1)
603                 proto_tree_add_text(tree, tvb, offset, 0, 
604                                     "Request in frame %d", 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 != -1)
636                 proto_tree_add_text(tree, tvb, offset, 0, 
637                                     "Response in frame %d", 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 != -1)
691                 proto_tree_add_text(tree, tvb, offset, 0, 
692                                     "Request in frame %d", 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, GList **dp_list, void **data)
951 {
952         int struct_start = offset;
953         guint32 rel_offset;
954         
955         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
956                             NULL, "Server name");
957         
958         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
959                             NULL, "Printer name");
960         
961         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
962                             NULL, "Share name");
963         
964         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
965                            NULL, "Port name");
966         
967         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
968                             NULL, "Driver name");
969         
970         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
971                             NULL, "Comment");
972         
973         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
974                             NULL, "Location");
975
976         /* This is a relative devicemode */
977
978         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
979
980         prs_DEVMODE(tvb, struct_start + rel_offset - 4, pinfo, tree, 
981                     dp_list, NULL);
982         
983         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
984                             NULL, "Separator file");
985
986         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
987                             NULL, "Print processor");
988
989         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
990                             NULL, "Datatype");
991
992         offset = prs_relstr(tvb, offset, pinfo, tree, dp_list, struct_start,
993                             NULL, "Parameters");
994
995         /* This is a relative security descriptor */
996
997         offset = prs_uint32(tvb, offset, pinfo, tree, &rel_offset, NULL);
998
999         dissect_nt_sec_desc(tvb, pinfo, struct_start + rel_offset, tree, 0);
1000         
1001         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Attributes");
1002
1003         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Priority");
1004
1005         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, 
1006                             "Default priority");
1007
1008         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Start time");
1009
1010         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "End time");
1011
1012         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Status");
1013
1014         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Jobs");
1015
1016         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Average PPM");
1017
1018         return offset;
1019 }
1020
1021 /*
1022  * PRINTER_INFO_3
1023  */
1024
1025 static gint ett_PRINTER_INFO_3 = -1;
1026
1027 static int prs_PRINTER_INFO_3(tvbuff_t *tvb, int offset, packet_info *pinfo,
1028                               proto_tree *tree, GList **dp_list, void **data)
1029 {
1030         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
1031
1032         offset = dissect_nt_sec_desc(tvb, pinfo, offset, tree, 0);
1033
1034         return offset;
1035 }
1036
1037 /*
1038  * DEVMODE_CTR
1039  */
1040
1041 static gint ett_DEVMODE_CTR = -1;
1042
1043 static int prs_DEVMODE_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
1044                            proto_tree *tree, GList **dp_list, void **data)
1045 {
1046         proto_item *item;
1047         proto_tree *subtree;
1048         guint32 ptr = 0;
1049
1050         item = proto_tree_add_text(tree, tvb, offset, 0, "DEVMODE_CTR");
1051
1052         subtree = proto_item_add_subtree(item, ett_DEVMODE_CTR);
1053
1054         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1055                 
1056         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Devicemode");
1057
1058         if (ptr)
1059                 offset = prs_DEVMODE(tvb, offset, pinfo, subtree, dp_list, 
1060                                      data);
1061
1062         return offset;
1063 }
1064
1065 /*
1066  * PRINTER_DEFAULT structure
1067  */
1068
1069 static gint ett_PRINTER_DEFAULT = -1;
1070
1071 static int prs_PRINTER_DEFAULT(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1072                                proto_tree *tree, GList **dp_list, void **data)
1073 {
1074         GList *child_dp_list = NULL;
1075         proto_item *item;
1076         proto_tree *subtree;
1077         guint32 ptr = 0, access;
1078
1079         item = proto_tree_add_text(tree, tvb, offset, 0, "PRINTER_DEFAULT");
1080
1081         subtree = proto_item_add_subtree(item, ett_PRINTER_DEFAULT);
1082
1083         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Datatype");
1084
1085         /* Not sure why this isn't a deferred pointer.  I think this may be
1086            two structures stuck together. */
1087
1088         if (ptr)
1089                 offset = prs_UNISTR2_dp(tvb, offset, pinfo, subtree, dp_list, 
1090                                         NULL);
1091
1092         offset = prs_DEVMODE_CTR(tvb, offset, pinfo, subtree,
1093                                  &child_dp_list, NULL);
1094                 
1095         offset = prs_uint32(tvb, offset, pinfo, subtree, &access, NULL);
1096
1097         proto_tree_add_text(subtree, tvb, offset - 4, 4, 
1098                             "Access required: 0x%08x", access);
1099
1100         offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
1101                                &child_dp_list, NULL);
1102
1103         return offset;
1104 }
1105
1106 /*
1107  * USER_LEVEL_1 structure
1108  */
1109
1110 static gint ett_USER_LEVEL_1 = -1;
1111
1112 static int prs_USER_LEVEL_1(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1113                             proto_tree *tree, GList **dp_list, void **data)
1114 {
1115         proto_item *item;
1116         proto_tree *subtree;
1117         guint32 ptr = 0;
1118
1119         item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL_1");
1120
1121         subtree = proto_item_add_subtree(item, ett_USER_LEVEL_1);
1122
1123         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Size");
1124
1125         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Client name");
1126
1127         if (ptr)
1128                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
1129
1130         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User name");
1131
1132         if (ptr)
1133                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
1134
1135         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Build");
1136
1137         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Major");
1138
1139         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Minor");
1140
1141         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Processor");
1142         
1143         return offset;
1144 }
1145
1146 /*
1147  * USER_LEVEL structure
1148  */
1149
1150 static gint ett_USER_LEVEL = -1;
1151
1152 static int prs_USER_LEVEL(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1153                           proto_tree *tree, GList **parent_dp_list,
1154                           void **data)
1155 {
1156         proto_item *item;
1157         proto_tree *subtree;
1158         guint32 ptr = 0;
1159         guint32 level;
1160
1161         item = proto_tree_add_text(tree, tvb, offset, 0, "USER_LEVEL");
1162
1163         subtree = proto_item_add_subtree(item, ett_USER_LEVEL);
1164
1165         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Info level");
1166
1167         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "User level");
1168
1169         if (ptr) {
1170                 switch (level) {
1171                 case 1:
1172                         defer_ptr(parent_dp_list, prs_USER_LEVEL_1, subtree);
1173                         break;
1174                 default:
1175                         proto_tree_add_text(
1176                                 tree, tvb, offset, 0, 
1177                                 "[GetPrinter level %d not decoded]", level);
1178                         break;
1179                 }
1180         }
1181
1182         return offset;
1183 }
1184
1185 /*
1186  * SpoolssOpenPrinterEx
1187  */
1188
1189 static int SpoolssOpenPrinterEx_q(tvbuff_t *tvb, int offset, 
1190                                   packet_info *pinfo, proto_tree *tree, 
1191                                   char *drep)
1192 {
1193         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1194         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1195         char *printer_name;
1196         guint32 ptr = 0;
1197
1198         /* Update informational fields */
1199
1200         if (check_col(pinfo->cinfo, COL_INFO))
1201                 col_set_str(pinfo->cinfo, COL_INFO, "OpenPrinterEx request");
1202
1203         if (dcv->rep_frame != -1)
1204                 proto_tree_add_text(tree, tvb, offset, 0, 
1205                                     "Response in frame %d", dcv->rep_frame);
1206
1207         /* Parse packet */
1208
1209         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Printer name");
1210
1211         if (ptr) {
1212                 char *printer_name;
1213
1214                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1215                                                   prs_UNISTR2_dp, 
1216                                                   (void **)&printer_name,
1217                                                   NULL); 
1218
1219                 if (check_col(pinfo->cinfo, COL_INFO))
1220                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1221                                         printer_name);
1222                 
1223                 /* Store printer name to match with response packet */
1224
1225                 dcv->private_data = printer_name;
1226         }
1227
1228         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1229                                           prs_PRINTER_DEFAULT, NULL, NULL);
1230
1231         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
1232
1233         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1234                                           prs_USER_LEVEL, NULL, NULL);
1235
1236         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1237
1238         return offset;
1239 }
1240
1241 static int SpoolssOpenPrinterEx_r(tvbuff_t *tvb, int offset,
1242                                   packet_info *pinfo, proto_tree *tree, 
1243                                   char *drep)
1244 {
1245         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1246         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1247         GList *dp_list = NULL;
1248         guint32 status;
1249         const guint8 *policy_hnd;
1250
1251         /* Display informational data */
1252
1253         if (check_col(pinfo->cinfo, COL_INFO))
1254                 col_set_str(pinfo->cinfo, COL_INFO, "OpenPrinterEx response");
1255
1256         if (dcv->req_frame != -1)
1257                 proto_tree_add_text(tree, tvb, offset, 0, 
1258                                     "Request in frame %d", dcv->req_frame);
1259
1260         /* Parse packet */
1261
1262         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1263
1264         display_pol(tree, tvb, offset - 20, policy_hnd);
1265
1266         offset = prs_werror(tvb, offset, pinfo, tree, &status);
1267
1268         if (status == 0) {
1269
1270                 /* Associate the returned printer handle with a name */
1271
1272                 if (dcv->private_data) {
1273                         dcerpc_smb_store_pol(policy_hnd, dcv->private_data,
1274                                              pinfo->fd->num, 0);
1275
1276                         g_free(dcv->private_data);
1277                         dcv->private_data = NULL;
1278                 }
1279         }
1280
1281         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1282
1283         return offset;
1284 }
1285
1286 /*
1287  * NOTIFY_OPTION_DATA structure
1288  */
1289
1290 static gint ett_NOTIFY_OPTION_DATA = -1;
1291
1292 static int prs_NOTIFY_OPTION_DATA(tvbuff_t *tvb, int offset, 
1293                                   packet_info *pinfo, proto_tree *tree,
1294                                   GList **parent_dp_list, void **data)
1295 {
1296         proto_item *item;
1297         proto_tree *subtree;
1298         guint32 count, i;
1299
1300         item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION_DATA");
1301
1302         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_DATA);
1303
1304         offset = prs_uint32(tvb, offset, pinfo, subtree, &count, "Count");
1305
1306         for (i = 0; i < count; i++)
1307                 offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, 
1308                                     "Field");
1309
1310         return offset;
1311 }
1312
1313 /*
1314  * NOTIFY_OPTION structure
1315  */
1316
1317 static gint ett_NOTIFY_OPTION = -1;
1318
1319 static int prs_NOTIFY_OPTION(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1320                              proto_tree *tree, GList **parent_dp_list,
1321                              void **data) 
1322 {
1323         proto_item *item;
1324         proto_tree *subtree;
1325         guint32 ptr = 0;
1326
1327         item = proto_tree_add_text(tree, tvb, offset, 0, "NOTIFY_OPTION");
1328
1329         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION);
1330
1331         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Type");
1332
1333         offset = prs_uint16(tvb, offset, pinfo, subtree, NULL, "Reserved");
1334
1335         offset = prs_uint32(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, "Count");
1340
1341         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Fields");
1342
1343         if (ptr)
1344                 defer_ptr(parent_dp_list, prs_NOTIFY_OPTION_DATA, subtree);
1345
1346         return offset;
1347 }
1348
1349 /*
1350  * NOTIFY_OPTION_CTR structure
1351  */
1352
1353 static gint ett_NOTIFY_OPTION_CTR = -1;
1354
1355 static int prs_NOTIFY_OPTION_CTR(tvbuff_t *tvb, int offset, 
1356                                  packet_info *pinfo, proto_tree *tree,
1357                                  GList **dp_list, void **data)
1358 {
1359         GList *child_dp_list = NULL;
1360         proto_item *item;
1361         proto_tree *subtree;
1362         guint32 count, i, ptr;
1363
1364         item = proto_tree_add_text(tree, tvb, offset, 0, 
1365                                    "NOTIFY_OPTION_CTR");
1366
1367         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_CTR);
1368
1369         offset = prs_uint32(tvb, offset, pinfo, subtree, &count, "Count");
1370
1371         for (i = 0; i < count; i++)
1372                 offset = prs_NOTIFY_OPTION(tvb, offset, pinfo, subtree, 
1373                                            &child_dp_list, NULL);
1374
1375         offset = prs_referents(tvb, offset, pinfo, subtree, dp_list,
1376                                &child_dp_list, NULL);
1377
1378         return offset;
1379 }
1380
1381 /*
1382  * NOTIFY_OPTION structure
1383  */
1384
1385 gint ett_NOTIFY_OPTION_ARRAY = -1;
1386
1387 static int prs_NOTIFY_OPTION_ARRAY(tvbuff_t *tvb, int offset,
1388                                    packet_info *pinfo, proto_tree *tree,
1389                                    GList **dp_list, void **data)
1390 {
1391         proto_item *item;
1392         proto_tree *subtree;
1393         guint32 ptr = 0;
1394
1395         item = proto_tree_add_text(tree, tvb, offset, 0, 
1396                                    "NOTIFY_OPTION_ARRAY");
1397
1398         subtree = proto_item_add_subtree(item, ett_NOTIFY_OPTION_ARRAY);
1399
1400         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Version");
1401         
1402         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Flags");
1403         
1404         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Count");
1405         
1406         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Option type");
1407
1408         if (ptr)
1409                 defer_ptr(dp_list, prs_NOTIFY_OPTION_CTR, subtree);
1410
1411         return offset;
1412 }
1413
1414 /*
1415  * SpoolssRFFPCNEX
1416  */
1417
1418 static int SpoolssRFFPCNEX_q(tvbuff_t *tvb, int offset, 
1419                              packet_info *pinfo, proto_tree *tree, 
1420                              char *drep)
1421 {
1422         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1423         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1424         char *printer_name;
1425         guint32 ptr = 0;
1426         const guint8 *policy_hnd;
1427
1428         /* Update informational fields */
1429
1430         if (check_col(pinfo->cinfo, COL_INFO))
1431                 col_set_str(pinfo->cinfo, COL_INFO, "RFFPCNEX request");
1432
1433         if (dcv->rep_frame != -1)
1434                 proto_tree_add_text(tree, tvb, offset, 0, 
1435                                     "Response in frame %d", dcv->rep_frame);
1436
1437         /* Parse packet */
1438
1439         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1440
1441         display_pol(tree, tvb, offset - 20, policy_hnd);
1442
1443         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
1444         
1445         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Options");
1446         
1447         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Local machine");
1448
1449         if (ptr) {
1450                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1451                                                   prs_UNISTR2_dp,
1452                                                   (void *)&printer_name, NULL);
1453
1454                 if (check_col(pinfo->cinfo, COL_INFO))
1455                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1456                                         printer_name);
1457
1458                 g_free(printer_name);
1459         }
1460
1461         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer local");
1462         
1463         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Option");
1464         
1465         if (ptr) {
1466                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1467                                                   prs_NOTIFY_OPTION_ARRAY,
1468                                                   NULL, NULL);
1469         }
1470         
1471         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1472
1473         return offset;
1474 }
1475
1476 static int SpoolssRFFPCNEX_r(tvbuff_t *tvb, int offset,
1477                              packet_info *pinfo, proto_tree *tree, 
1478                              char *drep)
1479 {
1480         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1481         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1482
1483         /* Update informational fields */
1484
1485         if (check_col(pinfo->cinfo, COL_INFO))
1486                 col_set_str(pinfo->cinfo, COL_INFO, "RFFPCNEX response");
1487
1488         if (dcv->req_frame != -1)
1489                 proto_tree_add_text(tree, tvb, offset, 0, 
1490                                     "Request in frame %d", dcv->req_frame);
1491
1492         /* Parse packet */
1493
1494         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1495
1496         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1497
1498         return offset;
1499 }
1500
1501 /*
1502  * SpoolssReplyOpenPrinter
1503  */
1504
1505 static int SpoolssReplyOpenPrinter_q(tvbuff_t *tvb, int offset, 
1506                                      packet_info *pinfo, proto_tree *tree, 
1507                                      char *drep)
1508 {
1509         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1510         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1511         guint32 ptr = 0, type;
1512
1513         /* Update informational fields */
1514
1515         if (check_col(pinfo->cinfo, COL_INFO))
1516                 col_set_str(pinfo->cinfo, COL_INFO, "ReplyOpenPrinter request");
1517
1518         if (dcv->rep_frame != -1)
1519                 proto_tree_add_text(tree, tvb, offset, 0, 
1520                                     "Response in frame %d", dcv->rep_frame);
1521
1522         /* Parse packet */
1523
1524         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1525                                           prs_UNISTR2_dp, NULL, NULL);
1526
1527         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Printer");
1528
1529         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
1530
1531         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
1532                             val_to_str(type, reg_datatypes, "Unknown type"));
1533
1534         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
1535
1536         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown"); 
1537
1538         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1539
1540         return offset;
1541 }       
1542
1543 static int SpoolssReplyOpenPrinter_r(tvbuff_t *tvb, int offset, 
1544                                      packet_info *pinfo, proto_tree *tree, 
1545                                      char *drep)
1546 {
1547         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1548         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1549         GList *dp_list = NULL;
1550         const guint8 *policy_hnd;
1551
1552         /* Update informational fields */
1553
1554         if (check_col(pinfo->cinfo, COL_INFO))
1555                 col_set_str(pinfo->cinfo, COL_INFO, "ReplyOpenPrinter response");
1556
1557         if (dcv->req_frame != -1)
1558                 proto_tree_add_text(tree, tvb, offset, 0, 
1559                                     "Request in frame %d", dcv->req_frame);
1560
1561         /* Parse packet */
1562
1563         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1564
1565         display_pol(tree, tvb, offset - 20, policy_hnd);
1566
1567         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1568
1569         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1570
1571         return offset;
1572 }       
1573
1574 /*
1575  * BUFFER_DATA
1576  */
1577
1578 static gint ett_BUFFER_DATA = -1;
1579 static gint ett_BUFFER_DATA_BUFFER = -1;
1580
1581 struct BUFFER_DATA {
1582         proto_item *item;       /* proto_item holding proto_tree */
1583         proto_tree *tree;       /* proto_tree holding buffer data */
1584         tvbuff_t *tvb;          
1585         int offset;             /* Offset where data starts in tvb*/
1586 };
1587
1588 static int prs_BUFFER_DATA(tvbuff_t *tvb, int offset, packet_info *pinfo,
1589                            proto_tree *tree, GList **dp_list, void **data)
1590 {
1591         proto_item *item, *subitem;
1592         proto_tree *subtree, *subsubtree;
1593         guint32 ptr = 0, size;
1594         int data8_offset;
1595
1596         item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER_DATA");
1597
1598         subtree = proto_item_add_subtree(item, ett_BUFFER_DATA);
1599
1600         offset = prs_uint32(tvb, offset, pinfo, subtree, &size, "Size");
1601
1602         subitem = proto_tree_add_text(subtree, tvb, offset, size, "Data");
1603
1604         subsubtree = proto_item_add_subtree(subitem, ett_BUFFER_DATA_BUFFER);
1605
1606         offset = prs_uint8s(tvb, offset, pinfo, subsubtree, size,
1607                             &data8_offset, NULL);
1608
1609         /* Return some info which will help the caller "cast" the buffer
1610            data and dissect it further. */
1611
1612         if (data) {
1613                 struct BUFFER_DATA *bd;
1614
1615                 bd = (struct BUFFER_DATA *)malloc(sizeof(struct BUFFER_DATA));
1616
1617                 bd->item = subitem;
1618                 bd->tree = subsubtree;
1619                 bd->tvb = tvb;
1620                 bd->offset = data8_offset;
1621
1622                 *data = bd;
1623         }
1624
1625         return offset;
1626 }
1627
1628 /*
1629  * BUFFER
1630  */
1631
1632 static gint ett_BUFFER = -1;
1633
1634 static int prs_BUFFER(tvbuff_t *tvb, int offset, packet_info *pinfo,
1635                       proto_tree *tree, GList **dp_list, void **data)
1636 {
1637         proto_item *item;
1638         proto_tree *subtree;
1639         guint32 ptr = 0;
1640
1641         item = proto_tree_add_text(tree, tvb, offset, 0, "BUFFER");
1642
1643         subtree = proto_item_add_subtree(item, ett_BUFFER);
1644
1645         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Data");
1646
1647         if (ptr)
1648                 defer_ptr(dp_list, prs_BUFFER_DATA, subtree);
1649
1650         return offset;
1651 }
1652
1653 /*
1654  * SpoolssGetPrinter
1655  */
1656
1657 static int SpoolssGetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
1658                                proto_tree *tree, char *drep)
1659 {
1660         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1661         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1662         GList *dp_list = NULL;
1663         guint32 level;
1664         const guint8 *policy_hnd;
1665
1666         /* Update informational fields */
1667
1668         if (check_col(pinfo->cinfo, COL_INFO))
1669                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinter request");
1670
1671         if (dcv->rep_frame != -1)
1672                 proto_tree_add_text(tree, tvb, offset, 0, 
1673                                     "Response in frame %d", dcv->rep_frame);
1674
1675         /* Parse packet */
1676
1677         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1678
1679         display_pol(tree, tvb, offset - 20, policy_hnd);
1680
1681         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
1682
1683         if (check_col(pinfo->cinfo, COL_INFO))
1684                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1685
1686         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1687                                           prs_BUFFER, NULL, NULL);
1688
1689         dcv->private_data = (void *)level;
1690
1691         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
1692
1693         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1694
1695         return offset;
1696 }       
1697
1698 static int SpoolssGetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
1699                                 proto_tree *tree, char *drep)
1700 {
1701         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1702         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1703         GList *dp_list = NULL;
1704         void **data_list;
1705         struct BUFFER_DATA *bd = NULL;
1706         gint16 level = (guint32)dcv->private_data;
1707
1708         /* Update informational fields */
1709
1710         if (check_col(pinfo->cinfo, COL_INFO))
1711                 col_set_str(pinfo->cinfo, COL_INFO, "GetPrinter response");
1712
1713         if (dcv->req_frame != -1)
1714                 proto_tree_add_text(tree, tvb, offset, 0, 
1715                                     "Request in frame %d", dcv->req_frame);
1716
1717         if (check_col(pinfo->cinfo, COL_INFO))
1718                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1719
1720         /* Parse packet */
1721
1722         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1723                                           prs_BUFFER, NULL, &data_list);
1724
1725         if (data_list)
1726                 bd = (struct BUFFER_DATA *)data_list[0];
1727
1728         if (bd && bd->tree) {
1729                 proto_item_append_text(bd->item, ", PRINTER_INFO_%d", level);
1730
1731                 switch (level) {
1732                 case 0:
1733                         prs_PRINTER_INFO_0(bd->tvb, bd->offset, pinfo, 
1734                                            bd->tree, &dp_list, NULL);
1735                         break;
1736                         
1737                 case 1:
1738                         prs_PRINTER_INFO_1(bd->tvb, bd->offset, pinfo, 
1739                                            bd->tree, &dp_list, NULL);
1740                         break;
1741                         
1742                 case 2:
1743                         prs_PRINTER_INFO_2(bd->tvb, bd->offset, pinfo,
1744                                            bd->tree, &dp_list, NULL);
1745                         break;
1746
1747                 case 3:
1748                         prs_PRINTER_INFO_3(bd->tvb, bd->offset, pinfo,
1749                                            bd->tree, &dp_list, NULL);
1750                         break;
1751
1752                 default:
1753                         proto_tree_add_text(tree, tvb, offset, 0,
1754                                             "[Unimplemented info level %d]", level);
1755                         break;
1756                 }
1757         }
1758         done:
1759
1760         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
1761
1762         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1763
1764         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1765
1766         return offset;
1767 }       
1768
1769 /*
1770  * SPOOL_PRINTER_INFO_LEVEL
1771  */
1772
1773 static gint ett_SPOOL_PRINTER_INFO_LEVEL = -1;
1774
1775 static int prs_SPOOL_PRINTER_INFO_LEVEL(tvbuff_t *tvb, int offset, 
1776                                         packet_info *pinfo, proto_tree *tree, 
1777                                         GList **dp_list, void **data)
1778 {
1779         proto_item *item;
1780         proto_tree *subtree;
1781         guint32 ptr = 0, level;
1782
1783         item = proto_tree_add_text(tree, tvb, offset, 0, 
1784                                    "SPOOL_PRINTER_INFO_LEVEL");
1785
1786         subtree = proto_item_add_subtree(item, ett_SPOOL_PRINTER_INFO_LEVEL);
1787
1788         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level");
1789
1790         /* ptr */
1791
1792         switch(level) {
1793         }
1794
1795         return offset;
1796 }
1797
1798 /*
1799  * SpoolssSetPrinter
1800  */
1801
1802 static int SpoolssSetPrinter_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
1803                                proto_tree *tree, char *drep)
1804 {
1805         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1806         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1807         GList *dp_list = NULL;
1808         guint32 level;
1809         const guint8 *policy_hnd;
1810
1811         /* Update informational fields */
1812
1813         if (check_col(pinfo->cinfo, COL_INFO))
1814                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinter request");
1815
1816         if (dcv->rep_frame != -1)
1817                 proto_tree_add_text(tree, tvb, offset, 0, 
1818                                     "Response in frame %d", dcv->rep_frame);
1819
1820         /* Parse packet */
1821
1822         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1823
1824         display_pol(tree, tvb, offset - 20, policy_hnd);
1825
1826         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
1827
1828         if (check_col(pinfo->cinfo, COL_INFO))
1829                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1830
1831         /* printer_info_level */
1832
1833         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1834                                           prs_SPOOL_PRINTER_INFO_LEVEL,
1835                                           NULL, NULL);
1836
1837         /* devmode_ctr */
1838
1839
1840         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Command");
1841
1842         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1843
1844         return offset;
1845 }       
1846
1847 static int SpoolssSetPrinter_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
1848                                 proto_tree *tree, char *drep)
1849 {
1850         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1851         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1852         GList *dp_list = NULL;
1853
1854         /* Update informational fields */
1855
1856         if (check_col(pinfo->cinfo, COL_INFO))
1857                 col_set_str(pinfo->cinfo, COL_INFO, "SetPrinter response");
1858
1859         if (dcv->req_frame != -1)
1860                 proto_tree_add_text(tree, tvb, offset, 0, 
1861                                     "Request in frame %d", dcv->req_frame);
1862
1863         /* Parse packet */
1864
1865         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
1866
1867         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1868
1869         return offset;
1870 }       
1871
1872 /*
1873  * FORM_REL
1874  */
1875
1876 static const value_string form_type_vals[] =
1877 {
1878         { FORM_USER, "FORM_USER" },
1879         { FORM_BUILTIN, "FORM_BUILTIN" },
1880         { FORM_PRINTER, "FORM_PRINTER" },
1881         { 0, NULL }
1882 };
1883
1884 static gint ett_FORM_REL = -1;
1885
1886 static int prs_FORM_REL(tvbuff_t *tvb, int offset, packet_info *pinfo,
1887                         proto_tree *tree, int struct_start, GList **dp_list, 
1888                         void **data)
1889 {
1890         proto_item *item;
1891         proto_tree *subtree;
1892         guint32 flags;
1893
1894         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_REL");
1895
1896         subtree = proto_item_add_subtree(item, ett_FORM_REL);
1897
1898         offset = prs_uint32(tvb, offset, pinfo, subtree, &flags, NULL);
1899
1900         proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s",
1901                             val_to_str(flags, form_type_vals, "Unknown type"));
1902
1903         offset = prs_relstr(tvb, offset, pinfo, subtree, dp_list,
1904                             struct_start, NULL, "Name");
1905
1906         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Width");
1907
1908         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Height");
1909
1910         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1911                             "Left margin");
1912
1913         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1914                             "Top margin");
1915
1916         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1917                             "Horizontal imageable length");
1918
1919         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
1920                             "Vertical imageable length");
1921
1922         return offset;
1923 }
1924
1925 /*
1926  * SpoolssEnumForms
1927  */
1928
1929 static int SpoolssEnumForms_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
1930                               proto_tree *tree, char *drep)
1931 {
1932         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1933         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1934         GList *dp_list = NULL;
1935         guint32 level;
1936         const guint8 *policy_hnd;
1937
1938         /* Update informational fields */
1939
1940         if (check_col(pinfo->cinfo, COL_INFO))
1941                 col_set_str(pinfo->cinfo, COL_INFO, "EnumForms request");
1942
1943         if (dcv->rep_frame != -1)
1944                 proto_tree_add_text(tree, tvb, offset, 0, 
1945                                     "Response in frame %d", dcv->rep_frame);
1946
1947         /* Parse packet */
1948
1949         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
1950         
1951         display_pol(tree, tvb, offset - 20, policy_hnd);
1952
1953         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
1954
1955         dcv->private_data = (void *)level;
1956
1957         if (check_col(pinfo->cinfo, COL_INFO))
1958                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
1959
1960         offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
1961                                           prs_BUFFER, NULL, NULL);
1962
1963         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
1964
1965         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
1966
1967         return offset;
1968 }       
1969
1970 static int SpoolssEnumForms_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
1971                               proto_tree *tree, char *drep)
1972 {
1973         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
1974         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1975         guint32 count;
1976         GList *dp_list = NULL;
1977         struct BUFFER_DATA *bd = NULL;
1978         void **data_list;
1979
1980         /* Update informational fields */
1981
1982         if (check_col(pinfo->cinfo, COL_INFO))
1983                 col_set_str(pinfo->cinfo, COL_INFO, "EnumForms response");
1984
1985         if (dcv->req_frame != -1)
1986                 proto_tree_add_text(tree, tvb, offset, 0, 
1987                                     "Request in frame %d", dcv->req_frame);
1988
1989         /* Parse packet */
1990
1991         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
1992                                            prs_BUFFER, NULL, &data_list);
1993
1994         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
1995
1996         offset = prs_uint32(tvb, offset, pinfo, tree, &count, "Num entries");
1997
1998         if (data_list)
1999                 bd = (struct BUFFER_DATA *)data_list[0];
2000
2001         CLEANUP_PUSH(g_free, bd);
2002
2003         if (bd && bd->tree) {
2004                 guint32 level = (guint32)dcv->private_data, i;
2005                 GList *child_dp_list = NULL;
2006
2007                 if (check_col(pinfo->cinfo, COL_INFO))
2008                         col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2009
2010                 proto_item_append_text(bd->item, ", FORM_%d", level);
2011
2012                 /* Unfortunately this array isn't in NDR format so we can't
2013                    use prs_array().  The other weird thing is the
2014                    struct_start being inside the loop rather than outside.
2015                    Very strange. */
2016
2017                 for (i = 0; i < count; i++) {
2018                         int struct_start = bd->offset;
2019
2020                         bd->offset = prs_FORM_REL(
2021                                 bd->tvb, bd->offset, pinfo, bd->tree, 
2022                                 struct_start, &child_dp_list, NULL);
2023                 }
2024
2025         }
2026  done:
2027
2028         CLEANUP_CALL_AND_POP;
2029
2030         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2031
2032         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2033
2034         return offset;
2035 }       
2036
2037 /*
2038  * SpoolssDeletePrinter
2039  */
2040
2041 static int SpoolssDeletePrinter_q(tvbuff_t *tvb, int offset, 
2042                                   packet_info *pinfo, proto_tree *tree, 
2043                                   char *drep)
2044 {
2045         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2046         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2047         const guint8 *policy_hnd;
2048
2049         /* Update informational fields */
2050
2051         if (check_col(pinfo->cinfo, COL_INFO))
2052                 col_set_str(pinfo->cinfo, COL_INFO, "DeletePrinter request");
2053         
2054         if (dcv->rep_frame != -1)
2055                 proto_tree_add_text(tree, tvb, offset, 0, 
2056                                     "Response in frame %d", dcv->rep_frame);
2057
2058         /* Parse packet */
2059
2060         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2061
2062         display_pol(tree, tvb, offset - 20, policy_hnd);
2063         
2064         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2065
2066         return offset;
2067 }       
2068
2069 static int SpoolssDeletePrinter_r(tvbuff_t *tvb, int offset, 
2070                                   packet_info *pinfo, proto_tree *tree, 
2071                                   char *drep)
2072 {
2073         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2074         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2075         const guint8 *policy_hnd;
2076
2077         /* Update informational fields */
2078
2079         if (check_col(pinfo->cinfo, COL_INFO))
2080                 col_set_str(pinfo->cinfo, COL_INFO, "DeletePrinter response");
2081
2082         if (dcv->req_frame != -1)
2083                 proto_tree_add_text(tree, tvb, offset, 0, 
2084                                     "Request in frame %d", dcv->req_frame);
2085
2086         /* Parse packet */
2087
2088         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2089
2090         display_pol(tree, tvb, offset - 20, policy_hnd);
2091
2092         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2093
2094         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2095
2096         return offset;
2097 }       
2098
2099 /*
2100  * AddPrinterEx
2101  */
2102
2103 static int SpoolssAddPrinterEx_q(tvbuff_t *tvb, int offset, 
2104                                  packet_info *pinfo, proto_tree *tree, 
2105                                  char *drep)
2106 {
2107         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2108         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2109         guint32 ptr;
2110         
2111         /* Update informational fields */
2112         
2113         if (check_col(pinfo->cinfo, COL_INFO))
2114                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterEx request");
2115         
2116         if (dcv->rep_frame != -1)
2117                 proto_tree_add_text(tree, tvb, offset, 0, 
2118                                     "Response in frame %d", dcv->rep_frame);
2119
2120         /* Parse packet */
2121         
2122         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Server name");
2123         
2124         if (ptr) {
2125                 char *printer_name;
2126
2127                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2128                                                   prs_UNISTR2_dp,
2129                                                   (void *)&printer_name, NULL);
2130
2131                 if (printer_name)
2132                         dcv->private_data = printer_name;
2133         }
2134         
2135         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Level");
2136         
2137         /* TODO: PRINTER INFO LEVEL */
2138         
2139         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2140         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2141         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2142         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Unknown");
2143         
2144         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "User switch");
2145         
2146         /* TODO: USER LEVEL */
2147         
2148         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2149         
2150         return offset;
2151 }      
2152
2153 static int SpoolssAddPrinterEx_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2154                                  proto_tree *tree, char *drep)
2155 {
2156         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2157         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2158         guint32 status;
2159         const guint8 *policy_hnd;
2160
2161         /* Update informational fields */
2162
2163         if (check_col(pinfo->cinfo, COL_INFO))
2164                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterEx response");
2165
2166         if (dcv->req_frame != -1)
2167                 proto_tree_add_text(tree, tvb, offset, 0, 
2168                                     "Request in frame %d", dcv->req_frame);
2169
2170         /* Parse packet */
2171
2172         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2173
2174         display_pol(tree, tvb, offset - 20, policy_hnd);
2175
2176         offset = prs_werror(tvb, offset, pinfo, tree, &status); 
2177
2178         if (status == 0) {
2179
2180                 /* Associate the returned printer handle with a name */
2181
2182                 if (dcv->private_data) {
2183
2184                         if (check_col(pinfo->cinfo, COL_INFO))
2185                                 col_append_fstr(
2186                                         pinfo->cinfo, COL_INFO, ", %s", 
2187                                         (char *)dcv->private_data);
2188
2189                         dcerpc_smb_store_pol(
2190                                 policy_hnd, dcv->private_data, pinfo->fd->num, 0);
2191
2192                         g_free(dcv->private_data);
2193                         dcv->private_data = NULL;
2194                 }
2195         }
2196
2197         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2198
2199         return offset;
2200 }       
2201
2202 /*
2203  * SpoolssEnumPrinterData
2204  */
2205
2206 static int SpoolssEnumPrinterData_q(tvbuff_t *tvb, int offset, 
2207                                     packet_info *pinfo, proto_tree *tree, 
2208                                     char *drep)
2209 {
2210         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2211         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2212         const guint8 *policy_hnd;
2213
2214         /* Update informational fields */
2215
2216         if (check_col(pinfo->cinfo, COL_INFO))
2217                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinterData request");
2218
2219         if (dcv->rep_frame != -1)
2220                 proto_tree_add_text(tree, tvb, offset, 0, 
2221                                     "Response in frame %d", dcv->rep_frame);
2222
2223         /* Parse packet */
2224
2225         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2226
2227         display_pol(tree, tvb, offset - 20, policy_hnd);
2228         
2229         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Index");
2230
2231         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Value size");
2232
2233         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Data size");
2234
2235         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2236
2237         return offset;
2238 }       
2239
2240 static int SpoolssEnumPrinterData_r(tvbuff_t *tvb, int offset, 
2241                                     packet_info *pinfo, proto_tree *tree, 
2242                                     char *drep)
2243 {
2244         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2245         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2246         guint32 data_size, type, value_size;
2247         int uint16s_offset;
2248         char *text;
2249
2250         /* Update informational fields */
2251
2252         if (check_col(pinfo->cinfo, COL_INFO))
2253                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinterData response");
2254
2255         if (dcv->req_frame != -1)
2256                 proto_tree_add_text(tree, tvb, offset, 0, 
2257                                     "Request in frame %d", dcv->req_frame);
2258
2259         /* Parse packet */
2260
2261         offset = prs_uint32(tvb, offset, pinfo, tree, &value_size, 
2262                             "Value size");
2263         
2264         offset = prs_uint16s(tvb, offset, pinfo, tree, value_size,
2265                              &uint16s_offset, NULL);
2266         
2267         text = fake_unicode(tvb, uint16s_offset, value_size);
2268         
2269         proto_tree_add_text(tree, tvb, uint16s_offset,
2270                             value_size * 2, "Value: %s", text);
2271        
2272         if (text[0] && check_col(pinfo->cinfo, COL_INFO))
2273                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", text);
2274         
2275         g_free(text);
2276
2277         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real value size");
2278
2279         offset = prs_uint32(tvb, offset, pinfo, tree, &type, NULL);
2280
2281         proto_tree_add_text(tree, tvb, offset - 4, 4, "Type: %s",
2282                             val_to_str(type, reg_datatypes, "Unknown type"));
2283
2284         offset = prs_uint32(tvb, offset, pinfo, tree, &data_size, "Data size");
2285
2286         offset = prs_uint8s(tvb, offset, pinfo, tree, data_size, NULL,
2287                             "Data");
2288
2289         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Real data size");
2290
2291         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2292         
2293         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2294
2295         return offset;
2296 }       
2297
2298 /*
2299  * SpoolssEnumPrinters
2300  */
2301
2302 static int SpoolssEnumPrinters_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2303                                  proto_tree *tree, char *drep)
2304 {
2305         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2306         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2307         guint32 ptr, level;
2308
2309         /* Update informational fields */
2310
2311         if (check_col(pinfo->cinfo, COL_INFO))
2312                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinters request");
2313
2314         if (dcv->rep_frame != -1)
2315                 proto_tree_add_text(tree, tvb, offset, 0, 
2316                                     "Response in frame %d", dcv->rep_frame);
2317
2318         /* Parse packet */
2319
2320         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Flags");
2321
2322         offset = prs_ptr(tvb, offset, pinfo, tree, &ptr, "Devicemode");
2323
2324         if (ptr)
2325                 offset = prs_struct_and_referents(tvb, offset, pinfo, tree,
2326                                                   prs_UNISTR2_dp, NULL, NULL);
2327
2328         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2329         
2330         if (check_col(pinfo->cinfo, COL_INFO))
2331                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level, %d", level);
2332         
2333         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2334                                           prs_BUFFER, NULL, NULL);
2335
2336         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
2337
2338         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2339
2340         return offset;
2341 }       
2342
2343 static int SpoolssEnumPrinters_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2344                                  proto_tree *tree, char *drep)
2345 {
2346         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2347         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2348
2349         /* Update informational fields */
2350
2351         if (check_col(pinfo->cinfo, COL_INFO))
2352                 col_set_str(pinfo->cinfo, COL_INFO, "EnumPrinters response");
2353
2354         if (dcv->req_frame != -1)
2355                 proto_tree_add_text(tree, tvb, offset, 0, 
2356                                     "Request in frame %d", dcv->req_frame);
2357
2358         /* Parse packet */
2359
2360         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2361                                           prs_BUFFER, NULL, NULL);
2362
2363         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
2364
2365         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Returned");
2366
2367         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2368
2369         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2370
2371         return offset;
2372 }       
2373
2374 /*
2375  * AddPrinterDriver
2376  */
2377
2378 static int SpoolssAddPrinterDriver_q(tvbuff_t *tvb, int offset, 
2379                                      packet_info *pinfo, proto_tree *tree, 
2380                                      char *drep)
2381 {
2382         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2383         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2384
2385         /* Update informational fields */
2386
2387         if (check_col(pinfo->cinfo, COL_INFO))
2388                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterDriver request");
2389
2390         if (dcv->rep_frame != -1)
2391                 proto_tree_add_text(tree, tvb, offset, 0, 
2392                                     "Response in frame %d", dcv->rep_frame);
2393
2394         /* Parse packet */
2395
2396         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2397
2398         return offset;
2399 }      
2400
2401 static int SpoolssAddPrinterDriver_r(tvbuff_t *tvb, int offset, 
2402                                      packet_info *pinfo, proto_tree *tree, 
2403                                      char *drep)
2404 {
2405         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2406         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2407
2408         /* Update informational fields */
2409
2410         if (check_col(pinfo->cinfo, COL_INFO))
2411                 col_set_str(pinfo->cinfo, COL_INFO, "AddPrinterDriver response");
2412
2413         if (dcv->req_frame != -1)
2414                 proto_tree_add_text(tree, tvb, offset, 0, 
2415                                     "Request in frame %d", dcv->req_frame);
2416
2417         /* Parse packet */
2418
2419         offset = prs_werror(tvb, offset, pinfo, tree, NULL);    
2420
2421         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2422
2423         return offset;
2424 }      
2425
2426 /*
2427  * FORM_1
2428  */
2429
2430 static gint ett_FORM_1 = -1;
2431
2432 static int prs_FORM_1(tvbuff_t *tvb, int offset, packet_info *pinfo,
2433                       proto_tree *tree, GList **dp_list, void **data)
2434 {
2435         proto_item *item;
2436         proto_tree *subtree;
2437         guint32 ptr = 0, flags;
2438
2439         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_1");
2440
2441         subtree = proto_item_add_subtree(item, ett_FORM_1);
2442
2443         offset = prs_ptr(tvb, offset, pinfo, subtree, &ptr, "Name");
2444
2445         if (ptr)
2446                 defer_ptr(dp_list, prs_UNISTR2_dp, subtree);
2447
2448         offset = prs_uint32(tvb, offset, pinfo, subtree, &flags, NULL);
2449
2450         proto_tree_add_text(subtree, tvb, offset - 4, 4, "Flags: %s",
2451                             val_to_str(flags, form_type_vals, "Unknown type"));
2452
2453         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Unknown");
2454
2455         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Width");
2456
2457         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, "Height");
2458
2459         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2460                             "Left margin");
2461
2462         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2463                             "Top margin");
2464
2465         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2466                             "Horizontal imageable length");
2467
2468         offset = prs_uint32(tvb, offset, pinfo, subtree, NULL, 
2469                             "Vertical imageable length");
2470
2471         return offset;
2472 }
2473
2474 /*
2475  * FORM_CTR
2476  */
2477
2478 static gint ett_FORM_CTR = -1;
2479
2480 static int prs_FORM_CTR(tvbuff_t *tvb, int offset, packet_info *pinfo,
2481                     proto_tree *tree, GList **dp_list, void **data)
2482 {
2483         proto_item *item;
2484         proto_tree *subtree;
2485         guint32 level;
2486
2487         item = proto_tree_add_text(tree, tvb, offset, 0, "FORM_CTR");
2488
2489         subtree = proto_item_add_subtree(item, ett_FORM_CTR);
2490
2491         offset = prs_uint32(tvb, offset, pinfo, subtree, &level, "Level");
2492
2493         switch(level) {
2494         case 1:
2495                 offset = prs_struct_and_referents(tvb, offset, pinfo, subtree,
2496                                                   prs_FORM_1, NULL, NULL);
2497                 break;
2498         default:
2499                 proto_tree_add_text(subtree, tvb, offset, 0,
2500                                     "[Unimplemented info level %d]", level);
2501                 break;
2502         }
2503
2504         return offset;
2505 }
2506
2507 /*
2508  * AddForm
2509  */
2510
2511 static int SpoolssAddForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2512                             proto_tree *tree, char *drep)
2513 {
2514         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2515         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2516         const guint8 *policy_hnd;
2517         guint32 level;
2518
2519         /* Update informational fields */
2520
2521         if (check_col(pinfo->cinfo, COL_INFO))
2522                 col_set_str(pinfo->cinfo, COL_INFO, "AddForm request");
2523
2524         if (dcv->rep_frame != -1)
2525                 proto_tree_add_text(tree, tvb, offset, 0, 
2526                                     "Response in frame %d", dcv->rep_frame);
2527
2528         /* Parse packet */
2529
2530         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2531
2532         display_pol(tree, tvb, offset - 20, policy_hnd);
2533
2534         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); 
2535
2536         if (check_col(pinfo->cinfo, COL_INFO))
2537                 col_append_fstr(pinfo->cinfo, COL_INFO, ", level %d", level);
2538
2539         /* Store info level to match with response packet */
2540
2541         dcv->private_data = (void *)level;
2542
2543         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2544                                           prs_FORM_CTR, NULL, NULL);
2545
2546         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2547
2548         return offset;
2549 }       
2550
2551 static int SpoolssAddForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2552                             proto_tree *tree, char *drep)
2553 {
2554         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2555         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2556
2557         /* Update informational fields */
2558
2559         if (check_col(pinfo->cinfo, COL_INFO))
2560                 col_set_str(pinfo->cinfo, COL_INFO, "AddForm response");
2561
2562         if (dcv->req_frame != -1)
2563                 proto_tree_add_text(tree, tvb, offset, 0, 
2564                                     "Request in frame %d", dcv->req_frame);
2565
2566         /* Parse packet */
2567
2568         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2569
2570         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2571
2572         return offset;
2573 }      
2574
2575 /*
2576  * DeleteForm
2577  */
2578
2579 static int SpoolssDeleteForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2580                                proto_tree *tree, char *drep)
2581 {
2582         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2583         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2584         const guint8 *policy_hnd;
2585         char *form_name;
2586
2587         /* Update informational fields */
2588
2589         if (check_col(pinfo->cinfo, COL_INFO))
2590                 col_set_str(pinfo->cinfo, COL_INFO, "DeleteForm request");
2591
2592         if (dcv->rep_frame != -1)
2593                 proto_tree_add_text(tree, tvb, offset, 0, 
2594                                     "Response in frame %d", dcv->rep_frame);
2595
2596         /* Parse packet */
2597
2598         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2599
2600         display_pol(tree, tvb, offset - 20, policy_hnd);
2601
2602         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2603                                           prs_UNISTR2_dp, (void **)&form_name,
2604                                           NULL);
2605
2606         if (check_col(pinfo->cinfo, COL_INFO))
2607                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", form_name);
2608
2609         g_free(form_name);
2610
2611         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2612
2613         return offset;
2614 }       
2615
2616 static int SpoolssDeleteForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2617                             proto_tree *tree, char *drep)
2618 {
2619         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2620         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2621
2622         /* Update informational fields */
2623
2624         if (check_col(pinfo->cinfo, COL_INFO))
2625                 col_set_str(pinfo->cinfo, COL_INFO, "DeleteForm response");
2626
2627         if (dcv->req_frame != -1)
2628                 proto_tree_add_text(tree, tvb, offset, 0, 
2629                                     "Request in frame %d", dcv->req_frame);
2630
2631         /* Parse packet */
2632
2633         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2634
2635         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2636
2637         return offset;
2638 }       
2639
2640 /*
2641  * SetForm
2642  */
2643
2644 static int SpoolssSetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2645                             proto_tree *tree, char *drep)
2646 {
2647         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2648         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2649         const guint8 *policy_hnd;
2650         guint32 level;
2651         char *form_name;
2652
2653         /* Update informational fields */
2654
2655         if (check_col(pinfo->cinfo, COL_INFO))
2656                 col_set_str(pinfo->cinfo, COL_INFO, "SetForm request");
2657
2658         if (dcv->rep_frame != -1)
2659                 proto_tree_add_text(tree, tvb, offset, 0, 
2660                                     "Response in frame %d", dcv->rep_frame);
2661
2662         /* Parse packet */
2663
2664         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2665
2666         display_pol(tree, tvb, offset - 20, policy_hnd);
2667
2668         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2669                                           prs_UNISTR2_dp, (void **)&form_name,
2670                                           NULL);        
2671
2672         CLEANUP_PUSH(g_free, form_name);
2673
2674         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level"); 
2675
2676         if (check_col(pinfo->cinfo, COL_INFO))
2677                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, level %d", 
2678                                 form_name, level);
2679
2680         CLEANUP_CALL_AND_POP;
2681
2682         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2683                                           prs_FORM_CTR, NULL, NULL);
2684
2685         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2686
2687         return offset;
2688 }       
2689
2690 static int SpoolssSetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2691                             proto_tree *tree, char *drep)
2692 {
2693         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2694         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2695         proto_item *info_item;
2696
2697         /* Update informational fields */
2698
2699         if (check_col(pinfo->cinfo, COL_INFO))
2700                 col_set_str(pinfo->cinfo, COL_INFO, "SetForm response");
2701
2702         if (dcv->req_frame != -1)
2703                 proto_tree_add_text(tree, tvb, offset, 0, 
2704                                     "Request in frame %d", dcv->req_frame);
2705
2706         /* Parse packet */
2707
2708         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2709
2710         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2711
2712         return offset;
2713 }      
2714
2715 /*
2716  * GetForm
2717  */
2718
2719 static int SpoolssGetForm_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2720                             proto_tree *tree, char *drep)
2721 {
2722         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2723         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2724         guint32 level;
2725         const guint8 *policy_hnd;
2726         char *form_name;
2727
2728         /* Update informational fields */
2729
2730         if (check_col(pinfo->cinfo, COL_INFO))
2731                 col_set_str(pinfo->cinfo, COL_INFO, "GetForm request");
2732
2733         if (dcv->rep_frame != -1)
2734                 proto_tree_add_text(tree, tvb, offset, 0, 
2735                                     "Response in frame %d", dcv->rep_frame);
2736
2737         /* Parse packet */
2738
2739         offset = prs_policy_hnd(tvb, offset, pinfo, NULL, &policy_hnd);
2740
2741         display_pol(tree, tvb, offset - 20, policy_hnd);
2742
2743         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2744                                           prs_UNISTR2_dp, (void **)&form_name,
2745                                           NULL);        
2746
2747         CLEANUP_PUSH(g_free, form_name);
2748
2749         offset = prs_uint32(tvb, offset, pinfo, tree, &level, "Level");
2750
2751         dcv->private_data = (void *)level;
2752
2753         if (check_col(pinfo->cinfo, COL_INFO))
2754                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, level %d",
2755                                 form_name, level);
2756
2757         CLEANUP_CALL_AND_POP;
2758
2759         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2760                                           prs_BUFFER, NULL, NULL);
2761
2762         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Offered");
2763
2764         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2765
2766         return offset;
2767 }       
2768
2769 static int SpoolssGetForm_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2770                             proto_tree *tree, char *drep)
2771 {
2772         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2773         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2774         void **data_list;
2775         struct BUFFER_DATA *bd = NULL;
2776
2777         /* Update informational fields */
2778
2779         if (check_col(pinfo->cinfo, COL_INFO))
2780                 col_set_str(pinfo->cinfo, COL_INFO, "GetForm response");
2781
2782         if (dcv->req_frame != -1)
2783                 proto_tree_add_text(tree, tvb, offset, 0, 
2784                                     "Request in frame %d", dcv->req_frame);
2785
2786         /* Parse packet */
2787
2788         offset = prs_struct_and_referents(tvb, offset, pinfo, tree, 
2789                                           prs_BUFFER, NULL, &data_list);
2790
2791         offset = prs_uint32(tvb, offset, pinfo, tree, NULL, "Needed");
2792
2793         if (data_list)
2794                 bd = (struct BUFFER_DATA *)data_list[0];
2795
2796         CLEANUP_PUSH(g_free, bd);
2797
2798         if (bd && bd->tree) {
2799                 guint32 level = (guint32)dcv->private_data;
2800
2801                 switch(level) {
2802                 case 1: {
2803                         int struct_start = bd->offset;
2804                         GList *dp_list = NULL;
2805
2806                         bd->offset = prs_FORM_REL(
2807                                 bd->tvb, bd->offset, pinfo, bd->tree, 
2808                                 struct_start, &dp_list, NULL);
2809                         break;
2810                 }
2811                 default:
2812                         proto_tree_add_text(
2813                                 bd->tree, bd->tvb, bd->offset, 0, 
2814                                 "[Unknown info level %d]", level);
2815                         break;
2816                 }
2817
2818         }
2819
2820         CLEANUP_CALL_AND_POP;
2821
2822         offset = prs_werror(tvb, offset, pinfo, tree, NULL);
2823
2824         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2825
2826         return offset;
2827 }       
2828
2829 /* A generic reply function that just parses the status code.  Useful for
2830    unimplemented dissectors so the status code can be inserted into the
2831    INFO column. */
2832
2833 static int SpoolssGeneric_r(tvbuff_t *tvb, int offset, packet_info *pinfo, 
2834                             proto_tree *tree, char *drep)
2835 {
2836         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2837         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2838         int len = tvb_length(tvb);
2839
2840         proto_tree_add_text(tree, tvb, offset, 0, 
2841                             "[Unimplemented dissector: SPOOLSS]");
2842
2843         if (dcv->req_frame != -1)
2844                 proto_tree_add_text(tree, tvb, offset, 0, 
2845                                     "Request in frame %d", dcv->req_frame);
2846
2847         prs_werror(tvb, len - 4, pinfo, tree, NULL);
2848
2849         return offset;
2850 }
2851
2852
2853
2854 #if 0
2855
2856 /* Templates for new subdissectors */
2857
2858 /*
2859  * FOO
2860  */
2861
2862 static int SpoolssFoo_q(tvbuff_t *tvb, int offset, packet_info *pinfo,
2863                         proto_tree *tree, char *drep)
2864 {
2865         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2866         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2867
2868         /* Update informational fields */
2869
2870         if (check_col(pinfo->cinfo, COL_INFO))
2871                 col_set_str(pinfo->cinfo, COL_INFO, "Foo request");
2872
2873         if (dcv->rep_frame != -1)
2874                 proto_tree_add_text(tree, tvb, offset, 0, 
2875                                     "Response in frame %d", dcv->rep_frame);
2876
2877         /* Parse packet */
2878
2879         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2880
2881         return offset;
2882 }       
2883
2884 static int SpoolssFoo_r(tvbuff_t *tvb, int offset, packet_info *pinfo,
2885                         proto_tree *tree, char *drep)
2886 {
2887         dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
2888         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2889
2890         /* Update informational fields */
2891
2892         if (check_col(pinfo->cinfo, COL_INFO))
2893                 col_set_str(pinfo->cinfo, COL_INFO, "Foo response");
2894
2895         if (dcv->req_frame != -1)
2896                 proto_tree_add_text(tree, tvb, offset, 0, 
2897                                     "Request in frame %d", dcv->req_frame);
2898
2899         /* Parse packet */
2900
2901         dcerpc_smb_check_long_frame(tvb, offset, pinfo, tree);
2902
2903         return offset;
2904 }       
2905
2906 #endif
2907
2908 /*
2909  * List of subdissectors for this pipe.
2910  */
2911
2912 static dcerpc_sub_dissector dcerpc_spoolss_dissectors[] = {
2913         { SPOOLSS_ENUMPRINTERS, "SPOOLSS_ENUMPRINTERS", 
2914           SpoolssEnumPrinters_q, SpoolssEnumPrinters_r },
2915         { SPOOLSS_OPENPRINTER, "SPOOLSS_OPENPRINTER", NULL, SpoolssGeneric_r },
2916         { SPOOLSS_SETJOB, "SPOOLSS_SETJOB", NULL, SpoolssGeneric_r },
2917         { SPOOLSS_GETJOB, "SPOOLSS_GETJOB", NULL, SpoolssGeneric_r },
2918         { SPOOLSS_ENUMJOBS, "SPOOLSS_ENUMJOBS", NULL, SpoolssGeneric_r },
2919         { SPOOLSS_ADDPRINTER, "SPOOLSS_ADDPRINTER", NULL, SpoolssGeneric_r },
2920         { SPOOLSS_DELETEPRINTER, "SPOOLSS_DELETEPRINTER", 
2921           SpoolssDeletePrinter_q, SpoolssDeletePrinter_r },
2922         { SPOOLSS_SETPRINTER, "SPOOLSS_SETPRINTER", 
2923           SpoolssSetPrinter_q, SpoolssSetPrinter_r },
2924         { SPOOLSS_GETPRINTER, "SPOOLSS_GETPRINTER", 
2925           SpoolssGetPrinter_q, SpoolssGetPrinter_r },
2926         { SPOOLSS_ADDPRINTERDRIVER, "SPOOLSS_ADDPRINTERDRIVER", 
2927           NULL, SpoolssAddPrinterDriver_r },
2928         { SPOOLSS_ENUMPRINTERDRIVERS, "SPOOLSS_ENUMPRINTERDRIVERS", NULL, 
2929           SpoolssGeneric_r },
2930         { SPOOLSS_GETPRINTERDRIVER, "SPOOLSS_GETPRINTERDRIVER", NULL, 
2931           SpoolssGeneric_r },
2932         { SPOOLSS_GETPRINTERDRIVERDIRECTORY, 
2933           "SPOOLSS_GETPRINTERDRIVERDIRECTORY", NULL, SpoolssGeneric_r },
2934         { SPOOLSS_DELETEPRINTERDRIVER, "SPOOLSS_DELETEPRINTERDRIVER", NULL, 
2935           SpoolssGeneric_r },
2936         { SPOOLSS_ADDPRINTPROCESSOR, "SPOOLSS_ADDPRINTPROCESSOR", NULL, 
2937           SpoolssGeneric_r },
2938         { SPOOLSS_ENUMPRINTPROCESSORS, "SPOOLSS_ENUMPRINTPROCESSORS", NULL, 
2939           SpoolssGeneric_r },
2940         { SPOOLSS_GETPRINTPROCESSORDIRECTORY,
2941           "SPOOLSS_GETPRINTPROCESSORDIRECTORY", NULL, SpoolssGeneric_r },
2942         { SPOOLSS_STARTDOCPRINTER, "SPOOLSS_STARTDOCPRINTER", NULL, 
2943           SpoolssGeneric_r },
2944         { SPOOLSS_STARTPAGEPRINTER, "SPOOLSS_STARTPAGEPRINTER", NULL, 
2945           SpoolssGeneric_r },
2946         { SPOOLSS_WRITEPRINTER, "SPOOLSS_WRITEPRINTER", NULL, 
2947           SpoolssGeneric_r },
2948         { SPOOLSS_ENDPAGEPRINTER, "SPOOLSS_ENDPAGEPRINTER", NULL, 
2949           SpoolssGeneric_r },
2950         { SPOOLSS_ABORTPRINTER, "SPOOLSS_ABORTPRINTER", NULL, 
2951           SpoolssGeneric_r },
2952         { SPOOLSS_READPRINTER,"SPOOLSS_READPRINTER", NULL, SpoolssGeneric_r },
2953         { SPOOLSS_ENDDOCPRINTER, "SPOOLSS_ENDDOCPRINTER", NULL, 
2954           SpoolssGeneric_r },
2955         { SPOOLSS_ADDJOB, "SPOOLSS_ADDJOB", NULL, SpoolssGeneric_r },
2956         { SPOOLSS_SCHEDULEJOB, "SPOOLSS_SCHEDULEJOB", NULL, SpoolssGeneric_r },
2957         { SPOOLSS_GETPRINTERDATA, "SPOOLSS_GETPRINTERDATA", 
2958           SpoolssGetPrinterData_q, SpoolssGetPrinterData_r },   
2959         { SPOOLSS_SETPRINTERDATA, "SPOOLSS_SETPRINTERDATA", 
2960           SpoolssSetPrinterData_q, SpoolssSetPrinterData_r },
2961         { SPOOLSS_WAITFORPRINTERCHANGE,"SPOOLSS_WAITFORPRINTERCHANGE", NULL, 
2962           SpoolssGeneric_r },
2963         { SPOOLSS_CLOSEPRINTER, "SPOOLSS_CLOSEPRINTER", 
2964           SpoolssClosePrinter_q, SpoolssClosePrinter_r },
2965         { SPOOLSS_ADDFORM, "SPOOLSS_ADDFORM", 
2966           SpoolssAddForm_q, SpoolssAddForm_r },
2967         { SPOOLSS_DELETEFORM, "SPOOLSS_DELETEFORM", 
2968           SpoolssDeleteForm_q, SpoolssDeleteForm_r },
2969         { SPOOLSS_GETFORM, "SPOOLSS_GETFORM", 
2970           SpoolssGetForm_q, SpoolssGetForm_r },
2971         { SPOOLSS_SETFORM, "SPOOLSS_SETFORM", 
2972           SpoolssSetForm_q, SpoolssSetForm_r },
2973         { SPOOLSS_ENUMFORMS, "SPOOLSS_ENUMFORMS", 
2974           SpoolssEnumForms_q, SpoolssEnumForms_r },
2975         { SPOOLSS_ENUMPORTS, "SPOOLSS_ENUMPORTS", NULL, SpoolssGeneric_r },
2976         { SPOOLSS_ENUMMONITORS, "SPOOLSS_ENUMMONITORS", NULL, 
2977           SpoolssGeneric_r },
2978         { SPOOLSS_ADDPORT,"SPOOLSS_ADDPORT", NULL, SpoolssGeneric_r },
2979         { SPOOLSS_CONFIGUREPORT,"SPOOLSS_CONFIGUREPORT", NULL, 
2980           SpoolssGeneric_r },
2981         { SPOOLSS_DELETEPORT,"SPOOLSS_DELETEPORT", NULL, SpoolssGeneric_r },
2982         { SPOOLSS_CREATEPRINTERIC,"SPOOLSS_CREATEPRINTERIC", NULL, 
2983           SpoolssGeneric_r },
2984         { SPOOLSS_PLAYGDISCRIPTONPRINTERIC, "SPOOLSS_PLAYGDISCRIPTONPRINTERIC",
2985           NULL, SpoolssGeneric_r },
2986         { SPOOLSS_DELETEPRINTERIC,"SPOOLSS_DELETEPRINTERIC", NULL, 
2987           SpoolssGeneric_r },
2988         { SPOOLSS_ADDPRINTERCONNECTION,"SPOOLSS_ADDPRINTERCONNECTION", NULL, 
2989           SpoolssGeneric_r },
2990         { SPOOLSS_DELETEPRINTERCONNECTION,"SPOOLSS_DELETEPRINTERCONNECTION", 
2991           NULL, SpoolssGeneric_r },
2992         { SPOOLSS_PRINTERMESSAGEBOX,"SPOOLSS_PRINTERMESSAGEBOX", NULL, 
2993           SpoolssGeneric_r },
2994         { SPOOLSS_ADDMONITOR,"SPOOLSS_ADDMONITOR", NULL, 
2995           SpoolssGeneric_r },
2996         { SPOOLSS_DELETEMONITOR,"SPOOLSS_DELETEMONITOR", NULL, 
2997           SpoolssGeneric_r },
2998         { SPOOLSS_DELETEPRINTPROCESSOR,"SPOOLSS_DELETEPRINTPROCESSOR", NULL, 
2999           SpoolssGeneric_r },
3000         { SPOOLSS_ADDPRINTPROVIDOR,"SPOOLSS_ADDPRINTPROVIDER", NULL, 
3001           SpoolssGeneric_r },
3002         { SPOOLSS_DELETEPRINTPROVIDOR,"SPOOLSS_DELETEPRINTPROVIDER", NULL, 
3003           SpoolssGeneric_r },
3004         { SPOOLSS_ENUMPRINTPROCDATATYPES, "SPOOLSS_ENUMPRINTPROCDATATYPES", 
3005           NULL, SpoolssGeneric_r },
3006         { SPOOLSS_RESETPRINTER,"SPOOLSS_RESETPRINTER", NULL, 
3007           SpoolssGeneric_r },
3008         { SPOOLSS_GETPRINTERDRIVER2, "SPOOLSS_GETPRINTERDRIVER2", NULL, 
3009           SpoolssGeneric_r },
3010         { SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION,
3011           "SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION", NULL, 
3012           SpoolssGeneric_r },
3013         { SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION,
3014           "SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION", NULL, 
3015           SpoolssGeneric_r },
3016         { SPOOLSS_FCPN, "SPOOLSS_FCPN", NULL, SpoolssGeneric_r },
3017         { SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD,
3018           "SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD", NULL, 
3019           SpoolssGeneric_r },
3020         { SPOOLSS_REPLYOPENPRINTER, "SPOOLSS_REPLYOPENPRINTER",
3021           SpoolssReplyOpenPrinter_q, SpoolssReplyOpenPrinter_r },
3022         { SPOOLSS_ROUTERREPLYPRINTER,"SPOOLSS_ROUTERREPLYPRINTER", NULL, 
3023           SpoolssGeneric_r },
3024         { SPOOLSS_REPLYCLOSEPRINTER, "SPOOLSS_REPLYCLOSEPRINTER", NULL, 
3025           SpoolssGeneric_r },
3026         { SPOOLSS_ADDPORTEX,"SPOOLSS_ADDPORTEX", NULL, SpoolssGeneric_r },
3027         { SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION,
3028           "SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION", NULL, 
3029           SpoolssGeneric_r },
3030         { SPOOLSS_SPOOLERINIT,"SPOOLSS_SPOOLERINIT", NULL, SpoolssGeneric_r },
3031         { SPOOLSS_RESETPRINTEREX,"SPOOLSS_RESETPRINTEREX", NULL, 
3032           SpoolssGeneric_r },
3033         { SPOOLSS_RFFPCNEX, "SPOOLSS_RFFPCNEX",
3034           SpoolssRFFPCNEX_q, SpoolssRFFPCNEX_r },
3035         { SPOOLSS_RRPCN, "SPOOLSS_RRPCN", NULL, SpoolssGeneric_r },
3036         { SPOOLSS_RFNPCNEX, "SPOOLSS_RFNPCNEX", NULL, SpoolssGeneric_r },
3037         { SPOOLSS_OPENPRINTEREX, "SPOOLSS_OPENPRINTEREX", 
3038           SpoolssOpenPrinterEx_q, SpoolssOpenPrinterEx_r },
3039         { SPOOLSS_ADDPRINTEREX, "SPOOLSS_ADDPRINTEREX", 
3040           NULL, SpoolssAddPrinterEx_r },
3041         { SPOOLSS_ENUMPRINTERDATA, "SPOOLSS_ENUMPRINTERDATA", 
3042           SpoolssEnumPrinterData_q, SpoolssEnumPrinterData_r },
3043         { SPOOLSS_DELETEPRINTERDATA, "SPOOLSS_DELETEPRINTERDATA", NULL, 
3044           SpoolssGeneric_r },
3045         { SPOOLSS_GETPRINTERDATAEX, "SPOOLSS_GETPRINTERDATAEX", 
3046           SpoolssGetPrinterDataEx_q, SpoolssGetPrinterDataEx_r },
3047         { SPOOLSS_SETPRINTERDATAEX, "SPOOLSS_SETPRINTERDATAEX", 
3048           SpoolssSetPrinterDataEx_q, SpoolssSetPrinterDataEx_r },
3049         { SPOOLSS_ENUMPRINTERDATAEX,"SPOOLSS_ENUMPRINTERDATAEX", NULL, 
3050           SpoolssGeneric_r },
3051         { SPOOLSS_ENUMPRINTERKEY,"SPOOLSS_ENUMPRINTERKEY", NULL, 
3052           SpoolssGeneric_r },
3053         { SPOOLSS_DELETEPRINTERDATAEX,"SPOOLSS_DELETEPRINTERDATAEX", NULL, 
3054           SpoolssGeneric_r },
3055         { SPOOLSS_DELETEPRINTERDRIVEREX,"SPOOLSS_DELETEPRINTERDRIVEREX", NULL,
3056           SpoolssGeneric_r },
3057         { SPOOLSS_ADDPRINTERDRIVEREX,"SPOOLSS_ADDPRINTERDRIVEREX", NULL, 
3058           SpoolssGeneric_r },
3059
3060         { 0, NULL, NULL, NULL },
3061 };
3062
3063 /*
3064  * Dissector initialisation function
3065  */
3066
3067 /* Protocol registration */
3068
3069 static int proto_dcerpc_spoolss = -1;
3070 static gint ett_dcerpc_spoolss = -1;
3071
3072 void 
3073 proto_register_dcerpc_spoolss(void)
3074 {
3075         static gint *ett[] = {
3076                 &ett_dcerpc_spoolss,
3077                 &ett_NOTIFY_OPTION_ARRAY,
3078                 &ett_NOTIFY_OPTION_CTR,
3079                 &ett_NOTIFY_OPTION,
3080                 &ett_NOTIFY_OPTION_DATA,
3081                 &ett_PRINTER_DEFAULT,
3082                 &ett_DEVMODE_CTR,
3083                 &ett_DEVMODE,
3084                 &ett_USER_LEVEL,
3085                 &ett_USER_LEVEL_1,
3086                 &ett_BUFFER,
3087                 &ett_BUFFER_DATA,
3088                 &ett_BUFFER_DATA_BUFFER,
3089                 &ett_UNISTR2,
3090                 &ett_SPOOL_PRINTER_INFO_LEVEL,
3091                 &ett_PRINTER_INFO_0,
3092                 &ett_PRINTER_INFO_1,
3093                 &ett_PRINTER_INFO_2,
3094                 &ett_PRINTER_INFO_3,
3095                 &ett_RELSTR,
3096                 &ett_POLICY_HND,
3097                 &ett_FORM_REL,
3098                 &ett_FORM_CTR,
3099                 &ett_FORM_1,
3100         };
3101
3102         proto_dcerpc_spoolss = proto_register_protocol(
3103                 "Microsoft Spool Subsystem", "SPOOLSS", "spoolss");
3104
3105         proto_register_subtree_array(ett, array_length(ett));
3106 }
3107
3108 /* Protocol handoff */
3109
3110 static e_uuid_t uuid_dcerpc_spoolss = {
3111         0x12345678, 0x1234, 0xabcd,
3112         { 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
3113 };
3114
3115 static guint16 ver_dcerpc_spoolss = 1;
3116
3117 void
3118 proto_reg_handoff_dcerpc_spoolss(void)
3119 {
3120         /* Register protocol as dcerpc */
3121
3122         dcerpc_init_uuid(proto_dcerpc_spoolss, ett_dcerpc_spoolss, 
3123                          &uuid_dcerpc_spoolss, ver_dcerpc_spoolss, 
3124                          dcerpc_spoolss_dissectors);
3125 }