2 * Routines for DCERPC over SMB packet disassembly
3 * Copyright 2001, Tim Potter <tpot@samba.org>
5 * $Id: packet-dcerpc-nt.c,v 1.46 2002/08/28 21:00:10 jmayer Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <epan/packet.h>
32 #include "packet-dcerpc.h"
33 #include "packet-dcerpc-nt.h"
35 #include "packet-smb-common.h" /* for dissect_smb_64bit_time() */
38 * This file contains helper routines that are used by the DCERPC over SMB
39 * dissectors for ethereal.
42 /* Align offset to a n-byte boundary */
44 int prs_align(int offset, int n)
47 offset += n - (offset % n);
52 /* Parse a 8-bit integer */
54 int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
55 proto_tree *tree, guint8 *data, char *name)
59 /* No alignment required */
61 i = tvb_get_guint8(tvb, offset);
65 proto_tree_add_text(tree, tvb, offset - 1, 1,
74 int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
75 proto_tree *tree, int count, int *data_offset, char *name)
77 /* No alignment required */
80 proto_tree_add_text(tree, tvb, offset, count, "%s", name);
83 *data_offset = offset;
90 /* Parse a 16-bit integer */
92 int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
93 proto_tree *tree, guint16 *data, char *name)
97 offset = prs_align(offset, 2);
99 i = tvb_get_letohs(tvb, offset);
103 proto_tree_add_text(tree, tvb, offset - 2, 2,
111 /* Parse a number of uint16's */
113 int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
114 proto_tree *tree, int count, int *data_offset, char *name)
116 offset = prs_align(offset, 2);
119 proto_tree_add_text(tree, tvb, offset, count * 2,
122 *data_offset = offset;
129 /* Parse a 32-bit integer */
131 int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
132 proto_tree *tree, guint32 *data, char *name)
136 offset = prs_align(offset, 4);
138 i = tvb_get_letohl(tvb, offset);
142 proto_tree_add_text(tree, tvb, offset - 4, 4,
151 /* Parse a number of 32-bit integers */
153 int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
154 proto_tree *tree, int count, int *data_offset, char *name)
156 offset = prs_align(offset, 4);
159 proto_tree_add_text(tree, tvb, offset - 4, 4,
162 *data_offset = offset;
169 /* Parse a NT status code */
171 int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
176 offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
179 proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
180 val_to_str(status, NT_errors, "???"));
186 * We need to keep track of deferred referrents as they appear in the
187 * packet after all the non-pointer objects.
188 * to keep track of pointers as they are parsed as scalars and need to be
189 * remembered for the next call to the prs function.
191 * Pointers are stored in a linked list and pushed in the PARSE_SCALARS
192 * section of the prs function and popped in the PARSE_BUFFERS section. If
193 * we try to pop off a referrent that has a different name then we are
194 * expecting then something has gone wrong.
204 /* Create a new pointer */
206 static struct ptr *new_ptr(char *name, guint32 value)
210 p = g_malloc(sizeof(struct ptr));
212 p->name = g_strdup(name);
220 static void free_ptr(struct ptr *p)
228 /* Parse a pointer and store it's value in a linked list */
230 int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
231 proto_tree *tree, GList **ptr_list, char *name)
236 offset = prs_uint32(tvb, offset, pinfo, tree, &value, NULL);
239 proto_tree_add_text(tree, tvb, offset - 4, 4,
240 "%s pointer: 0x%08x", name, value);
242 p = new_ptr(name, value);
244 *ptr_list = g_list_append(*ptr_list, p);
247 fprintf(stderr, "DEBUG_PTRS: pushing %s ptr = 0x%08x, %d ptrs in "
248 "list\n", name, value, g_list_length(*ptr_list));
254 /* Pop a pointer of a given name. Return it's value. */
256 guint32 prs_pop_ptr(GList **ptr_list, char *name _U_)
262 g_assert(g_list_length(*ptr_list) != 0); /* List too short */
264 /* Get pointer at head of list */
266 elt = g_list_first(*ptr_list);
267 p = (struct ptr *)elt->data;
271 if (strcmp(p->name, name) != 0) {
272 fprintf(stderr, "DEBUG_PTRS: wrong pointer (%s != %s)\n",
277 /* Free pointer record */
279 *ptr_list = g_list_remove_link(*ptr_list, elt);
282 fprintf(stderr, "DEBUG_PTRS: popping %s ptr = 0x%08x, %d ptrs in "
283 "list\n", p->name, p->value, g_list_length(*ptr_list));
291 /* Convert a string from little-endian unicode to ascii. At the moment we
292 fake it by taking every odd byte. )-: The caller must free the
295 char *fake_unicode(tvbuff_t *tvb, int offset, int len)
301 /* Make sure we have enough data before allocating the buffer,
302 so we don't blow up if the length is huge.
303 We do so by attempting to fetch the last character; it'll
304 throw an exception if it's past the end. */
305 tvb_get_letohs(tvb, offset + 2*(len - 1));
307 /* We know we won't throw an exception, so we don't have to worry
308 about leaking this buffer. */
309 buffer = g_malloc(len + 1);
311 for (i = 0; i < len; i++) {
312 character = tvb_get_letohs(tvb, offset);
313 buffer[i] = character & 0xff;
322 /* Parse a UNISTR2 structure */
324 int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
325 proto_tree *tree, int flags, char **data, char *name _U_)
327 guint32 len = 0, unknown = 0, max_len = 0;
329 if (flags & PARSE_SCALARS) {
330 offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
331 offset = prs_uint32(tvb, offset, pinfo, tree, &unknown,
333 offset = prs_uint32(tvb, offset, pinfo, tree, &max_len,
337 if (flags & PARSE_BUFFERS) {
340 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
341 &data16_offset, "Buffer");
344 *data = fake_unicode(tvb, data16_offset, max_len);
350 /* following are a few functions for dissecting common structures used by NT
351 services. These might need to be cleaned up at a later time but at least we get
352 them out of the real service dissectors.
356 /* UNICODE_STRING BEGIN */
357 /* functions to dissect a UNICODE_STRING structure, common to many
362 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
365 these variables can be found in packet-dcerpc-samr.c
367 extern int hf_nt_str_len;
368 extern int hf_nt_str_off;
369 extern int hf_nt_str_max_len;
370 extern int hf_nt_string_length;
371 extern int hf_nt_string_size;
373 gint ett_nt_unicode_string = -1;
374 static gint ett_nt_policy_hnd = -1;
376 /* this function will dissect the
377 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
378 part of the unicode string
383 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
385 structure used by NT to transmit unicode string values.
387 This function also looks at di->levels to see if whoever called us wanted us to append
388 the name: string to any higher levels in the tree .
391 dissect_ndr_nt_UNICODE_STRING_str(tvbuff_t *tvb, int offset,
392 packet_info *pinfo, proto_tree *tree,
395 guint32 len, off, max_len;
401 di=pinfo->private_data;
402 if(di->conformant_run){
403 /*just a run to handle conformant arrays, nothing to dissect */
407 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
408 hf_nt_str_max_len, &max_len);
409 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
410 hf_nt_str_off, &off);
411 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
412 hf_nt_str_len, &len);
415 offset = prs_uint16s(tvb, offset, pinfo, tree, len, &data16_offset,
417 text = fake_unicode(tvb, data16_offset, len);
419 proto_tree_add_string(tree, di->hf_index, tvb, old_offset,
420 offset-old_offset, text);
422 /* need to test di->levels before doing the proto_item_append_text()
423 since netlogon has these objects as top level objects in its representation
424 and trying to append to the tree object in that case will dump core */
425 if(tree && (di->levels>-1)){
426 proto_item_append_text(tree, ": %s", text);
430 proto_item_append_text(tree, ": %s", text);
432 while(di->levels>-1){
434 proto_item_append_text(tree, " %s", text);
443 /* this function will dissect the
447 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
449 structure used by NT to transmit unicode string values.
451 the function takes one additional parameter, level
452 which specifies how many additional levels up in the tree where we should
453 append the string. If unsure, specify levels as 0.
456 dissect_ndr_nt_UNICODE_STRING(tvbuff_t *tvb, int offset,
457 packet_info *pinfo, proto_tree *parent_tree,
458 char *drep, int hf_index, int levels)
460 proto_item *item=NULL;
461 proto_tree *tree=NULL;
462 int old_offset=offset;
466 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
468 di=pinfo->private_data;
469 if(di->conformant_run){
470 /*just a run to handle conformant arrays, nothing to dissect */
474 name = proto_registrar_get_name(hf_index);
476 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
478 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
481 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
482 hf_nt_string_length, NULL);
483 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
484 hf_nt_string_size, NULL);
485 di->levels=1; /* XXX - is this necessary? */
486 /* Add 1 level, for the extra level we added */
487 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
488 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
489 name, hf_index, levels + 1);
491 proto_item_set_len(item, offset-old_offset);
494 /* UNICODE_STRING END */
496 /* functions to dissect a STRING structure, common to many
501 [size_is(size), length_is(len), ptr] char *string;
505 dissect_ndr_nt_STRING_string (tvbuff_t *tvb, int offset,
506 packet_info *pinfo, proto_tree *tree,
509 guint32 len, off, max_len;
513 header_field_info *hfi;
516 di=pinfo->private_data;
517 if(di->conformant_run){
518 /*just a run to handle conformant arrays, nothing to dissect */
522 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
523 hf_nt_str_max_len, &max_len);
524 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
525 hf_nt_str_off, &off);
526 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
527 hf_nt_str_len, &len);
530 hfi = proto_registrar_get_nth(di->hf_index);
534 offset = prs_uint8s(tvb, offset, pinfo, tree, len,
536 text = tvb_get_ptr(tvb, text_offset, len);
537 proto_tree_add_string_format(tree, di->hf_index,
538 tvb, old_offset, offset-old_offset,
539 text, "%s: %s", hfi->name, text);
543 proto_tree_add_item(tree, di->hf_index, tvb, offset, len, FALSE);
548 g_assert_not_reached();
551 if(tree && text && (di->levels>-1)){
552 proto_item_append_text(tree, ": %s", text);
555 proto_item_append_text(tree, ": %s", text);
558 proto_item_append_text(tree, " %s", text);
567 dissect_ndr_nt_STRING (tvbuff_t *tvb, int offset,
568 packet_info *pinfo, proto_tree *parent_tree,
569 char *drep, int hf_index, int levels)
571 proto_item *item=NULL;
572 proto_tree *tree=NULL;
573 int old_offset=offset;
577 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
579 di=pinfo->private_data;
580 if(di->conformant_run){
581 /*just a run to handle conformant arrays, nothing to dissect */
585 name = proto_registrar_get_name(hf_index);
587 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
589 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
592 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
593 hf_nt_string_length, NULL);
594 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
595 hf_nt_string_size, NULL);
596 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
597 dissect_ndr_nt_STRING_string, NDR_POINTER_UNIQUE,
598 name, hf_index, levels);
600 proto_item_set_len(item, offset-old_offset);
605 /* This function is used to dissect a DCERPC encoded 64 bit time value.
606 XXX it should be fixed both here and in dissect_smb_64bit_time so
607 it can handle both BIG and LITTLE endian encodings
610 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
611 packet_info *pinfo, proto_tree *tree,
612 char *drep _U_, int hf_index)
616 di=pinfo->private_data;
617 if(di->conformant_run){
618 /*just a run to handle conformant arrays, nothing to dissect */
624 offset = dissect_smb_64bit_time(tvb, tree, offset, hf_index);
628 /* Define this symbol to display warnings about request/response and
629 policy handle hash table collisions. This happens when a packet with
630 the same conversation, smb fid and dcerpc call id occurs. I think this
631 is due to a bug in the dcerpc/smb fragment reassembly code. */
633 #undef DEBUG_HASH_COLL
636 * Policy handle hashing
640 guint8 policy_hnd[20];
644 guint32 open_frame, close_frame; /* Frame numbers for open/close */
645 char *name; /* Name of policy handle */
648 #define POL_HASH_INIT_COUNT 100
650 static GHashTable *pol_hash;
651 static GMemChunk *pol_hash_key_chunk;
652 static GMemChunk *pol_hash_value_chunk;
656 static guint pol_hash_fn(gconstpointer k)
658 pol_hash_key *key = (pol_hash_key *)k;
660 /* Bytes 4-7 of the policy handle are a timestamp so should make a
661 reasonable hash value */
663 return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
664 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
667 /* Return true if a policy handle is all zeros */
669 static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
671 static guint8 null_policy_hnd[20];
673 return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
676 /* Hash compare function */
678 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
680 pol_hash_key *key1 = (pol_hash_key *)k1;
681 pol_hash_key *key2 = (pol_hash_key *)k2;
683 return memcmp(key1->policy_hnd, key2->policy_hnd,
684 sizeof(key1->policy_hnd)) == 0;
687 /* Store the open and close frame numbers of a policy handle */
689 void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, guint32 open_frame,
693 pol_hash_value *value;
695 if (is_null_pol(policy_hnd) || (open_frame == 0 && close_frame == 0))
698 /* Look up existing value */
700 key = g_mem_chunk_alloc(pol_hash_key_chunk);
702 memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
704 if ((value = g_hash_table_lookup(pol_hash, key))) {
706 /* Update existing value */
709 #ifdef DEBUG_HASH_COLL
710 if (value->open_frame != open_frame)
711 g_warning("dcerpc_smb: pol_hash open frame collision %d/%d\n", value->open_frame, open_frame);
713 value->open_frame = open_frame;
717 #ifdef DEBUG_HASH_COLL
718 if (value->close_frame != close_frame)
719 g_warning("dcerpc_smb: pol_hash close frame collision %d/%d\n", value->close_frame, close_frame);
721 value->close_frame = close_frame;
727 /* Create a new value */
729 value = g_mem_chunk_alloc(pol_hash_value_chunk);
731 value->open_frame = open_frame;
732 value->close_frame = close_frame;
736 g_hash_table_insert(pol_hash, key, value);
739 /* Store a text string with a policy handle */
741 void dcerpc_smb_store_pol_name(e_ctx_hnd *policy_hnd, char *name)
744 pol_hash_value *value;
746 if (is_null_pol(policy_hnd))
749 /* Look up existing value */
751 key = g_mem_chunk_alloc(pol_hash_key_chunk);
753 memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
755 if ((value = g_hash_table_lookup(pol_hash, key))) {
757 /* Update existing value */
759 if (value->name && name) {
760 #ifdef DEBUG_HASH_COLL
761 if (strcmp(value->name, name) != 0)
762 g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
767 value->name = strdup(name);
772 /* Create a new value */
774 value = g_mem_chunk_alloc(pol_hash_value_chunk);
776 value->open_frame = 0;
777 value->close_frame = 0;
780 value->name = strdup(name);
782 value->name = strdup("UNKNOWN");
784 g_hash_table_insert(pol_hash, key, value);
787 /* Retrieve a policy handle */
789 gboolean dcerpc_smb_fetch_pol(e_ctx_hnd *policy_hnd, char **name,
790 guint32 *open_frame, guint32 *close_frame)
793 pol_hash_value *value;
795 /* Prevent uninitialised return vars */
806 /* Look up existing value */
808 memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
810 value = g_hash_table_lookup(pol_hash, &key);
812 /* Return name and frame numbers */
819 *open_frame = value->open_frame;
822 *close_frame = value->close_frame;
825 return value != NULL;
828 /* Iterator to free a policy handle key/value pair */
830 static void free_pol_keyvalue(gpointer key _U_, gpointer value,
831 gpointer user_data _U_)
833 pol_hash_value *pol_value = (pol_hash_value *)value;
837 if (pol_value->name) {
838 free(pol_value->name);
839 pol_value->name = NULL;
843 /* Initialise policy handle hash */
845 static void init_pol_hash(void)
847 /* Initialise memory chunks */
849 if (pol_hash_key_chunk)
850 g_mem_chunk_destroy(pol_hash_key_chunk);
852 pol_hash_key_chunk = g_mem_chunk_new(
853 "Policy handle hash keys", sizeof(pol_hash_key),
854 POL_HASH_INIT_COUNT * sizeof(pol_hash_key), G_ALLOC_ONLY);
856 if (pol_hash_value_chunk)
857 g_mem_chunk_destroy(pol_hash_value_chunk);
859 pol_hash_value_chunk = g_mem_chunk_new(
860 "Policy handle hash values", sizeof(pol_hash_value),
861 POL_HASH_INIT_COUNT * sizeof(pol_hash_value), G_ALLOC_ONLY);
863 /* Initialise hash table */
866 g_hash_table_foreach(pol_hash, free_pol_keyvalue, NULL);
867 g_hash_table_destroy(pol_hash);
870 pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
873 /* Dissect an access mask. All this stuff is kind of explained at MSDN:
875 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/windows_2000_windows_nt_access_mask_format.asp
879 static gint ett_nt_access_mask = -1;
880 static gint ett_nt_access_mask_generic = -1;
881 static gint ett_nt_access_mask_standard = -1;
882 static gint ett_nt_access_mask_specific = -1;
884 static int hf_access_sacl = -1;
885 static int hf_access_maximum_allowed = -1;
886 static int hf_access_generic_read = -1;
887 static int hf_access_generic_write = -1;
888 static int hf_access_generic_execute = -1;
889 static int hf_access_generic_all = -1;
890 static int hf_access_standard_delete = -1;
891 static int hf_access_standard_read_control = -1;
892 static int hf_access_standard_synchronise = -1;
893 static int hf_access_standard_write_dac = -1;
894 static int hf_access_standard_write_owner = -1;
895 static int hf_access_specific_15 = -1;
896 static int hf_access_specific_14 = -1;
897 static int hf_access_specific_13 = -1;
898 static int hf_access_specific_12 = -1;
899 static int hf_access_specific_11 = -1;
900 static int hf_access_specific_10 = -1;
901 static int hf_access_specific_9 = -1;
902 static int hf_access_specific_8 = -1;
903 static int hf_access_specific_7 = -1;
904 static int hf_access_specific_6 = -1;
905 static int hf_access_specific_5 = -1;
906 static int hf_access_specific_4 = -1;
907 static int hf_access_specific_3 = -1;
908 static int hf_access_specific_2 = -1;
909 static int hf_access_specific_1 = -1;
910 static int hf_access_specific_0 = -1;
913 dissect_nt_access_mask(tvbuff_t *tvb, gint offset, packet_info *pinfo,
914 proto_tree *tree, char *drep, int hfindex,
915 nt_access_mask_fn_t *specific_rights_fn)
918 proto_tree *subtree, *generic, *standard, *specific;
921 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
924 item = proto_tree_add_uint(tree, hfindex, tvb, offset - 4, 4, access);
926 subtree = proto_item_add_subtree(item, ett_nt_access_mask);
928 /* Generic access rights */
930 item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
931 "Generic rights: 0x%08x",
932 access & GENERIC_RIGHTS_MASK);
934 generic = proto_item_add_subtree(item, ett_nt_access_mask_generic);
936 proto_tree_add_boolean(
937 generic, hf_access_generic_read, tvb, offset - 4, 4,
940 proto_tree_add_boolean(
941 generic, hf_access_generic_write, tvb, offset - 4, 4,
944 proto_tree_add_boolean(
945 generic, hf_access_generic_execute, tvb, offset - 4, 4,
948 proto_tree_add_boolean(
949 generic, hf_access_generic_all, tvb, offset - 4, 4,
954 proto_tree_add_boolean(
955 subtree, hf_access_maximum_allowed, tvb, offset - 4, 4,
958 /* Access system security */
960 proto_tree_add_boolean(
961 subtree, hf_access_sacl, tvb, offset - 4, 4,
964 /* Standard access rights */
966 item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
967 "Standard rights: 0x%08x",
968 access & STANDARD_RIGHTS_MASK);
970 standard = proto_item_add_subtree(item, ett_nt_access_mask_standard);
972 proto_tree_add_boolean(
973 standard, hf_access_standard_synchronise, tvb, offset - 4, 4,
976 proto_tree_add_boolean(
977 standard, hf_access_standard_write_owner, tvb, offset - 4, 4,
980 proto_tree_add_boolean(
981 standard, hf_access_standard_write_dac, tvb, offset - 4, 4,
984 proto_tree_add_boolean(
985 standard, hf_access_standard_read_control, tvb, offset - 4, 4,
988 proto_tree_add_boolean(
989 standard, hf_access_standard_delete, tvb, offset - 4, 4,
992 /* Specific access rights. Call the specific_rights_fn
993 pointer if we have one, otherwise just display bits 0-15 in
996 item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
997 "Specific rights: 0x%08x",
998 access & SPECIFIC_RIGHTS_MASK);
1000 specific = proto_item_add_subtree(item, ett_nt_access_mask_specific);
1002 if (specific_rights_fn) {
1003 specific_rights_fn(tvb, offset - 4, specific, access);
1007 proto_tree_add_boolean(
1008 specific, hf_access_specific_15, tvb, offset - 4, 4,
1011 proto_tree_add_boolean(
1012 specific, hf_access_specific_14, tvb, offset - 4, 4,
1015 proto_tree_add_boolean(
1016 specific, hf_access_specific_13, tvb, offset - 4, 4,
1019 proto_tree_add_boolean(
1020 specific, hf_access_specific_12, tvb, offset - 4, 4,
1023 proto_tree_add_boolean(
1024 specific, hf_access_specific_11, tvb, offset - 4, 4,
1027 proto_tree_add_boolean(
1028 specific, hf_access_specific_10, tvb, offset - 4, 4,
1031 proto_tree_add_boolean(
1032 specific, hf_access_specific_9, tvb, offset - 4, 4,
1035 proto_tree_add_boolean(
1036 specific, hf_access_specific_8, tvb, offset - 4, 4,
1039 proto_tree_add_boolean(
1040 specific, hf_access_specific_7, tvb, offset - 4, 4,
1043 proto_tree_add_boolean(
1044 specific, hf_access_specific_6, tvb, offset - 4, 4,
1047 proto_tree_add_boolean(
1048 specific, hf_access_specific_5, tvb, offset - 4, 4,
1051 proto_tree_add_boolean(
1052 specific, hf_access_specific_4, tvb, offset - 4, 4,
1055 proto_tree_add_boolean(
1056 specific, hf_access_specific_3, tvb, offset - 4, 4,
1059 proto_tree_add_boolean(
1060 specific, hf_access_specific_2, tvb, offset - 4, 4,
1063 proto_tree_add_boolean(
1064 specific, hf_access_specific_1, tvb, offset - 4, 4,
1067 proto_tree_add_boolean(
1068 specific, hf_access_specific_0, tvb, offset - 4, 4,
1075 * Initialise global DCERPC/SMB data structures
1078 static void dcerpc_smb_init(void)
1080 /* Initialise policy handle hash */
1086 * Register ett_ values, and register "dcerpc_smb_init()" as an
1087 * initialisation routine.
1089 void proto_register_dcerpc_smb(void)
1091 static hf_register_info hf[] = {
1095 { &hf_access_generic_read,
1096 { "Generic read", "nt.access_mask.generic_read",
1097 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1098 GENERIC_READ_ACCESS, "Generic read", HFILL }},
1100 { &hf_access_generic_write,
1101 { "Generic write", "nt.access_mask.generic_write",
1102 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1103 GENERIC_WRITE_ACCESS, "Generic write", HFILL }},
1105 { &hf_access_generic_execute,
1106 { "Generic execute", "nt.access_mask.generic_execute",
1107 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1108 GENERIC_EXECUTE_ACCESS, "Generic execute", HFILL }},
1110 { &hf_access_generic_all,
1111 { "Generic all", "nt.access_mask.generic_all",
1112 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1113 GENERIC_ALL_ACCESS, "Generic all", HFILL }},
1115 { &hf_access_maximum_allowed,
1116 { "Maximum allowed", "nt.access_mask.maximum_allowed",
1117 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1118 MAXIMUM_ALLOWED_ACCESS, "Maximum allowed", HFILL }},
1121 { "Access SACL", "nt.access_mask.access_sacl",
1122 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1123 ACCESS_SACL_ACCESS, "Access SACL", HFILL }},
1125 { &hf_access_standard_read_control,
1126 { "Read control", "nt.access_mask.read_control",
1127 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1128 READ_CONTROL_ACCESS, "Read control", HFILL }},
1130 { &hf_access_standard_delete,
1131 { "Delete", "nt.access_mask.delete",
1132 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1133 DELETE_ACCESS, "Delete", HFILL }},
1135 { &hf_access_standard_synchronise,
1136 { "Synchronise", "nt.access_mask.synchronise",
1137 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1138 SYNCHRONIZE_ACCESS, "Synchronise", HFILL }},
1140 { &hf_access_standard_write_dac,
1141 { "Write DAC", "nt.access_mask.write_dac",
1142 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1143 WRITE_DAC_ACCESS, "Write DAC", HFILL }},
1145 { &hf_access_standard_write_owner,
1146 { "Write owner", "nt.access_mask.write_owner",
1147 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1148 WRITE_OWNER_ACCESS, "Write owner", HFILL }},
1150 { &hf_access_specific_15,
1151 { "Specific access, bit 15", "nt.access_mask.specific_15",
1152 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1153 0x8000, "Specific access, bit 15", HFILL }},
1155 { &hf_access_specific_14,
1156 { "Specific access, bit 14", "nt.access_mask.specific_14",
1157 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1158 0x4000, "Specific access, bit 14", HFILL }},
1160 { &hf_access_specific_13,
1161 { "Specific access, bit 13", "nt.access_mask.specific_13",
1162 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1163 0x2000, "Specific access, bit 13", HFILL }},
1165 { &hf_access_specific_12,
1166 { "Specific access, bit 12", "nt.access_mask.specific_12",
1167 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1168 0x1000, "Specific access, bit 12", HFILL }},
1170 { &hf_access_specific_11,
1171 { "Specific access, bit 11", "nt.access_mask.specific_11",
1172 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1173 0x0800, "Specific access, bit 11", HFILL }},
1175 { &hf_access_specific_10,
1176 { "Specific access, bit 10", "nt.access_mask.specific_10",
1177 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1178 0x0400, "Specific access, bit 10", HFILL }},
1180 { &hf_access_specific_9,
1181 { "Specific access, bit 9", "nt.access_mask.specific_9",
1182 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1183 0x0200, "Specific access, bit 9", HFILL }},
1185 { &hf_access_specific_8,
1186 { "Specific access, bit 8", "nt.access_mask.specific_8",
1187 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1188 0x0100, "Specific access, bit 8", HFILL }},
1190 { &hf_access_specific_7,
1191 { "Specific access, bit 7", "nt.access_mask.specific_7",
1192 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1193 0x0080, "Specific access, bit 7", HFILL }},
1195 { &hf_access_specific_6,
1196 { "Specific access, bit 6", "nt.access_mask.specific_6",
1197 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1198 0x0040, "Specific access, bit 6", HFILL }},
1200 { &hf_access_specific_5,
1201 { "Specific access, bit 5", "nt.access_mask.specific_5",
1202 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1203 0x0020, "Specific access, bit 5", HFILL }},
1205 { &hf_access_specific_4,
1206 { "Specific access, bit 4", "nt.access_mask.specific_4",
1207 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1208 0x0010, "Specific access, bit 4", HFILL }},
1210 { &hf_access_specific_3,
1211 { "Specific access, bit 3", "nt.access_mask.specific_3",
1212 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1213 0x0008, "Specific access, bit 3", HFILL }},
1215 { &hf_access_specific_2,
1216 { "Specific access, bit 2", "nt.access_mask.specific_2",
1217 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1218 0x0004, "Specific access, bit 2", HFILL }},
1220 { &hf_access_specific_1,
1221 { "Specific access, bit 1", "nt.access_mask.specific_1",
1222 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1223 0x0002, "Specific access, bit 1", HFILL }},
1225 { &hf_access_specific_0,
1226 { "Specific access, bit 0", "nt.access_mask.specific_0",
1227 FT_BOOLEAN, 32, TFS(&flags_set_truth),
1228 0x0001, "Specific access, bit 0", HFILL }},
1231 static gint *ett[] = {
1232 &ett_nt_unicode_string,
1234 &ett_nt_access_mask,
1235 &ett_nt_access_mask_generic,
1236 &ett_nt_access_mask_standard,
1237 &ett_nt_access_mask_specific,
1240 static int proto_dcerpc_nt = -1;
1242 /* Register ett's */
1244 proto_register_subtree_array(ett, array_length(ett));
1248 proto_dcerpc_nt = proto_register_protocol(
1249 "Dummy Protocol", "DCERPC_NT", "DCERPC_NT");
1251 proto_register_field_array(proto_dcerpc_nt, hf, array_length(hf));
1253 /* Register a routine to be called whenever initialisation
1256 register_init_routine(dcerpc_smb_init);
1259 /* Check if there is unparsed data remaining in a frame and display an
1260 error. I guess this could be made into an exception like the malformed
1261 frame exception. For the DCERPC over SMB dissectors a long frame
1262 indicates a bug in a dissector. */
1264 void dcerpc_smb_check_long_frame(tvbuff_t *tvb, int offset,
1265 packet_info *pinfo, proto_tree *tree)
1267 if (tvb_length_remaining(tvb, offset) != 0) {
1269 proto_tree_add_text(
1270 tree, tvb, offset, tvb_length_remaining(tvb, offset),
1271 "[Long frame (%d bytes): SPOOLSS]",
1272 tvb_length_remaining(tvb, offset));
1274 if (check_col(pinfo->cinfo, COL_INFO))
1275 col_append_fstr(pinfo->cinfo, COL_INFO,
1276 "[Long frame (%d bytes): SPOOLSS]",
1277 tvb_length_remaining(tvb, offset));
1281 /* Dissect a NT status code */
1284 dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1285 proto_tree *tree, char *drep,
1286 int hfindex, guint32 *pdata)
1290 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1293 if (tree && status != 0 && check_col(pinfo->cinfo, COL_INFO))
1294 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1295 val_to_str(status, NT_errors,
1296 "Unknown error 0x%08x"));
1303 /* Dissect a DOS status code */
1306 dissect_doserror(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1307 proto_tree *tree, char *drep,
1308 int hfindex, guint32 *pdata)
1312 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1315 if (tree && status != 0 && check_col(pinfo->cinfo, COL_INFO))
1316 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1317 val_to_str(status, DOS_errors,
1318 "Unknown error 0x%08x"));
1325 /* Dissect a NT policy handle */
1328 dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1329 proto_tree *tree, char *drep, int hfindex,
1330 e_ctx_hnd *pdata, gboolean is_open, gboolean is_close)
1333 proto_tree *subtree;
1335 guint32 open_frame = 0, close_frame = 0;
1337 int old_offset = offset;
1339 /* Add to proto tree */
1341 item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
1344 subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
1346 offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, drep,
1349 /* Store request/reply information */
1351 dcerpc_smb_store_pol_pkts(&hnd, 0, is_close ? pinfo->fd->num : 0);
1352 dcerpc_smb_store_pol_pkts(&hnd, is_open ? pinfo->fd->num: 0, 0);
1354 /* Insert request/reply information if known */
1356 if (dcerpc_smb_fetch_pol(&hnd, &name, &open_frame, &close_frame)) {
1359 proto_tree_add_text(subtree, tvb, old_offset,
1361 "Opened in frame %u", open_frame);
1364 proto_tree_add_text(subtree, tvb, old_offset,
1366 "Closed in frame %u", close_frame);
1368 proto_item_append_text(item, ": %s", name);
1377 /* Some helper routines to dissect a range of uint8 characters. I don't
1378 think these are "official" NDR representations and are probably specific
1379 to NT so for the moment they're put here instead of in packet-dcerpc.c
1380 and packet-dcerpc-ndr.c. */
1383 dissect_dcerpc_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1384 proto_tree *tree, char *drep, int hfindex,
1385 int length, guint8 **pdata)
1389 data = (guint8 *)tvb_get_ptr(tvb, offset, length);
1392 proto_tree_add_item (tree, hfindex, tvb, offset, length, (drep[0] & 0x10));
1398 return offset + length;
1402 dissect_ndr_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1403 proto_tree *tree, char *drep,
1404 int hfindex, int length, guint8 **pdata)
1408 di=pinfo->private_data;
1409 if(di->conformant_run){
1410 /* just a run to handle conformant arrays, no scalars to dissect */
1414 /* no alignment needed */
1415 return dissect_dcerpc_uint8s(tvb, offset, pinfo,
1416 tree, drep, hfindex, length, pdata);
1420 dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1421 proto_tree *tree, char *drep, int hfindex,
1422 int length, guint16 **pdata)
1426 data = (guint16 *)tvb_get_ptr(tvb, offset, length * 2);
1429 proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, (drep[0] & 0x10));
1435 return offset + length * 2;
1439 dissect_ndr_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1440 proto_tree *tree, char *drep,
1441 int hfindex, int length, guint16 **pdata)
1445 di=pinfo->private_data;
1446 if(di->conformant_run){
1447 /* just a run to handle conformant arrays, no scalars to dissect */
1454 return dissect_dcerpc_uint16s(tvb, offset, pinfo,
1455 tree, drep, hfindex, length, pdata);