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 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include <epan/packet.h>
20 #include <epan/expert.h>
23 #include <wsutil/array.h>
25 #include "packet-dcerpc.h"
26 #include "packet-dcerpc-nt.h"
27 #include "packet-windows-common.h"
33 static int hf_lsa_String_name_len
;
34 static int hf_lsa_String_name_size
;
35 static int hf_nt_data_blob_len
;
36 static int hf_nt_data_blob_data
;
37 static int hf_nt_midl_blob_len
;
38 static int hf_nt_midl_fill_bytes
;
39 static int hf_nt_midl_version
;
40 static int hf_nt_midl_hdr_len
;
42 static int ett_nt_MIDL_BLOB
;
43 static int ett_lsa_String
;
44 static int ett_nt_data_blob
;
45 static int ett_nt_counted_string
;
46 static expert_field ei_dcerpc_nt_badsid
;
49 static int cb_array_hdr_size(dcerpc_info
*di
,
50 bool is_conformant
, bool is_varying
,
51 int start_offset
, int end_offset
);
52 static void cb_str_postprocess_options(packet_info
*pinfo
,
58 /* This is used to safely walk the decode tree up, one item at a time safely.
59 This is used by dcerpc dissectors that want to push the display of a string
60 higher up in the tree for greater visibility.
62 #define GET_ITEM_PARENT(x) \
63 ((x->parent!=NULL)?x->parent:x)
66 * This file contains helper routines that are used by the DCERPC over SMB
67 * dissectors for wireshark.
71 * Used by several dissectors.
73 const value_string platform_id_vals
[] = {
76 { 500, "Windows NT" },
83 dissect_ndr_datablob(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
84 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int hf_index
,
85 int use_remaining_space
)
91 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, 0, ett_nt_data_blob
, &item
,
92 proto_registrar_get_name(hf_index
));
94 if (use_remaining_space
) {
95 len
= tvb_captured_length_remaining (tvb
, offset
);
97 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, subtree
, di
, drep
,
98 hf_nt_data_blob_len
, &len
);
100 proto_tree_add_item(subtree
, hf_nt_data_blob_data
, tvb
, offset
, (int)len
, ENC_NA
);
106 dissect_null_term_string_options(tvbuff_t
*tvb
,
111 const unsigned encoding
,
117 if (encoding
& ENC_UTF_16
) {
118 len
= tvb_unicode_strsize(tvb
, offset
);
120 len
= tvb_strsize(tvb
, offset
);
124 * we don't have 'di' so we can't support CB_STR_SAVE
127 options
&= ~CB_STR_SAVE
;
131 proto_tree_add_item(tree
, hf_index
, tvb
, offset
, len
, encoding
);
133 const uint8_t *s
= NULL
;
135 item
= proto_tree_add_item_ret_string(tree
, hf_index
, tvb
, offset
, len
, encoding
, pinfo
->pool
, &s
);
136 cb_str_postprocess_options(pinfo
, proto_item_get_parent(item
), di
, options
, (const char *)s
);
143 dissect_null_term_string(tvbuff_t
*tvb
, int offset
,
144 packet_info
*pinfo _U_
, proto_tree
*tree
,
145 uint8_t *drep _U_
, int hf_index
, int levels _U_
)
147 return dissect_null_term_string_options(tvb
, offset
, pinfo
, tree
,
148 hf_index
, ENC_ASCII
|ENC_NA
,
153 dissect_null_term_wstring(tvbuff_t
*tvb
, int offset
,
154 packet_info
*pinfo _U_
, proto_tree
*tree
,
155 uint8_t *drep _U_
, int hf_index
, int levels _U_
)
157 return dissect_null_term_string_options(tvb
, offset
, pinfo
, tree
,
158 hf_index
, ENC_UTF_16
|ENC_LITTLE_ENDIAN
,
162 /* Parse some common RPC structures */
164 /* Dissect a counted string as a callback to dissect_ndr_pointer_cb() */
167 dissect_ndr_counted_string_cb(tvbuff_t
*tvb
, int offset
,
168 packet_info
*pinfo
, proto_tree
*tree
,
169 dcerpc_info
*di
, uint8_t *drep
, int hf_index
,
170 dcerpc_callback_fnct_t
*callback
,
175 /* Structure starts with short, but is aligned for pointer */
179 if (di
->conformant_run
)
186 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
191 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, tree
, di
, drep
,
194 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, tree
, di
, drep
,
195 hf_nt_cs_size
, &size
);
197 offset
= dissect_ndr_pointer_cb(tvb
, offset
, pinfo
, tree
, di
, drep
,
198 dissect_ndr_wchar_cvstring
, NDR_POINTER_UNIQUE
,
199 "Character Array", hf_index
, callback
, callback_args
);
201 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
209 dissect_ndr_counted_string_helper(tvbuff_t
*tvb
, int offset
,
210 packet_info
*pinfo
, proto_tree
*tree
,
211 dcerpc_info
*di
, uint8_t *drep
, int hf_index
, int levels
,
215 proto_tree
*subtree
= tree
;
219 subtree
= proto_tree_add_subtree(
220 tree
, tvb
, offset
, 0, ett_nt_counted_string
, &item
,
221 proto_registrar_get_name(hf_index
));
225 * Add 2 levels, so that the string gets attached to the
226 * "Character Array" top-level item and to the top-level item
229 return dissect_ndr_counted_string_cb(
230 tvb
, offset
, pinfo
, subtree
, di
, drep
, hf_index
,
231 cb_wstr_postprocess
, GINT_TO_POINTER(2 + levels
));
234 /* Dissect a counted string in-line. */
237 dissect_ndr_counted_string(tvbuff_t
*tvb
, int offset
,
238 packet_info
*pinfo
, proto_tree
*tree
,
239 dcerpc_info
*di
, uint8_t *drep
, int hf_index
, int levels
)
241 return dissect_ndr_counted_string_helper(
242 tvb
, offset
, pinfo
, tree
, di
, drep
, hf_index
, levels
, true);
245 /* Dissect a counted string as a callback to dissect_ndr_pointer().
246 This doesn't add a adds a proto item and subtreee for the string as
247 the pointer dissection already creates one. */
250 dissect_ndr_counted_string_ptr(tvbuff_t
*tvb
, int offset
,
251 packet_info
*pinfo
, proto_tree
*tree
,
252 dcerpc_info
*di
, uint8_t *drep
)
254 return dissect_ndr_counted_string_helper(
255 tvb
, offset
, pinfo
, tree
, di
, drep
, di
->hf_index
, 0, false);
258 /* Dissect a counted byte_array as a callback to dissect_ndr_pointer_cb() */
260 static int ett_nt_counted_byte_array
;
262 /* Dissect a counted byte array in-line. */
265 dissect_ndr_counted_byte_array_cb(tvbuff_t
*tvb
, int offset
,
266 packet_info
*pinfo
, proto_tree
*tree
,
267 dcerpc_info
*di
, uint8_t *drep
, int hf_index
,
268 dcerpc_callback_fnct_t
*callback
,
275 /* Structure starts with short, but is aligned for pointer */
279 if (di
->conformant_run
)
282 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, 0, ett_nt_counted_byte_array
, &item
,
283 proto_registrar_get_name(hf_index
));
289 [size_is(size), length_is(len), ptr] unsigned char *string;
290 } WHATEVER_THIS_IS_CALLED;
294 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, subtree
, di
, drep
,
297 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, subtree
, di
, drep
,
298 hf_nt_cs_size
, &size
);
300 offset
= dissect_ndr_pointer_cb(tvb
, offset
, pinfo
, subtree
, di
, drep
,
301 dissect_ndr_char_cvstring
, NDR_POINTER_UNIQUE
,
302 "Byte Array", hf_index
, callback
, callback_args
);
304 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
311 static void cb_byte_array_postprocess(packet_info
*pinfo
, proto_tree
*tree _U_
,
312 proto_item
*item
, dcerpc_info
*di _U_
, tvbuff_t
*tvb
,
313 int start_offset
, int end_offset
,
316 int options
= GPOINTER_TO_INT(callback_args
);
320 hdr_size
= cb_array_hdr_size(di
,
321 true, /* is_conformant */
322 true, /* is_varying */
329 start_offset
+= hdr_size
;
331 s
= tvb_bytes_to_str(pinfo
->pool
, tvb
, start_offset
, end_offset
- start_offset
);
333 cb_str_postprocess_options(pinfo
, item
, di
, options
, s
);
337 dissect_ndr_counted_byte_array(tvbuff_t
*tvb
, int offset
,
338 packet_info
*pinfo
, proto_tree
*tree
,
339 dcerpc_info
*di
, uint8_t *drep
, int hf_index
, int levels
)
341 return dissect_ndr_counted_byte_array_cb(
342 tvb
, offset
, pinfo
, tree
, di
, drep
, hf_index
, cb_byte_array_postprocess
, GINT_TO_POINTER(2 + levels
));
345 /* Dissect a counted ascii string in-line. */
346 static int ett_nt_counted_ascii_string
;
349 dissect_ndr_counted_ascii_string_cb(tvbuff_t
*tvb
, int offset
,
350 packet_info
*pinfo
, proto_tree
*tree
,
351 dcerpc_info
*di
, uint8_t *drep
, int hf_index
,
352 dcerpc_callback_fnct_t
*callback
,
359 /* Structure starts with short, but is aligned for pointer */
363 if (di
->conformant_run
)
366 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, 0, ett_nt_counted_ascii_string
, &item
,
367 proto_registrar_get_name(hf_index
));
373 [size_is(size), length_is(len), ptr] unsigned char *string;
374 } WHATEVER_THIS_IS_CALLED;
378 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, subtree
, di
, drep
,
381 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, subtree
, di
, drep
,
382 hf_nt_cs_size
, &size
);
384 offset
= dissect_ndr_pointer_cb(tvb
, offset
, pinfo
, subtree
, di
, drep
,
385 dissect_ndr_char_cvstring
, NDR_POINTER_UNIQUE
,
386 "Ascii String", hf_index
, callback
, callback_args
);
388 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
396 dissect_ndr_counted_ascii_string(tvbuff_t
*tvb
, int offset
,
397 packet_info
*pinfo
, proto_tree
*tree
,
398 dcerpc_info
*di
, uint8_t *drep
, int hf_index
, int levels
)
400 return dissect_ndr_counted_ascii_string_cb(
401 tvb
, offset
, pinfo
, tree
, di
, drep
, hf_index
, cb_str_postprocess
, GINT_TO_POINTER(2 + levels
));
404 static int hf_nt_guid
;
407 dissect_nt_GUID(tvbuff_t
*tvb
, int offset
,
408 packet_info
*pinfo
, proto_tree
*tree
,
409 dcerpc_info
*di
, uint8_t *drep
)
411 offset
=dissect_ndr_uuid_t(tvb
, offset
, pinfo
, tree
, di
, drep
, hf_nt_guid
, NULL
);
416 /* This function is used to dissect a lsa_String
417 typedef [public] struct {
418 [value(strlen_m_term(name)*2)] uint16 name_len;
419 [value(strlen_m_term(name)*2)] uint16 name_size;
420 [string,charset(UTF16)] uint16 *name;
424 dissect_ndr_lsa_String(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*parent_tree
, dcerpc_info
*di
, uint8_t *drep
, uint32_t param
, int hfindex
)
429 header_field_info
*hf_info
;
434 hf_info
=proto_registrar_get_nth(hfindex
);
436 tree
= proto_tree_add_subtree_format(parent_tree
, tvb
, offset
, 0, ett_lsa_String
, &item
, "%s: ", hf_info
->name
);
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. */
459 dissect_ndr_nt_NTTIME (tvbuff_t
*tvb
, int offset
,
460 packet_info
*pinfo _U_
, proto_tree
*tree
,
461 dcerpc_info
*di
, uint8_t *drep
, int hf_index
)
463 if(di
->conformant_run
){
464 /*just a run to handle conformant arrays, nothing to dissect */
470 dissect_nttime(tvb
, tree
, offset
, hf_index
,
471 (drep
[0] & DREP_LITTLE_ENDIAN
) ? ENC_LITTLE_ENDIAN
: ENC_BIG_ENDIAN
);
477 dissect_ndr_nt_NTTIME_hyper (tvbuff_t
*tvb
, int offset
,
478 packet_info
*pinfo _U_
, proto_tree
*tree
,
479 dcerpc_info
*di
, uint8_t *drep _U_
, int hf_index
)
481 if(di
->conformant_run
){
482 /*just a run to handle conformant arrays, nothing to dissect */
488 dissect_nttime_hyper(tvb
, tree
, offset
, hf_index
,
489 (drep
[0] & DREP_LITTLE_ENDIAN
) ? ENC_LITTLE_ENDIAN
: ENC_BIG_ENDIAN
);
495 dissect_ndr_nt_NTTIME_1sec (tvbuff_t
*tvb
, int offset
,
496 packet_info
*pinfo _U_
, proto_tree
*tree
,
497 dcerpc_info
*di
, uint8_t *drep
, int hf_index
)
499 if(di
->conformant_run
){
500 /*just a run to handle conformant arrays, nothing to dissect */
506 dissect_nttime_hyper_1sec(tvb
, tree
, offset
, hf_index
,
507 (drep
[0] & DREP_LITTLE_ENDIAN
) ? ENC_LITTLE_ENDIAN
: ENC_BIG_ENDIAN
);
512 /* Define this symbol to display warnings about request/response and
513 policy handle hash table collisions. This happens when a packet with
514 the same conversation, smb fid and dcerpc call id occurs. I think this
515 is due to a bug in the dcerpc/smb fragment reassembly code. */
517 #undef DEBUG_HASH_COLL
520 * Policy handle hashing.
522 * We hash based on the policy handle value; the items in the hash table
523 * are lists of policy handle information about one or more policy
524 * handles with that value. We have multiple values in case a given
525 * policy handle is opened in frame N, closed in frame M, and re-opened
526 * in frame O, where N < M < O.
528 * XXX - we really should also use a DCE RPC conversation/session handle
529 * of some sort, in case two separate sessions have the same handle
530 * value. A transport-layer conversation might not be sufficient, as you
531 * might, for example, have multiple pipes in a single SMB connection,
532 * and you might have the same handle opened and closed separately on
535 * The policy handle information has "first frame" and "last frame"
536 * information; the entry should be used when dissecting a given frame
537 * only if that frame is within the interval [first frame,last frame].
538 * The list is sorted by "first frame".
540 * This doesn't handle the case of a handle being opened in frame N and
541 * re-opened in frame M, where N < M, with no intervening close, but I'm
542 * not sure anything can handle that if it's within the same DCE RPC
543 * session (if it's not, the conversation/session handle would fix that).
547 uint8_t policy_hnd
[20];
551 pol_value
*list
; /* List of policy handle entries */
554 static wmem_map_t
*pol_hash
;
558 static unsigned pol_hash_fn(const void *k
)
560 const pol_hash_key
*key
= (const pol_hash_key
*)k
;
562 /* Bytes 4-7 of the policy handle are a timestamp so should make a
563 reasonable hash value */
565 return key
->policy_hnd
[4] + (key
->policy_hnd
[5] << 8) +
566 (key
->policy_hnd
[6] << 16) + (key
->policy_hnd
[7] << 24);
569 /* Return true if a policy handle is all zeros */
571 static bool is_null_pol(e_ctx_hnd
*policy_hnd
)
573 static uint8_t null_policy_hnd
[20];
575 return memcmp(policy_hnd
, null_policy_hnd
, 20) == 0;
578 /* Hash compare function */
580 static int pol_hash_compare(const void *k1
, const void *k2
)
582 const pol_hash_key
*key1
= (const pol_hash_key
*)k1
;
583 const pol_hash_key
*key2
= (const pol_hash_key
*)k2
;
585 return memcmp(key1
->policy_hnd
, key2
->policy_hnd
,
586 sizeof(key1
->policy_hnd
)) == 0;
590 * Look up the instance of a policy handle value in whose range of frames
591 * the specified frame falls.
593 static pol_value
*find_pol_handle(e_ctx_hnd
*policy_hnd
, uint32_t frame
,
594 pol_hash_value
**valuep
)
599 memcpy(&key
.policy_hnd
, policy_hnd
, sizeof(key
.policy_hnd
));
600 if ((*valuep
= (pol_hash_value
*)wmem_map_lookup(pol_hash
, &key
))) {
602 * Look for the first value such that both:
604 * 1) the first frame in which it was seen is
605 * <= the specified frame;
607 * 2) the last frame in which it was seen is
608 * either unknown (meaning we haven't yet
609 * seen a close or another open of the
610 * same handle, which is assumed to imply
611 * an intervening close that wasn't captured)
612 * or is >= the specified frame.
614 * If there's more than one such frame, that's the
615 * case where a handle is opened in frame N and
616 * reopened in frame M, with no intervening close;
617 * there is no right answer for that, so the instance
618 * opened in frame N is as right as anything else.
620 for (pol
= (*valuep
)->list
; pol
!= NULL
; pol
= pol
->next
) {
621 if (pol
->first_frame
<= frame
&&
622 (pol
->last_frame
== 0 ||
623 pol
->last_frame
>= frame
))
624 break; /* found one */
629 * The handle isn't in the hash table.
635 static void add_pol_handle(e_ctx_hnd
*policy_hnd
, uint32_t frame
,
636 pol_value
*pol
, pol_hash_value
*value
)
639 pol_value
*polprev
, *polnext
;
643 * There's no hash value; create one, put the new
644 * value at the beginning of its policy handle list,
645 * and put the hash value in the policy handle hash
648 value
= wmem_new(wmem_file_scope(), pol_hash_value
);
651 key
= wmem_new(wmem_file_scope(), pol_hash_key
);
652 memcpy(&key
->policy_hnd
, policy_hnd
, sizeof(key
->policy_hnd
));
653 wmem_map_insert(pol_hash
, key
, value
);
656 * Put the new value in the hash value's policy handle
657 * list so that it's sorted by the first frame in
660 * Search for the first entry whose first frame number
661 * is greater than the current frame number, if any.
663 for (polnext
= value
->list
, polprev
= NULL
;
664 polnext
!= NULL
&& polnext
->first_frame
<= frame
;
665 polprev
= polnext
, polnext
= polnext
->next
)
669 * "polprev" points to the entry in the list after
670 * which we should put the new entry; if it's null,
671 * that means we should put it at the beginning of
680 * "polnext" points to the entry in the list before
681 * which we should put the new entry; if it's null,
682 * that means we should put it at the end of the list.
688 /* Store the open and close frame numbers of a policy handle */
690 void dcerpc_smb_store_pol_pkts(e_ctx_hnd
*policy_hnd
, packet_info
*pinfo
,
693 pol_hash_value
*value
;
697 * By the time the first pass is done, the policy handle database
698 * has been completely constructed. If we've already seen this
699 * frame, there's nothing to do.
701 if (pinfo
->fd
->visited
)
704 if (is_null_pol(policy_hnd
))
707 /* Look up existing value */
708 pol
= find_pol_handle(policy_hnd
, pinfo
->num
, &value
);
712 * Update the existing value as appropriate.
714 if (param
& PIDL_POLHND_OPEN
) {
716 * This is an open; we assume that we missed
717 * a close of this handle, so we set its
718 * "last frame" value and act as if we didn't
721 * XXX - note that we might be called twice for
722 * the same operation (see "dissect_pipe_dcerpc()",
723 * which calls the DCE RPC dissector twice), so we
724 * must first check to see if this is a handle we
727 * We check whether this handle's "first frame"
728 * frame number is this frame and its "last frame
729 * is 0; if so, this is presumably a duplicate call,
730 * and we don't do an implicit close.
732 if (pol
->first_frame
== pinfo
->num
&&
733 pol
->last_frame
== 0)
735 pol
->last_frame
= pinfo
->num
;
738 if (param
& PIDL_POLHND_CLOSE
) {
739 pol
->close_frame
= pinfo
->num
;
740 pol
->last_frame
= pinfo
->num
;
746 /* Create a new value */
748 pol
= wmem_new(wmem_file_scope(), pol_value
);
750 pol
->open_frame
= (param
& PIDL_POLHND_OPEN
) ? pinfo
->num
: 0;
751 pol
->close_frame
= (param
& PIDL_POLHND_CLOSE
) ? pinfo
->num
: 0;
752 pol
->first_frame
= pinfo
->num
;
753 pol
->last_frame
= pol
->close_frame
; /* if 0, unknown; if non-0, known */
757 add_pol_handle(policy_hnd
, pinfo
->num
, pol
, value
);
760 /* Store the type of a policy handle */
761 static void dcerpc_store_polhnd_type(e_ctx_hnd
*policy_hnd
, packet_info
*pinfo
,
764 pol_hash_value
*value
;
768 * By the time the first pass is done, the policy handle database
769 * has been completely constructed. If we've already seen this
770 * frame, there's nothing to do.
772 if (pinfo
->fd
->visited
)
775 if (is_null_pol(policy_hnd
))
778 /* Look up existing value */
779 pol
= find_pol_handle(policy_hnd
, pinfo
->num
, &value
);
783 * Update the existing value as appropriate.
789 /* Store a text string with a policy handle */
790 void dcerpc_store_polhnd_name(e_ctx_hnd
*policy_hnd
, packet_info
*pinfo
,
793 pol_hash_value
*value
;
797 * By the time the first pass is done, the policy handle database
798 * has been completely constructed. If we've already seen this
799 * frame, there's nothing to do.
801 if (pinfo
->fd
->visited
)
804 if (is_null_pol(policy_hnd
))
807 /* Look up existing value */
808 pol
= find_pol_handle(policy_hnd
, pinfo
->num
, &value
);
812 * This is the first pass; update the existing
813 * value as appropriate.
815 if (pol
->name
&& name
) {
816 #ifdef DEBUG_HASH_COLL
817 if (strcmp(pol
->name
, name
) != 0)
818 ws_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value
->name
, name
);
820 /* pol->name is wmem_file_scope() allocated, don't free it now */
823 pol
->name
= wmem_strdup(wmem_file_scope(), name
);
828 /* Create a new value */
830 pol
= wmem_new(wmem_file_scope(), pol_value
);
833 pol
->close_frame
= 0;
834 pol
->first_frame
= pinfo
->num
;
838 pol
->name
= wmem_strdup(wmem_file_scope(), name
);
840 pol
->name
= wmem_strdup(wmem_file_scope(), "<UNKNOWN>");
842 add_pol_handle(policy_hnd
, pinfo
->num
, pol
, value
);
846 * Retrieve a policy handle.
848 * XXX - should this get a "param" argument, and match even closed
849 * policy handles if the call closes the handle, so we can handle
850 * retransmitted close operations?
853 bool dcerpc_fetch_polhnd_data(e_ctx_hnd
*policy_hnd
,
854 char **name
, uint32_t *type
,
855 uint32_t *open_frame
, uint32_t *close_frame
,
858 pol_hash_value
*value
;
861 /* Prevent uninitialised return vars */
875 /* Look up existing value */
876 pol
= find_pol_handle(policy_hnd
, cur_frame
, &value
);
886 *open_frame
= pol
->open_frame
;
889 *close_frame
= pol
->close_frame
;
895 /* Dissect a NT status code */
898 dissect_ntstatus(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
899 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
900 int hfindex
, uint32_t *pdata
)
904 offset
= dissect_ndr_uint32(tvb
, offset
, pinfo
, tree
, di
, drep
,
908 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
909 val_to_str_ext(status
, &NT_errors_ext
,
910 "Unknown error 0x%08x"));
917 /* Dissect a DOS status code */
920 dissect_doserror(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
921 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
922 int hfindex
, uint32_t *pdata
)
926 offset
= dissect_ndr_uint32(tvb
, offset
, pinfo
, tree
, di
, drep
,
930 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
931 val_to_str_ext(status
, &DOS_errors_ext
,
932 "Unknown error 0x%08x"));
939 /* Dissect a HRESULT status code */
942 dissect_hresult(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
943 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
944 int hfindex
, uint32_t *pdata
)
948 offset
= dissect_ndr_uint32(tvb
, offset
, pinfo
, tree
, di
, drep
,
952 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
953 val_to_str_ext(status
, &HRES_errors_ext
,
954 "Unknown error 0x%08x"));
961 /* Dissect a NT policy handle */
963 static int hf_nt_policy_open_frame
;
964 static int hf_nt_policy_close_frame
;
966 static int ett_nt_policy_hnd
;
968 /* this function is used to dissect a "handle".
969 * it will keep track of which frame a handle is opened from and in which
970 * frame it is closed.
971 * normally, this function would be used for tracking 20 byte policy handles
972 * as used in dcerpc but it has shown VERY useful to also use it for tracking
973 * GUIDs such as for the file ids in smb2.
981 dissect_nt_hnd(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
982 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int hfindex
,
983 e_ctx_hnd
*pdata
, proto_item
**pitem
,
984 uint32_t param
, e_hnd_type type
)
986 proto_item
*item
=NULL
;
989 uint32_t open_frame
= 0, close_frame
= 0;
991 int old_offset
= offset
;
992 if(di
->conformant_run
){
994 * just a run to handle conformant arrays, no scalars to
995 * dissect - and "dissect_ndr_ctx_hnd()" won't return
996 * a handle, so we can't do the hashing stuff in any
1002 /* Add to proto tree */
1005 case HND_TYPE_CTX_HANDLE
:
1006 if (!di
->no_align
&& (offset
% 4)) {
1007 offset
+= 4 - (offset
% 4);
1009 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, sizeof(e_ctx_hnd
),
1010 ett_nt_policy_hnd
, &item
, "Policy Handle");
1012 offset
= dissect_ndr_ctx_hnd(tvb
, offset
, pinfo
, subtree
, di
, drep
,
1016 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, 16,
1017 ett_nt_policy_hnd
, &item
, "GUID handle");
1020 offset
=dissect_ndr_uuid_t(tvb
, offset
, pinfo
, subtree
, di
, drep
, hfindex
, &hnd
.uuid
);
1023 DISSECTOR_ASSERT_NOT_REACHED();
1028 * Create a new entry for this handle if it's not a null handle
1029 * and no entry already exists, and, in any case, set the
1030 * open, close, first, and last frame information as appropriate.
1032 dcerpc_smb_store_pol_pkts(&hnd
, pinfo
, param
);
1034 /* Insert open/close/name information if known */
1035 if (dcerpc_fetch_polhnd_data(&hnd
, &name
, NULL
, &open_frame
,
1036 &close_frame
, pinfo
->num
)) {
1039 proto_item
*item_local
;
1040 item_local
=proto_tree_add_uint(
1041 subtree
, hf_nt_policy_open_frame
, tvb
,
1042 old_offset
, sizeof(e_ctx_hnd
), open_frame
);
1043 proto_item_set_generated(item_local
);
1046 proto_item
*item_local
;
1047 item_local
=proto_tree_add_uint(
1048 subtree
, hf_nt_policy_close_frame
, tvb
,
1049 old_offset
, sizeof(e_ctx_hnd
), close_frame
);
1050 proto_item_set_generated(item_local
);
1054 * Don't append the handle name if pitem is null; that's
1055 * an indication that our caller will do so, as we're
1056 * supplying a pointer to the item so that they can do
1059 if (name
!= NULL
&& pitem
== NULL
)
1060 proto_item_append_text(item
, ": %s", name
);
1074 dissect_nt_policy_hnd(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1075 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int hfindex
,
1076 e_ctx_hnd
*pdata
, proto_item
**pitem
,
1079 offset
=dissect_nt_hnd(tvb
, offset
, pinfo
,
1080 tree
, di
, drep
, hfindex
,
1082 param
, HND_TYPE_CTX_HANDLE
);
1087 /* This function is called from PIDL generated dissectors to dissect a
1088 * NT style policy handle (contect handle).
1090 * param can be used to specify where policy handles are opened and closed
1091 * by setting PARAM_VALUE to
1092 * PIDL_POLHND_OPEN where the policy handle is opened/created
1093 * PIDL_POLHND_CLOSE where it is closed.
1094 * This enables policy handle tracking so that when a policy handle is
1095 * dissected it will be so as an expansion showing which frame it was
1098 * See conformance file for winreg (epan/dissectors/pidl/winreg.cnf)
1102 PIDL_dissect_policy_hnd(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1103 proto_tree
*tree
, dcerpc_info
* di
, uint8_t *drep
, int hfindex
,
1106 e_ctx_hnd policy_hnd
;
1108 offset
=dissect_nt_hnd(tvb
, offset
, pinfo
,
1109 tree
, di
, drep
, hfindex
,
1111 param
, HND_TYPE_CTX_HANDLE
);
1113 /* If this was an open/create and we don't yet have a policy name
1115 * XXX We do not yet have the infrastructure to know the name of the
1116 * actual object so just show it as <...> for the time being.
1118 if((param
&PIDL_POLHND_OPEN
)
1119 && !pinfo
->fd
->visited
1120 && !di
->conformant_run
){
1121 char *pol_string
=NULL
;
1122 const char *pol_name
=NULL
;
1123 dcerpc_call_value
*dcv
;
1125 dcv
= (dcerpc_call_value
*)di
->call_data
;
1126 pol_name
= (const char *)dcv
->private_data
;
1130 pol_string
=wmem_strdup_printf(pinfo
->pool
, "%s(%s)", di
->dcerpc_procedure_name
, pol_name
);
1131 dcerpc_store_polhnd_name(&policy_hnd
, pinfo
, pol_string
);
1132 dcerpc_store_polhnd_type(&policy_hnd
, pinfo
, param
&PIDL_POLHND_TYPE_MASK
);
1135 /* Track this policy handle for the response */
1136 if(!pinfo
->fd
->visited
1137 && !di
->conformant_run
){
1138 dcerpc_call_value
*dcv
;
1140 dcv
= (dcerpc_call_value
*)di
->call_data
;
1142 dcv
->pol
=(e_ctx_hnd
*)wmem_memdup(wmem_file_scope(), &policy_hnd
, sizeof(e_ctx_hnd
));
1149 /* this function must be called with hfindex being HF_GUID */
1151 dissect_nt_guid_hnd(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1152 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int hfindex
,
1153 e_ctx_hnd
*pdata
, proto_item
**pitem
,
1156 offset
=dissect_nt_hnd(tvb
, offset
, pinfo
,
1157 tree
, di
, drep
, hfindex
,
1159 param
, HND_TYPE_GUID
);
1164 /* Some helper routines to dissect a range of uint8 characters. I don't
1165 think these are "official" NDR representations and are probably specific
1166 to NT so for the moment they're put here instead of in packet-dcerpc.c
1167 and packet-dcerpc-ndr.c. */
1170 dissect_dcerpc_uint8s(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
1171 proto_tree
*tree
, dcerpc_info
*di _U_
, uint8_t *drep _U_
, int hfindex
,
1172 int length
, const uint8_t **pdata
)
1174 const uint8_t *data
;
1176 data
= (const uint8_t *)tvb_get_ptr(tvb
, offset
, length
);
1178 /* This should be an FT_BYTES, so the byte order should not matter */
1179 proto_tree_add_item (tree
, hfindex
, tvb
, offset
, length
, ENC_NA
);
1184 return offset
+ length
;
1188 dissect_ndr_uint8s(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1189 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
1190 int hfindex
, int length
, const uint8_t **pdata
)
1192 if(di
->conformant_run
){
1193 /* just a run to handle conformant arrays, no scalars to dissect */
1197 /* no alignment needed */
1198 return dissect_dcerpc_uint8s(tvb
, offset
, pinfo
,
1199 tree
, di
, drep
, hfindex
, length
, pdata
);
1203 dissect_dcerpc_uint16s(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
1204 proto_tree
*tree
, uint8_t *drep
, int hfindex
,
1207 /* These are FT_BYTES fields, so the byte order should not matter;
1208 however, perhaps there should be an FT_HEXADECTETS type,
1209 or something such as that, with each pair of octets
1210 displayed as a single unit, in which case the byte order
1211 would matter, so we'll calculate the byte order here. */
1212 proto_tree_add_item (tree
, hfindex
, tvb
, offset
, length
* 2, DREP_ENC_INTEGER(drep
));
1214 return offset
+ length
* 2;
1218 dissect_ndr_uint16s(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1219 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
1220 int hfindex
, int length
)
1222 if(di
->conformant_run
){
1223 /* just a run to handle conformant arrays, no scalars to dissect */
1230 return dissect_dcerpc_uint16s(tvb
, offset
, pinfo
,
1231 tree
, drep
, hfindex
, length
);
1234 static int cb_array_hdr_size(dcerpc_info
*di
,
1235 bool is_conformant
, bool is_varying
,
1236 int start_offset
, int end_offset
)
1238 uint8_t conformance_size
= 4;
1241 DISSECTOR_ASSERT(is_conformant
|| is_varying
);
1243 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
1244 conformance_size
= 8;
1247 /* Align start_offset on 4-byte or 8-byte boundary. */
1249 if (start_offset
% conformance_size
)
1250 hdr_size
+= conformance_size
- (start_offset
% conformance_size
);
1252 /* Get byte array value */
1254 hdr_size
+= conformance_size
;
1256 hdr_size
+= (2*conformance_size
);
1258 if ((end_offset
- start_offset
) <= hdr_size
)
1264 static void cb_str_postprocess_options(packet_info
*pinfo
,
1270 int levels
= CB_STR_ITEM_LEVELS(options
);
1272 /* Append string to COL_INFO */
1274 if (options
& CB_STR_COL_INFO
) {
1275 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", s
);
1278 /* Append string to upper-level proto_items */
1279 if (levels
> 0 && item
&& s
&& s
[0]) {
1280 proto_item_append_text(item
, ": %s", s
);
1281 item
= GET_ITEM_PARENT(item
);
1283 if (item
&& levels
> 0) {
1284 proto_item_append_text(item
, ": %s", s
);
1285 item
= GET_ITEM_PARENT(item
);
1287 while (item
&& levels
> 0) {
1288 proto_item_append_text(item
, " %s", s
);
1289 item
= GET_ITEM_PARENT(item
);
1295 /* Save string to dcv->private_data */
1296 if (options
& CB_STR_SAVE
) {
1297 dcerpc_call_value
*dcv
= (dcerpc_call_value
*)di
->call_data
;
1298 dcv
->private_data
= wmem_strdup(wmem_file_scope(), s
);
1303 * Helper routines for dissecting NDR strings
1305 void cb_wstr_postprocess(packet_info
*pinfo
, proto_tree
*tree _U_
,
1306 proto_item
*item
, dcerpc_info
*di
, tvbuff_t
*tvb
,
1307 int start_offset
, int end_offset
,
1308 void *callback_args
)
1310 int options
= GPOINTER_TO_INT(callback_args
);
1314 hdr_size
= cb_array_hdr_size(di
,
1315 true, /* is_conformant */
1316 true, /* is_varying */
1323 start_offset
+= hdr_size
;
1326 * XXX - need to handle non-printable characters here.
1328 * XXX - this is typically called after the string has already
1329 * been fetched and processed by some other routine; is there
1330 * some way we can get that string, rather than duplicating the
1331 * efforts of that routine?
1333 s
= tvb_get_string_enc(pinfo
->pool
,
1334 tvb
, start_offset
, end_offset
- start_offset
,
1335 ENC_UTF_16
|ENC_LITTLE_ENDIAN
);
1337 cb_str_postprocess_options(pinfo
, item
, di
, options
, (char *)s
);
1340 void cb_str_postprocess(packet_info
*pinfo
, proto_tree
*tree _U_
,
1341 proto_item
*item
, dcerpc_info
*di
, tvbuff_t
*tvb
,
1342 int start_offset
, int end_offset
,
1343 void *callback_args
)
1345 int options
= GPOINTER_TO_INT(callback_args
);
1349 hdr_size
= cb_array_hdr_size(di
,
1350 true, /* is_conformant */
1351 true, /* is_varying */
1358 start_offset
+= hdr_size
;
1361 * XXX - need to handle non-printable characters here.
1363 * XXX - this is typically called after the string has already
1364 * been fetched and processed by some other routine; is there
1365 * some way we can get that string, rather than duplicating the
1366 * efforts of that routine?
1368 s
= tvb_get_string_enc(pinfo
->pool
,
1369 tvb
, start_offset
, end_offset
- start_offset
, ENC_ASCII
);
1371 cb_str_postprocess_options(pinfo
, item
, di
, options
, (char *)s
);
1374 /* Dissect a pointer to a NDR string and append the string value to the
1377 int dissect_ndr_str_pointer_item(tvbuff_t
*tvb
, int offset
,
1378 packet_info
*pinfo
, proto_tree
*tree
,
1379 dcerpc_info
*di
, uint8_t *drep
, int type
, const char *text
,
1380 int hf_index
, int levels
)
1382 return dissect_ndr_pointer_cb(
1383 tvb
, offset
, pinfo
, tree
, di
, drep
,
1384 dissect_ndr_wchar_cvstring
, type
, text
, hf_index
,
1385 cb_wstr_postprocess
, GINT_TO_POINTER(levels
+ 1));
1388 /* SID dissection routines */
1390 static int hf_nt_count
;
1391 static int hf_nt_domain_sid
;
1393 /* That's a SID that is always 28 bytes long */
1395 dissect_ndr_nt_SID28(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1396 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep _U_
, int hf_index
)
1399 dcerpc_call_value
*dcv
= (dcerpc_call_value
*)di
->call_data
;
1405 name
=proto_registrar_get_name(hf_index
);
1409 if(di
->conformant_run
){
1410 /* just a run to handle conformant arrays, no scalars to dissect */
1414 newoffset
= dissect_nt_sid(tvb
, offset
, tree
, name
, &sid_str
,
1416 /* The dissected stuff can't be more than 28 bytes */
1417 if ((newoffset
- offset
) > 28) {
1418 item
= proto_tree_get_parent(tree
? tree
->last_child
: NULL
);
1419 expert_add_info(pinfo
, item
, &ei_dcerpc_nt_badsid
);
1421 /* The rest of the dissection will most probably wrong as we are not dissecting what we expect */
1425 /* No matter how much we used for the real dissection of the SID consume 28 bytes */
1427 item
= proto_tree_get_parent(tree
->last_child
);
1428 proto_item_set_len(item
, 28);
1431 /* dcv can be null, for example when this ndr structure is embedded
1432 * inside non-dcerpc pdus, i.e. kerberos PAC structure
1436 * sid_str has ephemeral storage duration;
1437 * dcerpc_call_values have session duration,
1438 * so we need to make its private data have
1439 * session duration as well.
1441 dcv
->private_data
= wmem_strdup(wmem_file_scope(), sid_str
);
1448 dissect_ndr_nt_SID(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1449 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
1451 dcerpc_call_value
*dcv
= (dcerpc_call_value
*)di
->call_data
;
1455 if(di
->hf_index
> 0){
1456 name
=proto_registrar_get_name(di
->hf_index
);
1460 if(di
->conformant_run
){
1461 /* just a run to handle conformant arrays, no scalars to dissect */
1465 /* the SID contains a conformant array, first we must eat
1466 the 4-byte max_count before we can hand it off */
1468 offset
= dissect_ndr_uint3264 (tvb
, offset
, pinfo
, tree
, di
, drep
,
1471 offset
= dissect_nt_sid(tvb
, offset
, tree
, name
, &sid_str
,
1474 /* dcv can be null, for example when this ndr structure is embedded
1475 * inside non-dcerpc pdus, i.e. kerberos PAC structure
1479 * sid_str has ephemeral storage duration;
1480 * dcerpc_call_values have session duration,
1481 * so we need to make its private data have
1482 * session duration as well.
1484 dcv
->private_data
= wmem_strdup(wmem_file_scope(), sid_str
);
1490 /* same as dissect_ndr_nt_SID() but takes the same options as counted strings
1491 do to prettify the dissect pane and the COL_INFO summary line
1493 /* Note this is in fact for dissecting the dom_sid2*/
1495 dissect_ndr_nt_SID_with_options(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1496 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, uint32_t options
, int hf_index
)
1498 dcerpc_call_value
*dcv
= (dcerpc_call_value
*)di
->call_data
;
1499 int levels
= CB_STR_ITEM_LEVELS(options
);
1501 di
->hf_index
= hf_index
;
1502 offset
=dissect_ndr_nt_SID(tvb
, offset
, pinfo
, tree
, di
, drep
);
1504 if(dcv
&& dcv
->private_data
){
1505 char *s
=(char *)dcv
->private_data
;
1506 proto_item
*item
=(proto_item
*)tree
;
1508 if ((options
& CB_STR_COL_INFO
)&&(!di
->conformant_run
)) {
1509 /* kludge, ugly, but this is called twice for all
1510 dcerpc interfaces due to how we chase pointers
1511 and putting the sid twice on the summary line
1513 Real solution would be to block updates to col_info
1514 while we just do a conformance run, this might
1515 have sideeffects so it needs some more thoughts first.
1517 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", s
);
1520 /* Append string to upper-level proto_items */
1522 if (levels
> 0 && item
&& s
&& s
[0]) {
1523 proto_item_append_text(item
, ": %s", s
);
1524 item
= GET_ITEM_PARENT(item
);
1527 proto_item_append_text(item
, ": %s", s
);
1528 item
= GET_ITEM_PARENT(item
);
1530 while (levels
> 0) {
1531 proto_item_append_text(item
, " %s", s
);
1532 item
= GET_ITEM_PARENT(item
);
1543 dissect_ndr_nt_SID_hf_through_ptr(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1544 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
1546 offset
= dissect_ndr_nt_SID_with_options(tvb
, offset
, pinfo
, tree
,
1548 CB_STR_ITEM_LEVELS(2),
1554 static int ett_nt_sid_pointer
;
1557 dissect_ndr_nt_PSID_cb(tvbuff_t
*tvb
, int offset
,
1558 packet_info
*pinfo
, proto_tree
*parent_tree
,
1559 dcerpc_info
*di
, uint8_t *drep
,
1560 dcerpc_callback_fnct_t
*callback
, void *callback_args
)
1564 int old_offset
=offset
;
1566 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, -1,
1567 ett_nt_sid_pointer
, &item
, "SID pointer");
1569 offset
= dissect_ndr_pointer_cb(tvb
, offset
, pinfo
, tree
, di
, drep
,
1570 dissect_ndr_nt_SID_hf_through_ptr
, NDR_POINTER_UNIQUE
,
1571 "SID pointer", hf_nt_domain_sid
,
1572 callback
, callback_args
);
1574 proto_item_set_len(item
, offset
-old_offset
);
1579 dissect_ndr_nt_PSID(tvbuff_t
*tvb
, int offset
,
1580 packet_info
*pinfo
, proto_tree
*parent_tree
,
1581 dcerpc_info
*di
, uint8_t *drep
)
1583 return dissect_ndr_nt_PSID_cb(tvb
, offset
, pinfo
, parent_tree
,
1584 di
, drep
, NULL
, NULL
);
1587 static const true_false_string tfs_nt_acb_disabled
= {
1588 "Account is DISABLED",
1589 "Account is NOT disabled"
1591 static const true_false_string tfs_nt_acb_homedirreq
= {
1592 "Homedir is REQUIRED",
1593 "Homedir is NOT required"
1595 static const true_false_string tfs_nt_acb_pwnotreq
= {
1596 "Password is NOT required",
1597 "Password is REQUIRED"
1599 static const true_false_string tfs_nt_acb_tempdup
= {
1600 "This is a TEMPORARY DUPLICATE account",
1601 "This is NOT a temporary duplicate account"
1603 static const true_false_string tfs_nt_acb_normal
= {
1604 "This is a NORMAL USER account",
1605 "This is NOT a normal user account"
1607 static const true_false_string tfs_nt_acb_mns
= {
1608 "This is a MNS account",
1609 "This is NOT a mns account"
1611 static const true_false_string tfs_nt_acb_domtrust
= {
1612 "This is a DOMAIN TRUST account",
1613 "This is NOT a domain trust account"
1615 static const true_false_string tfs_nt_acb_wstrust
= {
1616 "This is a WORKSTATION TRUST account",
1617 "This is NOT a workstation trust account"
1619 static const true_false_string tfs_nt_acb_svrtrust
= {
1620 "This is a SERVER TRUST account",
1621 "This is NOT a server trust account"
1623 static const true_false_string tfs_nt_acb_pwnoexp
= {
1624 "Passwords does NOT expire",
1625 "Password will EXPIRE"
1627 static const true_false_string tfs_nt_acb_autolock
= {
1628 "This account has been AUTO LOCKED",
1629 "This account has NOT been auto locked"
1632 static int ett_nt_acct_ctrl
;
1634 static int hf_nt_acct_ctrl
;
1635 static int hf_nt_acb_disabled
;
1636 static int hf_nt_acb_homedirreq
;
1637 static int hf_nt_acb_pwnotreq
;
1638 static int hf_nt_acb_tempdup
;
1639 static int hf_nt_acb_normal
;
1640 static int hf_nt_acb_mns
;
1641 static int hf_nt_acb_domtrust
;
1642 static int hf_nt_acb_wstrust
;
1643 static int hf_nt_acb_svrtrust
;
1644 static int hf_nt_acb_pwnoexp
;
1645 static int hf_nt_acb_autolock
;
1648 dissect_ndr_nt_acct_ctrl(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1649 proto_tree
*parent_tree
, dcerpc_info
*di
, uint8_t *drep
)
1652 static int * const flags
[] = {
1653 &hf_nt_acb_autolock
,
1655 &hf_nt_acb_svrtrust
,
1657 &hf_nt_acb_domtrust
,
1661 &hf_nt_acb_pwnotreq
,
1662 &hf_nt_acb_homedirreq
,
1663 &hf_nt_acb_disabled
,
1667 offset
=dissect_ndr_uint32(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &mask
);
1669 proto_tree_add_bitmask_value_with_flags(parent_tree
, tvb
, offset
-4, hf_nt_acct_ctrl
,
1670 ett_nt_acct_ctrl
, flags
, mask
, BMT_NO_APPEND
);
1675 static int hf_logonhours_unknown_char
;
1678 dissect_LOGON_HOURS_entry(tvbuff_t
*tvb
, int offset
,
1679 packet_info
*pinfo
, proto_tree
*tree
,
1680 dcerpc_info
*di
, uint8_t *drep
)
1682 offset
= dissect_ndr_uint8(tvb
, offset
, pinfo
, tree
, di
, drep
,
1683 hf_logonhours_unknown_char
, NULL
);
1687 static int ett_nt_logon_hours_hours
;
1690 dissect_LOGON_HOURS_hours(tvbuff_t
*tvb
, int offset
,
1691 packet_info
*pinfo
, proto_tree
*parent_tree
,
1692 dcerpc_info
*di
, uint8_t *drep
)
1696 int old_offset
=offset
;
1698 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, -1,
1699 ett_nt_logon_hours_hours
, &item
, "LOGON_HOURS:");
1701 offset
= dissect_ndr_ucvarray(tvb
, offset
, pinfo
, tree
, di
, drep
,
1702 dissect_LOGON_HOURS_entry
);
1704 proto_item_set_len(item
, offset
-old_offset
);
1708 static int ett_nt_logon_hours
;
1709 static int hf_logonhours_divisions
;
1712 dissect_ndr_nt_LOGON_HOURS(tvbuff_t
*tvb
, int offset
,
1713 packet_info
*pinfo
, proto_tree
*parent_tree
,
1714 dcerpc_info
*di
, uint8_t *drep
)
1718 int old_offset
=offset
;
1720 ALIGN_TO_4_BYTES
; /* structure starts with short, but is aligned for longs */
1722 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, -1,
1723 ett_nt_logon_hours
, &item
, "LOGON_HOURS:");
1725 offset
= dissect_ndr_uint16(tvb
, offset
, pinfo
, tree
, di
, drep
,
1726 hf_logonhours_divisions
, NULL
);
1727 /* XXX - is this a bitmask like the "logon hours" field in the
1728 Remote API call "NetUserGetInfo()" with an information level
1730 offset
= dissect_ndr_pointer(tvb
, offset
, pinfo
, tree
, di
, drep
,
1731 dissect_LOGON_HOURS_hours
, NDR_POINTER_UNIQUE
,
1734 proto_item_set_len(item
, offset
-old_offset
);
1739 dissect_ndr_nt_PSID_no_hf(tvbuff_t
*tvb
, int offset
,
1740 packet_info
*pinfo
, proto_tree
*parent_tree
,
1741 dcerpc_info
*di
, uint8_t *drep
)
1743 offset
=dissect_ndr_nt_PSID(tvb
, offset
, pinfo
, parent_tree
, di
, drep
);
1748 dissect_ndr_nt_PSID_ARRAY_sids (tvbuff_t
*tvb
, int offset
,
1749 packet_info
*pinfo
, proto_tree
*tree
,
1750 dcerpc_info
*di
, uint8_t *drep
)
1752 offset
= dissect_ndr_ucarray(tvb
, offset
, pinfo
, tree
, di
, drep
,
1753 dissect_ndr_nt_PSID_no_hf
);
1758 static int ett_nt_sid_array
;
1761 dissect_ndr_nt_PSID_ARRAY(tvbuff_t
*tvb
, int offset
,
1762 packet_info
*pinfo
, proto_tree
*parent_tree
,
1763 dcerpc_info
*di
, uint8_t *drep
)
1768 int old_offset
=offset
;
1770 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, -1,
1771 ett_nt_sid_array
, &item
, "SID array:");
1775 offset
= dissect_ndr_uint32 (tvb
, offset
, pinfo
, tree
, di
, drep
,
1776 hf_nt_count
, &count
);
1777 offset
= dissect_ndr_pointer(tvb
, offset
, pinfo
, tree
, di
, drep
,
1778 dissect_ndr_nt_PSID_ARRAY_sids
, NDR_POINTER_UNIQUE
,
1781 proto_item_set_len(item
, offset
-old_offset
);
1783 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
1790 static int ett_nt_sid_and_attributes
;
1791 static int ett_nt_se_group_attrs
;
1792 static int hf_nt_se_group_attrs
;
1793 static int hf_nt_se_group_attrs_mandatory
;
1794 static int hf_nt_se_group_attrs_enabled_by_default
;
1795 static int hf_nt_se_group_attrs_enabled
;
1796 static int hf_nt_se_group_attrs_owner
;
1797 static int hf_nt_se_group_attrs_resource_group
;
1799 static const true_false_string group_attrs_mandatory
= {
1800 "The MANDATORY bit is SET",
1801 "The mandatory bit is NOT set",
1803 static const true_false_string group_attrs_enabled_by_default
= {
1804 "The ENABLED_BY_DEFAULT bit is SET",
1805 "The enabled_by_default bit is NOT set",
1807 static const true_false_string group_attrs_enabled
= {
1808 "The ENABLED bit is SET",
1809 "The enabled bit is NOT set",
1811 static const true_false_string group_attrs_owner
= {
1812 "The OWNER bit is SET",
1813 "The owner bit is NOT set",
1815 static const true_false_string group_attrs_resource_group
= {
1816 "The RESOURCE GROUP bit is SET",
1817 "The resource group bit is NOT set",
1821 dissect_ndr_nt_SE_GROUP_ATTRIBUTES(tvbuff_t
*tvb
, int offset
,
1822 packet_info
*pinfo
, proto_tree
*parent_tree
,
1823 dcerpc_info
*di
, uint8_t *drep
)
1826 static int * const attr
[] = {
1827 &hf_nt_se_group_attrs_mandatory
,
1828 &hf_nt_se_group_attrs_enabled_by_default
,
1829 &hf_nt_se_group_attrs_enabled
,
1830 &hf_nt_se_group_attrs_owner
,
1831 &hf_nt_se_group_attrs_resource_group
,
1835 if(di
->conformant_run
){
1836 /*just a run to handle conformant arrays, nothing to dissect */
1840 offset
=dissect_ndr_uint32(tvb
, offset
, pinfo
, NULL
, di
, drep
,
1843 proto_tree_add_bitmask_value_with_flags(parent_tree
, tvb
, offset
-4,
1844 hf_nt_se_group_attrs
, ett_nt_se_group_attrs
,
1845 attr
, mask
, BMT_NO_APPEND
);
1850 dissect_ndr_nt_SID_AND_ATTRIBUTES(tvbuff_t
*tvb
, int offset
,
1851 packet_info
*pinfo
, proto_tree
*parent_tree
,
1852 dcerpc_info
*di
, uint8_t *drep
)
1857 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, 0,
1858 ett_nt_sid_and_attributes
, &item
, "SID_AND_ATTRIBUTES:");
1860 offset
= dissect_ndr_nt_PSID(tvb
, offset
, pinfo
, tree
, di
, drep
);
1862 offset
= dissect_ndr_nt_SE_GROUP_ATTRIBUTES(tvb
, offset
, pinfo
, tree
, di
, drep
);
1867 static int ett_nt_sid_and_attributes_array
;
1870 dissect_ndr_nt_SID_AND_ATTRIBUTES_ARRAY(tvbuff_t
*tvb
, int offset
,
1871 packet_info
*pinfo
, proto_tree
*parent_tree
,
1872 dcerpc_info
*di
, uint8_t *drep
)
1876 int old_offset
=offset
;
1878 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, 0,
1879 ett_nt_sid_and_attributes_array
, &item
, "SID_AND_ATTRIBUTES array:");
1881 /*offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep,
1882 hf_samr_count, &count); */
1883 offset
= dissect_ndr_ucarray(tvb
, offset
, pinfo
, tree
, di
, drep
,
1884 dissect_ndr_nt_SID_AND_ATTRIBUTES
);
1886 proto_item_set_len(item
, offset
-old_offset
);
1890 /* This might be some sort of header that MIDL generates when creating
1891 * marshalling/unmarshalling code for blobs that are not to be transported
1892 * ontop of DCERPC and where the DREP fields specifying things such as
1893 * endianess and similar are not available.
1896 nt_dissect_MIDL_NDRHEADERBLOB(proto_tree
*parent_tree
, tvbuff_t
*tvb
, int offset
, uint8_t *drep
)
1901 tree
=proto_tree_add_subtree(parent_tree
, tvb
, offset
, 16, ett_nt_MIDL_BLOB
, NULL
, "MES header");
1903 /* modified DREP field that is used for stuff that is transporetd ontop
1906 proto_tree_add_item(tree
, hf_nt_midl_version
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1909 val
= tvb_get_uint8(tvb
, offset
);
1910 proto_tree_add_uint(tree
, hf_dcerpc_drep_byteorder
, tvb
, offset
, 1, val
>>4);
1918 proto_tree_add_item(tree
, hf_nt_midl_hdr_len
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1921 proto_tree_add_item(tree
, hf_nt_midl_fill_bytes
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
1924 /* length of blob that follows */
1925 proto_tree_add_item(tree
, hf_nt_midl_blob_len
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
1932 * Register ett/hf values and perform DCERPC over SMB specific
1935 void dcerpc_smb_init(int proto_dcerpc
)
1937 expert_module_t
* expert_dcerpc_nt
;
1938 static hf_register_info hf
[] = {
1940 /* String handling */
1943 { "Size", "dcerpc.nt.str.size", FT_UINT16
, BASE_DEC
,
1944 NULL
, 0x0, "Size of string in short integers",
1948 { "Length", "dcerpc.nt.str.len", FT_UINT16
, BASE_DEC
,
1949 NULL
, 0x0, "Length of string in short integers",
1954 { "GUID", "dcerpc.nt.guid", FT_GUID
, BASE_NONE
,
1955 NULL
, 0x0, "GUID (uuid for groups?)", HFILL
}},
1957 /* Policy handles */
1959 { &hf_nt_policy_open_frame
,
1960 { "Frame handle opened", "dcerpc.nt.open_frame",
1961 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1964 { &hf_nt_policy_close_frame
,
1965 { "Frame handle closed", "dcerpc.nt.close_frame",
1966 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1972 { "Acct Ctrl", "dcerpc.nt.acct_ctrl", FT_UINT32
, BASE_HEX
,
1973 NULL
, 0x0, NULL
, HFILL
}},
1975 { &hf_nt_acb_disabled
,
1976 { "Account disabled", "dcerpc.nt.acb.disabled", FT_BOOLEAN
, 32,
1977 TFS(&tfs_nt_acb_disabled
), 0x00000001,
1978 "If this account is enabled or disabled", HFILL
}},
1980 { &hf_nt_acb_homedirreq
,
1981 { "Home dir required", "dcerpc.nt.acb.homedirreq", FT_BOOLEAN
, 32,
1982 TFS(&tfs_nt_acb_homedirreq
), 0x00000002,
1983 "Is homedirs required for this account?", HFILL
}},
1985 { &hf_nt_acb_pwnotreq
,
1986 { "Password required", "dcerpc.nt.acb.pwnotreq", FT_BOOLEAN
, 32,
1987 TFS(&tfs_nt_acb_pwnotreq
), 0x00000004,
1988 "If a password is required for this account?", HFILL
}},
1990 { &hf_nt_acb_tempdup
,
1991 { "Temporary duplicate account", "dcerpc.nt.acb.tempdup", FT_BOOLEAN
, 32,
1992 TFS(&tfs_nt_acb_tempdup
), 0x00000008,
1993 "If this is a temporary duplicate account", HFILL
}},
1995 { &hf_nt_acb_normal
,
1996 { "Normal user account", "dcerpc.nt.acb.normal", FT_BOOLEAN
, 32,
1997 TFS(&tfs_nt_acb_normal
), 0x00000010,
1998 "If this is a normal user account", HFILL
}},
2001 { "MNS logon user account", "dcerpc.nt.acb.mns", FT_BOOLEAN
, 32,
2002 TFS(&tfs_nt_acb_mns
), 0x00000020,
2005 { &hf_nt_acb_domtrust
,
2006 { "Interdomain trust account", "dcerpc.nt.acb.domtrust", FT_BOOLEAN
, 32,
2007 TFS(&tfs_nt_acb_domtrust
), 0x00000040,
2010 { &hf_nt_acb_wstrust
,
2011 { "Workstation trust account", "dcerpc.nt.acb.wstrust", FT_BOOLEAN
, 32,
2012 TFS(&tfs_nt_acb_wstrust
), 0x00000080,
2015 { &hf_nt_acb_svrtrust
,
2016 { "Server trust account", "dcerpc.nt.acb.svrtrust", FT_BOOLEAN
, 32,
2017 TFS(&tfs_nt_acb_svrtrust
), 0x00000100,
2020 { &hf_nt_acb_pwnoexp
,
2021 { "Password expires", "dcerpc.nt.acb.pwnoexp", FT_BOOLEAN
, 32,
2022 TFS(&tfs_nt_acb_pwnoexp
), 0x00000200,
2023 "If this account expires or not", HFILL
}},
2025 { &hf_nt_acb_autolock
,
2026 { "Account is autolocked", "dcerpc.nt.acb.autolock", FT_BOOLEAN
, 32,
2027 TFS(&tfs_nt_acb_autolock
), 0x00000400,
2028 "If this account has been autolocked", HFILL
}},
2031 { "Wrong string type", "dcerpc.nt.sting_error",
2032 FT_STRING
, BASE_NONE
, NULL
, 0x0,
2033 "Non terminated string", HFILL
}},
2037 { &hf_nt_domain_sid
,
2038 { "Domain SID", "dcerpc.nt.domain_sid",
2039 FT_STRING
, BASE_NONE
, NULL
, 0x0,
2040 "The Domain SID", HFILL
}},
2043 { "Count", "dcerpc.nt.count",
2044 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
2045 "Number of elements in following array", HFILL
}},
2049 { &hf_logonhours_divisions
,
2050 { "Divisions", "dcerpc.nt.logonhours.divisions",
2051 FT_UINT16
, BASE_DEC
, NULL
, 0,
2052 "Number of divisions for LOGON_HOURS", HFILL
}},
2054 { &hf_logonhours_unknown_char
,
2055 { "Unknown char", "dcerpc.nt.unknown.char",
2056 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
2057 "Unknown char. If you know what this is, contact wireshark developers.", HFILL
}},
2061 { &hf_lsa_String_name_len
,
2062 { "Name Len", "dcerpc.lsa_String.name_len",
2063 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2065 { &hf_lsa_String_name_size
,
2066 { "Name Size", "dcerpc.lsa_String.name_size",
2067 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2069 { &hf_nt_data_blob_len
,
2070 { "Blob size", "dcerpc.nt.blob.size",
2071 FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2073 { &hf_nt_data_blob_data
,
2074 { "Blob data", "dcerpc.nt.blob.data",
2075 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
2077 { &hf_nt_midl_blob_len
, {
2078 "Blob Length", "nt.midl_blob_len", FT_UINT64
, BASE_DEC
,
2079 NULL
, 0, "Length of NDR encoded data that follows", HFILL
}},
2081 { &hf_nt_midl_fill_bytes
, {
2082 "Fill bytes", "nt.midl.fill_bytes", FT_UINT32
, BASE_HEX
,
2083 NULL
, 0, "Just some fill bytes", HFILL
}},
2085 { &hf_nt_midl_version
, {
2086 "Version", "nt.midl.version", FT_UINT8
, BASE_DEC
,
2087 NULL
, 0, "Version of pickling", HFILL
}},
2089 { &hf_nt_midl_hdr_len
, {
2090 "HDR Length", "nt.midl.hdr_len", FT_UINT16
, BASE_DEC
,
2091 NULL
, 0, "Length of header", HFILL
}},
2093 { &hf_nt_se_group_attrs
,
2094 { "Group Attributes", "dcerpc.nt.groups.attrs",
2095 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2097 { &hf_nt_se_group_attrs_mandatory
,
2098 { "Mandatory", "dcerpc.nt.groups.attrs.mandatory",
2099 FT_BOOLEAN
, 32, TFS(&group_attrs_mandatory
), 0x00000001,
2100 "The group attributes MANDATORY flag", HFILL
}},
2102 { &hf_nt_se_group_attrs_enabled_by_default
, {
2103 "Enabled By Default", "dcerpc.nt.groups.attrs.enabled_by_default",
2104 FT_BOOLEAN
, 32, TFS(&group_attrs_enabled_by_default
), 0x00000002,
2105 "The group attributes ENABLED_BY_DEFAULT flag", HFILL
}},
2107 { &hf_nt_se_group_attrs_enabled
, {
2108 "Enabled", "dcerpc.nt.groups.attrs.enabled",
2109 FT_BOOLEAN
, 32, TFS(&group_attrs_enabled
), 0x00000004,
2110 "The group attributes ENABLED flag", HFILL
}},
2112 { &hf_nt_se_group_attrs_owner
, {
2113 "Owner", "dcerpc.nt.groups.attrs.owner",
2114 FT_BOOLEAN
, 32, TFS(&group_attrs_owner
), 0x00000008,
2115 "The group attributes OWNER flag", HFILL
}},
2117 { &hf_nt_se_group_attrs_resource_group
, {
2118 "Resource Group", "dcerpc.nt.groups.attrs.resource_group",
2119 FT_BOOLEAN
, 32, TFS(&group_attrs_resource_group
), 0x20000000,
2120 "The group attributes RESOURCE GROUP flag", HFILL
}},
2124 static int *ett
[] = {
2126 &ett_nt_counted_string
,
2127 &ett_nt_counted_byte_array
,
2129 &ett_nt_sid_pointer
,
2131 &ett_nt_logon_hours
,
2132 &ett_nt_logon_hours_hours
,
2134 &ett_nt_sid_and_attributes_array
,
2135 &ett_nt_sid_and_attributes
,
2136 &ett_nt_se_group_attrs
,
2137 &ett_nt_counted_ascii_string
,
2141 static ei_register_info ei
[] = {
2142 { &ei_dcerpc_nt_badsid
, { "dcerpc.nt.badsid", PI_MALFORMED
, PI_ERROR
, "Association rejected", EXPFILL
}},
2145 /* Register ett's and hf's */
2147 proto_register_subtree_array(ett
, array_length(ett
));
2148 proto_register_field_array(proto_dcerpc
, hf
, array_length(hf
));
2150 /* Initialise policy handle hash */
2151 expert_dcerpc_nt
= expert_register_protocol(proto_dcerpc
);
2152 expert_register_field_array(expert_dcerpc_nt
, ei
, array_length(ei
));
2154 pol_hash
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), pol_hash_fn
, pol_hash_compare
);
2158 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2163 * indent-tabs-mode: t
2166 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2167 * :indentSize=8:tabSize=8:noTabs=false: