2 dissect_ndr_nt_SID_with_options see comment.
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>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
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.
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.
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.
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"
41 int hf_nt_cs_len = -1;
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;
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;
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.
58 #define GET_ITEM_PARENT(x) \
59 ((x->parent!=NULL)?x->parent:x)
62 * This file contains helper routines that are used by the DCERPC over SMB
63 * dissectors for wireshark.
67 * Used by several dissectors.
69 const value_string platform_id_vals[] = {
72 { 500, "Windows NT" },
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)
87 item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
88 proto_registrar_get_name(hf_index));
90 subtree = proto_item_add_subtree(item, ett_nt_data_blob);
92 if (use_remaining_space) {
93 len = tvb_length_remaining (tvb, offset);
95 offset = dissect_ndr_uint3264(tvb, offset, pinfo, subtree, di, drep,
96 hf_nt_data_blob_len, &len);
98 proto_tree_add_text(subtree, tvb, offset, (int)len, "Blob data");
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_)
110 len = tvb_strsize(tvb, offset);
111 proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_ASCII|ENC_NA);
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_)
123 len = tvb_unicode_strsize(tvb, offset);
124 proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_UTF_16|ENC_LITTLE_ENDIAN);
129 /* Parse some common RPC structures */
131 /* Dissect a counted string as a callback to dissect_ndr_pointer_cb() */
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,
142 /* Structure starts with short, but is aligned for pointer */
146 if (di->conformant_run)
153 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
158 offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep,
161 offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep,
162 hf_nt_cs_size, &size);
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);
168 if (di->call_data->flags & DCERPC_IS_NDR64) {
175 static gint ett_nt_counted_string = -1;
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)
184 proto_tree *subtree = tree;
188 item = proto_tree_add_text(
189 tree, tvb, offset, 0, "%s",
190 proto_registrar_get_name(hf_index));
192 subtree = proto_item_add_subtree(item, ett_nt_counted_string);
196 * Add 2 levels, so that the string gets attached to the
197 * "Character Array" top-level item and to the top-level item
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));
205 /* Dissect a counted string in-line. */
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)
212 return dissect_ndr_counted_string_helper(
213 tvb, offset, pinfo, tree, di, drep, hf_index, levels, TRUE);
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. */
221 dissect_ndr_counted_string_ptr(tvbuff_t *tvb, int offset,
222 packet_info *pinfo, proto_tree *tree,
223 dcerpc_info *di, guint8 *drep)
225 return dissect_ndr_counted_string_helper(
226 tvb, offset, pinfo, tree, di, drep, di->hf_index, 0, FALSE);
229 /* Dissect a counted byte_array as a callback to dissect_ndr_pointer_cb() */
231 static gint ett_nt_counted_byte_array = -1;
233 /* Dissect a counted byte array in-line. */
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,
246 /* Structure starts with short, but is aligned for pointer */
250 if (di->conformant_run)
253 item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
254 proto_registrar_get_name(hf_index));
256 subtree = proto_item_add_subtree(item, ett_nt_counted_byte_array);
262 [size_is(size), length_is(len), ptr] unsigned char *string;
263 } WHATEVER_THIS_IS_CALLED;
267 offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
270 offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
271 hf_nt_cs_size, &size);
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);
277 if (di->call_data->flags & DCERPC_IS_NDR64) {
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,
289 gint options = GPOINTER_TO_INT(callback_args);
290 gint levels = CB_STR_ITEM_LEVELS(options);
293 /* Align start_offset on 4-byte boundary. */
295 if (start_offset % 4)
296 start_offset += 4 - (start_offset % 4);
298 /* Get byte array value */
300 if ((end_offset - start_offset) <= 12)
303 s = tvb_bytes_to_ep_str(
304 tvb, start_offset + 12, (end_offset - start_offset - 12) );
306 /* Append string to COL_INFO */
308 if (options & CB_STR_COL_INFO) {
309 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
312 /* Append string to upper-level proto_items */
314 if (levels > 0 && item && s && s[0]) {
315 proto_item_append_text(item, ": %s", s);
316 item = GET_ITEM_PARENT(item);
319 proto_item_append_text(item, ": %s", s);
320 item = GET_ITEM_PARENT(item);
323 proto_item_append_text(item, " %s", s);
324 item = GET_ITEM_PARENT(item);
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)
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));
340 /* Dissect a counted ascii string in-line. */
341 static gint ett_nt_counted_ascii_string = -1;
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,
354 /* Structure starts with short, but is aligned for pointer */
358 if (di->conformant_run)
361 item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
362 proto_registrar_get_name(hf_index));
364 subtree = proto_item_add_subtree(item, ett_nt_counted_ascii_string);
370 [size_is(size), length_is(len), ptr] unsigned char *string;
371 } WHATEVER_THIS_IS_CALLED;
375 offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
378 offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep,
379 hf_nt_cs_size, &size);
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);
385 if (di->call_data->flags & DCERPC_IS_NDR64) {
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)
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));
401 static int hf_nt_guid = -1;
404 dissect_nt_GUID(tvbuff_t *tvb, int offset,
405 packet_info *pinfo, proto_tree *tree,
406 dcerpc_info *di, guint8 *drep)
408 offset=dissect_ndr_uuid_t(tvb, offset, pinfo, tree, di, drep, hf_nt_guid, NULL);
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;
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)
423 proto_item *item = NULL;
424 proto_tree *tree = NULL;
426 header_field_info *hf_info;
431 hf_info=proto_registrar_get_nth(hfindex);
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);
438 offset = PIDL_dissect_uint16(tvb, offset, pinfo, tree, di, drep, hf_lsa_String_name_len, 0);
440 offset = PIDL_dissect_uint16(tvb, offset, pinfo, tree, di, drep, hf_lsa_String_name_size, 0);
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));
448 proto_item_set_len(item, offset-old_offset);
450 if (di->call_data->flags & DCERPC_IS_NDR64) {
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
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)
466 if(di->conformant_run){
467 /*just a run to handle conformant arrays, nothing to dissect */
473 offset = dissect_nt_64bit_time(tvb, tree, offset, hf_index);
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. */
482 #undef DEBUG_HASH_COLL
485 * Policy handle hashing.
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.
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
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".
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).
512 guint8 policy_hnd[20];
516 pol_value *list; /* List of policy handle entries */
519 static GHashTable *pol_hash = NULL;
523 static guint pol_hash_fn(gconstpointer k)
525 const pol_hash_key *key = (const pol_hash_key *)k;
527 /* Bytes 4-7 of the policy handle are a timestamp so should make a
528 reasonable hash value */
530 return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
531 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
534 /* Return true if a policy handle is all zeros */
536 static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
538 static guint8 null_policy_hnd[20];
540 return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
543 /* Hash compare function */
545 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
547 const pol_hash_key *key1 = (const pol_hash_key *)k1;
548 const pol_hash_key *key2 = (const pol_hash_key *)k2;
550 return memcmp(key1->policy_hnd, key2->policy_hnd,
551 sizeof(key1->policy_hnd)) == 0;
555 * Look up the instance of a policy handle value in whose range of frames
556 * the specified frame falls.
558 static pol_value *find_pol_handle(e_ctx_hnd *policy_hnd, guint32 frame,
559 pol_hash_value **valuep)
564 memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
565 if ((*valuep = (pol_hash_value *)g_hash_table_lookup(pol_hash, &key))) {
567 * Look for the first value such that both:
569 * 1) the first frame in which it was seen is
570 * <= the specified frame;
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.
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.
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 */
594 * The handle isn't in the hash table.
600 static void add_pol_handle(e_ctx_hnd *policy_hnd, guint32 frame,
601 pol_value *pol, pol_hash_value *value)
604 pol_value *polprev, *polnext;
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
613 value = (pol_hash_value *)wmem_alloc(wmem_file_scope(), sizeof(pol_hash_value));
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);
621 * Put the new value in the hash value's policy handle
622 * list so that it's sorted by the first frame in
625 * Search for the first entry whose first frame number
626 * is greater than the current frame number, if any.
628 for (polnext = value->list, polprev = NULL;
629 polnext != NULL && polnext->first_frame <= frame;
630 polprev = polnext, polnext = polnext->next)
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
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.
653 /* Store the open and close frame numbers of a policy handle */
655 void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, packet_info *pinfo,
656 gboolean is_open, gboolean is_close)
658 pol_hash_value *value;
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.
666 if (pinfo->fd->flags.visited)
669 if (is_null_pol(policy_hnd))
672 /* Look up existing value */
673 pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
677 * Update the existing value as appropriate.
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
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
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.
697 if (pol->first_frame == pinfo->fd->num &&
698 pol->last_frame == 0)
700 pol->last_frame = pinfo->fd->num;
704 pol->close_frame = pinfo->fd->num;
705 pol->last_frame = pinfo->fd->num;
711 /* Create a new value */
713 pol = (pol_value *)wmem_alloc(wmem_file_scope(), sizeof(pol_value));
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 */
722 add_pol_handle(policy_hnd, pinfo->fd->num, pol, value);
725 /* Store the type of a policy handle */
726 static void dcerpc_store_polhnd_type(e_ctx_hnd *policy_hnd, packet_info *pinfo,
729 pol_hash_value *value;
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.
737 if (pinfo->fd->flags.visited)
740 if (is_null_pol(policy_hnd))
743 /* Look up existing value */
744 pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
748 * Update the existing value as appropriate.
754 /* Store a text string with a policy handle */
755 void dcerpc_store_polhnd_name(e_ctx_hnd *policy_hnd, packet_info *pinfo,
758 pol_hash_value *value;
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.
766 if (pinfo->fd->flags.visited)
769 if (is_null_pol(policy_hnd))
772 /* Look up existing value */
773 pol = find_pol_handle(policy_hnd, pinfo->fd->num, &value);
777 * This is the first pass; update the existing
778 * value as appropriate.
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);
785 /* pol->name is wmem_file_scope() allocated, don't free it now */
788 pol->name = wmem_strdup(wmem_file_scope(), name);
793 /* Create a new value */
795 pol = (pol_value *)wmem_alloc(wmem_file_scope(), sizeof(pol_value));
798 pol->close_frame = 0;
799 pol->first_frame = pinfo->fd->num;
803 pol->name = wmem_strdup(wmem_file_scope(), name);
805 pol->name = wmem_strdup(wmem_file_scope(), "<UNKNOWN>");
807 add_pol_handle(policy_hnd, pinfo->fd->num, pol, value);
811 * Retrieve a policy handle.
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
818 gboolean dcerpc_fetch_polhnd_data(e_ctx_hnd *policy_hnd,
819 char **name, guint32 *type,
820 guint32 *open_frame, guint32 *close_frame,
823 pol_hash_value *value;
826 /* Prevent uninitialised return vars */
840 /* Look up existing value */
841 pol = find_pol_handle(policy_hnd, cur_frame, &value);
851 *open_frame = pol->open_frame;
854 *close_frame = pol->close_frame;
860 /* Initialise policy handle hash */
862 static void init_pol_hash(void)
864 /* Initialise hash table */
867 /* Everything in the table is se_ allocated so there's no
868 * need to go through and free it all.
870 g_hash_table_destroy(pol_hash);
873 pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
876 /* Dissect a NT status code */
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)
885 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep,
889 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
890 val_to_str_ext(status, &NT_errors_ext,
891 "Unknown error 0x%08x"));
898 /* Dissect a DOS status code */
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)
907 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep,
911 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
912 val_to_str_ext(status, &DOS_errors_ext,
913 "Unknown error 0x%08x"));
920 /* Dissect a NT policy handle */
922 static int hf_nt_policy_open_frame = -1;
923 static int hf_nt_policy_close_frame = -1;
925 static gint ett_nt_policy_hnd = -1;
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.
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)
945 proto_item *item=NULL;
948 guint32 open_frame = 0, close_frame = 0;
950 int old_offset = offset;
951 if(di->conformant_run){
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
961 /* Add to proto tree */
964 case HND_TYPE_CTX_HANDLE:
965 item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
968 subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
970 offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, di, drep,
974 item = proto_tree_add_text(tree, tvb, offset, 16,
977 subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
980 offset=dissect_ndr_uuid_t(tvb, offset, pinfo, subtree, di, drep, hfindex, &hnd.uuid);
983 DISSECTOR_ASSERT_NOT_REACHED();
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.
992 dcerpc_smb_store_pol_pkts(&hnd, pinfo, is_open, is_close);
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)) {
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);
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);
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
1019 if (name != NULL && pitem == NULL)
1020 proto_item_append_text(item, ": %s", name);
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)
1039 offset=dissect_nt_hnd(tvb, offset, pinfo,
1040 tree, di, drep, hfindex,
1042 is_open, is_close, HND_TYPE_CTX_HANDLE);
1047 /* This function is called from PIDL generated dissectors to dissect a
1048 * NT style policy handle (contect handle).
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
1058 * See conformance file for winreg (epan/dissectors/pidl/winreg.cnf)
1062 PIDL_dissect_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1063 proto_tree *tree, dcerpc_info* di, guint8 *drep, int hfindex,
1066 e_ctx_hnd policy_hnd;
1068 offset=dissect_nt_hnd(tvb, offset, pinfo,
1069 tree, di, drep, hfindex,
1071 param&PIDL_POLHND_OPEN, param&PIDL_POLHND_CLOSE,
1072 HND_TYPE_CTX_HANDLE);
1074 /* If this was an open/create and we dont yet have a policy name
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.
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;
1086 dcv = (dcerpc_call_value *)di->call_data;
1087 pol_name = (const char *)dcv->private_data;
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);
1096 /* Track this policy handle for the response */
1097 if(!pinfo->fd->flags.visited
1098 && !di->conformant_run){
1099 dcerpc_call_value *dcv;
1101 dcv = (dcerpc_call_value *)di->call_data;
1103 dcv->pol=(e_ctx_hnd *)wmem_memdup(wmem_file_scope(), &policy_hnd, sizeof(e_ctx_hnd));
1110 /* this function must be called with hfindex being HF_GUID */
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)
1117 offset=dissect_nt_hnd(tvb, offset, pinfo,
1118 tree, di, drep, hfindex,
1120 is_open, is_close, HND_TYPE_GUID);
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. */
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)
1137 data = (const guint8 *)tvb_get_ptr(tvb, offset, length);
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);
1147 return offset + length;
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)
1155 if(di->conformant_run){
1156 /* just a run to handle conformant arrays, no scalars to dissect */
1160 /* no alignment needed */
1161 return dissect_dcerpc_uint8s(tvb, offset, pinfo,
1162 tree, di, drep, hfindex, length, pdata);
1166 dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1167 proto_tree *tree, guint8 *drep, int hfindex,
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));
1179 return offset + length * 2;
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)
1187 if(di->conformant_run){
1188 /* just a run to handle conformant arrays, no scalars to dissect */
1195 return dissect_dcerpc_uint16s(tvb, offset, pinfo,
1196 tree, drep, hfindex, length);
1200 * Helper routines for dissecting NDR strings
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)
1207 gint options = GPOINTER_TO_INT(callback_args);
1208 gint levels = CB_STR_ITEM_LEVELS(options);
1211 /* Align start_offset on 4-byte boundary. */
1213 if (start_offset % 4)
1214 start_offset += 4 - (start_offset % 4);
1216 /* Get string value */
1218 if ((end_offset - start_offset) <= 12)
1219 return; /* XXX: Use unistr2 dissector instead? */
1222 * XXX - need to handle non-printable characters here.
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?
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);
1233 /* Append string to COL_INFO */
1235 if (options & CB_STR_COL_INFO) {
1236 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
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);
1244 if (item && levels > 0) {
1245 proto_item_append_text(item, ": %s", s);
1246 item = GET_ITEM_PARENT(item);
1248 while (item && levels > 0) {
1249 proto_item_append_text(item, " %s", s);
1250 item = GET_ITEM_PARENT(item);
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;
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)
1268 gint options = GPOINTER_TO_INT(callback_args);
1269 gint levels = CB_STR_ITEM_LEVELS(options);
1272 /* Align start_offset on 4-byte boundary. */
1274 if (start_offset % 4)
1275 start_offset += 4 - (start_offset % 4);
1277 /* Get string value */
1279 if ((end_offset - start_offset) <= 12)
1280 return; /* XXX: Use unistr2 dissector instead? */
1283 * XXX - need to handle non-printable characters here.
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?
1290 s = tvb_get_string_enc(wmem_packet_scope(),
1291 tvb, start_offset + 12, (end_offset - start_offset - 12), ENC_ASCII);
1293 /* Append string to COL_INFO */
1295 if (options & CB_STR_COL_INFO) {
1296 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1299 /* Append string to upper-level proto_items */
1301 if (levels > 0 && item && s && s[0]) {
1302 proto_item_append_text(item, ": %s", s);
1303 item = GET_ITEM_PARENT(item);
1306 proto_item_append_text(item, ": %s", s);
1307 item = GET_ITEM_PARENT(item);
1309 while (levels > 0) {
1310 proto_item_append_text(item, " %s", s);
1311 item = GET_ITEM_PARENT(item);
1317 /* Save string to dcv->private_data */
1319 if (options & CB_STR_SAVE) {
1320 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1322 dcv->private_data = s;
1326 /* Dissect a pointer to a NDR string and append the string value to the
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)
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));
1340 /* SID dissection routines */
1342 static int hf_nt_count = -1;
1343 static int hf_nt_domain_sid = -1;
1345 /* That's a SID that is always 28 bytes long */
1347 dissect_ndr_nt_SID28(tvbuff_t *tvb, int offset, packet_info *pinfo,
1348 proto_tree *tree, dcerpc_info *di, guint8 *drep _U_)
1351 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1356 if(di->hf_index!=-1){
1357 name=proto_registrar_get_name(di->hf_index);
1361 if(di->conformant_run){
1362 /* just a run to handle conformant arrays, no scalars to dissect */
1366 newoffset = dissect_nt_sid(tvb, offset, tree, name, &sid_str,
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);
1373 /* The rest of the dissection will most probably wrong as we are not dissecting what we expect */
1377 /* No matter how much we used for the real dissection of the SID consume 28 bytes */
1379 item = proto_tree_get_parent(tree->last_child);
1380 proto_item_set_len(item, 28);
1383 /* dcv can be null, for example when this ndr structure is embedded
1384 * inside non-dcerpc pdus, i.e. kerberos PAC structure
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.
1393 dcv->private_data = wmem_strdup(wmem_file_scope(), sid_str);
1400 dissect_ndr_nt_SID(tvbuff_t *tvb, int offset, packet_info *pinfo,
1401 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1403 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1407 if(di->hf_index!=-1){
1408 name=proto_registrar_get_name(di->hf_index);
1412 if(di->conformant_run){
1413 /* just a run to handle conformant arrays, no scalars to dissect */
1417 /* the SID contains a conformant array, first we must eat
1418 the 4-byte max_count before we can hand it off */
1420 offset = dissect_ndr_uint3264 (tvb, offset, pinfo, tree, di, drep,
1423 offset = dissect_nt_sid(tvb, offset, tree, name, &sid_str,
1426 /* dcv can be null, for example when this ndr structure is embedded
1427 * inside non-dcerpc pdus, i.e. kerberos PAC structure
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.
1436 dcv->private_data = wmem_strdup(wmem_file_scope(), sid_str);
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
1445 /* Note this is in fact for dissecting the dom_sid2*/
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)
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);
1453 if(dcv && dcv->private_data){
1454 char *s=(char *)dcv->private_data;
1455 proto_item *item=(proto_item *)tree;
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
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.
1466 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1469 /* Append string to upper-level proto_items */
1471 if (levels > 0 && item && s && s[0]) {
1472 proto_item_append_text(item, ": %s", s);
1473 item = GET_ITEM_PARENT(item);
1476 proto_item_append_text(item, ": %s", s);
1477 item = GET_ITEM_PARENT(item);
1479 while (levels > 0) {
1480 proto_item_append_text(item, " %s", s);
1481 item = GET_ITEM_PARENT(item);
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)
1495 offset = dissect_ndr_nt_SID(tvb, offset, pinfo, tree, di, drep);
1500 static gint ett_nt_sid_pointer = -1;
1503 dissect_ndr_nt_PSID(tvbuff_t *tvb, int offset,
1504 packet_info *pinfo, proto_tree *parent_tree,
1505 dcerpc_info *di, guint8 *drep)
1507 proto_item *item=NULL;
1508 proto_tree *tree=NULL;
1509 int old_offset=offset;
1512 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1514 tree = proto_item_add_subtree(item, ett_nt_sid_pointer);
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);
1521 proto_item_set_len(item, offset-old_offset);
1525 static const true_false_string tfs_nt_acb_disabled = {
1526 "Account is DISABLED",
1527 "Account is NOT disabled"
1529 static const true_false_string tfs_nt_acb_homedirreq = {
1530 "Homedir is REQUIRED",
1531 "Homedir is NOT required"
1533 static const true_false_string tfs_nt_acb_pwnotreq = {
1534 "Password is NOT required",
1535 "Password is REQUIRED"
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"
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"
1545 static const true_false_string tfs_nt_acb_mns = {
1546 "This is a MNS account",
1547 "This is NOT a mns account"
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"
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"
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"
1561 static const true_false_string tfs_nt_acb_pwnoexp = {
1562 "Passwords does NOT expire",
1563 "Password will EXPIRE"
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"
1570 static gint ett_nt_acct_ctrl = -1;
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;
1586 dissect_ndr_nt_acct_ctrl(tvbuff_t *tvb, int offset, packet_info *pinfo,
1587 proto_tree *parent_tree, dcerpc_info *di, guint8 *drep)
1590 proto_item *item = NULL;
1591 proto_tree *tree = NULL;
1593 offset=dissect_ndr_uint32(tvb, offset, pinfo, NULL, di, drep,
1594 hf_nt_acct_ctrl, &mask);
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);
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);
1628 static int hf_logonhours_unknown_char = -1;
1631 dissect_LOGON_HOURS_entry(tvbuff_t *tvb, int offset,
1632 packet_info *pinfo, proto_tree *tree,
1633 dcerpc_info *di, guint8 *drep)
1635 offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, di, drep,
1636 hf_logonhours_unknown_char, NULL);
1640 static gint ett_nt_logon_hours_hours = -1;
1643 dissect_LOGON_HOURS_hours(tvbuff_t *tvb, int offset,
1644 packet_info *pinfo, proto_tree *parent_tree,
1645 dcerpc_info *di, guint8 *drep)
1647 proto_item *item=NULL;
1648 proto_tree *tree=NULL;
1649 int old_offset=offset;
1652 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1654 tree = proto_item_add_subtree(item, ett_nt_logon_hours_hours);
1657 offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, di, drep,
1658 dissect_LOGON_HOURS_entry);
1660 proto_item_set_len(item, offset-old_offset);
1664 static gint ett_nt_logon_hours = -1;
1665 static int hf_logonhours_divisions = -1;
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)
1672 proto_item *item=NULL;
1673 proto_tree *tree=NULL;
1674 int old_offset=offset;
1676 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
1679 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1681 tree = proto_item_add_subtree(item, ett_nt_logon_hours);
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
1689 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, di, drep,
1690 dissect_LOGON_HOURS_hours, NDR_POINTER_UNIQUE,
1693 proto_item_set_len(item, offset-old_offset);
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)
1702 offset=dissect_ndr_nt_PSID(tvb, offset, pinfo, parent_tree, di, drep);
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)
1711 offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep,
1712 dissect_ndr_nt_PSID_no_hf);
1717 static gint ett_nt_sid_array = -1;
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)
1725 proto_item *item=NULL;
1726 proto_tree *tree=NULL;
1727 int old_offset=offset;
1730 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
1732 tree = proto_item_add_subtree(item, ett_nt_sid_array);
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,
1743 proto_item_set_len(item, offset-old_offset);
1745 if (di->call_data->flags & DCERPC_IS_NDR64) {
1752 static gint ett_nt_sid_and_attributes = -1;
1753 static int hf_nt_attrib = -1;
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)
1760 proto_item *item=NULL;
1761 proto_tree *tree=NULL;
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);
1769 offset = dissect_ndr_nt_PSID(tvb, offset, pinfo, tree, di, drep);
1771 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep,
1772 hf_nt_attrib, NULL);
1777 static gint ett_nt_sid_and_attributes_array = -1;
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)
1784 proto_item *item=NULL;
1785 proto_tree *tree=NULL;
1786 int old_offset=offset;
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);
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);
1799 proto_item_set_len(item, offset-old_offset);
1804 * Register ett/hf values and perform DCERPC over SMB specific
1807 void dcerpc_smb_init(int proto_dcerpc)
1809 expert_module_t* expert_dcerpc_nt;
1810 static hf_register_info hf[] = {
1812 /* String handling */
1815 { "Size", "dcerpc.nt.str.size", FT_UINT16, BASE_DEC,
1816 NULL, 0x0, "Size of string in short integers",
1820 { "Length", "dcerpc.nt.str.len", FT_UINT16, BASE_DEC,
1821 NULL, 0x0, "Length of string in short integers",
1826 { "GUID", "dcerpc.nt.guid", FT_GUID, BASE_NONE,
1827 NULL, 0x0, "GUID (uuid for groups?)", HFILL }},
1829 /* Policy handles */
1831 { &hf_nt_policy_open_frame,
1832 { "Frame handle opened", "dcerpc.nt.open_frame",
1833 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1836 { &hf_nt_policy_close_frame,
1837 { "Frame handle closed", "dcerpc.nt.close_frame",
1838 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1844 { "Acct Ctrl", "dcerpc.nt.acct_ctrl", FT_UINT32, BASE_HEX,
1845 NULL, 0x0, NULL, HFILL }},
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 }},
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 }},
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 }},
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 }},
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 }},
1873 { "MNS logon user account", "dcerpc.nt.acb.mns", FT_BOOLEAN, 32,
1874 TFS(&tfs_nt_acb_mns), 0x0020,
1877 { &hf_nt_acb_domtrust,
1878 { "Interdomain trust account", "dcerpc.nt.acb.domtrust", FT_BOOLEAN, 32,
1879 TFS(&tfs_nt_acb_domtrust), 0x0040,
1882 { &hf_nt_acb_wstrust,
1883 { "Workstation trust account", "dcerpc.nt.acb.wstrust", FT_BOOLEAN, 32,
1884 TFS(&tfs_nt_acb_wstrust), 0x0080,
1887 { &hf_nt_acb_svrtrust,
1888 { "Server trust account", "dcerpc.nt.acb.svrtrust", FT_BOOLEAN, 32,
1889 TFS(&tfs_nt_acb_svrtrust), 0x0100,
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 }},
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 }},
1903 { "Wrong string type", "dcerpc.nt.sting_error",
1904 FT_STRING, BASE_NONE, NULL, 0x0,
1905 "Non terminated string", HFILL }},
1909 { &hf_nt_domain_sid,
1910 { "Domain SID", "dcerpc.nt.domain_sid",
1911 FT_STRING, BASE_NONE, NULL, 0x0,
1912 "The Domain SID", HFILL }},
1915 { "Count", "dcerpc.nt.count",
1916 FT_UINT32, BASE_DEC, NULL, 0x0,
1917 "Number of elements in following array", HFILL }},
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 }},
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 }},
1934 { "Attributes", "dcerpc.nt.attr",
1935 FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1937 { &hf_lsa_String_name_len,
1938 { "Name Len", "dcerpc.lsa_String.name_len",
1939 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
1941 { &hf_lsa_String_name_size,
1942 { "Name Size", "dcerpc.lsa_String.name_size",
1943 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
1945 { &hf_nt_data_blob_len,
1946 { "Blob size", "dcerpc.nt.blob.size",
1947 FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
1950 static gint *ett[] = {
1952 &ett_nt_counted_string,
1953 &ett_nt_counted_byte_array,
1955 &ett_nt_sid_pointer,
1957 &ett_nt_logon_hours,
1958 &ett_nt_logon_hours_hours,
1960 &ett_nt_sid_and_attributes_array,
1961 &ett_nt_sid_and_attributes,
1962 &ett_nt_counted_ascii_string,
1965 static ei_register_info ei[] = {
1966 { &ei_dcerpc_nt_badsid, { "dcerpc.nt.badsid", PI_MALFORMED, PI_ERROR, "Association rejected", EXPFILL }},
1969 /* Register ett's and hf's */
1971 proto_register_subtree_array(ett, array_length(ett));
1972 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
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);