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