2 * Routines for DCERPC over SMB packet disassembly
3 * Copyright 2001, Tim Potter <tpot@samba.org>
5 * $Id: packet-dcerpc-nt.c,v 1.20 2002/03/20 07:39:18 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));
292 * Parse a UNISTR2 structure
297 * [size_is(size/2)] [length_is(length/2)] [unique] wchar_t *string;
302 /* Convert a string from little-endian unicode to ascii. At the moment we
303 fake it by taking every odd byte. )-: The caller must free the
306 char *fake_unicode(tvbuff_t *tvb, int offset, int len)
312 /* Make sure we have enough data before allocating the buffer,
313 so we don't blow up if the length is huge.
314 We do so by attempting to fetch the last character; it'll
315 throw an exception if it's past the end. */
316 tvb_get_letohs(tvb, offset + 2*(len - 1));
318 /* We know we won't throw an exception, so we don't have to worry
319 about leaking this buffer. */
320 buffer = g_malloc(len + 1);
322 for (i = 0; i < len; i++) {
323 character = tvb_get_letohs(tvb, offset);
324 buffer[i] = character & 0xff;
333 /* Parse a UNISTR2 structure */
335 int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
336 proto_tree *tree, int flags, char **data, char *name)
338 guint32 len = 0, unknown = 0, max_len = 0;
340 if (flags & PARSE_SCALARS) {
341 offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
342 offset = prs_uint32(tvb, offset, pinfo, tree, &unknown,
344 offset = prs_uint32(tvb, offset, pinfo, tree, &max_len,
348 if (flags & PARSE_BUFFERS) {
351 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
352 &data16_offset, "Buffer");
355 *data = fake_unicode(tvb, data16_offset, max_len);
361 /* Parse a policy handle. */
363 int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo,
364 proto_tree *tree, const guint8 **data)
368 offset = prs_align(offset, 4);
370 proto_tree_add_text(tree, tvb, offset, 20, "Policy Handle: %s",
371 tvb_bytes_to_str(tvb, offset, 20));
373 data8 = tvb_get_ptr(tvb, offset, 20);
383 /* following are a few functions for dissecting common structures used by NT
384 services. These might need to be cleaned up at a later time but at least we get
385 them out of the real service dissectors.
389 /* UNICODE_STRING BEGIN */
390 /* functions to dissect a UNICODE_STRING structure, common to many
395 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
398 these variables can be found in packet-dcerpc-samr.c
400 extern int hf_nt_str_len;
401 extern int hf_nt_str_off;
402 extern int hf_nt_str_max_len;
403 extern int hf_nt_string_length;
404 extern int hf_nt_string_size;
405 extern gint ett_nt_unicode_string;
408 /* this function will dissect the
409 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
410 part of the unicode string
415 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
417 structure used by NT to transmit unicode string values.
419 This function also looks at di->levels to see if whoever called us wanted us to append
420 the name: string to any higher levels in the tree .
423 dissect_ndr_nt_UNICODE_STRING_str(tvbuff_t *tvb, int offset,
424 packet_info *pinfo, proto_tree *tree,
427 guint32 len, off, max_len;
433 di=pinfo->private_data;
434 if(di->conformant_run){
435 /*just a run to handle conformant arrays, nothing to dissect */
439 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
440 hf_nt_str_len, &len);
441 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
442 hf_nt_str_off, &off);
443 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
444 hf_nt_str_max_len, &max_len);
447 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len, &data16_offset,
449 text = fake_unicode(tvb, data16_offset, max_len);
451 proto_tree_add_string(tree, di->hf_index, tvb, old_offset,
452 offset-old_offset, text);
454 /* need to test di->levels before doing the proto_item_append_text()
455 since netlogon has these objects as top level objects in its representation
456 and trying to append to the tree object in that case will dump core */
457 if(tree && (di->levels>-1)){
458 proto_item_append_text(tree, ": %s", text);
461 proto_item_append_text(tree, ": %s", text);
464 proto_item_append_text(tree, " %s", text);
473 /* this function will dissect the
477 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
479 structure used by NT to transmit unicode string values.
481 the function takes one additional parameter, level
482 which specifies how many additional levels up in the tree where we should
483 append the string. If unsure, specify levels as 0.
486 dissect_ndr_nt_UNICODE_STRING(tvbuff_t *tvb, int offset,
487 packet_info *pinfo, proto_tree *parent_tree,
488 char *drep, int hf_index, int levels)
490 proto_item *item=NULL;
491 proto_tree *tree=NULL;
492 int old_offset=offset;
496 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
498 di=pinfo->private_data;
499 if(di->conformant_run){
500 /*just a run to handle conformant arrays, nothing to dissect */
504 name = proto_registrar_get_name(hf_index);
506 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
508 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
511 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
512 hf_nt_string_length, NULL);
513 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
514 hf_nt_string_size, NULL);
516 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
517 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
518 name, hf_index, levels);
520 proto_item_set_len(item, offset-old_offset);
523 /* UNICODE_STRING END */
525 /* functions to dissect a STRING structure, common to many
530 [size_is(size), length_is(len), ptr] char *string;
534 dissect_ndr_nt_STRING_string (tvbuff_t *tvb, int offset,
535 packet_info *pinfo, proto_tree *tree,
538 guint32 len, off, max_len;
542 header_field_info *hfi;
545 di=pinfo->private_data;
546 if(di->conformant_run){
547 /*just a run to handle conformant arrays, nothing to dissect */
551 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
552 hf_nt_str_len, &len);
553 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
554 hf_nt_str_off, &off);
555 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
556 hf_nt_str_max_len, &max_len);
559 hfi = proto_registrar_get_nth(di->hf_index);
563 offset = prs_uint8s(tvb, offset, pinfo, tree, max_len,
565 text = tvb_get_ptr(tvb, text_offset, max_len);
566 proto_tree_add_string_format(tree, di->hf_index,
567 tvb, old_offset, offset-old_offset,
568 text, "%s: %s", hfi->name, text);
572 proto_tree_add_item(tree, di->hf_index, tvb, offset, max_len, FALSE);
577 g_assert_not_reached();
580 if(tree && text && (di->levels>-1)){
581 proto_item_append_text(tree, ": %s", text);
584 proto_item_append_text(tree, ": %s", text);
587 proto_item_append_text(tree, " %s", text);
596 dissect_ndr_nt_STRING (tvbuff_t *tvb, int offset,
597 packet_info *pinfo, proto_tree *parent_tree,
598 char *drep, int hf_index, int levels)
600 proto_item *item=NULL;
601 proto_tree *tree=NULL;
602 int old_offset=offset;
606 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
608 di=pinfo->private_data;
609 if(di->conformant_run){
610 /*just a run to handle conformant arrays, nothing to dissect */
614 name = proto_registrar_get_name(hf_index);
616 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
618 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
621 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
622 hf_nt_string_length, NULL);
623 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
624 hf_nt_string_size, NULL);
625 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
626 dissect_ndr_nt_STRING_string, NDR_POINTER_UNIQUE,
627 name, hf_index, levels);
629 proto_item_set_len(item, offset-old_offset);
634 /* This function is used to dissect a DCERPC encoded 64 bit time value.
635 XXX it should be fixed both here and in dissect_smb_64bit_time so
636 it can handle both BIG and LITTLE endian encodings
639 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
640 packet_info *pinfo, proto_tree *tree,
641 char *drep, int hf_index)
645 di=pinfo->private_data;
646 if(di->conformant_run){
647 /*just a run to handle conformant arrays, nothing to dissect */
653 offset = dissect_smb_64bit_time(tvb, pinfo, tree, offset,