wireshark/packet-dcerpc-nt.c

1457 lines
37 KiB
C
Raw Normal View History

/* packet-dcerpc-nt.c
* Routines for DCERPC over SMB packet disassembly
* Copyright 2001, Tim Potter <tpot@samba.org>
*
* $Id: packet-dcerpc-nt.c,v 1.46 2002/08/28 21:00:10 jmayer Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#include <epan/packet.h>
#include "packet-dcerpc.h"
#include "packet-dcerpc-nt.h"
#include "smb.h"
#include "packet-smb-common.h" /* for dissect_smb_64bit_time() */
/*
* This file contains helper routines that are used by the DCERPC over SMB
* dissectors for ethereal.
*/
/* Align offset to a n-byte boundary */
int prs_align(int offset, int n)
{
if (offset % n)
offset += n - (offset % n);
return offset;
}
/* Parse a 8-bit integer */
int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint8 *data, char *name)
{
guint8 i;
/* No alignment required */
i = tvb_get_guint8(tvb, offset);
offset++;
if (name && tree)
proto_tree_add_text(tree, tvb, offset - 1, 1,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
"%s: %u", name, i);
if (data)
*data = i;
return offset;
}
int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
proto_tree *tree, int count, int *data_offset, char *name)
{
/* No alignment required */
if (name && tree)
proto_tree_add_text(tree, tvb, offset, count, "%s", name);
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
if (data_offset)
*data_offset = offset;
offset += count;
return offset;
}
/* Parse a 16-bit integer */
int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint16 *data, char *name)
{
guint16 i;
offset = prs_align(offset, 2);
i = tvb_get_letohs(tvb, offset);
offset += 2;
if (name && tree)
proto_tree_add_text(tree, tvb, offset - 2, 2,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
"%s: %u", name, i);
if (data)
*data = i;
return offset;
}
/* Parse a number of uint16's */
int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
proto_tree *tree, int count, int *data_offset, char *name)
{
offset = prs_align(offset, 2);
if (name && tree)
proto_tree_add_text(tree, tvb, offset, count * 2,
"%s", name);
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
if (data_offset)
*data_offset = offset;
offset += count * 2;
return offset;
}
/* Parse a 32-bit integer */
int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
proto_tree *tree, guint32 *data, char *name)
{
guint32 i;
offset = prs_align(offset, 4);
i = tvb_get_letohl(tvb, offset);
offset += 4;
if (name && tree)
proto_tree_add_text(tree, tvb, offset - 4, 4,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
"%s: %u", name, i);
if (data)
*data = i;
return offset;
}
/* Parse a number of 32-bit integers */
int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
proto_tree *tree, int count, int *data_offset, char *name)
{
offset = prs_align(offset, 4);
if (name && tree)
proto_tree_add_text(tree, tvb, offset - 4, 4,
"%s", name);
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
if (data_offset)
*data_offset = offset;
offset += count * 4;
return offset;
}
/* Parse a NT status code */
int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree)
{
guint32 status;
offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
if (tree)
proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
val_to_str(status, NT_errors, "???"));
return offset;
}
/*
* We need to keep track of deferred referrents as they appear in the
* packet after all the non-pointer objects.
* to keep track of pointers as they are parsed as scalars and need to be
* remembered for the next call to the prs function.
*
* Pointers are stored in a linked list and pushed in the PARSE_SCALARS
* section of the prs function and popped in the PARSE_BUFFERS section. If
* we try to pop off a referrent that has a different name then we are
* expecting then something has gone wrong.
*/
#undef DEBUG_PTRS
struct ptr {
char *name;
guint32 value;
};
/* Create a new pointer */
static struct ptr *new_ptr(char *name, guint32 value)
{
struct ptr *p;
p = g_malloc(sizeof(struct ptr));
p->name = g_strdup(name);
p->value = value;
return p;
}
/* Free a pointer */
static void free_ptr(struct ptr *p)
{
if (p) {
g_free(p->name);
g_free(p);
}
}
/* Parse a pointer and store it's value in a linked list */
int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, GList **ptr_list, char *name)
{
struct ptr *p;
guint32 value;
offset = prs_uint32(tvb, offset, pinfo, tree, &value, NULL);
if (name && tree)
proto_tree_add_text(tree, tvb, offset - 4, 4,
"%s pointer: 0x%08x", name, value);
p = new_ptr(name, value);
*ptr_list = g_list_append(*ptr_list, p);
#ifdef DEBUG_PTRS
fprintf(stderr, "DEBUG_PTRS: pushing %s ptr = 0x%08x, %d ptrs in "
"list\n", name, value, g_list_length(*ptr_list));
#endif
return offset;
}
/* Pop a pointer of a given name. Return it's value. */
guint32 prs_pop_ptr(GList **ptr_list, char *name _U_)
{
GList *elt;
struct ptr *p;
guint32 result;
g_assert(g_list_length(*ptr_list) != 0); /* List too short */
/* Get pointer at head of list */
elt = g_list_first(*ptr_list);
p = (struct ptr *)elt->data;
result = p->value;
#ifdef DEBUG_PTRS
if (strcmp(p->name, name) != 0) {
fprintf(stderr, "DEBUG_PTRS: wrong pointer (%s != %s)\n",
p->name, name);
}
#endif
/* Free pointer record */
*ptr_list = g_list_remove_link(*ptr_list, elt);
#ifdef DEBUG_PTRS
fprintf(stderr, "DEBUG_PTRS: popping %s ptr = 0x%08x, %d ptrs in "
"list\n", p->name, p->value, g_list_length(*ptr_list));
#endif
free_ptr(p);
return result;
}
/* Convert a string from little-endian unicode to ascii. At the moment we
fake it by taking every odd byte. )-: The caller must free the
result returned. */
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
char *fake_unicode(tvbuff_t *tvb, int offset, int len)
{
char *buffer;
int i;
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
guint16 character;
/* Make sure we have enough data before allocating the buffer,
so we don't blow up if the length is huge.
We do so by attempting to fetch the last character; it'll
throw an exception if it's past the end. */
tvb_get_letohs(tvb, offset + 2*(len - 1));
/* We know we won't throw an exception, so we don't have to worry
about leaking this buffer. */
buffer = g_malloc(len + 1);
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
for (i = 0; i < len; i++) {
character = tvb_get_letohs(tvb, offset);
buffer[i] = character & 0xff;
offset += 2;
}
buffer[len] = 0;
return buffer;
}
/* Parse a UNISTR2 structure */
int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, int flags, char **data, char *name _U_)
{
guint32 len = 0, unknown = 0, max_len = 0;
if (flags & PARSE_SCALARS) {
offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
offset = prs_uint32(tvb, offset, pinfo, tree, &unknown,
"Offset");
offset = prs_uint32(tvb, offset, pinfo, tree, &max_len,
"Max length");
}
if (flags & PARSE_BUFFERS) {
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
int data16_offset;
offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
&data16_offset, "Buffer");
if (data)
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
*data = fake_unicode(tvb, data16_offset, max_len);
}
return offset;
}
/* following are a few functions for dissecting common structures used by NT
services. These might need to be cleaned up at a later time but at least we get
them out of the real service dissectors.
*/
/* UNICODE_STRING BEGIN */
/* functions to dissect a UNICODE_STRING structure, common to many
NT services
struct {
short len;
short size;
[size_is(size/2), length_is(len/2), ptr] unsigned short *string;
} UNICODE_STRING;
these variables can be found in packet-dcerpc-samr.c
*/
extern int hf_nt_str_len;
extern int hf_nt_str_off;
extern int hf_nt_str_max_len;
extern int hf_nt_string_length;
extern int hf_nt_string_size;
gint ett_nt_unicode_string = -1;
static gint ett_nt_policy_hnd = -1;
/* this function will dissect the
[size_is(size/2), length_is(len/2), ptr] unsigned short *string;
part of the unicode string
struct {
short len;
short size;
[size_is(size/2), length_is(len/2), ptr] unsigned short *string;
} UNICODE_STRING;
structure used by NT to transmit unicode string values.
This function also looks at di->levels to see if whoever called us wanted us to append
the name: string to any higher levels in the tree .
*/
int
dissect_ndr_nt_UNICODE_STRING_str(tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *tree,
char *drep)
{
guint32 len, off, max_len;
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
int data16_offset;
char *text;
int old_offset;
dcerpc_info *di;
di=pinfo->private_data;
if(di->conformant_run){
/*just a run to handle conformant arrays, nothing to dissect */
return offset;
}
offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
hf_nt_str_max_len, &max_len);
offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
hf_nt_str_off, &off);
offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
hf_nt_str_len, &len);
old_offset=offset;
offset = prs_uint16s(tvb, offset, pinfo, tree, len, &data16_offset,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
NULL);
text = fake_unicode(tvb, data16_offset, len);
proto_tree_add_string(tree, di->hf_index, tvb, old_offset,
offset-old_offset, text);
/* need to test di->levels before doing the proto_item_append_text()
since netlogon has these objects as top level objects in its representation
and trying to append to the tree object in that case will dump core */
if(tree && (di->levels>-1)){
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
proto_item_append_text(tree, ": %s", text);
di->levels--;
if(di->levels>-1){
tree=tree->parent;
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
proto_item_append_text(tree, ": %s", text);
di->levels--;
while(di->levels>-1){
tree=tree->parent;
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
proto_item_append_text(tree, " %s", text);
di->levels--;
}
}
}
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
g_free(text);
return offset;
}
/* this function will dissect the
struct {
short len;
short size;
[size_is(size/2), length_is(len/2), ptr] unsigned short *string;
} UNICODE_STRING;
structure used by NT to transmit unicode string values.
the function takes one additional parameter, level
which specifies how many additional levels up in the tree where we should
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
append the string. If unsure, specify levels as 0.
*/
int
dissect_ndr_nt_UNICODE_STRING(tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *parent_tree,
char *drep, int hf_index, int levels)
{
proto_item *item=NULL;
proto_tree *tree=NULL;
int old_offset=offset;
dcerpc_info *di;
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
char *name;
ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
di=pinfo->private_data;
if(di->conformant_run){
/*just a run to handle conformant arrays, nothing to dissect */
return offset;
}
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
name = proto_registrar_get_name(hf_index);
if(parent_tree){
item = proto_tree_add_text(parent_tree, tvb, offset, -1,
Use "dissect_ndr_nt_UNICODE_STRING_str()", not "dissect_ndr_nt_UNICODE_STRING_string()", in "samr_dissect_connect2_server()"; that eliminates an unnecessary extra level of protocol tree. That removes the last call to "dissect_ndr_nt_UNICODE_STRING_string()"; eliminate that routine. In "dissect_ndr_nt_UNICODE_STRING()", initially create the subtree with the name of the field as a string, so that if an exception is thrown before the name is set, the subtree won't show up as blank when displayed or printed. Also pass in the name to "dissect_ndr_pointer()", so the same happens for subtrees below it. Append only the string data, not its name, to items up the tree, as the name was put in when the item was created. Also, when adding a colon before the string, put a space after the colon, as is done elsewhere in Ethereal. When appending additional strings, put the blank before the new string, not after it. In "dissect_ndr_nt_STRING()", put the subtree into the string with the name of the field, rather than just "String". Pass in that name to "dissect_ndr_pointer()", so subtrees below it get a name when they're initially created. Get rid of colons in the name string passed to "dissect_ndr_pointer()" in some calls. Supply a non-null name string in more calls to "dissect_ndr_pointer()", and fix some calls to pass in the name of the field being handed to "dissect_ndr_pointer()". There's no need to fetch the entire "header_field_info" structure for a protocol field in order to get the field's name - just use "proto_registrar_get_name()" to get the name. Use a length of -1, not 0, when creating a subtree whose length will be set when the dissection of the items under the subtree is complete; that way, if an exception is thrown while dissecting the items - which means the item goes past the end of the tvbuff - the item will refer to all data to the end of the tvbuff, rather than referring to nothing. Fix a typo in the name of the "hf_samr_unknown_string" field. svn path=/trunk/; revision=4912
2002-03-10 21:30:11 +00:00
"%s", name);
tree = proto_item_add_subtree(item, ett_nt_unicode_string);
}
offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
hf_nt_string_length, NULL);
offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
hf_nt_string_size, NULL);
di->levels=1; /* XXX - is this necessary? */
/* Add 1 level, for the extra level we added */
offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
name, hf_index, levels + 1);
proto_item_set_len(item, offset-old_offset);
return offset;
}
/* UNICODE_STRING END */
/* functions to dissect a STRING structure, common to many
NT services
struct {
short len;
short size;
[size_is(size), length_is(len), ptr] char *string;
} STRING;
*/
int
dissect_ndr_nt_STRING_string (tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *tree,
char *drep)
{
guint32 len, off, max_len;
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
int text_offset;
const guint8 *text;
int old_offset;
header_field_info *hfi;
dcerpc_info *di;
di=pinfo->private_data;
if(di->conformant_run){
/*just a run to handle conformant arrays, nothing to dissect */
return offset;
}
offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
hf_nt_str_max_len, &max_len);
offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
hf_nt_str_off, &off);
offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
hf_nt_str_len, &len);
old_offset=offset;
hfi = proto_registrar_get_nth(di->hf_index);
switch(hfi->type){
case FT_STRING:
offset = prs_uint8s(tvb, offset, pinfo, tree, len,
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
&text_offset, NULL);
text = tvb_get_ptr(tvb, text_offset, len);
proto_tree_add_string_format(tree, di->hf_index,
tvb, old_offset, offset-old_offset,
text, "%s: %s", hfi->name, text);
break;
case FT_BYTES:
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
text = NULL;
proto_tree_add_item(tree, di->hf_index, tvb, offset, len, FALSE);
offset += len;
break;
default:
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
text = NULL;
g_assert_not_reached();
}
There is no guarantee that a buffer obtained using "tvb_get_ptr()" is neatly aligned on a 2-byte or a 4-byte boundary, and there is no guarantee that a misaligned pointer can be dereferenced without getting a fault. Furthermore, there is no guarantee that, even if you *can* dereference a pointer to a 2-byte or 4-byte quantity in a packet, the resulting number you get back is in the right byte order; the data in the packet might have a different byte order from the machine on which you're running. Therefore, we change "prs_uint8s()", "prs_uint16s()", and "prs_uint32s()" to return the starting offset, in the tvbuff, of the collection of 8-bit, 16-bit, or 32-bit integral values, rather than a pointer to the raw packet data, and change their callers to fetch the data using "tvb_get_guint8()", "tvb_get_letohs()", and "tvb_get_letohl()" (the stuff in all the NT protocols is presumed to be little-endian here). We also change "fake_unicode()" to take a tvbuff and an offset, rather than a data pointer, as arguments, and to use "tvb_get_letohs()" to fetch the Unicode characters (again, we assume little-endian Unicode). This requires "fake_unicode()" to establish a cleanup handler, so we don't leak memory if it throws an exception. We also make "fake_unicode()" use "g_malloc()" to allocate its buffer (we weren't checking for allocation failures in any case; with "g_malloc()", we'll abort on an allocation failure - if we can come up with a cleverer way of handling them, fine), and the matching frees to use "g_free()". (We also insert some missing frees....) Fix some formats to print unsigned quantities with "%u", not "%d". Don't append text to items in the tree for non-string values in "dissect_ndr_nt_STRING_string()". svn path=/trunk/; revision=4986
2002-03-19 22:09:23 +00:00
if(tree && text && (di->levels>-1)){
proto_item_append_text(tree, ": %s", text);
if(di->levels>-1){
tree=tree->parent;
proto_item_append_text(tree, ": %s", text);
while(di->levels>0){
tree=tree->parent;
proto_item_append_text(tree, " %s", text);
di->levels--;
}
}
}
return offset;
}
int
dissect_ndr_nt_STRING (tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *parent_tree,
char *drep, int hf_index, int levels)
{
proto_item *item=NULL;
proto_tree *tree=NULL;
int old_offset=offset;
dcerpc_info *di;
char *name;
ALIGN_TO_4_BYTES; /* strcture starts with short, but is aligned for longs */
di=pinfo->private_data;
if(di->conformant_run){
/*just a run to handle conformant arrays, nothing to dissect */
return offset;
}
name = proto_registrar_get_name(hf_index);
if(parent_tree){
item = proto_tree_add_text(parent_tree, tvb, offset, -1,
"%s", name);
tree = proto_item_add_subtree(item, ett_nt_unicode_string);
}
offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
hf_nt_string_length, NULL);
offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
hf_nt_string_size, NULL);
offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
dissect_ndr_nt_STRING_string, NDR_POINTER_UNIQUE,
name, hf_index, levels);
proto_item_set_len(item, offset-old_offset);
return offset;
}
/* This function is used to dissect a DCERPC encoded 64 bit time value.
XXX it should be fixed both here and in dissect_smb_64bit_time so
it can handle both BIG and LITTLE endian encodings
*/
int
dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *tree,
char *drep _U_, int hf_index)
{
dcerpc_info *di;
di=pinfo->private_data;
if(di->conformant_run){
/*just a run to handle conformant arrays, nothing to dissect */
return offset;
}
ALIGN_TO_4_BYTES;
offset = dissect_smb_64bit_time(tvb, tree, offset, hf_index);
return offset;
}
/* Define this symbol to display warnings about request/response and
policy handle hash table collisions. This happens when a packet with
the same conversation, smb fid and dcerpc call id occurs. I think this
is due to a bug in the dcerpc/smb fragment reassembly code. */
#undef DEBUG_HASH_COLL
/*
* Policy handle hashing
*/
typedef struct {
guint8 policy_hnd[20];
} pol_hash_key;
typedef struct {
guint32 open_frame, close_frame; /* Frame numbers for open/close */
char *name; /* Name of policy handle */
} pol_hash_value;
#define POL_HASH_INIT_COUNT 100
static GHashTable *pol_hash;
static GMemChunk *pol_hash_key_chunk;
static GMemChunk *pol_hash_value_chunk;
/* Hash function */
static guint pol_hash_fn(gconstpointer k)
{
pol_hash_key *key = (pol_hash_key *)k;
/* Bytes 4-7 of the policy handle are a timestamp so should make a
reasonable hash value */
return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
(key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
}
/* Return true if a policy handle is all zeros */
static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
{
static guint8 null_policy_hnd[20];
return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
}
/* Hash compare function */
static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
{
pol_hash_key *key1 = (pol_hash_key *)k1;
pol_hash_key *key2 = (pol_hash_key *)k2;
return memcmp(key1->policy_hnd, key2->policy_hnd,
sizeof(key1->policy_hnd)) == 0;
}
/* Store the open and close frame numbers of a policy handle */
void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, guint32 open_frame,
guint32 close_frame)
{
pol_hash_key *key;
pol_hash_value *value;
if (is_null_pol(policy_hnd) || (open_frame == 0 && close_frame == 0))
return;
/* Look up existing value */
key = g_mem_chunk_alloc(pol_hash_key_chunk);
memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
if ((value = g_hash_table_lookup(pol_hash, key))) {
/* Update existing value */
if (open_frame) {
#ifdef DEBUG_HASH_COLL
if (value->open_frame != open_frame)
g_warning("dcerpc_smb: pol_hash open frame collision %d/%d\n", value->open_frame, open_frame);
#endif
value->open_frame = open_frame;
}
if (close_frame) {
#ifdef DEBUG_HASH_COLL
if (value->close_frame != close_frame)
g_warning("dcerpc_smb: pol_hash close frame collision %d/%d\n", value->close_frame, close_frame);
#endif
value->close_frame = close_frame;
}
return;
}
/* Create a new value */
value = g_mem_chunk_alloc(pol_hash_value_chunk);
value->open_frame = open_frame;
value->close_frame = close_frame;
value->name = NULL;
g_hash_table_insert(pol_hash, key, value);
}
/* Store a text string with a policy handle */
void dcerpc_smb_store_pol_name(e_ctx_hnd *policy_hnd, char *name)
{
pol_hash_key *key;
pol_hash_value *value;
if (is_null_pol(policy_hnd))
return;
/* Look up existing value */
key = g_mem_chunk_alloc(pol_hash_key_chunk);
memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
if ((value = g_hash_table_lookup(pol_hash, key))) {
/* Update existing value */
if (value->name && name) {
#ifdef DEBUG_HASH_COLL
if (strcmp(value->name, name) != 0)
g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
#endif
free(value->name);
}
value->name = strdup(name);
return;
}
/* Create a new value */
value = g_mem_chunk_alloc(pol_hash_value_chunk);
value->open_frame = 0;
value->close_frame = 0;
if (name)
value->name = strdup(name);
else
value->name = strdup("UNKNOWN");
g_hash_table_insert(pol_hash, key, value);
}
/* Retrieve a policy handle */
gboolean dcerpc_smb_fetch_pol(e_ctx_hnd *policy_hnd, char **name,
guint32 *open_frame, guint32 *close_frame)
{
pol_hash_key key;
pol_hash_value *value;
/* Prevent uninitialised return vars */
if (name)
*name = NULL;
if (open_frame)
*open_frame = 0;
if (close_frame)
*close_frame = 0;
/* Look up existing value */
memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
value = g_hash_table_lookup(pol_hash, &key);
/* Return name and frame numbers */
if (value) {
if (name)
*name = value->name;
if (open_frame)
*open_frame = value->open_frame;
if (close_frame)
*close_frame = value->close_frame;
}
return value != NULL;
}
/* Iterator to free a policy handle key/value pair */
static void free_pol_keyvalue(gpointer key _U_, gpointer value,
gpointer user_data _U_)
{
pol_hash_value *pol_value = (pol_hash_value *)value;
/* Free user data */
if (pol_value->name) {
free(pol_value->name);
pol_value->name = NULL;
}
}
/* Initialise policy handle hash */
static void init_pol_hash(void)
{
/* Initialise memory chunks */
if (pol_hash_key_chunk)
g_mem_chunk_destroy(pol_hash_key_chunk);
pol_hash_key_chunk = g_mem_chunk_new(
"Policy handle hash keys", sizeof(pol_hash_key),
POL_HASH_INIT_COUNT * sizeof(pol_hash_key), G_ALLOC_ONLY);
if (pol_hash_value_chunk)
g_mem_chunk_destroy(pol_hash_value_chunk);
pol_hash_value_chunk = g_mem_chunk_new(
"Policy handle hash values", sizeof(pol_hash_value),
POL_HASH_INIT_COUNT * sizeof(pol_hash_value), G_ALLOC_ONLY);
/* Initialise hash table */
if (pol_hash) {
g_hash_table_foreach(pol_hash, free_pol_keyvalue, NULL);
g_hash_table_destroy(pol_hash);
}
pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
}
/* Dissect an access mask. All this stuff is kind of explained at MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/windows_2000_windows_nt_access_mask_format.asp
*/
static gint ett_nt_access_mask = -1;
static gint ett_nt_access_mask_generic = -1;
static gint ett_nt_access_mask_standard = -1;
static gint ett_nt_access_mask_specific = -1;
static int hf_access_sacl = -1;
static int hf_access_maximum_allowed = -1;
static int hf_access_generic_read = -1;
static int hf_access_generic_write = -1;
static int hf_access_generic_execute = -1;
static int hf_access_generic_all = -1;
static int hf_access_standard_delete = -1;
static int hf_access_standard_read_control = -1;
static int hf_access_standard_synchronise = -1;
static int hf_access_standard_write_dac = -1;
static int hf_access_standard_write_owner = -1;
static int hf_access_specific_15 = -1;
static int hf_access_specific_14 = -1;
static int hf_access_specific_13 = -1;
static int hf_access_specific_12 = -1;
static int hf_access_specific_11 = -1;
static int hf_access_specific_10 = -1;
static int hf_access_specific_9 = -1;
static int hf_access_specific_8 = -1;
static int hf_access_specific_7 = -1;
static int hf_access_specific_6 = -1;
static int hf_access_specific_5 = -1;
static int hf_access_specific_4 = -1;
static int hf_access_specific_3 = -1;
static int hf_access_specific_2 = -1;
static int hf_access_specific_1 = -1;
static int hf_access_specific_0 = -1;
int
dissect_nt_access_mask(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep, int hfindex,
nt_access_mask_fn_t *specific_rights_fn)
{
proto_item *item;
proto_tree *subtree, *generic, *standard, *specific;
guint32 access;
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
hfindex, &access);
item = proto_tree_add_uint(tree, hfindex, tvb, offset - 4, 4, access);
subtree = proto_item_add_subtree(item, ett_nt_access_mask);
/* Generic access rights */
item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
"Generic rights: 0x%08x",
access & GENERIC_RIGHTS_MASK);
generic = proto_item_add_subtree(item, ett_nt_access_mask_generic);
proto_tree_add_boolean(
generic, hf_access_generic_read, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
generic, hf_access_generic_write, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
generic, hf_access_generic_execute, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
generic, hf_access_generic_all, tvb, offset - 4, 4,
access);
/* Reserved (??) */
proto_tree_add_boolean(
subtree, hf_access_maximum_allowed, tvb, offset - 4, 4,
access);
/* Access system security */
proto_tree_add_boolean(
subtree, hf_access_sacl, tvb, offset - 4, 4,
access);
/* Standard access rights */
item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
"Standard rights: 0x%08x",
access & STANDARD_RIGHTS_MASK);
standard = proto_item_add_subtree(item, ett_nt_access_mask_standard);
proto_tree_add_boolean(
standard, hf_access_standard_synchronise, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
standard, hf_access_standard_write_owner, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
standard, hf_access_standard_write_dac, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
standard, hf_access_standard_read_control, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
standard, hf_access_standard_delete, tvb, offset - 4, 4,
access);
/* Specific access rights. Call the specific_rights_fn
pointer if we have one, otherwise just display bits 0-15 in
boring fashion. */
item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
"Specific rights: 0x%08x",
access & SPECIFIC_RIGHTS_MASK);
specific = proto_item_add_subtree(item, ett_nt_access_mask_specific);
if (specific_rights_fn) {
specific_rights_fn(tvb, offset - 4, specific, access);
return offset;
}
proto_tree_add_boolean(
specific, hf_access_specific_15, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_14, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_13, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_12, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_11, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_10, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_9, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_8, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_7, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_6, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_5, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_4, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_3, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_2, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_1, tvb, offset - 4, 4,
access);
proto_tree_add_boolean(
specific, hf_access_specific_0, tvb, offset - 4, 4,
access);
return offset;
}
/*
* Initialise global DCERPC/SMB data structures
*/
Add a "proto_register_dcerpc_smb()" which registers ett_ values for "packet-dcerpc-nt.c", and registers "dcerpc_smb_init()" as an initialization routine. Take the ett_ registration out of the latter routine, and also take out the "do this only once" stuff. Get rid of the initialization routines for netlogon, samr, and spoolss; they just call "dcerpc_smb_init()", which is now an initialization routine of its own. The policy hash initialization should be done before every capture, so it should be done in an initialization routine, and should not do any "do this only once" stuff. It should also be called only once before every capture, rather than 3 times. The ett_ initialization should, however, be done at the same time all other ett_ initialization is done - at protocol registration time - so it should be done in a "proto_register_" routine. This fixes a bug I saw wherein 1) the tree for Unicode strings was open by default and 2) if you closed one and then exited, Ethereal would crash. The problem is that "proto_register_subtree_array()" doesn't expand the array, it just bumps the number of registered ett_ values; the array is allocated in "proto_init()". As such, if you register ett_ values with "proto_register_subtree_array()" *after* "proto_init()" is called - and, even for the first capture, initialization routines are called after "proto_init()" is called - you will get ett_ numbers that go past the number of elements in the array. Move the declaration of "ett_nt_unicode_string" to "packet-dcerpc-nt.h", as it's exported from "packet-dcerpc-nt.c". Get rid of the declaration of "dcerpc_smb_init()" in "packet-dcerpc-nt.h", and make it static, as it's no longer called from outside "packet-dcerpc-nt.c". svn path=/trunk/; revision=5196
2002-04-18 00:29:17 +00:00
static void dcerpc_smb_init(void)
{
Add a "proto_register_dcerpc_smb()" which registers ett_ values for "packet-dcerpc-nt.c", and registers "dcerpc_smb_init()" as an initialization routine. Take the ett_ registration out of the latter routine, and also take out the "do this only once" stuff. Get rid of the initialization routines for netlogon, samr, and spoolss; they just call "dcerpc_smb_init()", which is now an initialization routine of its own. The policy hash initialization should be done before every capture, so it should be done in an initialization routine, and should not do any "do this only once" stuff. It should also be called only once before every capture, rather than 3 times. The ett_ initialization should, however, be done at the same time all other ett_ initialization is done - at protocol registration time - so it should be done in a "proto_register_" routine. This fixes a bug I saw wherein 1) the tree for Unicode strings was open by default and 2) if you closed one and then exited, Ethereal would crash. The problem is that "proto_register_subtree_array()" doesn't expand the array, it just bumps the number of registered ett_ values; the array is allocated in "proto_init()". As such, if you register ett_ values with "proto_register_subtree_array()" *after* "proto_init()" is called - and, even for the first capture, initialization routines are called after "proto_init()" is called - you will get ett_ numbers that go past the number of elements in the array. Move the declaration of "ett_nt_unicode_string" to "packet-dcerpc-nt.h", as it's exported from "packet-dcerpc-nt.c". Get rid of the declaration of "dcerpc_smb_init()" in "packet-dcerpc-nt.h", and make it static, as it's no longer called from outside "packet-dcerpc-nt.c". svn path=/trunk/; revision=5196
2002-04-18 00:29:17 +00:00
/* Initialise policy handle hash */
init_pol_hash();
}
Add a "proto_register_dcerpc_smb()" which registers ett_ values for "packet-dcerpc-nt.c", and registers "dcerpc_smb_init()" as an initialization routine. Take the ett_ registration out of the latter routine, and also take out the "do this only once" stuff. Get rid of the initialization routines for netlogon, samr, and spoolss; they just call "dcerpc_smb_init()", which is now an initialization routine of its own. The policy hash initialization should be done before every capture, so it should be done in an initialization routine, and should not do any "do this only once" stuff. It should also be called only once before every capture, rather than 3 times. The ett_ initialization should, however, be done at the same time all other ett_ initialization is done - at protocol registration time - so it should be done in a "proto_register_" routine. This fixes a bug I saw wherein 1) the tree for Unicode strings was open by default and 2) if you closed one and then exited, Ethereal would crash. The problem is that "proto_register_subtree_array()" doesn't expand the array, it just bumps the number of registered ett_ values; the array is allocated in "proto_init()". As such, if you register ett_ values with "proto_register_subtree_array()" *after* "proto_init()" is called - and, even for the first capture, initialization routines are called after "proto_init()" is called - you will get ett_ numbers that go past the number of elements in the array. Move the declaration of "ett_nt_unicode_string" to "packet-dcerpc-nt.h", as it's exported from "packet-dcerpc-nt.c". Get rid of the declaration of "dcerpc_smb_init()" in "packet-dcerpc-nt.h", and make it static, as it's no longer called from outside "packet-dcerpc-nt.c". svn path=/trunk/; revision=5196
2002-04-18 00:29:17 +00:00
/*
* Register ett_ values, and register "dcerpc_smb_init()" as an
* initialisation routine.
*/
void proto_register_dcerpc_smb(void)
{
static hf_register_info hf[] = {
/* Access mask */
{ &hf_access_generic_read,
{ "Generic read", "nt.access_mask.generic_read",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
GENERIC_READ_ACCESS, "Generic read", HFILL }},
{ &hf_access_generic_write,
{ "Generic write", "nt.access_mask.generic_write",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
GENERIC_WRITE_ACCESS, "Generic write", HFILL }},
{ &hf_access_generic_execute,
{ "Generic execute", "nt.access_mask.generic_execute",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
GENERIC_EXECUTE_ACCESS, "Generic execute", HFILL }},
{ &hf_access_generic_all,
{ "Generic all", "nt.access_mask.generic_all",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
GENERIC_ALL_ACCESS, "Generic all", HFILL }},
{ &hf_access_maximum_allowed,
{ "Maximum allowed", "nt.access_mask.maximum_allowed",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
MAXIMUM_ALLOWED_ACCESS, "Maximum allowed", HFILL }},
{ &hf_access_sacl,
{ "Access SACL", "nt.access_mask.access_sacl",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
ACCESS_SACL_ACCESS, "Access SACL", HFILL }},
{ &hf_access_standard_read_control,
{ "Read control", "nt.access_mask.read_control",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
READ_CONTROL_ACCESS, "Read control", HFILL }},
{ &hf_access_standard_delete,
{ "Delete", "nt.access_mask.delete",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
DELETE_ACCESS, "Delete", HFILL }},
{ &hf_access_standard_synchronise,
{ "Synchronise", "nt.access_mask.synchronise",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
SYNCHRONIZE_ACCESS, "Synchronise", HFILL }},
{ &hf_access_standard_write_dac,
{ "Write DAC", "nt.access_mask.write_dac",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
WRITE_DAC_ACCESS, "Write DAC", HFILL }},
{ &hf_access_standard_write_owner,
{ "Write owner", "nt.access_mask.write_owner",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
WRITE_OWNER_ACCESS, "Write owner", HFILL }},
{ &hf_access_specific_15,
{ "Specific access, bit 15", "nt.access_mask.specific_15",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x8000, "Specific access, bit 15", HFILL }},
{ &hf_access_specific_14,
{ "Specific access, bit 14", "nt.access_mask.specific_14",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x4000, "Specific access, bit 14", HFILL }},
{ &hf_access_specific_13,
{ "Specific access, bit 13", "nt.access_mask.specific_13",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x2000, "Specific access, bit 13", HFILL }},
{ &hf_access_specific_12,
{ "Specific access, bit 12", "nt.access_mask.specific_12",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x1000, "Specific access, bit 12", HFILL }},
{ &hf_access_specific_11,
{ "Specific access, bit 11", "nt.access_mask.specific_11",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0800, "Specific access, bit 11", HFILL }},
{ &hf_access_specific_10,
{ "Specific access, bit 10", "nt.access_mask.specific_10",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0400, "Specific access, bit 10", HFILL }},
{ &hf_access_specific_9,
{ "Specific access, bit 9", "nt.access_mask.specific_9",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0200, "Specific access, bit 9", HFILL }},
{ &hf_access_specific_8,
{ "Specific access, bit 8", "nt.access_mask.specific_8",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0100, "Specific access, bit 8", HFILL }},
{ &hf_access_specific_7,
{ "Specific access, bit 7", "nt.access_mask.specific_7",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0080, "Specific access, bit 7", HFILL }},
{ &hf_access_specific_6,
{ "Specific access, bit 6", "nt.access_mask.specific_6",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0040, "Specific access, bit 6", HFILL }},
{ &hf_access_specific_5,
{ "Specific access, bit 5", "nt.access_mask.specific_5",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0020, "Specific access, bit 5", HFILL }},
{ &hf_access_specific_4,
{ "Specific access, bit 4", "nt.access_mask.specific_4",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0010, "Specific access, bit 4", HFILL }},
{ &hf_access_specific_3,
{ "Specific access, bit 3", "nt.access_mask.specific_3",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0008, "Specific access, bit 3", HFILL }},
{ &hf_access_specific_2,
{ "Specific access, bit 2", "nt.access_mask.specific_2",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0004, "Specific access, bit 2", HFILL }},
{ &hf_access_specific_1,
{ "Specific access, bit 1", "nt.access_mask.specific_1",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0002, "Specific access, bit 1", HFILL }},
{ &hf_access_specific_0,
{ "Specific access, bit 0", "nt.access_mask.specific_0",
FT_BOOLEAN, 32, TFS(&flags_set_truth),
0x0001, "Specific access, bit 0", HFILL }},
};
static gint *ett[] = {
&ett_nt_unicode_string,
&ett_nt_policy_hnd,
&ett_nt_access_mask,
&ett_nt_access_mask_generic,
&ett_nt_access_mask_standard,
&ett_nt_access_mask_specific,
};
static int proto_dcerpc_nt = -1;
/* Register ett's */
proto_register_subtree_array(ett, array_length(ett));
/* Register hf's */
proto_dcerpc_nt = proto_register_protocol(
"Dummy Protocol", "DCERPC_NT", "DCERPC_NT");
proto_register_field_array(proto_dcerpc_nt, hf, array_length(hf));
Add a "proto_register_dcerpc_smb()" which registers ett_ values for "packet-dcerpc-nt.c", and registers "dcerpc_smb_init()" as an initialization routine. Take the ett_ registration out of the latter routine, and also take out the "do this only once" stuff. Get rid of the initialization routines for netlogon, samr, and spoolss; they just call "dcerpc_smb_init()", which is now an initialization routine of its own. The policy hash initialization should be done before every capture, so it should be done in an initialization routine, and should not do any "do this only once" stuff. It should also be called only once before every capture, rather than 3 times. The ett_ initialization should, however, be done at the same time all other ett_ initialization is done - at protocol registration time - so it should be done in a "proto_register_" routine. This fixes a bug I saw wherein 1) the tree for Unicode strings was open by default and 2) if you closed one and then exited, Ethereal would crash. The problem is that "proto_register_subtree_array()" doesn't expand the array, it just bumps the number of registered ett_ values; the array is allocated in "proto_init()". As such, if you register ett_ values with "proto_register_subtree_array()" *after* "proto_init()" is called - and, even for the first capture, initialization routines are called after "proto_init()" is called - you will get ett_ numbers that go past the number of elements in the array. Move the declaration of "ett_nt_unicode_string" to "packet-dcerpc-nt.h", as it's exported from "packet-dcerpc-nt.c". Get rid of the declaration of "dcerpc_smb_init()" in "packet-dcerpc-nt.h", and make it static, as it's no longer called from outside "packet-dcerpc-nt.c". svn path=/trunk/; revision=5196
2002-04-18 00:29:17 +00:00
/* Register a routine to be called whenever initialisation
is done. */
register_init_routine(dcerpc_smb_init);
}
/* Check if there is unparsed data remaining in a frame and display an
error. I guess this could be made into an exception like the malformed
frame exception. For the DCERPC over SMB dissectors a long frame
indicates a bug in a dissector. */
void dcerpc_smb_check_long_frame(tvbuff_t *tvb, int offset,
packet_info *pinfo, proto_tree *tree)
{
if (tvb_length_remaining(tvb, offset) != 0) {
proto_tree_add_text(
tree, tvb, offset, tvb_length_remaining(tvb, offset),
"[Long frame (%d bytes): SPOOLSS]",
tvb_length_remaining(tvb, offset));
if (check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO,
"[Long frame (%d bytes): SPOOLSS]",
tvb_length_remaining(tvb, offset));
}
}
/* Dissect a NT status code */
int
dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep,
int hfindex, guint32 *pdata)
{
guint32 status;
offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
hfindex, &status);
if (tree && status != 0 && check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
val_to_str(status, NT_errors,
"Unknown error 0x%08x"));
if (pdata)
*pdata = status;
return offset;
}
/* Dissect a DOS status code */
int
dissect_doserror(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep,
int hfindex, guint32 *pdata)
{
guint32 status;
offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
hfindex, &status);
if (tree && status != 0 && check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
val_to_str(status, DOS_errors,
"Unknown error 0x%08x"));
if (pdata)
*pdata = status;
return offset;
}
/* Dissect a NT policy handle */
int
dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep, int hfindex,
e_ctx_hnd *pdata, gboolean is_open, gboolean is_close)
{
proto_item *item;
proto_tree *subtree;
e_ctx_hnd hnd;
guint32 open_frame = 0, close_frame = 0;
char *name;
int old_offset = offset;
/* Add to proto tree */
item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
"Policy Handle");
subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, drep,
hfindex, &hnd);
/* Store request/reply information */
dcerpc_smb_store_pol_pkts(&hnd, 0, is_close ? pinfo->fd->num : 0);
dcerpc_smb_store_pol_pkts(&hnd, is_open ? pinfo->fd->num: 0, 0);
/* Insert request/reply information if known */
if (dcerpc_smb_fetch_pol(&hnd, &name, &open_frame, &close_frame)) {
if (open_frame)
proto_tree_add_text(subtree, tvb, old_offset,
sizeof(e_ctx_hnd),
"Opened in frame %u", open_frame);
if (close_frame)
proto_tree_add_text(subtree, tvb, old_offset,
sizeof(e_ctx_hnd),
"Closed in frame %u", close_frame);
if (name != NULL)
proto_item_append_text(item, ": %s", name);
}
if (pdata)
*pdata = hnd;
return offset;
}
/* Some helper routines to dissect a range of uint8 characters. I don't
think these are "official" NDR representations and are probably specific
to NT so for the moment they're put here instead of in packet-dcerpc.c
and packet-dcerpc-ndr.c. */
int
dissect_dcerpc_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
proto_tree *tree, char *drep, int hfindex,
int length, guint8 **pdata)
{
guint8 *data;
data = (guint8 *)tvb_get_ptr(tvb, offset, length);
if (tree) {
proto_tree_add_item (tree, hfindex, tvb, offset, length, (drep[0] & 0x10));
}
if (pdata)
*pdata = data;
return offset + length;
}
int
dissect_ndr_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep,
int hfindex, int length, guint8 **pdata)
{
dcerpc_info *di;
di=pinfo->private_data;
if(di->conformant_run){
/* just a run to handle conformant arrays, no scalars to dissect */
return offset;
}
/* no alignment needed */
return dissect_dcerpc_uint8s(tvb, offset, pinfo,
tree, drep, hfindex, length, pdata);
}
int
dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
proto_tree *tree, char *drep, int hfindex,
int length, guint16 **pdata)
{
guint16 *data;
data = (guint16 *)tvb_get_ptr(tvb, offset, length * 2);
if (tree) {
proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, (drep[0] & 0x10));
}
if (pdata)
*pdata = data;
return offset + length * 2;
}
int
dissect_ndr_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep,
int hfindex, int length, guint16 **pdata)
{
dcerpc_info *di;
di=pinfo->private_data;
if(di->conformant_run){
/* just a run to handle conformant arrays, no scalars to dissect */
return offset;
}
if (offset % 2)
offset++;
return dissect_dcerpc_uint16s(tvb, offset, pinfo,
tree, drep, hfindex, length, pdata);
}