char *drep -> guint8 *drep
[obnox/wireshark/wip.git] / packet-dcerpc-nt.c
1 /* packet-dcerpc-nt.c
2  * Routines for DCERPC over SMB packet disassembly
3  * Copyright 2001-2003, Tim Potter <tpot@samba.org>
4  *
5  * $Id: packet-dcerpc-nt.c,v 1.78 2004/01/19 20:10:35 jmayer 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 <epan/packet.h>
32 #include "packet-dcerpc.h"
33 #include "packet-dcerpc-nt.h"
34 #include "smb.h"
35 #include "packet-smb-common.h" /* for dissect_smb_64bit_time() */
36
37 /*
38  * This file contains helper routines that are used by the DCERPC over SMB
39  * dissectors for ethereal.
40  */
41
42 /*
43  * Used by several dissectors.
44  */
45 const value_string platform_id_vals[] = {
46         { 300, "DOS" },
47         { 400, "OS/2" },
48         { 500, "Windows NT" },
49         { 600, "OSF" },
50         { 700, "VMS" },
51         { 0,   NULL }
52 };
53
54 /* Parse some common RPC structures */
55
56 gint ett_nt_unicode_string = -1; /* FIXME: make static */
57
58 /* Dissect a counted string as a callback to dissect_ndr_pointer_cb() */
59
60 static int hf_nt_cs_len = -1;
61 static int hf_nt_cs_size = -1;
62
63 int
64 dissect_ndr_counted_string_cb(tvbuff_t *tvb, int offset,
65                               packet_info *pinfo, proto_tree *tree,
66                               guint8 *drep, int hf_index,
67                               dcerpc_callback_fnct_t *callback,
68                               void *callback_args)
69 {
70         dcerpc_info *di = pinfo->private_data;
71         guint16 len, size;
72
73         /* Structure starts with short, but is aligned for longs */
74
75         ALIGN_TO_4_BYTES;
76
77         if (di->conformant_run)
78                 return offset;
79         
80         /* 
81            struct {
82                short len;
83                short size;
84                [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
85            } UNICODE_STRING;
86
87          */
88
89         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, drep,
90                         hf_nt_cs_len, &len);
91
92         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, drep,
93                         hf_nt_cs_size, &size);  
94
95         offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, tree, drep,
96                         dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE,
97                         "Character Array", hf_index, callback, callback_args);
98
99         return offset;
100 }
101
102 static gint ett_nt_counted_string = -1;
103
104 static int
105 dissect_ndr_counted_string_helper(tvbuff_t *tvb, int offset,
106                                   packet_info *pinfo, proto_tree *tree,
107                                   guint8 *drep, int hf_index, int levels,
108                                   gboolean add_subtree)
109 {
110         proto_item *item;
111         proto_tree *subtree = tree;
112
113         if (add_subtree) {
114
115                 item = proto_tree_add_text(
116                         tree, tvb, offset, 0, 
117                         proto_registrar_get_name(hf_index));
118
119                 subtree = proto_item_add_subtree(item, ett_nt_counted_string);
120         }
121
122         /*
123          * Add 2 levels, so that the string gets attached to the
124          * "Character Array" top-level item and to the top-level item
125          * added above.
126          */
127         return dissect_ndr_counted_string_cb(
128                 tvb, offset, pinfo, subtree, drep, hf_index,
129                 cb_wstr_postprocess, GINT_TO_POINTER(2 + levels));
130 }
131
132 /* Dissect a counted string in-line. */
133
134 int
135 dissect_ndr_counted_string(tvbuff_t *tvb, int offset,
136                            packet_info *pinfo, proto_tree *tree,
137                            guint8 *drep, int hf_index, int levels)
138 {
139         return dissect_ndr_counted_string_helper(
140                 tvb, offset, pinfo, tree, drep, hf_index, levels, TRUE);
141 }
142
143 /* Dissect a counted string as a callback to dissect_ndr_pointer().
144    This doesn't add a adds a proto item and subtreee for the string as
145    the pointer dissection already creates one. */
146
147 int
148 dissect_ndr_counted_string_ptr(tvbuff_t *tvb, int offset,
149                                packet_info *pinfo, proto_tree *tree,
150                                guint8 *drep)
151 {
152         dcerpc_info *di = pinfo->private_data;
153
154         return dissect_ndr_counted_string_helper(
155                 tvb, offset, pinfo, tree, drep, di->hf_index, 0, FALSE);
156 }
157
158 /* Dissect a counted byte_array as a callback to dissect_ndr_pointer_cb() */
159
160 static gint ett_nt_counted_byte_array = -1;
161
162 /* Dissect a counted byte array in-line. */
163
164 int
165 dissect_ndr_counted_byte_array_cb(tvbuff_t *tvb, int offset,
166                                   packet_info *pinfo, proto_tree *tree,
167                                   guint8 *drep, int hf_index,
168                                   dcerpc_callback_fnct_t *callback,
169                                   void *callback_args)
170 {
171         dcerpc_info *di = pinfo->private_data;
172         proto_item *item;
173         proto_tree *subtree;
174         guint16 len, size;
175
176         /* Structure starts with short, but is aligned for longs */
177
178         ALIGN_TO_4_BYTES;
179
180         if (di->conformant_run)
181                 return offset;
182
183         item = proto_tree_add_text(tree, tvb, offset, 0, 
184                 proto_registrar_get_name(hf_index));
185
186         subtree = proto_item_add_subtree(item, ett_nt_counted_byte_array);
187         
188         /* 
189            struct {
190                short len;
191                short size;
192                [size_is(size), length_is(len), ptr] unsigned char *string;
193            } WHATEVER_THIS_IS_CALLED;
194
195          */
196
197         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep,
198                         hf_nt_cs_len, &len);
199
200         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep,
201                         hf_nt_cs_size, &size);  
202
203         offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, subtree, drep,
204                         dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
205                         "Byte Array", hf_index, callback, callback_args);
206
207         return offset;
208 }
209
210 int
211 dissect_ndr_counted_byte_array(tvbuff_t *tvb, int offset,
212                                packet_info *pinfo, proto_tree *tree,
213                                guint8 *drep, int hf_index)
214 {
215         return dissect_ndr_counted_byte_array_cb(
216                 tvb, offset, pinfo, tree, drep, hf_index, NULL, NULL);
217 }
218
219 /* This function is used to dissect a DCERPC encoded 64 bit time value.
220    XXX it should be fixed both here and in dissect_smb_64bit_time so
221    it can handle both BIG and LITTLE endian encodings
222  */
223 int
224 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
225                         packet_info *pinfo, proto_tree *tree,
226                         guint8 *drep _U_, int hf_index)
227 {
228         dcerpc_info *di;
229
230         di=pinfo->private_data;
231         if(di->conformant_run){
232                 /*just a run to handle conformant arrays, nothing to dissect */
233                 return offset;
234         }
235
236         ALIGN_TO_4_BYTES;
237
238         offset = dissect_smb_64bit_time(tvb, tree, offset, hf_index);
239         return offset;
240 }
241
242 /* Define this symbol to display warnings about request/response and
243    policy handle hash table collisions.  This happens when a packet with
244    the same conversation, smb fid and dcerpc call id occurs.  I think this
245    is due to a bug in the dcerpc/smb fragment reassembly code. */
246
247 #undef DEBUG_HASH_COLL
248
249 /*
250  * Policy handle hashing.
251  *
252  * We hash based on the policy handle value; the items in the hash table
253  * are lists of policy handle information about one or more policy
254  * handles with that value.  We have multiple values in case a given
255  * policy handle is opened in frame N, closed in frame M, and re-opened
256  * in frame O, where N < M < O.
257  *
258  * XXX - we really should also use a DCE RPC conversation/session handle
259  * of some sort, in case two separate sessions have the same handle
260  * value.  A transport-layer conversation might not be sufficient, as you
261  * might, for example, have multiple pipes in a single SMB connection,
262  * and you might have the same handle opened and closed separately on
263  * those two pipes.
264  *
265  * The policy handle information has "first frame" and "last frame"
266  * information; the entry should be used when dissecting a given frame
267  * only if that frame is within the interval [first frame,last frame].
268  * The list is sorted by "first frame".
269  *
270  * This doesn't handle the case of a handle being opened in frame N and
271  * re-opened in frame M, where N < M, with no intervening close, but I'm
272  * not sure anything can handle that if it's within the same DCE RPC
273  * session (if it's not, the conversation/session handle would fix that).
274  */
275
276 typedef struct {
277         guint8 policy_hnd[20];
278 } pol_hash_key;
279
280 typedef struct pol_value {
281         struct pol_value *next;          /* Next entry in hash bucket */
282         guint32 open_frame, close_frame; /* Frame numbers for open/close */
283         guint32 first_frame;             /* First frame in which this instance was seen */
284         guint32 last_frame;              /* Last frame in which this instance was seen */
285         char *name;                      /* Name of policy handle */
286 } pol_value;
287
288 typedef struct {
289         pol_value *list;                 /* List of policy handle entries */
290 } pol_hash_value;
291
292 #define POL_HASH_INIT_COUNT 100
293
294 static GHashTable *pol_hash;
295 static GMemChunk *pol_hash_key_chunk;
296 static GMemChunk *pol_value_chunk;
297 static GMemChunk *pol_hash_value_chunk;
298
299 /* Hash function */
300
301 static guint pol_hash_fn(gconstpointer k)
302 {
303         const pol_hash_key *key = (const pol_hash_key *)k;
304
305         /* Bytes 4-7 of the policy handle are a timestamp so should make a
306            reasonable hash value */
307
308         return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
309                 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
310 }
311
312 /* Return true if a policy handle is all zeros */
313
314 static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
315 {
316         static guint8 null_policy_hnd[20];
317
318         return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
319 }
320
321 /* Hash compare function */
322
323 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
324 {
325         const pol_hash_key *key1 = (const pol_hash_key *)k1;
326         const pol_hash_key *key2 = (const pol_hash_key *)k2;
327
328         return memcmp(key1->policy_hnd, key2->policy_hnd,
329                       sizeof(key1->policy_hnd)) == 0;
330 }
331
332 /*
333  * Look up the instance of a policy handle value in whose range of frames
334  * the specified frame falls.
335  */
336 static pol_value *find_pol_handle(e_ctx_hnd *policy_hnd, guint32 frame,
337                                   pol_hash_value **valuep)
338 {
339         pol_hash_key key;
340         pol_value *pol;
341
342         memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
343         if ((*valuep = g_hash_table_lookup(pol_hash, &key))) {
344                 /*
345                  * Look for the first value such that both:
346                  *
347                  *      1) the first frame in which it was seen is
348                  *         <= the specified frame;
349                  *
350                  *      2) the last frame in which it was seen is
351                  *         either unknown (meaning we haven't yet
352                  *         seen a close or another open of the
353                  *         same handle, which is assumed to imply
354                  *         an intervening close that wasn't captured)
355                  *         or is >= the specified frame.
356                  *
357                  * If there's more than one such frame, that's the
358                  * case where a handle is opened in frame N and
359                  * reopened in frame M, with no intervening close;
360                  * there is no right answer for that, so the instance
361                  * opened in frame N is as right as anything else.
362                  */
363                 for (pol = (*valuep)->list; pol != NULL; pol = pol->next) {
364                         if (pol->first_frame <= frame &&
365                             (pol->last_frame == 0 ||
366                              pol->last_frame >= frame))
367                                 break;  /* found one */
368                 }
369                 return pol;
370         } else {
371                 /*
372                  * The handle isn't in the hash table.
373                  */
374                 return NULL;
375         }
376 }
377
378 static void add_pol_handle(e_ctx_hnd *policy_hnd, guint32 frame,
379                            pol_value *pol, pol_hash_value *value)
380 {
381         pol_hash_key *key;
382         pol_value *polprev, *polnext;
383
384         if (value == NULL) {
385                 /*
386                  * There's no hash value; create one, put the new
387                  * value at the beginning of its policy handle list,
388                  * and put the hash value in the policy handle hash
389                  * table.
390                  */
391                 value = g_mem_chunk_alloc(pol_hash_value_chunk);
392                 value->list = pol;
393                 pol->next = NULL;
394                 key = g_mem_chunk_alloc(pol_hash_key_chunk);
395                 memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
396                 g_hash_table_insert(pol_hash, key, value);
397         } else {
398                 /*
399                  * Put the new value in the hash value's policy handle
400                  * list so that it's sorted by the first frame in
401                  * which it appeared.
402                  *
403                  * Search for the first entry whose first frame number
404                  * is greater than the current frame number, if any.
405                  */
406                 for (polnext = value->list, polprev = NULL;
407                     polnext != NULL && polnext->first_frame <= frame;
408                     polprev = polnext, polnext = polnext->next)
409                         ;
410
411                 /*
412                  * "polprev" points to the entry in the list after
413                  * which we should put the new entry; if it's null,
414                  * that means we should put it at the beginning of
415                  * the list.
416                  */
417                 if (polprev == NULL)
418                         value->list = pol;
419                 else
420                         polprev->next = pol;
421                 
422                 /*
423                  * "polnext" points to the entry in the list before
424                  * which we should put the new entry; if it's null,
425                  * that means we should put it at the end of the list.
426                  */
427                 pol->next = polnext;
428         }
429 }
430
431 /* Store the open and close frame numbers of a policy handle */
432
433 void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, packet_info *pinfo,
434                                gboolean is_open, gboolean is_close)
435 {
436         pol_hash_value *value;
437         pol_value *pol;
438
439         /*
440          * By the time the first pass is done, the policy handle database
441          * has been completely constructed.  If we've already seen this
442          * frame, there's nothing to do.
443          */
444         if (pinfo->fd->flags.visited)
445                 return;
446
447         if (is_null_pol(policy_hnd))
448                 return;
449
450         /* Look up existing value */
451         pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
452
453         if (pol != NULL) {
454                 /*
455                  * Update the existing value as appropriate.
456                  */
457                 if (is_open) {
458                         /*
459                          * This is an open; we assume that we missed
460                          * a close of this handle, so we set its
461                          * "last frame" value and act as if we didn't
462                          * see it.
463                          *
464                          * XXX - note that we might be called twice for
465                          * the same operation (see "dissect_pipe_dcerpc()",
466                          * which calls the DCE RPC dissector twice), so we
467                          * must first check to see if this is a handle we
468                          * just filled in.
469                          *
470                          * We check whether this handle's "first frame"
471                          * frame number is this frame and its "last frame
472                          * is 0; if so, this is presumably a duplicate call,
473                          * and we don't do an implicit close.
474                          */
475                         if (pol->first_frame == pinfo->fd->num &&
476                             pol->last_frame == 0)
477                                 return;
478                         pol->last_frame = pinfo->fd->num;
479                         pol = NULL;
480                 } else {
481                         if (is_close) {
482                                 pol->close_frame = pinfo->fd->num;
483                                 pol->last_frame = pinfo->fd->num;
484                         }
485                         return;
486                 }
487         }
488
489         /* Create a new value */
490
491         pol = g_mem_chunk_alloc(pol_value_chunk);
492
493         pol->open_frame = is_open ? pinfo->fd->num : 0;
494         pol->close_frame = is_close ? pinfo->fd->num : 0;
495         pol->first_frame = pinfo->fd->num;
496         pol->last_frame = pol->close_frame;     /* if 0, unknown; if non-0, known */
497
498         pol->name = NULL;
499
500         add_pol_handle(policy_hnd, pinfo->fd->num, pol, value);
501 }
502
503 /* Store a text string with a policy handle */
504
505 void dcerpc_smb_store_pol_name(e_ctx_hnd *policy_hnd, packet_info *pinfo,
506                                char *name)
507 {
508         pol_hash_value *value;
509         pol_value *pol;
510
511         /*
512          * By the time the first pass is done, the policy handle database
513          * has been completely constructed.  If we've already seen this
514          * frame, there's nothing to do.
515          */
516         if (pinfo->fd->flags.visited)
517                 return;
518
519         if (is_null_pol(policy_hnd))
520                 return;
521
522         /* Look up existing value */
523         pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
524
525         if (pol != NULL) {
526                 /*
527                  * This is the first pass; update the existing
528                  * value as appropriate.
529                  */
530                 if (pol->name && name) {
531 #ifdef DEBUG_HASH_COLL
532                         if (strcmp(pol->name, name) != 0)
533                                 g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
534 #endif
535                         free(pol->name);
536                 }
537
538                 pol->name = strdup(name);
539
540                 return;
541         }
542
543         /* Create a new value */
544
545         pol = g_mem_chunk_alloc(pol_value_chunk);
546
547         pol->open_frame = 0;
548         pol->close_frame = 0;
549         pol->first_frame = pinfo->fd->num;
550         pol->last_frame = 0;
551
552         if (name)
553                 pol->name = strdup(name);
554         else
555                 pol->name = strdup("<UNKNOWN>");
556
557         add_pol_handle(policy_hnd, pinfo->fd->num, pol, value);
558 }
559
560 /*
561  * Retrieve a policy handle.
562  *
563  * XXX - should this get an "is_close" argument, and match even closed
564  * policy handles if the call is a close, so we can handle retransmitted
565  * close operations?
566  */
567
568 gboolean dcerpc_smb_fetch_pol(e_ctx_hnd *policy_hnd, char **name,
569                               guint32 *open_frame, guint32 *close_frame,
570                               guint32 cur_frame)
571 {
572         pol_hash_value *value;
573         pol_value *pol;
574
575         /* Prevent uninitialised return vars */
576
577         if (name)
578                 *name = NULL;
579
580         if (open_frame)
581                 *open_frame = 0;
582
583         if (close_frame)
584                 *close_frame = 0;
585
586         /* Look up existing value */
587         pol = find_pol_handle(policy_hnd, cur_frame, &value);
588
589         if (pol) {
590                 if (name)
591                         *name = pol->name;
592
593                 if (open_frame)
594                         *open_frame = pol->open_frame;
595
596                 if (close_frame)
597                         *close_frame = pol->close_frame;
598         }
599
600         return pol != NULL;
601 }
602
603 /* Iterator to free a policy handle key/value pair, and all
604    the policy handle values to which the hash table value
605    points */
606
607 static void free_pol_keyvalue(gpointer key _U_, gpointer value_arg,
608     gpointer user_data _U_)
609 {
610         pol_hash_value *value = (pol_hash_value *)value_arg;
611         pol_value *pol;
612
613         /* Free user data */
614
615         for (pol = value->list; pol != NULL; pol = pol->next) {
616                 free(pol->name);
617                 pol->name = NULL;
618         }
619 }
620
621 /* Initialise policy handle hash */
622
623 static void init_pol_hash(void)
624 {
625         /* Initialise memory chunks */
626
627         if (pol_hash_key_chunk)
628                 g_mem_chunk_destroy(pol_hash_key_chunk);
629
630         pol_hash_key_chunk = g_mem_chunk_new(
631                 "Policy handle hash keys", sizeof(pol_hash_key),
632                 POL_HASH_INIT_COUNT * sizeof(pol_hash_key), G_ALLOC_ONLY);
633
634         if (pol_value_chunk)
635                 g_mem_chunk_destroy(pol_value_chunk);
636
637         pol_value_chunk = g_mem_chunk_new(
638                 "Policy handle values", sizeof(pol_value),
639                 POL_HASH_INIT_COUNT * sizeof(pol_value), G_ALLOC_ONLY);
640
641         if (pol_hash_value_chunk)
642                 g_mem_chunk_destroy(pol_hash_value_chunk);
643
644         pol_hash_value_chunk = g_mem_chunk_new(
645                 "Policy handle hash values", sizeof(pol_hash_value),
646                 POL_HASH_INIT_COUNT * sizeof(pol_hash_value), G_ALLOC_ONLY);
647
648         /* Initialise hash table */
649
650         if (pol_hash) {
651                 g_hash_table_foreach(pol_hash, free_pol_keyvalue, NULL);
652                 g_hash_table_destroy(pol_hash);
653         }
654
655         pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
656 }
657
658 /* Dissect a NT status code */
659
660 int
661 dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
662                  proto_tree *tree, guint8 *drep,
663                  int hfindex, guint32 *pdata)
664 {
665         guint32 status;
666
667         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
668                                     hfindex, &status);
669
670         if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
671                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
672                                 val_to_str(status, NT_errors,
673                                            "Unknown error 0x%08x"));
674         if (pdata)
675                 *pdata = status;
676
677         return offset;
678 }
679
680 /* Dissect a DOS status code */
681
682 int
683 dissect_doserror(tvbuff_t *tvb, gint offset, packet_info *pinfo,
684                proto_tree *tree, guint8 *drep,
685                int hfindex, guint32 *pdata)
686 {
687         guint32 status;
688
689         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
690                                     hfindex, &status);
691
692         if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
693                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
694                                 val_to_str(status, DOS_errors,
695                                            "Unknown error 0x%08x"));
696         if (pdata)
697                 *pdata = status;
698
699         return offset;
700 }
701
702 /* Dissect a NT policy handle */
703
704 static int hf_nt_policy_open_frame = -1;
705 static int hf_nt_policy_close_frame = -1;
706
707 static gint ett_nt_policy_hnd = -1;
708
709 int
710 dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
711                       proto_tree *tree, guint8 *drep, int hfindex,
712                       e_ctx_hnd *pdata, proto_item **pitem,
713                       gboolean is_open, gboolean is_close)
714 {
715         proto_item *item;
716         proto_tree *subtree;
717         e_ctx_hnd hnd;
718         guint32 open_frame = 0, close_frame = 0;
719         char *name;
720         int old_offset = offset;
721         dcerpc_info *di;
722
723         di=pinfo->private_data;
724         if(di->conformant_run){
725                 /*
726                  * just a run to handle conformant arrays, no scalars to
727                  * dissect - and "dissect_ndr_ctx_hnd()" won't return
728                  * a handle, so we can't do the hashing stuff in any
729                  * case
730                  */
731                 return offset;
732         }
733
734         /* Add to proto tree */
735
736         item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
737                                    "Policy Handle");
738
739         subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
740
741         offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, drep,
742                                      hfindex, &hnd);
743
744         /*
745          * Create a new entry for this handle if it's not a null handle
746          * and no entry already exists, and, in any case, set the
747          * open, close, first, and last frame information as appropriate.
748          */
749         dcerpc_smb_store_pol_pkts(&hnd, pinfo, is_open, is_close);
750
751         /* Insert open/close/name information if known */
752
753         if (dcerpc_smb_fetch_pol(&hnd, &name, &open_frame, &close_frame,
754             pinfo->fd->num)) {
755
756                 if (open_frame)
757                         proto_tree_add_uint(
758                                 subtree, hf_nt_policy_open_frame, tvb,
759                                 old_offset, sizeof(e_ctx_hnd), open_frame);
760
761                 if (close_frame)
762                         proto_tree_add_uint(
763                                 subtree, hf_nt_policy_close_frame, tvb,
764                                 old_offset, sizeof(e_ctx_hnd), close_frame);
765
766                 /*
767                  * Don't append the handle name if pitem is null; that's
768                  * an indication that our caller will do so, as we're
769                  * supplying a pointer to the item so that they can do
770                  * so.
771                  */
772                 if (name != NULL && pitem == NULL)
773                         proto_item_append_text(item, ": %s", name);
774         }
775
776         if (pdata)
777                 *pdata = hnd;
778
779         if (pitem)
780                 *pitem = item;
781
782         return offset;
783 }
784
785 /* Some helper routines to dissect a range of uint8 characters.  I don't
786    think these are "official" NDR representations and are probably specific
787    to NT so for the moment they're put here instead of in packet-dcerpc.c
788    and packet-dcerpc-ndr.c. */
789
790 int
791 dissect_dcerpc_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
792                       proto_tree *tree, guint8 *drep, int hfindex,
793                       int length, const guint8 **pdata)
794 {
795     const guint8 *data;
796
797     data = (const guint8 *)tvb_get_ptr(tvb, offset, length);
798
799     if (tree) {
800         proto_tree_add_item (tree, hfindex, tvb, offset, length, (drep[0] & 0x10));
801     }
802
803     if (pdata)
804         *pdata = data;
805
806     return offset + length;
807 }
808
809 int
810 dissect_ndr_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
811                    proto_tree *tree, guint8 *drep,
812                    int hfindex, int length, const guint8 **pdata)
813 {
814     dcerpc_info *di;
815
816     di=pinfo->private_data;
817     if(di->conformant_run){
818       /* just a run to handle conformant arrays, no scalars to dissect */
819       return offset;
820     }
821
822     /* no alignment needed */
823     return dissect_dcerpc_uint8s(tvb, offset, pinfo,
824                                  tree, drep, hfindex, length, pdata);
825 }
826
827 int
828 dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
829                       proto_tree *tree, guint8 *drep, int hfindex,
830                       int length)
831 {
832     if (tree) {
833         proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, (drep[0] & 0x10));
834     }
835
836     return offset + length * 2;
837 }
838
839 int
840 dissect_ndr_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
841                    proto_tree *tree, guint8 *drep,
842                    int hfindex, int length)
843 {
844     dcerpc_info *di;
845
846     di=pinfo->private_data;
847     if(di->conformant_run){
848       /* just a run to handle conformant arrays, no scalars to dissect */
849       return offset;
850     }
851
852     if (offset % 2)
853         offset++;
854
855     return dissect_dcerpc_uint16s(tvb, offset, pinfo,
856                                  tree, drep, hfindex, length);
857 }
858
859 /*
860  * Helper routines for dissecting NDR strings
861  */
862
863 void cb_wstr_postprocess(packet_info *pinfo, proto_tree *tree _U_,
864                         proto_item *item, tvbuff_t *tvb, 
865                         int start_offset, int end_offset,
866                         void *callback_args)
867 {
868         gint options = GPOINTER_TO_INT(callback_args);
869         gint levels = CB_STR_ITEM_LEVELS(options);
870         char *s;
871
872         /* Align start_offset on 4-byte boundary. */
873
874         if (start_offset % 4)
875                 start_offset += 4 - (start_offset % 4);
876
877         /* Get string value */
878
879         if ((end_offset - start_offset) <= 12)
880                 return;         /* XXX: Use unistr2 dissector instead? */
881
882         /*
883          * XXX - need to handle non-printable characters here.
884          *
885          * XXX - this is typically called after the string has already
886          * been fetched and processed by some other routine; is there
887          * some way we can get that string, rather than duplicating the
888          * efforts of that routine?
889          */
890         s = tvb_fake_unicode(
891                 tvb, start_offset + 12, (end_offset - start_offset - 12) / 2,
892                 TRUE);
893
894         /* Append string to COL_INFO */
895
896         if (options & CB_STR_COL_INFO) {
897                 if (check_col(pinfo->cinfo, COL_INFO))
898                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
899         }
900
901         /* Append string to upper-level proto_items */
902
903         if (levels > 0 && item && s && s[0]) {
904                 proto_item_append_text(item, ": %s", s);
905                 item = item->parent;
906                 levels--;
907                 if (levels > 0) {
908                         proto_item_append_text(item, ": %s", s);
909                         item = item->parent;
910                         levels--;
911                         while (levels > 0) {
912                                 proto_item_append_text(item, " %s", s);
913                                 item = item->parent;
914                                 levels--;
915                         }
916                 }
917         }
918
919         /* Save string to dcv->private_data */
920
921         if (options & CB_STR_SAVE) {
922                 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
923                 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
924                 
925                 dcv->private_data = g_strdup(s);
926         }
927
928         g_free(s);
929 }
930
931 void cb_str_postprocess(packet_info *pinfo, proto_tree *tree _U_,
932                         proto_item *item, tvbuff_t *tvb, 
933                         int start_offset, int end_offset,
934                         void *callback_args)
935 {
936         gint options = GPOINTER_TO_INT(callback_args);
937         gint levels = CB_STR_ITEM_LEVELS(options);
938         char *s;
939
940         /* Align start_offset on 4-byte boundary. */
941
942         if (start_offset % 4)
943                 start_offset += 4 - (start_offset % 4);
944
945         /* Get string value */
946
947         if ((end_offset - start_offset) <= 12)
948                 return;         /* XXX: Use unistr2 dissector instead? */
949
950         /*
951          * XXX - need to handle non-printable characters here.
952          *
953          * XXX - this is typically called after the string has already
954          * been fetched and processed by some other routine; is there
955          * some way we can get that string, rather than duplicating the
956          * efforts of that routine?
957          */
958         s = tvb_get_string(
959                 tvb, start_offset + 12, (end_offset - start_offset - 12) );
960
961         /* Append string to COL_INFO */
962
963         if (options & CB_STR_COL_INFO) {
964                 if (check_col(pinfo->cinfo, COL_INFO))
965                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
966         }
967
968         /* Append string to upper-level proto_items */
969
970         if (levels > 0 && item && s && s[0]) {
971                 proto_item_append_text(item, ": %s", s);
972                 item = item->parent;
973                 levels--;
974                 if (levels > 0) {
975                         proto_item_append_text(item, ": %s", s);
976                         item = item->parent;
977                         levels--;
978                         while (levels > 0) {
979                                 proto_item_append_text(item, " %s", s);
980                                 item = item->parent;
981                                 levels--;
982                         }
983                 }
984         }
985
986         /* Save string to dcv->private_data */
987
988         if (options & CB_STR_SAVE) {
989                 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
990                 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
991                 
992                 dcv->private_data = g_strdup(s);
993         }
994
995         g_free(s);
996 }
997
998 /* Dissect a pointer to a NDR string and append the string value to the
999    proto_item. */
1000
1001 int dissect_ndr_str_pointer_item(tvbuff_t *tvb, gint offset, 
1002                                  packet_info *pinfo, proto_tree *tree, 
1003                                  guint8 *drep, int type, char *text, 
1004                                  int hf_index, int levels)
1005 {
1006         return dissect_ndr_pointer_cb(
1007                 tvb, offset, pinfo, tree, drep, 
1008                 dissect_ndr_wchar_cvstring, type, text, hf_index, 
1009                 cb_wstr_postprocess, GINT_TO_POINTER(levels + 1));
1010 }
1011
1012 /*
1013  * Register ett/hf values and perform DCERPC over SMB specific
1014  * initialisation.
1015  */
1016 void dcerpc_smb_init(int proto_dcerpc)
1017 {
1018         static hf_register_info hf[] = {
1019
1020                 /* String handling */
1021
1022                 { &hf_nt_cs_size,
1023                   { "Size", "nt.str.size", FT_UINT16, BASE_DEC,
1024                     NULL, 0x0, "Size of string in short integers", 
1025                     HFILL }},
1026                 
1027                 { &hf_nt_cs_len,
1028                   { "Length", "nt.str.len", FT_UINT16, BASE_DEC,
1029                     NULL, 0x0, "Length of string in short integers", 
1030                     HFILL }},
1031                 
1032                 /* Policy handles */
1033
1034                 { &hf_nt_policy_open_frame,
1035                   { "Frame handle opened", "dcerpc.nt.open_frame",
1036                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1037                     "Frame handle opened", HFILL }},
1038
1039                 { &hf_nt_policy_close_frame,
1040                   { "Frame handle closed", "dcerpc.nt.close_frame",
1041                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1042                     "Frame handle closed", HFILL }},
1043         };
1044
1045         static gint *ett[] = {
1046                 &ett_nt_unicode_string,
1047                 &ett_nt_counted_string,
1048                 &ett_nt_counted_byte_array,
1049                 &ett_nt_policy_hnd,
1050         };
1051
1052         /* Register ett's and hf's */
1053
1054         proto_register_subtree_array(ett, array_length(ett));
1055         proto_register_field_array(proto_dcerpc, hf, array_length(hf));
1056
1057         /* Initialise policy handle hash */
1058
1059         init_pol_hash();
1060 }