2 * Routines for DCERPC over SMB packet disassembly
3 * Copyright 2001, Tim Potter <tpot@samba.org>
5 * $Id: packet-dcerpc-nt.c,v 1.10 2002/03/10 21:30:10 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"
37 * This file contains helper routines that are used by the DCERPC over SMB
38 * dissectors for ethereal.
41 /* Align offset to a n-byte boundary */
43 int prs_align(int offset, int n)
46 offset += n - (offset % n);
51 /* Parse a 8-bit integer */
53 int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo,
54 proto_tree *tree, guint8 *data, char *name)
58 /* No alignment required */
60 i = tvb_get_guint8(tvb, offset);
64 proto_tree_add_text(tree, tvb, offset - 1, 1,
73 int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo,
74 proto_tree *tree, int count, guint8 **data, char *name)
78 /* The tvb_get_ptr() function fails an assertion if count < -1 */
83 /* No alignment required */
85 ptr = tvb_get_ptr(tvb, offset, count);
88 proto_tree_add_text(tree, tvb, offset, count, "%s", name);
91 *data = (guint8 *)ptr;
98 /* Parse a 16-bit integer */
100 int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo,
101 proto_tree *tree, guint16 *data, char *name)
105 offset = prs_align(offset, 2);
107 i = tvb_get_letohs(tvb, offset);
111 proto_tree_add_text(tree, tvb, offset - 2, 2,
119 /* Parse a number of uint16's */
121 int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo,
122 proto_tree *tree, int count, guint16 **data, char *name)
126 /* The tvb_get_ptr() function fails an assertion if count < -1 */
131 offset = prs_align(offset, 2);
133 ptr = tvb_get_ptr(tvb, offset, count * 2);
136 proto_tree_add_text(tree, tvb, offset, count * 2,
139 *data = (guint16 *)ptr;
146 /* Parse a 32-bit integer */
148 int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
149 proto_tree *tree, guint32 *data, char *name)
153 offset = prs_align(offset, 4);
155 i = tvb_get_letohl(tvb, offset);
159 proto_tree_add_text(tree, tvb, offset - 4, 4,
168 /* Parse a number of 32-bit integers */
170 int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo,
171 proto_tree *tree, int count, guint32 **data, char *name)
175 /* The tvb_get_ptr() function fails an assertion if count < -1 */
180 offset = prs_align(offset, 4);
182 ptr = tvb_get_ptr(tvb, offset, count * 4);
185 proto_tree_add_text(tree, tvb, offset - 4, 4,
188 *data = (guint32 *)ptr;
195 /* Parse a NT status code */
197 int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
202 offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
205 proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
206 val_to_str(status, NT_errors, "???"));
212 * We need to keep track of deferred referrents as they appear in the
213 * packet after all the non-pointer objects.
214 * to keep track of pointers as they are parsed as scalars and need to be
215 * remembered for the next call to the prs function.
217 * Pointers are stored in a linked list and pushed in the PARSE_SCALARS
218 * section of the prs function and popped in the PARSE_BUFFERS section. If
219 * we try to pop off a referrent that has a different name then we are
220 * expecting then something has gone wrong.
230 /* Create a new pointer */
232 static struct ptr *new_ptr(char *name, guint32 value)
236 p = g_malloc(sizeof(struct ptr));
238 p->name = g_strdup(name);
246 static void free_ptr(struct ptr *p)
254 /* Parse a pointer and store it's value in a linked list */
256 int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
257 proto_tree *tree, GList **ptr_list, char *name)
262 offset = prs_uint32(tvb, offset, pinfo, tree, &value, NULL);
265 proto_tree_add_text(tree, tvb, offset - 4, 4,
266 "%s pointer: 0x%08x", name, value);
268 p = new_ptr(name, value);
270 *ptr_list = g_list_append(*ptr_list, p);
273 fprintf(stderr, "DEBUG_PTRS: pushing %s ptr = 0x%08x, %d ptrs in "
274 "list\n", name, value, g_list_length(*ptr_list));
280 /* Pop a pointer of a given name. Return it's value. */
282 guint32 prs_pop_ptr(GList **ptr_list, char *name)
288 g_assert(g_list_length(*ptr_list) != 0); /* List too short */
290 /* Get pointer at head of list */
292 elt = g_list_first(*ptr_list);
293 p = (struct ptr *)elt->data;
297 if (strcmp(p->name, name) != 0) {
298 fprintf(stderr, "DEBUG_PTRS: wrong pointer (%s != %s)\n",
303 /* Free pointer record */
305 *ptr_list = g_list_remove_link(*ptr_list, elt);
308 fprintf(stderr, "DEBUG_PTRS: popping %s ptr = 0x%08x, %d ptrs in "
309 "list\n", p->name, p->value, g_list_length(*ptr_list));
318 * Parse a UNISTR2 structure
323 * [size_is(size/2)] [length_is(length/2)] [unique] wchar_t *string;
328 /* Convert a string from little-endian unicode to ascii. At the moment we
329 fake it by taking every odd byte. )-: The caller must free the
332 char *fake_unicode(guint16 *data, int len)
337 buffer = malloc(len + 1);
339 for (i = 0; i < len; i++)
340 buffer[i] = data[i] & 0xff;
347 /* Parse a UNISTR2 structure */
349 int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
350 proto_tree *tree, int flags, char **data, char *name)
352 guint32 len = 0, unknown = 0, max_len = 0;
354 if (flags & PARSE_SCALARS) {
355 offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
356 offset = prs_uint32(tvb, offset, pinfo, tree, &unknown,
358 offset = prs_uint32(tvb, offset, pinfo, tree, &max_len,
362 if (flags & PARSE_BUFFERS) {
365 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
369 *data = fake_unicode(data16, max_len);
375 /* Parse a policy handle. */
377 int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo,
378 proto_tree *tree, const guint8 **data)
382 offset = prs_align(offset, 4);
384 proto_tree_add_text(tree, tvb, offset, 20, "Policy Handle");
386 data8 = tvb_get_ptr(tvb, offset, 20);
396 /* following are a few functions for dissecting common structures used by NT
397 services. These might need to be cleaned up at a later time but at least we get
398 them out of the real service dissectors.
402 /* UNICODE_STRING BEGIN */
403 /* functions to dissect a UNICODE_STRING structure, common to many
408 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
411 these variables can be found in packet-dcerpc-samr.c
413 extern int hf_nt_str_len;
414 extern int hf_nt_str_off;
415 extern int hf_nt_str_max_len;
416 extern int hf_nt_string_length;
417 extern int hf_nt_string_size;
418 extern gint ett_nt_unicode_string;
421 /* this function will dissect the
422 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
423 part of the unicode string
428 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
430 structure used by NT to transmit unicode string values.
432 This function also looks at di->levels to see if whoever called us wanted us to append
433 the name: string to any higher levels in the tree .
436 dissect_ndr_nt_UNICODE_STRING_str(tvbuff_t *tvb, int offset,
437 packet_info *pinfo, proto_tree *tree,
440 guint32 len, off, max_len;
447 di=pinfo->private_data;
448 if(di->conformant_run){
449 /*just a run to handle conformant arrays, nothing to dissect */
453 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
454 hf_nt_str_len, &len);
455 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
456 hf_nt_str_off, &off);
457 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
458 hf_nt_str_max_len, &max_len);
461 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len, &data16, NULL);
462 text = fake_unicode(data16, max_len);
464 name = proto_registrar_get_name(di->hf_index);
465 proto_tree_add_string_format(tree, di->hf_index,
466 tvb, old_offset, offset-old_offset,
467 text, "%s: %s", name, text);
470 proto_item_append_text(tree, ": %s", text);
473 proto_item_append_text(tree, ": %s", text);
476 proto_item_append_text(tree, " %s", text);
484 /* this function will dissect the
488 [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
490 structure used by NT to transmit unicode string values.
492 the function takes one additional parameter, level
493 which specifies how many additional levels up in the tree where we should
494 append the string. If unsure, specify levels as 0.
497 dissect_ndr_nt_UNICODE_STRING(tvbuff_t *tvb, int offset,
498 packet_info *pinfo, proto_tree *parent_tree,
499 char *drep, int hf_index, int levels)
501 proto_item *item=NULL;
502 proto_tree *tree=NULL;
503 int old_offset=offset;
507 ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
509 di=pinfo->private_data;
510 if(di->conformant_run){
511 /*just a run to handle conformant arrays, nothing to dissect */
515 name = proto_registrar_get_name(hf_index);
517 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
519 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
522 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
523 hf_nt_string_length, NULL);
524 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
525 hf_nt_string_size, NULL);
527 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
528 dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
529 name, hf_index, levels);
531 proto_item_set_len(item, offset-old_offset);
534 /* UNICODE_STRING END */