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