2 * Routines for DCERPC over SMB packet disassembly
3 * Copyright 2001, Tim Potter <tpot@samba.org>
5 * $Id: packet-dcerpc-nt.c,v 1.28 2002/04/22 09:43:02 guy 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,
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,
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,
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,
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,
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,
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)
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)
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 /* Parse a policy handle. */
352 int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo,
353 proto_tree *tree, const guint8 **data)
357 offset = prs_align(offset, 4);
359 proto_tree_add_text(tree, tvb, offset, 20, "Policy Handle: %s",
360 tvb_bytes_to_str(tvb, offset, 20));
362 data8 = tvb_get_ptr(tvb, offset, 20);
372 /* following are a few functions for dissecting common structures used by NT
373 services. These might need to be cleaned up at a later time but at least we get
374 them out of the real service dissectors.
378 /* UNICODE_STRING BEGIN */
379 /* functions to dissect a UNICODE_STRING structure, common to many
384 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
387 these variables can be found in packet-dcerpc-samr.c
389 extern int hf_nt_str_len;
390 extern int hf_nt_str_off;
391 extern int hf_nt_str_max_len;
392 extern int hf_nt_string_length;
393 extern int hf_nt_string_size;
395 gint ett_nt_unicode_string = -1;
396 static gint ett_nt_policy_hnd = -1;
398 /* this function will dissect the
399 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
400 part of the unicode string
405 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
407 structure used by NT to transmit unicode string values.
409 This function also looks at di->levels to see if whoever called us wanted us to append
410 the name: string to any higher levels in the tree .
413 dissect_ndr_nt_UNICODE_STRING_str(tvbuff_t *tvb, int offset,
414 packet_info *pinfo, proto_tree *tree,
417 guint32 len, off, max_len;
423 di=pinfo->private_data;
424 if(di->conformant_run){
425 /*just a run to handle conformant arrays, nothing to dissect */
429 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
430 hf_nt_str_max_len, &max_len);
431 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
432 hf_nt_str_off, &off);
433 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
434 hf_nt_str_len, &len);
437 offset = prs_uint16s(tvb, offset, pinfo, tree, len, &data16_offset,
439 text = fake_unicode(tvb, data16_offset, len);
441 proto_tree_add_string(tree, di->hf_index, tvb, old_offset,
442 offset-old_offset, text);
444 /* need to test di->levels before doing the proto_item_append_text()
445 since netlogon has these objects as top level objects in its representation
446 and trying to append to the tree object in that case will dump core */
447 if(tree && (di->levels>-1)){
448 proto_item_append_text(tree, ": %s", text);
452 proto_item_append_text(tree, ": %s", text);
454 while(di->levels>-1){
456 proto_item_append_text(tree, " %s", text);
465 /* this function will dissect the
469 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
471 structure used by NT to transmit unicode string values.
473 the function takes one additional parameter, level
474 which specifies how many additional levels up in the tree where we should
475 append the string. If unsure, specify levels as 0.
478 dissect_ndr_nt_UNICODE_STRING(tvbuff_t *tvb, int offset,
479 packet_info *pinfo, proto_tree *parent_tree,
480 char *drep, int hf_index, int levels)
482 proto_item *item=NULL;
483 proto_tree *tree=NULL;
484 int old_offset=offset;
488 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
490 di=pinfo->private_data;
491 if(di->conformant_run){
492 /*just a run to handle conformant arrays, nothing to dissect */
496 name = proto_registrar_get_name(hf_index);
498 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
500 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
503 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
504 hf_nt_string_length, NULL);
505 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
506 hf_nt_string_size, NULL);
507 di->levels=1; /* XXX - is this necessary? */
508 /* Add 1 level, for the extra level we added */
509 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
510 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
511 name, hf_index, levels + 1);
513 proto_item_set_len(item, offset-old_offset);
516 /* UNICODE_STRING END */
518 /* functions to dissect a STRING structure, common to many
523 [size_is(size), length_is(len), ptr] char *string;
527 dissect_ndr_nt_STRING_string (tvbuff_t *tvb, int offset,
528 packet_info *pinfo, proto_tree *tree,
531 guint32 len, off, max_len;
535 header_field_info *hfi;
538 di=pinfo->private_data;
539 if(di->conformant_run){
540 /*just a run to handle conformant arrays, nothing to dissect */
544 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
545 hf_nt_str_len, &len);
546 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
547 hf_nt_str_off, &off);
548 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
549 hf_nt_str_max_len, &max_len);
552 hfi = proto_registrar_get_nth(di->hf_index);
556 offset = prs_uint8s(tvb, offset, pinfo, tree, max_len,
558 text = tvb_get_ptr(tvb, text_offset, max_len);
559 proto_tree_add_string_format(tree, di->hf_index,
560 tvb, old_offset, offset-old_offset,
561 text, "%s: %s", hfi->name, text);
565 proto_tree_add_item(tree, di->hf_index, tvb, offset, max_len, FALSE);
570 g_assert_not_reached();
573 if(tree && text && (di->levels>-1)){
574 proto_item_append_text(tree, ": %s", text);
577 proto_item_append_text(tree, ": %s", text);
580 proto_item_append_text(tree, " %s", text);
589 dissect_ndr_nt_STRING (tvbuff_t *tvb, int offset,
590 packet_info *pinfo, proto_tree *parent_tree,
591 char *drep, int hf_index, int levels)
593 proto_item *item=NULL;
594 proto_tree *tree=NULL;
595 int old_offset=offset;
599 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
601 di=pinfo->private_data;
602 if(di->conformant_run){
603 /*just a run to handle conformant arrays, nothing to dissect */
607 name = proto_registrar_get_name(hf_index);
609 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
611 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
614 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
615 hf_nt_string_length, NULL);
616 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
617 hf_nt_string_size, NULL);
618 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
619 dissect_ndr_nt_STRING_string, NDR_POINTER_UNIQUE,
620 name, hf_index, levels);
622 proto_item_set_len(item, offset-old_offset);
627 /* This function is used to dissect a DCERPC encoded 64 bit time value.
628 XXX it should be fixed both here and in dissect_smb_64bit_time so
629 it can handle both BIG and LITTLE endian encodings
632 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
633 packet_info *pinfo, proto_tree *tree,
634 char *drep, int hf_index)
638 di=pinfo->private_data;
639 if(di->conformant_run){
640 /*just a run to handle conformant arrays, nothing to dissect */
646 offset = dissect_smb_64bit_time(tvb, pinfo, tree, offset,
651 /* Define this symbol to display warnings about request/response and
652 policy handle hash table collisions. This happens when a packet with
653 the same conversation, smb fid and dcerpc call id occurs. I think this
654 is due to a bug in the dcerpc/smb fragment reassembly code. */
656 #undef DEBUG_HASH_COLL
659 * Policy handle hashing
663 guint8 policy_hnd[20];
667 guint32 open_frame, close_frame; /* Frame numbers for open/close */
668 char *name; /* Name of policy handle */
671 #define POL_HASH_INIT_COUNT 100
673 static GHashTable *pol_hash;
674 static GMemChunk *pol_hash_key_chunk;
675 static GMemChunk *pol_hash_value_chunk;
679 static guint pol_hash_fn(gconstpointer k)
681 pol_hash_key *key = (pol_hash_key *)k;
683 /* Bytes 4-7 of the policy handle are a timestamp so should make a
684 reasonable hash value */
686 return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
687 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
690 /* Return true if a policy handle is all zeros */
692 static gboolean is_null_pol(const guint8 *policy_hnd)
694 static guint8 null_policy_hnd[20];
696 return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
699 /* Hash compare function */
701 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
703 pol_hash_key *key1 = (pol_hash_key *)k1;
704 pol_hash_key *key2 = (pol_hash_key *)k2;
706 return memcmp(key1->policy_hnd, key2->policy_hnd,
707 sizeof(key1->policy_hnd)) == 0;
710 /* Store a policy handle */
712 void dcerpc_smb_store_pol(const guint8 *policy_hnd, char *name,
713 guint32 open_frame, guint32 close_frame)
716 pol_hash_value *value;
718 if (is_null_pol(policy_hnd))
721 /* Look up existing value */
723 key = g_mem_chunk_alloc(pol_hash_key_chunk);
725 memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
727 if ((value = g_hash_table_lookup(pol_hash, key))) {
729 /* Update existing value */
731 if (value->name && name) {
732 #ifdef DEBUG_HASH_COLL
733 if (strcmp(value->name, name) != 0)
734 g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
737 value->name = strdup(name);
741 #ifdef DEBUG_HASH_COLL
742 if (value->open_frame != open_frame)
743 g_warning("dcerpc_smb: pol_hash open frame collision %d/%d\n", value->open_frame, open_frame);
745 value->open_frame = open_frame;
749 #ifdef DEBUG_HASH_COLL
750 if (value->close_frame != close_frame)
751 g_warning("dcerpc_smb: pol_hash close frame collision %d/%d\n", value->close_frame, close_frame);
753 value->close_frame = close_frame;
759 /* Create a new value */
761 value = g_mem_chunk_alloc(pol_hash_value_chunk);
763 value->open_frame = open_frame;
764 value->close_frame = close_frame;
767 value->name = strdup(name);
769 value->name = strdup("UNKNOWN");
771 g_hash_table_insert(pol_hash, key, value);
774 /* Retrieve a policy handle */
776 gboolean dcerpc_smb_fetch_pol(const guint8 *policy_hnd, char **name,
777 guint32 *open_frame, guint32 *close_frame)
780 pol_hash_value *value;
782 /* Prevent uninitialised return vars */
793 /* Look up existing value */
795 memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
797 value = g_hash_table_lookup(pol_hash, &key);
802 /* Return name and frame numbers */
808 *open_frame = value->open_frame;
811 *close_frame = value->close_frame;
816 /* Iterator to free a policy handle key/value pair */
818 static void free_pol_keyvalue(gpointer key, gpointer value, gpointer user_data)
820 pol_hash_value *pol_value = (pol_hash_value *)value;
824 if (pol_value->name) {
825 free(pol_value->name);
826 pol_value->name = NULL;
830 /* Initialise policy handle hash */
832 static void init_pol_hash(void)
834 /* Initialise memory chunks */
836 if (pol_hash_key_chunk)
837 g_mem_chunk_destroy(pol_hash_key_chunk);
839 pol_hash_key_chunk = g_mem_chunk_new(
840 "Policy handle hash keys", sizeof(pol_hash_key),
841 POL_HASH_INIT_COUNT * sizeof(pol_hash_key), G_ALLOC_ONLY);
843 if (pol_hash_value_chunk)
844 g_mem_chunk_destroy(pol_hash_value_chunk);
846 pol_hash_value_chunk = g_mem_chunk_new(
847 "Policy handle hash values", sizeof(pol_hash_value),
848 POL_HASH_INIT_COUNT * sizeof(pol_hash_value), G_ALLOC_ONLY);
850 /* Initialise hash table */
853 g_hash_table_foreach(pol_hash, free_pol_keyvalue, NULL);
854 g_hash_table_destroy(pol_hash);
857 pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
861 * Initialise global DCERPC/SMB data structures
864 static void dcerpc_smb_init(void)
866 /* Initialise policy handle hash */
872 * Register ett_ values, and register "dcerpc_smb_init()" as an
873 * initialisation routine.
875 void proto_register_dcerpc_smb(void)
877 static gint *ett[] = {
878 &ett_nt_unicode_string,
885 proto_register_subtree_array(ett, array_length(ett));
887 /* Register a routine to be called whenever initialisation
890 register_init_routine(dcerpc_smb_init);
893 /* Check if there is unparsed data remaining in a frame and display an
894 error. I guess this could be made into an exception like the malformed
895 frame exception. For the DCERPC over SMB dissectors a long frame
896 indicates a bug in a dissector. */
898 void dcerpc_smb_check_long_frame(tvbuff_t *tvb, int offset,
899 packet_info *pinfo, proto_tree *tree)
901 if (tvb_length_remaining(tvb, offset) != 0) {
903 proto_tree_add_text(tree, tvb, offset, 0,
904 "[Long frame (%d bytes): SPOOLSS]",
905 tvb_length_remaining(tvb, offset));
907 if (check_col(pinfo->cinfo, COL_INFO))
908 col_append_fstr(pinfo->cinfo, COL_INFO,
909 "[Long frame (%d bytes): SPOOLSS]",
910 tvb_length_remaining(tvb, offset));
914 /* Dissect a NT status code */
917 dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
918 proto_tree *tree, char *drep,
919 int hfindex, guint32 *pdata)
923 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
926 if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
927 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
928 val_to_str(status, NT_errors,
936 /* Dissect a NT policy handle */
939 dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
940 proto_tree *tree, char *drep, int hfindex,
943 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
947 guint32 open_frame = 0, close_frame = 0;
950 /* Add to proto tree */
952 item = proto_tree_add_text(tree, tvb, offset, 0, "Policy Handle");
954 subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
956 offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, drep,
959 /* Insert request/reply information if known */
961 if (dcerpc_smb_fetch_pol((const guint8 *)&hnd, &name, &open_frame,
965 proto_tree_add_text(subtree, tvb, offset, 0,
966 "Opened in frame %u", open_frame);
969 proto_tree_add_text(subtree, tvb, offset, 0,
970 "Closed in frame %u", close_frame);
973 /* Store request/reply information */
976 dcerpc_smb_store_pol((const guint8 *)&hnd, NULL, 0,
979 dcerpc_smb_store_pol((const guint8 *)&hnd, NULL,