Fixup: tvb_get_string(z) -> tvb_get_string(z)_enc
[metze/wireshark/wip.git] / epan / dissectors / packet-dcerpc-nt.c
1 /* TODO:
2     dissect_ndr_nt_SID_with_options    see comment.
3 */
4 /* packet-dcerpc-nt.c
5  * Routines for DCERPC over SMB packet disassembly
6  * Copyright 2001-2003, Tim Potter <tpot@samba.org>
7  * Copyright 2011-2013, Matthieu Patou <mat@matws.net>
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <string.h>
31
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include <epan/wmem/wmem.h>
35 #include <epan/expert.h>
36 #include "packet-dcerpc.h"
37 #include "packet-dcerpc-nt.h"
38 #include "packet-windows-common.h"
39
40
41 int hf_nt_cs_len = -1;
42 int hf_nt_error;
43 int hf_nt_cs_size = -1;
44 static int hf_lsa_String_name_len = -1;
45 static int hf_lsa_String_name_size = -1;
46 static int hf_nt_data_blob_len = -1;
47
48 static gint ett_lsa_String = -1;
49 static gint ett_nt_data_blob = -1;
50 static expert_field ei_dcerpc_nt_badsid = EI_INIT;
51
52
53
54 /* This is used to safely walk the decode tree up, one item at a time safely.
55    This is used by dcerpc dissectors that want to push the display of a string
56    higher up in the tree for greater visibility.
57 */
58 #define GET_ITEM_PARENT(x) \
59         ((x->parent!=NULL)?x->parent:x)
60
61 /*
62  * This file contains helper routines that are used by the DCERPC over SMB
63  * dissectors for wireshark.
64  */
65
66 /*
67  * Used by several dissectors.
68  */
69 const value_string platform_id_vals[] = {
70         { 300, "DOS" },
71         { 400, "OS/2" },
72         { 500, "Windows NT" },
73         { 600, "OSF" },
74         { 700, "VMS" },
75         { 0,   NULL }
76 };
77
78 int
79 dissect_ndr_datablob(tvbuff_t *tvb, int offset, packet_info *pinfo,
80                         proto_tree *tree, dcerpc_info *di, guint8 *drep, int hf_index,
81                         int use_remaining_space)
82 {
83         proto_item *item;
84         guint3264 len;
85         proto_tree *subtree;
86
87         item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
88                         proto_registrar_get_name(hf_index));
89
90         subtree = proto_item_add_subtree(item, ett_nt_data_blob);
91
92         if (use_remaining_space) {
93                 len = tvb_length_remaining (tvb, offset);
94         } else {
95                 offset = dissect_ndr_uint3264(tvb, offset, pinfo, subtree, di, drep,
96                                     hf_nt_data_blob_len, &len);
97         }
98         proto_tree_add_text(subtree, tvb, offset, (int)len, "Blob data");
99         offset += (int)len;
100         return offset;
101 }
102
103 int
104 dissect_null_term_string(tvbuff_t *tvb, int offset,
105                                 packet_info *pinfo _U_, proto_tree *tree,
106                                 guint8 *drep _U_, int hf_index, int levels _U_)
107 {
108         guint len;
109
110         len = tvb_strsize(tvb, offset);
111         proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_ASCII|ENC_NA);
112
113         return offset + len;
114 }
115
116 int
117 dissect_null_term_wstring(tvbuff_t *tvb, int offset,
118                                 packet_info *pinfo _U_, proto_tree *tree,
119                                 guint8 *drep _U_, int hf_index, int levels _U_)
120 {
121         guint len;
122
123         len = tvb_unicode_strsize(tvb, offset);
124         proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_UTF_16|ENC_LITTLE_ENDIAN);
125
126         return offset + len;
127 }
128
129 /* Parse some common RPC structures */
130
131 /* Dissect a counted string as a callback to dissect_ndr_pointer_cb() */
132
133 int
134 dissect_ndr_counted_string_cb(tvbuff_t *tvb, int offset,
135                               packet_info *pinfo, proto_tree *tree,
136                               dcerpc_info *di, guint8 *drep, int hf_index,
137                               dcerpc_callback_fnct_t *callback,
138                               void *callback_args)
139 {
140         guint16 len, size;
141
142         /* Structure starts with short, but is aligned for pointer */
143
144         ALIGN_TO_5_BYTES;
145
146         if (di->conformant_run)
147                 return offset;
148
149         /*
150            struct {
151                short len;
152                short size;
153                [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
154            } UNICODE_STRING;
155
156          */
157
158         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep,
159                         hf_nt_cs_len, &len);
160
161         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep,
162                         hf_nt_cs_size, &size);
163
164         offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, tree, di, drep,
165                         dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE,
166                         "Character Array", hf_index, callback, callback_args);
167
168         if (di->call_data->flags & DCERPC_IS_NDR64) {
169                 ALIGN_TO_5_BYTES;
170         }
171
172         return offset;
173 }
174
175 static gint ett_nt_counted_string = -1;
176
177 static int
178 dissect_ndr_counted_string_helper(tvbuff_t *tvb, int offset,
179                                   packet_info *pinfo, proto_tree *tree,
180                                   dcerpc_info *di, guint8 *drep, int hf_index, int levels,
181                                   gboolean add_subtree)
182 {
183         proto_item *item;
184         proto_tree *subtree = tree;
185
186         if (add_subtree) {
187
188                 item = proto_tree_add_text(
189                         tree, tvb, offset, 0, "%s",
190                         proto_registrar_get_name(hf_index));
191
192                 subtree = proto_item_add_subtree(item, ett_nt_counted_string);
193         }
194
195         /*
196          * Add 2 levels, so that the string gets attached to the
197          * "Character Array" top-level item and to the top-level item
198          * added above.
199          */
200         return dissect_ndr_counted_string_cb(
201                 tvb, offset, pinfo, subtree, di, drep, hf_index,
202                 cb_wstr_postprocess, GINT_TO_POINTER(2 + levels));
203 }
204
205 /* Dissect a counted string in-line. */
206
207 int
208 dissect_ndr_counted_string(tvbuff_t *tvb, int offset,
209                            packet_info *pinfo, proto_tree *tree,
210                            dcerpc_info *di, guint8 *drep, int hf_index, int levels)
211 {
212         return dissect_ndr_counted_string_helper(
213                 tvb, offset, pinfo, tree, di, drep, hf_index, levels, TRUE);
214 }
215
216 /* Dissect a counted string as a callback to dissect_ndr_pointer().
217    This doesn't add a adds a proto item and subtreee for the string as
218    the pointer dissection already creates one. */
219
220 int
221 dissect_ndr_counted_string_ptr(tvbuff_t *tvb, int offset,
222                                packet_info *pinfo, proto_tree *tree,
223                                dcerpc_info *di, guint8 *drep)
224 {
225         return dissect_ndr_counted_string_helper(
226                 tvb, offset, pinfo, tree, di, drep, di->hf_index, 0, FALSE);
227 }
228
229 /* Dissect a counted byte_array as a callback to dissect_ndr_pointer_cb() */
230
231 static gint ett_nt_counted_byte_array = -1;
232
233 /* Dissect a counted byte array in-line. */
234
235 int
236 dissect_ndr_counted_byte_array_cb(tvbuff_t *tvb, int offset,
237                                   packet_info *pinfo, proto_tree *tree,
238                                   dcerpc_info *di, guint8 *drep, int hf_index,
239                                   dcerpc_callback_fnct_t *callback,
240                                   void *callback_args)
241 {
242         proto_item *item;
243         proto_tree *subtree;
244         guint16 len, size;
245
246         /* Structure starts with short, but is aligned for pointer */
247
248         ALIGN_TO_5_BYTES;
249
250         if (di->conformant_run)
251                 return offset;
252
253         item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
254                 proto_registrar_get_name(hf_index));
255
256         subtree = proto_item_add_subtree(item, ett_nt_counted_byte_array);
257
258         /*
259            struct {
260                short len;
261                short size;
262                [size_is(size), length_is(len), ptr] unsigned char *string;
263            } WHATEVER_THIS_IS_CALLED;
264
265          */
266
267         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
268                         hf_nt_cs_len, &len);
269
270         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
271                         hf_nt_cs_size, &size);
272
273         offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, subtree, di, drep,
274                         dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
275                         "Byte Array", hf_index, callback, callback_args);
276
277         if (di->call_data->flags & DCERPC_IS_NDR64) {
278                 ALIGN_TO_5_BYTES;
279         }
280
281         return offset;
282 }
283
284 static void cb_byte_array_postprocess(packet_info *pinfo, proto_tree *tree _U_,
285                         proto_item *item, dcerpc_info *di _U_, tvbuff_t *tvb,
286                         int start_offset, int end_offset,
287                         void *callback_args)
288 {
289         gint options = GPOINTER_TO_INT(callback_args);
290         gint levels = CB_STR_ITEM_LEVELS(options);
291         char *s;
292
293         /* Align start_offset on 4-byte boundary. */
294
295         if (start_offset % 4)
296                 start_offset += 4 - (start_offset % 4);
297
298         /* Get byte array value */
299
300         if ((end_offset - start_offset) <= 12)
301                 return;
302
303         s = tvb_bytes_to_ep_str(
304                 tvb, start_offset + 12, (end_offset - start_offset - 12) );
305
306         /* Append string to COL_INFO */
307
308         if (options & CB_STR_COL_INFO) {
309                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
310         }
311
312         /* Append string to upper-level proto_items */
313
314         if (levels > 0 && item && s && s[0]) {
315                 proto_item_append_text(item, ": %s", s);
316                 item = GET_ITEM_PARENT(item);
317                 levels--;
318                 if (levels > 0) {
319                         proto_item_append_text(item, ": %s", s);
320                         item = GET_ITEM_PARENT(item);
321                         levels--;
322                         while (levels > 0) {
323                                 proto_item_append_text(item, " %s", s);
324                                 item = GET_ITEM_PARENT(item);
325                                 levels--;
326                         }
327                 }
328         }
329 }
330
331 int
332 dissect_ndr_counted_byte_array(tvbuff_t *tvb, int offset,
333                                packet_info *pinfo, proto_tree *tree,
334                                dcerpc_info *di, guint8 *drep, int hf_index, int levels)
335 {
336         return dissect_ndr_counted_byte_array_cb(
337                 tvb, offset, pinfo, tree, di, drep, hf_index, cb_byte_array_postprocess, GINT_TO_POINTER(2 + levels));
338 }
339
340 /* Dissect a counted ascii string in-line. */
341 static gint ett_nt_counted_ascii_string = -1;
342
343 int
344 dissect_ndr_counted_ascii_string_cb(tvbuff_t *tvb, int offset,
345                                   packet_info *pinfo, proto_tree *tree,
346                                   dcerpc_info *di, guint8 *drep, int hf_index,
347                                   dcerpc_callback_fnct_t *callback,
348                                   void *callback_args)
349 {
350         proto_item *item;
351         proto_tree *subtree;
352         guint16 len, size;
353
354         /* Structure starts with short, but is aligned for pointer */
355
356         ALIGN_TO_5_BYTES;
357
358         if (di->conformant_run)
359                 return offset;
360
361         item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
362                 proto_registrar_get_name(hf_index));
363
364         subtree = proto_item_add_subtree(item, ett_nt_counted_ascii_string);
365
366         /*
367            struct {
368                short len;
369                short size;
370                [size_is(size), length_is(len), ptr] unsigned char *string;
371            } WHATEVER_THIS_IS_CALLED;
372
373          */
374
375         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
376                         hf_nt_cs_len, &len);
377
378         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
379                         hf_nt_cs_size, &size);
380
381         offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, subtree, di, drep,
382                         dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
383                         "Ascii String", hf_index, callback, callback_args);
384
385         if (di->call_data->flags & DCERPC_IS_NDR64) {
386                 ALIGN_TO_5_BYTES;
387         }
388
389         return offset;
390 }
391
392 int
393 dissect_ndr_counted_ascii_string(tvbuff_t *tvb, int offset,
394                                packet_info *pinfo, proto_tree *tree,
395                                dcerpc_info *di, guint8 *drep, int hf_index, int levels)
396 {
397         return dissect_ndr_counted_ascii_string_cb(
398                 tvb, offset, pinfo, tree, di, drep, hf_index, cb_str_postprocess, GINT_TO_POINTER(2 + levels));
399 }
400
401 static int hf_nt_guid = -1;
402
403 int
404 dissect_nt_GUID(tvbuff_t *tvb, int offset,
405                         packet_info *pinfo, proto_tree *tree,
406                         dcerpc_info *di, guint8 *drep)
407 {
408         offset=dissect_ndr_uuid_t(tvb, offset, pinfo, tree, di, drep, hf_nt_guid, NULL);
409
410         return offset;
411 }
412
413 /* This function is used to dissect a lsa_String
414         typedef [public] struct {
415                 [value(strlen_m_term(name)*2)] uint16 name_len;
416                 [value(strlen_m_term(name)*2)] uint16 name_size;
417                 [string,charset(UTF16)] uint16 *name;
418         } lsa_String;
419  */
420 int
421 dissect_ndr_lsa_String(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, dcerpc_info *di, guint8 *drep, guint32 param, int hfindex)
422 {
423         proto_item *item = NULL;
424         proto_tree *tree = NULL;
425         int old_offset;
426         header_field_info *hf_info;
427
428         ALIGN_TO_5_BYTES;
429
430         old_offset = offset;
431         hf_info=proto_registrar_get_nth(hfindex);
432
433         if (parent_tree) {
434                 item = proto_tree_add_text(parent_tree, tvb, offset, 0, "%s: ", hf_info->name);
435                 tree = proto_item_add_subtree(item, ett_lsa_String);
436         }
437
438         offset = PIDL_dissect_uint16(tvb, offset, pinfo, tree, di, drep, hf_lsa_String_name_len, 0);
439
440         offset = PIDL_dissect_uint16(tvb, offset, pinfo, tree, di, drep, hf_lsa_String_name_size, 0);
441
442         offset = dissect_ndr_pointer_cb(
443                 tvb, offset, pinfo, tree, di, drep,
444                 dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE,
445                 hf_info->name, hfindex, cb_wstr_postprocess,
446                 GINT_TO_POINTER(param));
447
448         proto_item_set_len(item, offset-old_offset);
449
450         if (di->call_data->flags & DCERPC_IS_NDR64) {
451                 ALIGN_TO_5_BYTES;
452         }
453
454         return offset;
455 }
456
457 /* This function is used to dissect a DCERPC encoded 64 bit time value.
458    XXX it should be fixed both here and in dissect_nt_64bit_time so
459    it can handle both BIG and LITTLE endian encodings
460  */
461 int
462 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
463                         packet_info *pinfo _U_, proto_tree *tree,
464                         dcerpc_info *di, guint8 *drep _U_, int hf_index)
465 {
466         if(di->conformant_run){
467                 /*just a run to handle conformant arrays, nothing to dissect */
468                 return offset;
469         }
470
471         ALIGN_TO_4_BYTES;
472
473         offset = dissect_nt_64bit_time(tvb, tree, offset, hf_index);
474         return offset;
475 }
476
477 /* Define this symbol to display warnings about request/response and
478    policy handle hash table collisions.  This happens when a packet with
479    the same conversation, smb fid and dcerpc call id occurs.  I think this
480    is due to a bug in the dcerpc/smb fragment reassembly code. */
481
482 #undef DEBUG_HASH_COLL
483
484 /*
485  * Policy handle hashing.
486  *
487  * We hash based on the policy handle value; the items in the hash table
488  * are lists of policy handle information about one or more policy
489  * handles with that value.  We have multiple values in case a given
490  * policy handle is opened in frame N, closed in frame M, and re-opened
491  * in frame O, where N < M < O.
492  *
493  * XXX - we really should also use a DCE RPC conversation/session handle
494  * of some sort, in case two separate sessions have the same handle
495  * value.  A transport-layer conversation might not be sufficient, as you
496  * might, for example, have multiple pipes in a single SMB connection,
497  * and you might have the same handle opened and closed separately on
498  * those two pipes.
499  *
500  * The policy handle information has "first frame" and "last frame"
501  * information; the entry should be used when dissecting a given frame
502  * only if that frame is within the interval [first frame,last frame].
503  * The list is sorted by "first frame".
504  *
505  * This doesn't handle the case of a handle being opened in frame N and
506  * re-opened in frame M, where N < M, with no intervening close, but I'm
507  * not sure anything can handle that if it's within the same DCE RPC
508  * session (if it's not, the conversation/session handle would fix that).
509  */
510
511 typedef struct {
512         guint8 policy_hnd[20];
513 } pol_hash_key;
514
515 typedef struct {
516         pol_value *list;                 /* List of policy handle entries */
517 } pol_hash_value;
518
519 static GHashTable *pol_hash = NULL;
520
521 /* Hash function */
522
523 static guint pol_hash_fn(gconstpointer k)
524 {
525         const pol_hash_key *key = (const pol_hash_key *)k;
526
527         /* Bytes 4-7 of the policy handle are a timestamp so should make a
528            reasonable hash value */
529
530         return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
531                 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
532 }
533
534 /* Return true if a policy handle is all zeros */
535
536 static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
537 {
538         static guint8 null_policy_hnd[20];
539
540         return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
541 }
542
543 /* Hash compare function */
544
545 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
546 {
547         const pol_hash_key *key1 = (const pol_hash_key *)k1;
548         const pol_hash_key *key2 = (const pol_hash_key *)k2;
549
550         return memcmp(key1->policy_hnd, key2->policy_hnd,
551                       sizeof(key1->policy_hnd)) == 0;
552 }
553
554 /*
555  * Look up the instance of a policy handle value in whose range of frames
556  * the specified frame falls.
557  */
558 static pol_value *find_pol_handle(e_ctx_hnd *policy_hnd, guint32 frame,
559                                   pol_hash_value **valuep)
560 {
561         pol_hash_key key;
562         pol_value *pol;
563
564         memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
565         if ((*valuep = (pol_hash_value *)g_hash_table_lookup(pol_hash, &key))) {
566                 /*
567                  * Look for the first value such that both:
568                  *
569                  *      1) the first frame in which it was seen is
570                  *         <= the specified frame;
571                  *
572                  *      2) the last frame in which it was seen is
573                  *         either unknown (meaning we haven't yet
574                  *         seen a close or another open of the
575                  *         same handle, which is assumed to imply
576                  *         an intervening close that wasn't captured)
577                  *         or is >= the specified frame.
578                  *
579                  * If there's more than one such frame, that's the
580                  * case where a handle is opened in frame N and
581                  * reopened in frame M, with no intervening close;
582                  * there is no right answer for that, so the instance
583                  * opened in frame N is as right as anything else.
584                  */
585                 for (pol = (*valuep)->list; pol != NULL; pol = pol->next) {
586                         if (pol->first_frame <= frame &&
587                             (pol->last_frame == 0 ||
588                              pol->last_frame >= frame))
589                                 break;  /* found one */
590                 }
591                 return pol;
592         } else {
593                 /*
594                  * The handle isn't in the hash table.
595                  */
596                 return NULL;
597         }
598 }
599
600 static void add_pol_handle(e_ctx_hnd *policy_hnd, guint32 frame,
601                            pol_value *pol, pol_hash_value *value)
602 {
603         pol_hash_key *key;
604         pol_value *polprev, *polnext;
605
606         if (value == NULL) {
607                 /*
608                  * There's no hash value; create one, put the new
609                  * value at the beginning of its policy handle list,
610                  * and put the hash value in the policy handle hash
611                  * table.
612                  */
613                 value = (pol_hash_value *)wmem_alloc(wmem_file_scope(), sizeof(pol_hash_value));
614                 value->list = pol;
615                 pol->next = NULL;
616                 key = (pol_hash_key *)wmem_alloc(wmem_file_scope(), sizeof(pol_hash_key));
617                 memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
618                 g_hash_table_insert(pol_hash, key, value);
619         } else {
620                 /*
621                  * Put the new value in the hash value's policy handle
622                  * list so that it's sorted by the first frame in
623                  * which it appeared.
624                  *
625                  * Search for the first entry whose first frame number
626                  * is greater than the current frame number, if any.
627                  */
628                 for (polnext = value->list, polprev = NULL;
629                     polnext != NULL && polnext->first_frame <= frame;
630                     polprev = polnext, polnext = polnext->next)
631                         ;
632
633                 /*
634                  * "polprev" points to the entry in the list after
635                  * which we should put the new entry; if it's null,
636                  * that means we should put it at the beginning of
637                  * the list.
638                  */
639                 if (polprev == NULL)
640                         value->list = pol;
641                 else
642                         polprev->next = pol;
643
644                 /*
645                  * "polnext" points to the entry in the list before
646                  * which we should put the new entry; if it's null,
647                  * that means we should put it at the end of the list.
648                  */
649                 pol->next = polnext;
650         }
651 }
652
653 /* Store the open and close frame numbers of a policy handle */
654
655 void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, packet_info *pinfo,
656                                gboolean is_open, gboolean is_close)
657 {
658         pol_hash_value *value;
659         pol_value *pol;
660
661         /*
662          * By the time the first pass is done, the policy handle database
663          * has been completely constructed.  If we've already seen this
664          * frame, there's nothing to do.
665          */
666         if (pinfo->fd->flags.visited)
667                 return;
668
669         if (is_null_pol(policy_hnd))
670                 return;
671
672         /* Look up existing value */
673         pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
674
675         if (pol != NULL) {
676                 /*
677                  * Update the existing value as appropriate.
678                  */
679                 if (is_open) {
680                         /*
681                          * This is an open; we assume that we missed
682                          * a close of this handle, so we set its
683                          * "last frame" value and act as if we didn't
684                          * see it.
685                          *
686                          * XXX - note that we might be called twice for
687                          * the same operation (see "dissect_pipe_dcerpc()",
688                          * which calls the DCE RPC dissector twice), so we
689                          * must first check to see if this is a handle we
690                          * just filled in.
691                          *
692                          * We check whether this handle's "first frame"
693                          * frame number is this frame and its "last frame
694                          * is 0; if so, this is presumably a duplicate call,
695                          * and we don't do an implicit close.
696                          */
697                         if (pol->first_frame == pinfo->fd->num &&
698                             pol->last_frame == 0)
699                                 return;
700                         pol->last_frame = pinfo->fd->num;
701                         pol = NULL;
702                 } else {
703                         if (is_close) {
704                                 pol->close_frame = pinfo->fd->num;
705                                 pol->last_frame = pinfo->fd->num;
706                         }
707                         return;
708                 }
709         }
710
711         /* Create a new value */
712
713         pol = (pol_value *)wmem_alloc(wmem_file_scope(), sizeof(pol_value));
714
715         pol->open_frame = is_open ? pinfo->fd->num : 0;
716         pol->close_frame = is_close ? pinfo->fd->num : 0;
717         pol->first_frame = pinfo->fd->num;
718         pol->last_frame = pol->close_frame;     /* if 0, unknown; if non-0, known */
719         pol->type=0;
720         pol->name = NULL;
721
722         add_pol_handle(policy_hnd, pinfo->fd->num, pol, value);
723 }
724
725 /* Store the type of a policy handle */
726 static void dcerpc_store_polhnd_type(e_ctx_hnd *policy_hnd, packet_info *pinfo,
727                                guint32 type)
728 {
729         pol_hash_value *value;
730         pol_value *pol;
731
732         /*
733          * By the time the first pass is done, the policy handle database
734          * has been completely constructed.  If we've already seen this
735          * frame, there's nothing to do.
736          */
737         if (pinfo->fd->flags.visited)
738                 return;
739
740         if (is_null_pol(policy_hnd))
741                 return;
742
743         /* Look up existing value */
744         pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
745
746         if (pol != NULL) {
747                 /*
748                  * Update the existing value as appropriate.
749                  */
750                 pol->type=type;
751         }
752 }
753
754 /* Store a text string with a policy handle */
755 void dcerpc_store_polhnd_name(e_ctx_hnd *policy_hnd, packet_info *pinfo,
756                                const char *name)
757 {
758         pol_hash_value *value;
759         pol_value *pol;
760
761         /*
762          * By the time the first pass is done, the policy handle database
763          * has been completely constructed.  If we've already seen this
764          * frame, there's nothing to do.
765          */
766         if (pinfo->fd->flags.visited)
767                 return;
768
769         if (is_null_pol(policy_hnd))
770                 return;
771
772         /* Look up existing value */
773         pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
774
775         if (pol != NULL) {
776                 /*
777                  * This is the first pass; update the existing
778                  * value as appropriate.
779                  */
780                 if (pol->name && name) {
781 #ifdef DEBUG_HASH_COLL
782                         if (strcmp(pol->name, name) != 0)
783                                 g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
784 #endif
785                         /* pol->name is wmem_file_scope() allocated, don't free it now */
786                 }
787
788                 pol->name = wmem_strdup(wmem_file_scope(), name);
789
790                 return;
791         }
792
793         /* Create a new value */
794
795         pol = (pol_value *)wmem_alloc(wmem_file_scope(), sizeof(pol_value));
796
797         pol->open_frame = 0;
798         pol->close_frame = 0;
799         pol->first_frame = pinfo->fd->num;
800         pol->last_frame = 0;
801         pol->type = 0;
802         if (name)
803                 pol->name = wmem_strdup(wmem_file_scope(), name);
804         else
805                 pol->name = wmem_strdup(wmem_file_scope(), "<UNKNOWN>");
806
807         add_pol_handle(policy_hnd, pinfo->fd->num, pol, value);
808 }
809
810 /*
811  * Retrieve a policy handle.
812  *
813  * XXX - should this get an "is_close" argument, and match even closed
814  * policy handles if the call is a close, so we can handle retransmitted
815  * close operations?
816  */
817
818 gboolean dcerpc_fetch_polhnd_data(e_ctx_hnd *policy_hnd,
819                               char **name, guint32 *type,
820                               guint32 *open_frame, guint32 *close_frame,
821                               guint32 cur_frame)
822 {
823         pol_hash_value *value;
824         pol_value *pol;
825
826         /* Prevent uninitialised return vars */
827
828         if (name)
829                 *name = NULL;
830
831         if (type)
832                 *type = 0;
833
834         if (open_frame)
835                 *open_frame = 0;
836
837         if (close_frame)
838                 *close_frame = 0;
839
840         /* Look up existing value */
841         pol = find_pol_handle(policy_hnd, cur_frame, &value);
842
843         if (pol) {
844                 if (name)
845                         *name = pol->name;
846
847                 if (type)
848                         *type = pol->type;
849
850                 if (open_frame)
851                         *open_frame = pol->open_frame;
852
853                 if (close_frame)
854                         *close_frame = pol->close_frame;
855         }
856
857         return pol != NULL;
858 }
859
860 /* Initialise policy handle hash */
861
862 static void init_pol_hash(void)
863 {
864         /* Initialise hash table */
865
866         if (pol_hash) {
867                 /*  Everything in the table is se_ allocated so there's no
868                  *  need to go through and free it all.
869                  */
870                 g_hash_table_destroy(pol_hash);
871         }
872
873         pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
874 }
875
876 /* Dissect a NT status code */
877
878 int
879 dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
880                  proto_tree *tree, dcerpc_info *di, guint8 *drep,
881                  int hfindex, guint32 *pdata)
882 {
883         guint32 status;
884
885         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep,
886                                     hfindex, &status);
887
888         if (status != 0)
889                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
890                                 val_to_str_ext(status, &NT_errors_ext,
891                                            "Unknown error 0x%08x"));
892         if (pdata)
893                 *pdata = status;
894
895         return offset;
896 }
897
898 /* Dissect a DOS status code */
899
900 int
901 dissect_doserror(tvbuff_t *tvb, gint offset, packet_info *pinfo,
902                proto_tree *tree, dcerpc_info *di, guint8 *drep,
903                int hfindex, guint32 *pdata)
904 {
905         guint32 status;
906
907         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep,
908                                     hfindex, &status);
909
910         if (status != 0)
911                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
912                                 val_to_str_ext(status, &DOS_errors_ext,
913                                            "Unknown error 0x%08x"));
914         if (pdata)
915                 *pdata = status;
916
917         return offset;
918 }
919
920 /* Dissect a NT policy handle */
921
922 static int hf_nt_policy_open_frame = -1;
923 static int hf_nt_policy_close_frame = -1;
924
925 static gint ett_nt_policy_hnd = -1;
926
927 /* this function is used to dissect a "handle".
928  * it will keep track of which frame a handle is opened from and in which
929  * frame it is closed.
930  * normally, this function would be used for tracking 20 byte policy handles
931  * as used in dcerpc  but it has shown VERY useful to also use it for tracking
932  * GUIDs such as for the file ids in smb2.
933  */
934 typedef enum {
935         HND_TYPE_CTX_HANDLE,
936         HND_TYPE_GUID
937 } e_hnd_type;
938
939 static int
940 dissect_nt_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
941                       proto_tree *tree, dcerpc_info *di, guint8 *drep, int hfindex,
942                       e_ctx_hnd *pdata, proto_item **pitem,
943                       gboolean is_open, gboolean is_close, e_hnd_type type)
944 {
945         proto_item *item=NULL;
946         proto_tree *subtree;
947         e_ctx_hnd hnd;
948         guint32 open_frame = 0, close_frame = 0;
949         char *name;
950         int old_offset = offset;
951         if(di->conformant_run){
952                 /*
953                  * just a run to handle conformant arrays, no scalars to
954                  * dissect - and "dissect_ndr_ctx_hnd()" won't return
955                  * a handle, so we can't do the hashing stuff in any
956                  * case
957                  */
958                 return offset;
959         }
960
961         /* Add to proto tree */
962
963         switch(type){
964         case HND_TYPE_CTX_HANDLE:
965                 item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
966                                            "Policy Handle");
967
968                 subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
969
970                 offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, di, drep,
971                                              hfindex, &hnd);
972                 break;
973         case HND_TYPE_GUID:
974                 item = proto_tree_add_text(tree, tvb, offset, 16,
975                                            "GUID handle");
976
977                 subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
978
979                 hnd.attributes=0;
980                 offset=dissect_ndr_uuid_t(tvb, offset, pinfo, subtree, di, drep, hfindex, &hnd.uuid);
981                 break;
982         default:
983                 DISSECTOR_ASSERT_NOT_REACHED();
984                 return offset;
985         }
986
987         /*
988          * Create a new entry for this handle if it's not a null handle
989          * and no entry already exists, and, in any case, set the
990          * open, close, first, and last frame information as appropriate.
991          */
992         dcerpc_smb_store_pol_pkts(&hnd, pinfo, is_open, is_close);
993
994         /* Insert open/close/name information if known */
995         if (dcerpc_fetch_polhnd_data(&hnd, &name, NULL, &open_frame,
996                         &close_frame, pinfo->fd->num)) {
997
998                 if (open_frame) {
999                         proto_item *item_local;
1000                         item_local=proto_tree_add_uint(
1001                                 subtree, hf_nt_policy_open_frame, tvb,
1002                                 old_offset, sizeof(e_ctx_hnd), open_frame);
1003                         PROTO_ITEM_SET_GENERATED(item_local);
1004                 }
1005                 if (close_frame) {
1006                         proto_item *item_local;
1007                         item_local=proto_tree_add_uint(
1008                                 subtree, hf_nt_policy_close_frame, tvb,
1009                                 old_offset, sizeof(e_ctx_hnd), close_frame);
1010                         PROTO_ITEM_SET_GENERATED(item_local);
1011                 }
1012
1013                 /*
1014                  * Don't append the handle name if pitem is null; that's
1015                  * an indication that our caller will do so, as we're
1016                  * supplying a pointer to the item so that they can do
1017                  * so.
1018                  */
1019                 if (name != NULL && pitem == NULL)
1020                         proto_item_append_text(item, ": %s", name);
1021         }
1022
1023         if (pdata)
1024                 *pdata = hnd;
1025
1026         if (pitem)
1027                 *pitem = item;
1028
1029         return offset;
1030 }
1031
1032
1033 int
1034 dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1035                       proto_tree *tree, dcerpc_info *di, guint8 *drep, int hfindex,
1036                       e_ctx_hnd *pdata, proto_item **pitem,
1037                       gboolean is_open, gboolean is_close)
1038 {
1039         offset=dissect_nt_hnd(tvb, offset, pinfo,
1040                       tree, di, drep, hfindex,
1041                       pdata, pitem,
1042                       is_open, is_close, HND_TYPE_CTX_HANDLE);
1043
1044         return offset;
1045 }
1046
1047 /* This function is called from PIDL generated dissectors to dissect a
1048  * NT style policy handle (contect handle).
1049  *
1050  * param can be used to specify where policy handles are opened and closed
1051  * by setting PARAM_VALUE to
1052  *  PIDL_POLHND_OPEN where the policy handle is opened/created
1053  *  PIDL_POLHND_CLOSE where it is closed.
1054  * This enables policy handle tracking so that when a policy handle is
1055  * dissected it will be so as an expansion showing which frame it was
1056  * opened/closed in.
1057  *
1058  * See conformance file for winreg (epan/dissectors/pidl/winreg.cnf)
1059  * for examples.
1060  */
1061 int
1062 PIDL_dissect_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1063                       proto_tree *tree, dcerpc_info* di, guint8 *drep, int hfindex,
1064                       guint32 param)
1065 {
1066         e_ctx_hnd policy_hnd;
1067
1068         offset=dissect_nt_hnd(tvb, offset, pinfo,
1069                       tree, di, drep, hfindex,
1070                       &policy_hnd, NULL,
1071                       param&PIDL_POLHND_OPEN, param&PIDL_POLHND_CLOSE,
1072                       HND_TYPE_CTX_HANDLE);
1073
1074         /* If this was an open/create and we dont yet have a policy name
1075          * then create one.
1076          * XXX We do not yet have the infrastructure to know the name of the
1077          * actual object  so just show it as <...> for the time being.
1078          */
1079         if((param&PIDL_POLHND_OPEN)
1080         && !pinfo->fd->flags.visited
1081         && !di->conformant_run){
1082                 char *pol_string=NULL;
1083                 const char *pol_name=NULL;
1084                 dcerpc_call_value *dcv;
1085
1086                 dcv = (dcerpc_call_value *)di->call_data;
1087                 pol_name = (const char *)dcv->private_data;
1088                 if(!pol_name){
1089                         pol_name="<...>";
1090                 }
1091                 pol_string=wmem_strdup_printf(wmem_packet_scope(), "%s(%s)", di->dcerpc_procedure_name, pol_name);
1092                 dcerpc_store_polhnd_name(&policy_hnd, pinfo, pol_string);
1093                 dcerpc_store_polhnd_type(&policy_hnd, pinfo, param&PIDL_POLHND_TYPE_MASK);
1094         }
1095
1096         /* Track this policy handle for the response */
1097         if(!pinfo->fd->flags.visited
1098         && !di->conformant_run){
1099                 dcerpc_call_value *dcv;
1100
1101                 dcv = (dcerpc_call_value *)di->call_data;
1102                 if(!dcv->pol){
1103                         dcv->pol=(e_ctx_hnd *)wmem_memdup(wmem_file_scope(), &policy_hnd, sizeof(e_ctx_hnd));
1104                 }
1105         }
1106
1107         return offset;
1108 }
1109
1110 /* this function must be called with   hfindex being HF_GUID */
1111 int
1112 dissect_nt_guid_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1113                       proto_tree *tree, dcerpc_info *di, guint8 *drep, int hfindex,
1114                       e_ctx_hnd *pdata, proto_item **pitem,
1115                       gboolean is_open, gboolean is_close)
1116 {
1117         offset=dissect_nt_hnd(tvb, offset, pinfo,
1118                       tree, di, drep, hfindex,
1119                       pdata, pitem,
1120                       is_open, is_close, HND_TYPE_GUID);
1121
1122         return offset;
1123 }
1124
1125 /* Some helper routines to dissect a range of uint8 characters.  I don't
1126    think these are "official" NDR representations and are probably specific
1127    to NT so for the moment they're put here instead of in packet-dcerpc.c
1128    and packet-dcerpc-ndr.c. */
1129
1130 int
1131 dissect_dcerpc_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1132                       proto_tree *tree, dcerpc_info *di _U_, guint8 *drep _U_, int hfindex,
1133                       int length, const guint8 **pdata)
1134 {
1135         const guint8 *data;
1136
1137         data = (const guint8 *)tvb_get_ptr(tvb, offset, length);
1138
1139         if (tree) {
1140                 /* This should be an FT_BYTES, so the byte order should not matter */
1141                 proto_tree_add_item (tree, hfindex, tvb, offset, length, ENC_NA);
1142         }
1143
1144         if (pdata)
1145                 *pdata = data;
1146
1147         return offset + length;
1148 }
1149
1150 int
1151 dissect_ndr_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1152                    proto_tree *tree, dcerpc_info *di, guint8 *drep,
1153                    int hfindex, int length, const guint8 **pdata)
1154 {
1155         if(di->conformant_run){
1156                 /* just a run to handle conformant arrays, no scalars to dissect */
1157                 return offset;
1158         }
1159
1160         /* no alignment needed */
1161         return dissect_dcerpc_uint8s(tvb, offset, pinfo,
1162                                      tree, di, drep, hfindex, length, pdata);
1163 }
1164
1165 int
1166 dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1167                        proto_tree *tree, guint8 *drep, int hfindex,
1168                        int length)
1169 {
1170         if (tree) {
1171                 /* These are FT_BYTES fields, so the byte order should not matter;
1172                    however, perhaps there should be an FT_HEXADECTETS type,
1173                    or something such as that, with each pair of octets
1174                    displayed as a single unit, in which case the byte order
1175                    would matter, so we'll calculate the byte order here.  */
1176                 proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, DREP_ENC_INTEGER(drep));
1177         }
1178
1179         return offset + length * 2;
1180 }
1181
1182 int
1183 dissect_ndr_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1184                     proto_tree *tree, dcerpc_info *di, guint8 *drep,
1185                     int hfindex, int length)
1186 {
1187         if(di->conformant_run){
1188                 /* just a run to handle conformant arrays, no scalars to dissect */
1189                 return offset;
1190         }
1191
1192         if (offset % 2)
1193                 offset++;
1194
1195         return dissect_dcerpc_uint16s(tvb, offset, pinfo,
1196                                       tree, drep, hfindex, length);
1197 }
1198
1199 /*
1200  * Helper routines for dissecting NDR strings
1201  */
1202 void cb_wstr_postprocess(packet_info *pinfo, proto_tree *tree _U_,
1203                         proto_item *item, dcerpc_info *di _U_, tvbuff_t *tvb,
1204                         int start_offset, int end_offset,
1205                         void *callback_args)
1206 {
1207         gint options = GPOINTER_TO_INT(callback_args);
1208         gint levels = CB_STR_ITEM_LEVELS(options);
1209         char *s;
1210
1211         /* Align start_offset on 4-byte boundary. */
1212
1213         if (start_offset % 4)
1214                 start_offset += 4 - (start_offset % 4);
1215
1216         /* Get string value */
1217
1218         if ((end_offset - start_offset) <= 12)
1219                 return;         /* XXX: Use unistr2 dissector instead? */
1220
1221         /*
1222          * XXX - need to handle non-printable characters here.
1223          *
1224          * XXX - this is typically called after the string has already
1225          * been fetched and processed by some other routine; is there
1226          * some way we can get that string, rather than duplicating the
1227          * efforts of that routine?
1228          */
1229         s = tvb_get_string_enc(wmem_packet_scope(),
1230                 tvb, start_offset + 12, end_offset - start_offset - 12,
1231                 ENC_UTF_16|ENC_LITTLE_ENDIAN);
1232
1233         /* Append string to COL_INFO */
1234
1235         if (options & CB_STR_COL_INFO) {
1236                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1237         }
1238
1239         /* Append string to upper-level proto_items */
1240         if (levels > 0 && item && s && s[0]) {
1241                 proto_item_append_text(item, ": %s", s);
1242                 item = GET_ITEM_PARENT(item);
1243                 levels--;
1244                 if (item && levels > 0) {
1245                         proto_item_append_text(item, ": %s", s);
1246                         item = GET_ITEM_PARENT(item);
1247                         levels--;
1248                         while (item && levels > 0) {
1249                                 proto_item_append_text(item, " %s", s);
1250                                 item = GET_ITEM_PARENT(item);
1251                                 levels--;
1252                         }
1253                 }
1254         }
1255
1256         /* Save string to dcv->private_data */
1257         if (options & CB_STR_SAVE) {
1258                 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1259                 dcv->private_data = s;
1260         }
1261 }
1262
1263 void cb_str_postprocess(packet_info *pinfo, proto_tree *tree _U_,
1264                         proto_item *item, dcerpc_info *di _U_, tvbuff_t *tvb,
1265                         int start_offset, int end_offset,
1266                         void *callback_args)
1267 {
1268         gint options = GPOINTER_TO_INT(callback_args);
1269         gint levels = CB_STR_ITEM_LEVELS(options);
1270         guint8 *s;
1271
1272         /* Align start_offset on 4-byte boundary. */
1273
1274         if (start_offset % 4)
1275                 start_offset += 4 - (start_offset % 4);
1276
1277         /* Get string value */
1278
1279         if ((end_offset - start_offset) <= 12)
1280                 return;         /* XXX: Use unistr2 dissector instead? */
1281
1282         /*
1283          * XXX - need to handle non-printable characters here.
1284          *
1285          * XXX - this is typically called after the string has already
1286          * been fetched and processed by some other routine; is there
1287          * some way we can get that string, rather than duplicating the
1288          * efforts of that routine?
1289          */
1290         s = tvb_get_string_enc(wmem_packet_scope(),
1291                 tvb, start_offset + 12, (end_offset - start_offset - 12), ENC_ASCII);
1292
1293         /* Append string to COL_INFO */
1294
1295         if (options & CB_STR_COL_INFO) {
1296                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1297         }
1298
1299         /* Append string to upper-level proto_items */
1300
1301         if (levels > 0 && item && s && s[0]) {
1302                 proto_item_append_text(item, ": %s", s);
1303                 item = GET_ITEM_PARENT(item);
1304                 levels--;
1305                 if (levels > 0) {
1306                         proto_item_append_text(item, ": %s", s);
1307                         item = GET_ITEM_PARENT(item);
1308                         levels--;
1309                         while (levels > 0) {
1310                                 proto_item_append_text(item, " %s", s);
1311                                 item = GET_ITEM_PARENT(item);
1312                                 levels--;
1313                         }
1314                 }
1315         }
1316
1317         /* Save string to dcv->private_data */
1318
1319         if (options & CB_STR_SAVE) {
1320                 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1321
1322                 dcv->private_data = s;
1323         }
1324 }
1325
1326 /* Dissect a pointer to a NDR string and append the string value to the
1327    proto_item. */
1328
1329 int dissect_ndr_str_pointer_item(tvbuff_t *tvb, gint offset,
1330                                  packet_info *pinfo, proto_tree *tree,
1331                                  dcerpc_info *di, guint8 *drep, int type, const char *text,
1332                                  int hf_index, int levels)
1333 {
1334         return dissect_ndr_pointer_cb(
1335                 tvb, offset, pinfo, tree, di, drep,
1336                 dissect_ndr_wchar_cvstring, type, text, hf_index,
1337                 cb_wstr_postprocess, GINT_TO_POINTER(levels + 1));
1338 }
1339
1340 /* SID dissection routines */
1341
1342 static int hf_nt_count = -1;
1343 static int hf_nt_domain_sid = -1;
1344
1345 /* That's a SID that is always 28 bytes long */
1346 int
1347 dissect_ndr_nt_SID28(tvbuff_t *tvb, int offset, packet_info *pinfo,
1348                         proto_tree *tree, dcerpc_info *di, guint8 *drep _U_)
1349 {
1350         proto_item *item;
1351         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1352         char *sid_str=NULL;
1353         const char *name;
1354         int newoffset;
1355
1356         if(di->hf_index!=-1){
1357                 name=proto_registrar_get_name(di->hf_index);
1358         } else {
1359                 name="Domain";
1360         }
1361         if(di->conformant_run){
1362                 /* just a run to handle conformant arrays, no scalars to dissect */
1363                 return offset;
1364         }
1365
1366         newoffset = dissect_nt_sid(tvb, offset, tree, name, &sid_str,
1367                                 hf_nt_domain_sid);
1368         /* The dissected stuff cant be more than 28 bytes */
1369         if ((newoffset - offset) > 28) {
1370                 item = proto_tree_get_parent(tree->last_child);
1371                 expert_add_info(pinfo, item, &ei_dcerpc_nt_badsid);
1372
1373                 /* The rest of the dissection will most probably wrong as we are not dissecting what we expect */
1374                 return newoffset;
1375         }
1376
1377     /* No matter how much we used for the real dissection of the SID consume 28 bytes */
1378         if (tree) {
1379                 item = proto_tree_get_parent(tree->last_child);
1380                 proto_item_set_len(item, 28);
1381         }
1382         offset += 28;
1383         /* dcv can be null, for example when this ndr structure is embedded
1384          * inside non-dcerpc pdus, i.e. kerberos PAC structure
1385          */
1386         if(dcv){
1387                 /*
1388                  * sid_str has ephemeral storage duration;
1389                  * dcerpc_call_values have session duration,
1390                  * so we need to make its private data have
1391                  * session duration as well.
1392                  */
1393                 dcv->private_data = wmem_strdup(wmem_file_scope(), sid_str);
1394         }
1395
1396         return offset;
1397 }
1398
1399 int
1400 dissect_ndr_nt_SID(tvbuff_t *tvb, int offset, packet_info *pinfo,
1401                    proto_tree *tree, dcerpc_info *di, guint8 *drep)
1402 {
1403         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1404         char *sid_str=NULL;
1405         const char *name;
1406
1407         if(di->hf_index!=-1){
1408                 name=proto_registrar_get_name(di->hf_index);
1409         } else {
1410                 name="Domain";
1411         }
1412         if(di->conformant_run){
1413                 /* just a run to handle conformant arrays, no scalars to dissect */
1414                 return offset;
1415         }
1416
1417         /* the SID contains a conformant array, first we must eat
1418            the 4-byte max_count before we can hand it off */
1419
1420         offset = dissect_ndr_uint3264 (tvb, offset, pinfo, tree, di, drep,
1421                         hf_nt_count, NULL);
1422
1423         offset = dissect_nt_sid(tvb, offset, tree, name, &sid_str,
1424                                 hf_nt_domain_sid);
1425
1426         /* dcv can be null, for example when this ndr structure is embedded
1427          * inside non-dcerpc pdus, i.e. kerberos PAC structure
1428          */
1429         if(dcv){
1430                 /*
1431                  * sid_str has ephemeral storage duration;
1432                  * dcerpc_call_values have session duration,
1433                  * so we need to make its private data have
1434                  * session duration as well.
1435                  */
1436                 dcv->private_data = wmem_strdup(wmem_file_scope(), sid_str);
1437         }
1438
1439         return offset;
1440 }
1441
1442 /* same as dissect_ndr_nt_SID() but takes the same options as counted strings
1443    do to prettify the dissect pane and the COL_INFO summary line
1444 */
1445 /* Note this is in fact for dissecting the dom_sid2*/
1446 int
1447 dissect_ndr_nt_SID_with_options(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep, guint32 options)
1448 {
1449         dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1450         gint levels = CB_STR_ITEM_LEVELS(options);
1451         offset=dissect_ndr_nt_SID(tvb, offset, pinfo, tree, di, drep);
1452
1453         if(dcv && dcv->private_data){
1454                 char *s=(char *)dcv->private_data;
1455                 proto_item *item=(proto_item *)tree;
1456
1457                 if ((options & CB_STR_COL_INFO)&&(!di->conformant_run)) {
1458                         /* kludge, ugly,   but this is called twice for all
1459                            dcerpc interfaces due to how we chase pointers
1460                            and putting the sid twice on the summary line
1461                            looks even worse.
1462                            Real solution would be to block updates to col_info
1463                            while we just do a conformance run,   this might
1464                            have sideeffects so it needs some more thoughts first.
1465                         */
1466                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1467                 }
1468
1469                 /* Append string to upper-level proto_items */
1470
1471                 if (levels > 0 && item && s && s[0]) {
1472                         proto_item_append_text(item, ": %s", s);
1473                         item = GET_ITEM_PARENT(item);
1474                         levels--;
1475                         if (levels > 0) {
1476                                 proto_item_append_text(item, ": %s", s);
1477                                 item = GET_ITEM_PARENT(item);
1478                                 levels--;
1479                                 while (levels > 0) {
1480                                         proto_item_append_text(item, " %s", s);
1481                                         item = GET_ITEM_PARENT(item);
1482                                         levels--;
1483                                 }
1484                         }
1485                 }
1486         }
1487
1488         return offset;
1489 }
1490
1491 static int
1492 dissect_ndr_nt_SID_hf_through_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
1493                    proto_tree *tree, dcerpc_info *di, guint8 *drep)
1494 {
1495         offset = dissect_ndr_nt_SID(tvb, offset, pinfo, tree, di, drep);
1496
1497         return offset;
1498 }
1499
1500 static gint ett_nt_sid_pointer = -1;
1501
1502 int
1503 dissect_ndr_nt_PSID(tvbuff_t *tvb, int offset,
1504                     packet_info *pinfo, proto_tree *parent_tree,
1505                     dcerpc_info *di, guint8 *drep)
1506 {
1507         proto_item *item=NULL;
1508         proto_tree *tree=NULL;
1509         int old_offset=offset;
1510
1511         if(parent_tree){
1512                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1513                         "SID pointer:");
1514                 tree = proto_item_add_subtree(item, ett_nt_sid_pointer);
1515         }
1516
1517         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, di, drep,
1518                         dissect_ndr_nt_SID_hf_through_ptr, NDR_POINTER_UNIQUE,
1519                         "SID pointer", hf_nt_domain_sid);
1520
1521         proto_item_set_len(item, offset-old_offset);
1522         return offset;
1523 }
1524
1525 static const true_false_string tfs_nt_acb_disabled = {
1526         "Account is DISABLED",
1527         "Account is NOT disabled"
1528 };
1529 static const true_false_string tfs_nt_acb_homedirreq = {
1530         "Homedir is REQUIRED",
1531         "Homedir is NOT required"
1532 };
1533 static const true_false_string tfs_nt_acb_pwnotreq = {
1534         "Password is NOT required",
1535         "Password is REQUIRED"
1536 };
1537 static const true_false_string tfs_nt_acb_tempdup = {
1538         "This is a TEMPORARY DUPLICATE account",
1539         "This is NOT a temporary duplicate account"
1540 };
1541 static const true_false_string tfs_nt_acb_normal = {
1542         "This is a NORMAL USER account",
1543         "This is NOT a normal user account"
1544 };
1545 static const true_false_string tfs_nt_acb_mns = {
1546         "This is a MNS account",
1547         "This is NOT a mns account"
1548 };
1549 static const true_false_string tfs_nt_acb_domtrust = {
1550         "This is a DOMAIN TRUST account",
1551         "This is NOT a domain trust account"
1552 };
1553 static const true_false_string tfs_nt_acb_wstrust = {
1554         "This is a WORKSTATION TRUST account",
1555         "This is NOT a workstation trust account"
1556 };
1557 static const true_false_string tfs_nt_acb_svrtrust = {
1558         "This is a SERVER TRUST account",
1559         "This is NOT a server trust account"
1560 };
1561 static const true_false_string tfs_nt_acb_pwnoexp = {
1562         "Passwords does NOT expire",
1563         "Password will EXPIRE"
1564 };
1565 static const true_false_string tfs_nt_acb_autolock = {
1566         "This account has been AUTO LOCKED",
1567         "This account has NOT been auto locked"
1568 };
1569
1570 static gint ett_nt_acct_ctrl = -1;
1571
1572 static int hf_nt_acct_ctrl = -1;
1573 static int hf_nt_acb_disabled = -1;
1574 static int hf_nt_acb_homedirreq = -1;
1575 static int hf_nt_acb_pwnotreq = -1;
1576 static int hf_nt_acb_tempdup = -1;
1577 static int hf_nt_acb_normal = -1;
1578 static int hf_nt_acb_mns = -1;
1579 static int hf_nt_acb_domtrust = -1;
1580 static int hf_nt_acb_wstrust = -1;
1581 static int hf_nt_acb_svrtrust = -1;
1582 static int hf_nt_acb_pwnoexp = -1;
1583 static int hf_nt_acb_autolock = -1;
1584
1585 int
1586 dissect_ndr_nt_acct_ctrl(tvbuff_t *tvb, int offset, packet_info *pinfo,
1587                         proto_tree *parent_tree, dcerpc_info *di, guint8 *drep)
1588 {
1589         guint32 mask;
1590         proto_item *item = NULL;
1591         proto_tree *tree = NULL;
1592
1593         offset=dissect_ndr_uint32(tvb, offset, pinfo, NULL, di, drep,
1594                         hf_nt_acct_ctrl, &mask);
1595
1596         if(parent_tree){
1597                 item = proto_tree_add_uint(parent_tree, hf_nt_acct_ctrl,
1598                         tvb, offset-4, 4, mask);
1599                 tree = proto_item_add_subtree(item, ett_nt_acct_ctrl);
1600         }
1601
1602         proto_tree_add_boolean(tree, hf_nt_acb_autolock,
1603                 tvb, offset-4, 4, mask);
1604         proto_tree_add_boolean(tree, hf_nt_acb_pwnoexp,
1605                 tvb, offset-4, 4, mask);
1606         proto_tree_add_boolean(tree, hf_nt_acb_svrtrust,
1607                 tvb, offset-4, 4, mask);
1608         proto_tree_add_boolean(tree, hf_nt_acb_wstrust,
1609                 tvb, offset-4, 4, mask);
1610         proto_tree_add_boolean(tree, hf_nt_acb_domtrust,
1611                 tvb, offset-4, 4, mask);
1612         proto_tree_add_boolean(tree, hf_nt_acb_mns,
1613                 tvb, offset-4, 4, mask);
1614         proto_tree_add_boolean(tree, hf_nt_acb_normal,
1615                 tvb, offset-4, 4, mask);
1616         proto_tree_add_boolean(tree, hf_nt_acb_tempdup,
1617                 tvb, offset-4, 4, mask);
1618         proto_tree_add_boolean(tree, hf_nt_acb_pwnotreq,
1619                 tvb, offset-4, 4, mask);
1620         proto_tree_add_boolean(tree, hf_nt_acb_homedirreq,
1621                 tvb, offset-4, 4, mask);
1622         proto_tree_add_boolean(tree, hf_nt_acb_disabled,
1623                 tvb, offset-4, 4, mask);
1624
1625         return offset;
1626 }
1627
1628 static int hf_logonhours_unknown_char = -1;
1629
1630 static int
1631 dissect_LOGON_HOURS_entry(tvbuff_t *tvb, int offset,
1632                           packet_info *pinfo, proto_tree *tree,
1633                           dcerpc_info *di, guint8 *drep)
1634 {
1635         offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, di, drep,
1636                         hf_logonhours_unknown_char, NULL);
1637         return offset;
1638 }
1639
1640 static gint ett_nt_logon_hours_hours = -1;
1641
1642 static int
1643 dissect_LOGON_HOURS_hours(tvbuff_t *tvb, int offset,
1644                           packet_info *pinfo, proto_tree *parent_tree,
1645                           dcerpc_info *di, guint8 *drep)
1646 {
1647         proto_item *item=NULL;
1648         proto_tree *tree=NULL;
1649         int old_offset=offset;
1650
1651         if(parent_tree){
1652                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1653                         "LOGON_HOURS:");
1654                 tree = proto_item_add_subtree(item, ett_nt_logon_hours_hours);
1655         }
1656
1657         offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, di, drep,
1658                         dissect_LOGON_HOURS_entry);
1659
1660         proto_item_set_len(item, offset-old_offset);
1661         return offset;
1662 }
1663
1664 static gint ett_nt_logon_hours = -1;
1665 static int hf_logonhours_divisions = -1;
1666
1667 int
1668 dissect_ndr_nt_LOGON_HOURS(tvbuff_t *tvb, int offset,
1669                         packet_info *pinfo, proto_tree *parent_tree,
1670                         dcerpc_info *di, guint8 *drep)
1671 {
1672         proto_item *item=NULL;
1673         proto_tree *tree=NULL;
1674         int old_offset=offset;
1675
1676         ALIGN_TO_4_BYTES;  /* strcture starts with short, but is aligned for longs */
1677
1678         if(parent_tree){
1679                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1680                         "LOGON_HOURS:");
1681                 tree = proto_item_add_subtree(item, ett_nt_logon_hours);
1682         }
1683
1684         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep,
1685                                 hf_logonhours_divisions, NULL);
1686         /* XXX - is this a bitmask like the "logon hours" field in the
1687            Remote API call "NetUserGetInfo()" with an information level
1688            of 11? */
1689         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, di, drep,
1690                         dissect_LOGON_HOURS_hours, NDR_POINTER_UNIQUE,
1691                         "LOGON_HOURS", -1);
1692
1693         proto_item_set_len(item, offset-old_offset);
1694         return offset;
1695 }
1696
1697 static int
1698 dissect_ndr_nt_PSID_no_hf(tvbuff_t *tvb, int offset,
1699                              packet_info *pinfo, proto_tree *parent_tree,
1700                              dcerpc_info *di, guint8 *drep)
1701 {
1702         offset=dissect_ndr_nt_PSID(tvb, offset, pinfo, parent_tree, di, drep);
1703         return offset;
1704 }
1705
1706 static int
1707 dissect_ndr_nt_PSID_ARRAY_sids (tvbuff_t *tvb, int offset,
1708                              packet_info *pinfo, proto_tree *tree,
1709                              dcerpc_info *di, guint8 *drep)
1710 {
1711         offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep,
1712                         dissect_ndr_nt_PSID_no_hf);
1713
1714         return offset;
1715 }
1716
1717 static gint ett_nt_sid_array = -1;
1718
1719 int
1720 dissect_ndr_nt_PSID_ARRAY(tvbuff_t *tvb, int offset,
1721                         packet_info *pinfo, proto_tree *parent_tree,
1722                         dcerpc_info *di, guint8 *drep)
1723 {
1724         guint32 count;
1725         proto_item *item=NULL;
1726         proto_tree *tree=NULL;
1727         int old_offset=offset;
1728
1729         if(parent_tree){
1730                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1731                         "SID array:");
1732                 tree = proto_item_add_subtree(item, ett_nt_sid_array);
1733         }
1734
1735         ALIGN_TO_5_BYTES;
1736
1737         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep,
1738                         hf_nt_count, &count);
1739         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, di, drep,
1740                         dissect_ndr_nt_PSID_ARRAY_sids, NDR_POINTER_UNIQUE,
1741                         "PSID_ARRAY", -1);
1742
1743         proto_item_set_len(item, offset-old_offset);
1744
1745         if (di->call_data->flags & DCERPC_IS_NDR64) {
1746                 ALIGN_TO_5_BYTES;
1747         }
1748
1749         return offset;
1750 }
1751
1752 static gint ett_nt_sid_and_attributes = -1;
1753 static int hf_nt_attrib = -1;
1754
1755 int
1756 dissect_ndr_nt_SID_AND_ATTRIBUTES(tvbuff_t *tvb, int offset,
1757                         packet_info *pinfo, proto_tree *parent_tree,
1758                         dcerpc_info *di, guint8 *drep)
1759 {
1760         proto_item *item=NULL;
1761         proto_tree *tree=NULL;
1762
1763         if(parent_tree){
1764                 item = proto_tree_add_text(parent_tree, tvb, offset, 0,
1765                         "SID_AND_ATTRIBUTES:");
1766                 tree = proto_item_add_subtree(item, ett_nt_sid_and_attributes);
1767         }
1768
1769         offset = dissect_ndr_nt_PSID(tvb, offset, pinfo, tree, di, drep);
1770
1771         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep,
1772                                      hf_nt_attrib, NULL);
1773
1774         return offset;
1775 }
1776
1777 static gint ett_nt_sid_and_attributes_array = -1;
1778
1779 int
1780 dissect_ndr_nt_SID_AND_ATTRIBUTES_ARRAY(tvbuff_t *tvb, int offset,
1781                         packet_info *pinfo, proto_tree *parent_tree,
1782                         dcerpc_info *di, guint8 *drep)
1783 {
1784         proto_item *item=NULL;
1785         proto_tree *tree=NULL;
1786         int old_offset=offset;
1787
1788         if(parent_tree){
1789                 item = proto_tree_add_text(parent_tree, tvb, offset, 0,
1790                         "SID_AND_ATTRIBUTES array:");
1791                 tree = proto_item_add_subtree(item, ett_nt_sid_and_attributes_array);
1792         }
1793
1794         /*offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep,
1795           hf_samr_count, &count); */
1796         offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep,
1797                         dissect_ndr_nt_SID_AND_ATTRIBUTES);
1798
1799         proto_item_set_len(item, offset-old_offset);
1800         return offset;
1801 }
1802
1803 /*
1804  * Register ett/hf values and perform DCERPC over SMB specific
1805  * initialisation.
1806  */
1807 void dcerpc_smb_init(int proto_dcerpc)
1808 {
1809         expert_module_t* expert_dcerpc_nt;
1810         static hf_register_info hf[] = {
1811
1812                 /* String handling */
1813
1814                 { &hf_nt_cs_size,
1815                   { "Size", "dcerpc.nt.str.size", FT_UINT16, BASE_DEC,
1816                     NULL, 0x0, "Size of string in short integers",
1817                     HFILL }},
1818
1819                 { &hf_nt_cs_len,
1820                   { "Length", "dcerpc.nt.str.len", FT_UINT16, BASE_DEC,
1821                     NULL, 0x0, "Length of string in short integers",
1822                     HFILL }},
1823
1824                 /* GUIDs */
1825                 { &hf_nt_guid,
1826                   { "GUID", "dcerpc.nt.guid", FT_GUID, BASE_NONE,
1827                     NULL, 0x0, "GUID (uuid for groups?)", HFILL }},
1828
1829                 /* Policy handles */
1830
1831                 { &hf_nt_policy_open_frame,
1832                   { "Frame handle opened", "dcerpc.nt.open_frame",
1833                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1834                     NULL, HFILL }},
1835
1836                 { &hf_nt_policy_close_frame,
1837                   { "Frame handle closed", "dcerpc.nt.close_frame",
1838                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1839                     NULL, HFILL }},
1840
1841                 /* ACBs */
1842
1843                 { &hf_nt_acct_ctrl,
1844                   { "Acct Ctrl", "dcerpc.nt.acct_ctrl", FT_UINT32, BASE_HEX,
1845                     NULL, 0x0, NULL, HFILL }},
1846
1847                 { &hf_nt_acb_disabled,
1848                   { "Account disabled", "dcerpc.nt.acb.disabled", FT_BOOLEAN, 32,
1849                     TFS(&tfs_nt_acb_disabled), 0x0001,
1850                     "If this account is enabled or disabled", HFILL }},
1851
1852                 { &hf_nt_acb_homedirreq,
1853                   { "Home dir required", "dcerpc.nt.acb.homedirreq", FT_BOOLEAN, 32,
1854                     TFS(&tfs_nt_acb_homedirreq), 0x0002,
1855                     "Is homedirs required for this account?", HFILL }},
1856
1857                 { &hf_nt_acb_pwnotreq,
1858                   { "Password required", "dcerpc.nt.acb.pwnotreq", FT_BOOLEAN, 32,
1859                     TFS(&tfs_nt_acb_pwnotreq), 0x0004,
1860                     "If a password is required for this account?", HFILL }},
1861
1862                 { &hf_nt_acb_tempdup,
1863                   { "Temporary duplicate account", "dcerpc.nt.acb.tempdup", FT_BOOLEAN, 32,
1864                     TFS(&tfs_nt_acb_tempdup), 0x0008,
1865                     "If this is a temporary duplicate account", HFILL }},
1866
1867                 { &hf_nt_acb_normal,
1868                   { "Normal user account", "dcerpc.nt.acb.normal", FT_BOOLEAN, 32,
1869                     TFS(&tfs_nt_acb_normal), 0x0010,
1870                     "If this is a normal user account", HFILL }},
1871
1872                 { &hf_nt_acb_mns,
1873                   { "MNS logon user account", "dcerpc.nt.acb.mns", FT_BOOLEAN, 32,
1874                     TFS(&tfs_nt_acb_mns), 0x0020,
1875                     NULL, HFILL }},
1876
1877                 { &hf_nt_acb_domtrust,
1878                   { "Interdomain trust account", "dcerpc.nt.acb.domtrust", FT_BOOLEAN, 32,
1879                     TFS(&tfs_nt_acb_domtrust), 0x0040,
1880                     NULL, HFILL }},
1881
1882                 { &hf_nt_acb_wstrust,
1883                   { "Workstation trust account", "dcerpc.nt.acb.wstrust", FT_BOOLEAN, 32,
1884                     TFS(&tfs_nt_acb_wstrust), 0x0080,
1885                     NULL, HFILL }},
1886
1887                 { &hf_nt_acb_svrtrust,
1888                   { "Server trust account", "dcerpc.nt.acb.svrtrust", FT_BOOLEAN, 32,
1889                     TFS(&tfs_nt_acb_svrtrust), 0x0100,
1890                     NULL, HFILL }},
1891
1892                 { &hf_nt_acb_pwnoexp,
1893                   { "Password expires", "dcerpc.nt.acb.pwnoexp", FT_BOOLEAN, 32,
1894                     TFS(&tfs_nt_acb_pwnoexp), 0x0200,
1895                     "If this account expires or not", HFILL }},
1896
1897                 { &hf_nt_acb_autolock,
1898                   { "Account is autolocked", "dcerpc.nt.acb.autolock", FT_BOOLEAN, 32,
1899                     TFS(&tfs_nt_acb_autolock), 0x0400,
1900                     "If this account has been autolocked", HFILL }},
1901
1902                 { &hf_nt_error,
1903                   { "Wrong string type", "dcerpc.nt.sting_error",
1904                     FT_STRING, BASE_NONE, NULL, 0x0,
1905                     "Non terminated string", HFILL }},
1906
1907                 /* SIDs */
1908
1909                 { &hf_nt_domain_sid,
1910                   { "Domain SID", "dcerpc.nt.domain_sid",
1911                     FT_STRING, BASE_NONE, NULL, 0x0,
1912                     "The Domain SID", HFILL }},
1913
1914                 { &hf_nt_count,
1915                   { "Count", "dcerpc.nt.count",
1916                     FT_UINT32, BASE_DEC, NULL, 0x0,
1917                     "Number of elements in following array", HFILL }},
1918
1919                 /* Logon hours */
1920
1921                 { &hf_logonhours_divisions,
1922                   { "Divisions", "dcerpc.nt.logonhours.divisions",
1923                     FT_UINT16, BASE_DEC, NULL, 0,
1924                     "Number of divisions for LOGON_HOURS", HFILL }},
1925
1926                 { &hf_logonhours_unknown_char,
1927                   { "Unknown char", "dcerpc.nt.unknown.char",
1928                     FT_UINT8, BASE_HEX, NULL, 0x0,
1929                     "Unknown char. If you know what this is, contact wireshark developers.", HFILL }},
1930
1931                 /* Misc */
1932
1933                 { &hf_nt_attrib,
1934                   { "Attributes", "dcerpc.nt.attr",
1935                     FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1936
1937                 { &hf_lsa_String_name_len,
1938                   { "Name Len", "dcerpc.lsa_String.name_len",
1939                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
1940
1941                 { &hf_lsa_String_name_size,
1942                   { "Name Size", "dcerpc.lsa_String.name_size",
1943                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
1944
1945                 { &hf_nt_data_blob_len,
1946                   { "Blob size", "dcerpc.nt.blob.size",
1947                     FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
1948         };
1949
1950         static gint *ett[] = {
1951                 &ett_nt_data_blob,
1952                 &ett_nt_counted_string,
1953                 &ett_nt_counted_byte_array,
1954                 &ett_nt_policy_hnd,
1955                 &ett_nt_sid_pointer,
1956                 &ett_nt_acct_ctrl,
1957                 &ett_nt_logon_hours,
1958                 &ett_nt_logon_hours_hours,
1959                 &ett_nt_sid_array,
1960                 &ett_nt_sid_and_attributes_array,
1961                 &ett_nt_sid_and_attributes,
1962                 &ett_nt_counted_ascii_string,
1963                 &ett_lsa_String,
1964         };
1965         static ei_register_info ei[] = {
1966                 { &ei_dcerpc_nt_badsid, { "dcerpc.nt.badsid", PI_MALFORMED, PI_ERROR, "Association rejected", EXPFILL }},
1967         };
1968
1969         /* Register ett's and hf's */
1970
1971         proto_register_subtree_array(ett, array_length(ett));
1972         proto_register_field_array(proto_dcerpc, hf, array_length(hf));
1973
1974         /* Initialise policy handle hash */
1975         expert_dcerpc_nt = expert_register_protocol(proto_dcerpc);
1976         expert_register_field_array(expert_dcerpc_nt, ei, array_length(ei));
1977         register_init_routine(&init_pol_hash);
1978 }