forked from osmocom/wireshark
![Ronnie Sahlberg](/assets/img/avatar_default.png)
Other protocol, not only SMB will populate pinfo->private_data thus checking for existence of non-NULL pinfo->private_data is not sufficient to determine we have SMB data and this is what it is. Refactor the adding of salt/FID from lower layer protocols and generalize it. Create a new dissector_handle specific for SMB so that we know that IFF we came in through that handle, then whatever pinfo->private_data is what we expect it to be. svn path=/trunk/; revision=11129
3932 lines
114 KiB
C
3932 lines
114 KiB
C
/*
|
|
XXX Fixme : shouldnt show [malformed frame] for long packets
|
|
*/
|
|
|
|
/* packet-smb-pipe.c
|
|
* Routines for SMB named pipe packet dissection
|
|
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
|
|
* significant rewrite to tvbuffify the dissector, Ronnie Sahlberg and
|
|
* Guy Harris 2001
|
|
*
|
|
* $Id: packet-smb-pipe.c,v 1.101 2004/06/09 09:24:07 sahlberg Exp $
|
|
*
|
|
* Ethereal - Network traffic analyzer
|
|
* By Gerald Combs <gerald@ethereal.com>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* Copied from packet-pop.c
|
|
*
|
|
* 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 <stdio.h>
|
|
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <glib.h>
|
|
#include <ctype.h>
|
|
#include <epan/packet.h>
|
|
#include "smb.h"
|
|
#include "packet-smb-pipe.h"
|
|
#include "packet-smb-browse.h"
|
|
#include "packet-smb-common.h"
|
|
#include "packet-dcerpc.h"
|
|
#include "reassemble.h"
|
|
|
|
static int proto_smb_pipe = -1;
|
|
static int hf_pipe_function = -1;
|
|
static int hf_pipe_priority = -1;
|
|
static int hf_pipe_peek_available = -1;
|
|
static int hf_pipe_peek_remaining = -1;
|
|
static int hf_pipe_peek_status = -1;
|
|
static int hf_pipe_getinfo_info_level = -1;
|
|
static int hf_pipe_getinfo_output_buffer_size = -1;
|
|
static int hf_pipe_getinfo_input_buffer_size = -1;
|
|
static int hf_pipe_getinfo_maximum_instances = -1;
|
|
static int hf_pipe_getinfo_current_instances = -1;
|
|
static int hf_pipe_getinfo_pipe_name_length = -1;
|
|
static int hf_pipe_getinfo_pipe_name = -1;
|
|
static int hf_pipe_write_raw_bytes_written = -1;
|
|
static int hf_pipe_fragments = -1;
|
|
static int hf_pipe_fragment = -1;
|
|
static int hf_pipe_fragment_overlap = -1;
|
|
static int hf_pipe_fragment_overlap_conflict = -1;
|
|
static int hf_pipe_fragment_multiple_tails = -1;
|
|
static int hf_pipe_fragment_too_long_fragment = -1;
|
|
static int hf_pipe_fragment_error = -1;
|
|
static int hf_pipe_reassembled_in = -1;
|
|
|
|
static gint ett_smb_pipe = -1;
|
|
static gint ett_smb_pipe_fragment = -1;
|
|
static gint ett_smb_pipe_fragments = -1;
|
|
|
|
static const fragment_items smb_pipe_frag_items = {
|
|
&ett_smb_pipe_fragment,
|
|
&ett_smb_pipe_fragments,
|
|
&hf_pipe_fragments,
|
|
&hf_pipe_fragment,
|
|
&hf_pipe_fragment_overlap,
|
|
&hf_pipe_fragment_overlap_conflict,
|
|
&hf_pipe_fragment_multiple_tails,
|
|
&hf_pipe_fragment_too_long_fragment,
|
|
&hf_pipe_fragment_error,
|
|
NULL,
|
|
"fragments"
|
|
};
|
|
|
|
static int proto_smb_lanman = -1;
|
|
static int hf_function_code = -1;
|
|
static int hf_param_desc = -1;
|
|
static int hf_return_desc = -1;
|
|
static int hf_aux_data_desc = -1;
|
|
static int hf_detail_level = -1;
|
|
static int hf_recv_buf_len = -1;
|
|
static int hf_send_buf_len = -1;
|
|
static int hf_continuation_from = -1;
|
|
static int hf_status = -1;
|
|
static int hf_convert = -1;
|
|
static int hf_ecount = -1;
|
|
static int hf_acount = -1;
|
|
static int hf_share_name = -1;
|
|
static int hf_share_type = -1;
|
|
static int hf_share_comment = -1;
|
|
static int hf_share_permissions = -1;
|
|
static int hf_share_max_uses = -1;
|
|
static int hf_share_current_uses = -1;
|
|
static int hf_share_path = -1;
|
|
static int hf_share_password = -1;
|
|
static int hf_server_name = -1;
|
|
static int hf_server_major = -1;
|
|
static int hf_server_minor = -1;
|
|
static int hf_server_comment = -1;
|
|
static int hf_abytes = -1;
|
|
static int hf_current_time = -1;
|
|
static int hf_msecs = -1;
|
|
static int hf_hour = -1;
|
|
static int hf_minute = -1;
|
|
static int hf_second = -1;
|
|
static int hf_hundredths = -1;
|
|
static int hf_tzoffset = -1;
|
|
static int hf_timeinterval = -1;
|
|
static int hf_day = -1;
|
|
static int hf_month = -1;
|
|
static int hf_year = -1;
|
|
static int hf_weekday = -1;
|
|
static int hf_enumeration_domain = -1;
|
|
static int hf_last_entry = -1;
|
|
static int hf_computer_name = -1;
|
|
static int hf_user_name = -1;
|
|
static int hf_group_name = -1;
|
|
static int hf_workstation_domain = -1;
|
|
static int hf_workstation_major = -1;
|
|
static int hf_workstation_minor = -1;
|
|
static int hf_logon_domain = -1;
|
|
static int hf_other_domains = -1;
|
|
static int hf_password = -1;
|
|
static int hf_workstation_name = -1;
|
|
static int hf_ustruct_size = -1;
|
|
static int hf_logon_code = -1;
|
|
static int hf_privilege_level = -1;
|
|
static int hf_operator_privileges = -1;
|
|
static int hf_num_logons = -1;
|
|
static int hf_bad_pw_count = -1;
|
|
static int hf_last_logon = -1;
|
|
static int hf_last_logoff = -1;
|
|
static int hf_logoff_time = -1;
|
|
static int hf_kickoff_time = -1;
|
|
static int hf_password_age = -1;
|
|
static int hf_password_can_change = -1;
|
|
static int hf_password_must_change = -1;
|
|
static int hf_script_path = -1;
|
|
static int hf_logoff_code = -1;
|
|
static int hf_duration = -1;
|
|
static int hf_comment = -1;
|
|
static int hf_user_comment = -1;
|
|
static int hf_full_name = -1;
|
|
static int hf_homedir = -1;
|
|
static int hf_parameters = -1;
|
|
static int hf_logon_server = -1;
|
|
static int hf_country_code = -1;
|
|
static int hf_workstations = -1;
|
|
static int hf_max_storage = -1;
|
|
static int hf_units_per_week = -1;
|
|
static int hf_logon_hours = -1;
|
|
static int hf_code_page = -1;
|
|
static int hf_new_password = -1;
|
|
static int hf_old_password = -1;
|
|
static int hf_reserved = -1;
|
|
|
|
static gint ett_lanman = -1;
|
|
static gint ett_lanman_unknown_entries = -1;
|
|
static gint ett_lanman_unknown_entry = -1;
|
|
static gint ett_lanman_shares = -1;
|
|
static gint ett_lanman_share = -1;
|
|
static gint ett_lanman_groups = -1;
|
|
static gint ett_lanman_servers = -1;
|
|
static gint ett_lanman_server = -1;
|
|
|
|
static dissector_handle_t data_handle;
|
|
|
|
/*
|
|
* See
|
|
*
|
|
* ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
|
|
*
|
|
* among other documents.
|
|
*/
|
|
|
|
static const value_string status_vals[] = {
|
|
{0, "Success"},
|
|
{5, "User has insufficient privilege"},
|
|
{65, "Network access is denied"},
|
|
{86, "The specified password is invalid"},
|
|
{SMBE_moredata, "Additional data is available"},
|
|
{2114, "Service is not running on the remote computer"},
|
|
{2123, "Supplied buffer is too small"},
|
|
{2141, "Server is not configured for transactions (IPC$ not shared)"},
|
|
{2212, "An error occurred while loading or running the logon script"},
|
|
{2214, "The logon was not validated by any server"},
|
|
{2217, "The logon server is running an older software version"},
|
|
{2221, "The user name was not found"},
|
|
{2226, "Operation not permitted on Backup Domain Controller"},
|
|
{2240, "The user is not allowed to logon from this computer"},
|
|
{2241, "The user is not allowed to logon at this time"},
|
|
{2242, "The user password has expired"},
|
|
{2243, "The password cannot be changed"},
|
|
{2246, "The password is too short"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static const value_string privilege_vals[] = {
|
|
{0, "Guest"},
|
|
{1, "User"},
|
|
{2, "Administrator"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static const value_string op_privilege_vals[] = {
|
|
{0, "Print operator"},
|
|
{1, "Communications operator"},
|
|
{2, "Server operator"},
|
|
{3, "Accounts operator"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static const value_string weekday_vals[] = {
|
|
{0, "Sunday"},
|
|
{1, "Monday"},
|
|
{2, "Tuesday"},
|
|
{3, "Wednesday"},
|
|
{4, "Thursday"},
|
|
{5, "Friday"},
|
|
{6, "Saturday"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static int
|
|
add_word_param(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint16 WParam;
|
|
|
|
if (hf_index != -1)
|
|
proto_tree_add_item(tree, hf_index, tvb, offset, 2, TRUE);
|
|
else {
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"Word Param: %u (0x%04X)", WParam, WParam);
|
|
}
|
|
offset += 2;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_dword_param(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint32 LParam;
|
|
|
|
if (hf_index != -1)
|
|
proto_tree_add_item(tree, hf_index, tvb, offset, 4, TRUE);
|
|
else {
|
|
LParam = tvb_get_letohl(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 4,
|
|
"Doubleword Param: %u (0x%08X)", LParam, LParam);
|
|
}
|
|
offset += 4;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_byte_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint8 BParam;
|
|
|
|
if (hf_index != -1)
|
|
proto_tree_add_item(tree, hf_index, tvb, offset, count, TRUE);
|
|
else {
|
|
if (count == 1) {
|
|
BParam = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"Byte Param: %u (0x%02X)",
|
|
BParam, BParam);
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"Byte Param: %s",
|
|
tvb_bytes_to_str(tvb, offset, count));
|
|
}
|
|
}
|
|
offset += count;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_pad_param(tvbuff_t *tvb _U_, int offset, int count, packet_info *pinfo _U_,
|
|
proto_tree *tree _U_, int convert _U_, int hf_index _U_)
|
|
{
|
|
/*
|
|
* This is for parameters that have descriptor entries but that
|
|
* are, in practice, just padding.
|
|
*/
|
|
offset += count;
|
|
return offset;
|
|
}
|
|
|
|
static void
|
|
add_null_pointer_param(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
if (hf_index != -1) {
|
|
proto_tree_add_text(tree, tvb, offset, 0,
|
|
"%s (Null pointer)",
|
|
proto_registrar_get_name(hf_index));
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, offset, 0,
|
|
"String Param (Null pointer)");
|
|
}
|
|
}
|
|
|
|
static int
|
|
add_string_param(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint string_len;
|
|
|
|
string_len = tvb_strsize(tvb, offset);
|
|
if (hf_index != -1) {
|
|
proto_tree_add_item(tree, hf_index, tvb, offset, string_len,
|
|
TRUE);
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, offset, string_len,
|
|
"String Param: %s",
|
|
tvb_format_text(tvb, offset, string_len));
|
|
}
|
|
offset += string_len;
|
|
return offset;
|
|
}
|
|
|
|
static const char *
|
|
get_stringz_pointer_value(tvbuff_t *tvb, int offset, int convert, int *cptrp,
|
|
int *lenp)
|
|
{
|
|
int cptr;
|
|
gint string_len;
|
|
|
|
/* pointer to string */
|
|
cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
|
|
*cptrp = cptr;
|
|
|
|
/* string */
|
|
if (tvb_offset_exists(tvb, cptr) &&
|
|
(string_len = tvb_strnlen(tvb, cptr, -1)) != -1) {
|
|
string_len++; /* include the terminating '\0' */
|
|
*lenp = string_len;
|
|
return tvb_format_text(tvb, cptr, string_len - 1);
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
add_stringz_pointer_param(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert, int hf_index)
|
|
{
|
|
int cptr;
|
|
const char *string;
|
|
gint string_len;
|
|
|
|
string = get_stringz_pointer_value(tvb, offset, convert, &cptr,
|
|
&string_len);
|
|
offset += 4;
|
|
|
|
/* string */
|
|
if (string != NULL) {
|
|
if (hf_index != -1) {
|
|
proto_tree_add_item(tree, hf_index, tvb, cptr,
|
|
string_len, TRUE);
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, cptr, string_len,
|
|
"String Param: %s", string);
|
|
}
|
|
} else {
|
|
if (hf_index != -1) {
|
|
proto_tree_add_text(tree, tvb, 0, 0,
|
|
"%s: <String goes past end of frame>",
|
|
proto_registrar_get_name(hf_index));
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, 0, 0,
|
|
"String Param: <String goes past end of frame>");
|
|
}
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_bytes_pointer_param(tvbuff_t *tvb, int offset, int count,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert, int hf_index)
|
|
{
|
|
int cptr;
|
|
|
|
/* pointer to byte array */
|
|
cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
|
|
offset += 4;
|
|
|
|
/* bytes */
|
|
if (tvb_bytes_exist(tvb, cptr, count)) {
|
|
if (hf_index != -1) {
|
|
proto_tree_add_item(tree, hf_index, tvb, cptr,
|
|
count, TRUE);
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, cptr, count,
|
|
"Byte Param: %s",
|
|
tvb_bytes_to_str(tvb, cptr, count));
|
|
}
|
|
} else {
|
|
if (hf_index != -1) {
|
|
proto_tree_add_text(tree, tvb, 0, 0,
|
|
"%s: <Bytes go past end of frame>",
|
|
proto_registrar_get_name(hf_index));
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, 0, 0,
|
|
"Byte Param: <Bytes goes past end of frame>");
|
|
}
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_detail_level(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo,
|
|
proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
struct smb_info *smb_info = pinfo->private_data;
|
|
smb_transact_info_t *trp = smb_info->sip->extra_info;
|
|
guint16 level;
|
|
|
|
level = tvb_get_letohs(tvb, offset);
|
|
if (!pinfo->fd->flags.visited)
|
|
trp->info_level = level; /* remember this for the response */
|
|
proto_tree_add_uint(tree, hf_index, tvb, offset, 2, level);
|
|
offset += 2;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_max_uses(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint16 WParam;
|
|
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
if (WParam == 0xffff) { /* -1 */
|
|
proto_tree_add_uint_format(tree, hf_index, tvb,
|
|
offset, 2, WParam,
|
|
"%s: No limit",
|
|
proto_registrar_get_name(hf_index));
|
|
} else {
|
|
proto_tree_add_uint(tree, hf_index, tvb,
|
|
offset, 2, WParam);
|
|
}
|
|
offset += 2;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_server_type(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo, proto_tree *tree, int convert _U_, int hf_index _U_)
|
|
{
|
|
offset = dissect_smb_server_type_flags(
|
|
tvb, offset, pinfo, tree, NULL, FALSE);
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_server_type_info(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo, proto_tree *tree, int convert _U_, int hf_index _U_)
|
|
{
|
|
offset = dissect_smb_server_type_flags(
|
|
tvb, offset, pinfo, tree, NULL, TRUE);
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_reltime(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
nstime_t nstime;
|
|
|
|
nstime.secs = tvb_get_letohl(tvb, offset);
|
|
nstime.nsecs = 0;
|
|
proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
|
|
&nstime, "%s: %s", proto_registrar_get_name(hf_index),
|
|
time_secs_to_str(nstime.secs));
|
|
offset += 4;
|
|
return offset;
|
|
}
|
|
|
|
/*
|
|
* Sigh. These are for handling Microsoft's annoying almost-UNIX-time-but-
|
|
* it's-local-time-not-UTC time.
|
|
*/
|
|
static int
|
|
add_abstime_common(tvbuff_t *tvb, int offset, proto_tree *tree, int hf_index,
|
|
const char *absent_name)
|
|
{
|
|
nstime_t nstime;
|
|
struct tm *tmp;
|
|
|
|
nstime.secs = tvb_get_letohl(tvb, offset);
|
|
nstime.nsecs = 0;
|
|
/*
|
|
* Sigh. Sometimes it appears that -1 means "unknown", and
|
|
* sometimes it appears that 0 means "unknown", for the last
|
|
* logoff date/time.
|
|
*/
|
|
if (nstime.secs == -1 || nstime.secs == 0) {
|
|
proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
|
|
&nstime, "%s: %s", proto_registrar_get_name(hf_index),
|
|
absent_name);
|
|
} else {
|
|
/*
|
|
* Run it through "gmtime()" to break it down, and then
|
|
* run it through "mktime()" to put it back together
|
|
* as UTC.
|
|
*/
|
|
tmp = gmtime(&nstime.secs);
|
|
tmp->tm_isdst = -1; /* we don't know if it's DST or not */
|
|
nstime.secs = mktime(tmp);
|
|
proto_tree_add_time(tree, hf_index, tvb, offset, 4,
|
|
&nstime);
|
|
}
|
|
offset += 4;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_abstime_absent_never(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
return add_abstime_common(tvb, offset, tree, hf_index, "Never");
|
|
}
|
|
|
|
static int
|
|
add_abstime_absent_unknown(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
return add_abstime_common(tvb, offset, tree, hf_index, "Unknown");
|
|
}
|
|
|
|
static int
|
|
add_nlogons(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint16 nlogons;
|
|
|
|
nlogons = tvb_get_letohs(tvb, offset);
|
|
if (nlogons == 0xffff) /* -1 */
|
|
proto_tree_add_uint_format(tree, hf_index, tvb, offset, 2,
|
|
nlogons, "%s: Unknown",
|
|
proto_registrar_get_name(hf_index));
|
|
else
|
|
proto_tree_add_uint(tree, hf_index, tvb, offset, 2,
|
|
nlogons);
|
|
offset += 2;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_max_storage(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint32 max_storage;
|
|
|
|
max_storage = tvb_get_letohl(tvb, offset);
|
|
if (max_storage == 0xffffffff)
|
|
proto_tree_add_uint_format(tree, hf_index, tvb, offset, 4,
|
|
max_storage, "%s: No limit",
|
|
proto_registrar_get_name(hf_index));
|
|
else
|
|
proto_tree_add_uint(tree, hf_index, tvb, offset, 4,
|
|
max_storage);
|
|
offset += 4;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_logon_hours(tvbuff_t *tvb, int offset, int count, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert, int hf_index)
|
|
{
|
|
int cptr;
|
|
|
|
/* pointer to byte array */
|
|
cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
|
|
offset += 4;
|
|
|
|
/* bytes */
|
|
if (tvb_bytes_exist(tvb, cptr, count)) {
|
|
if (count == 21) {
|
|
/*
|
|
* The logon hours should be exactly 21 bytes long.
|
|
*
|
|
* XXX - should actually carve up the bits;
|
|
* we need the units per week to do that, though.
|
|
*/
|
|
proto_tree_add_item(tree, hf_index, tvb, cptr, count,
|
|
TRUE);
|
|
} else {
|
|
proto_tree_add_bytes_format(tree, hf_index, tvb,
|
|
cptr, count, tvb_get_ptr(tvb, cptr, count),
|
|
"%s: %s (wrong length, should be 21, is %d",
|
|
proto_registrar_get_name(hf_index),
|
|
tvb_bytes_to_str(tvb, cptr, count), count);
|
|
}
|
|
} else {
|
|
proto_tree_add_text(tree, tvb, 0, 0,
|
|
"%s: <Bytes go past end of frame>",
|
|
proto_registrar_get_name(hf_index));
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_tzoffset(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
gint16 tzoffset;
|
|
|
|
tzoffset = tvb_get_letohs(tvb, offset);
|
|
if (tzoffset < 0) {
|
|
proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
|
|
tzoffset, "%s: %s east of UTC",
|
|
proto_registrar_get_name(hf_index),
|
|
time_secs_to_str(-tzoffset*60));
|
|
} else if (tzoffset > 0) {
|
|
proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
|
|
tzoffset, "%s: %s west of UTC",
|
|
proto_registrar_get_name(hf_index),
|
|
time_secs_to_str(tzoffset*60));
|
|
} else {
|
|
proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
|
|
tzoffset, "%s: at UTC",
|
|
proto_registrar_get_name(hf_index));
|
|
}
|
|
offset += 2;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_timeinterval(tvbuff_t *tvb, int offset, int count _U_,
|
|
packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
|
|
{
|
|
guint16 timeinterval;
|
|
|
|
timeinterval = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2,
|
|
timeinterval, "%s: %f seconds", proto_registrar_get_name(hf_index),
|
|
timeinterval*.0001);
|
|
offset += 2;
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
add_logon_args(tvbuff_t *tvb, int offset, int count, packet_info *pinfo _U_,
|
|
proto_tree *tree, int convert _U_, int hf_index _U_)
|
|
{
|
|
if (count != 54) {
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"Bogus NetWkstaUserLogon parameters: length is %d, should be 54",
|
|
count);
|
|
offset += count;
|
|
return offset;
|
|
}
|
|
|
|
/* user name */
|
|
proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
|
|
offset += 21;
|
|
|
|
/* pad1 */
|
|
offset += 1;
|
|
|
|
/* password */
|
|
proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE);
|
|
offset += 15;
|
|
|
|
/* pad2 */
|
|
offset += 1;
|
|
|
|
/* workstation name */
|
|
proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
|
|
offset += 16;
|
|
return offset;
|
|
}
|
|
|
|
/*
|
|
* The following data structure describes the Remote API requests we
|
|
* understand.
|
|
*
|
|
* Simply fill in the number and parameter information.
|
|
* Try to keep them in order.
|
|
*
|
|
* We will extend this data structure as we try to decode more.
|
|
*/
|
|
|
|
/*
|
|
* This is a pointer to a function to process an item.
|
|
*/
|
|
typedef int (*item_func)(tvbuff_t *, int, int, packet_info *, proto_tree *,
|
|
int, int);
|
|
|
|
/*
|
|
* Type of an item; determines what parameter strings are valid for
|
|
* the item.
|
|
*/
|
|
typedef enum {
|
|
PARAM_NONE, /* for the end-of-list stopper */
|
|
PARAM_WORD, /* 'W' or 'h' - 16-bit word */
|
|
PARAM_DWORD, /* 'D' or 'i' - 32-bit word */
|
|
PARAM_BYTES, /* 'B' or 'b' or 'g' or 'O' - one or more bytes */
|
|
PARAM_STRINGZ /* 'z' or 'O' - null-terminated string */
|
|
} param_type_t;
|
|
|
|
/*
|
|
* This structure describes an item; "hf_index" points to the index
|
|
* for the field corresponding to that item, "func" points to the
|
|
* function to use to add that item to the tree, and "type" is the
|
|
* type that the item is supposed to have.
|
|
*/
|
|
typedef struct {
|
|
int *hf_index;
|
|
item_func func;
|
|
param_type_t type;
|
|
} item_t;
|
|
|
|
/*
|
|
* This structure describes a list of items; each list of items
|
|
* has a corresponding detail level.
|
|
*/
|
|
typedef struct {
|
|
int level;
|
|
const item_t *item_list;
|
|
} item_list_t;
|
|
|
|
struct lanman_desc {
|
|
int lanman_num;
|
|
const item_t *req;
|
|
proto_item *(*req_data_item)(tvbuff_t *, packet_info *,
|
|
proto_tree *, int);
|
|
gint *ett_req_data;
|
|
const item_t *req_data;
|
|
const item_t *req_aux_data;
|
|
const item_t *resp;
|
|
const gchar *resp_data_entry_list_label;
|
|
gint *ett_data_entry_list;
|
|
proto_item *(*resp_data_element_item)(tvbuff_t *, proto_tree *,
|
|
int);
|
|
gint *ett_resp_data_element_item;
|
|
const item_list_t *resp_data_list;
|
|
const item_t *resp_aux_data;
|
|
};
|
|
|
|
static int no_hf = -1; /* for padding crap */
|
|
|
|
static const item_t lm_params_req_netshareenum[] = {
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ &hf_recv_buf_len, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netshareenum[] = {
|
|
{ &hf_acount, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
/*
|
|
* Create a subtree for a share.
|
|
*/
|
|
static proto_item *
|
|
netshareenum_share_entry(tvbuff_t *tvb, proto_tree *tree, int offset)
|
|
{
|
|
if (tree) {
|
|
return proto_tree_add_text(tree, tvb, offset, -1,
|
|
"Share %.13s", tvb_get_ptr(tvb, offset, 13));
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
static const item_t lm_null[] = {
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_null_list[] = {
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netshareenum_1[] = {
|
|
{ &hf_share_name, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_pad_param, PARAM_BYTES },
|
|
{ &hf_share_type, add_word_param, PARAM_WORD },
|
|
{ &hf_share_comment, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netshareenum[] = {
|
|
{ 1, lm_data_resp_netshareenum_1 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_netsharegetinfo[] = {
|
|
{ &hf_share_name, add_string_param, PARAM_STRINGZ },
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netsharegetinfo[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netsharegetinfo_0[] = {
|
|
{ &hf_share_name, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netsharegetinfo_1[] = {
|
|
{ &hf_share_name, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_pad_param, PARAM_BYTES },
|
|
{ &hf_share_type, add_word_param, PARAM_WORD },
|
|
{ &hf_share_comment, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netsharegetinfo_2[] = {
|
|
{ &hf_share_name, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_pad_param, PARAM_BYTES },
|
|
{ &hf_share_type, add_word_param, PARAM_WORD },
|
|
{ &hf_share_comment, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_share_permissions, add_word_param, PARAM_WORD }, /* XXX - do as bit fields */
|
|
{ &hf_share_max_uses, add_max_uses, PARAM_WORD },
|
|
{ &hf_share_current_uses, add_word_param, PARAM_WORD },
|
|
{ &hf_share_path, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_share_password, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netsharegetinfo[] = {
|
|
{ 0, lm_data_resp_netsharegetinfo_0 },
|
|
{ 1, lm_data_resp_netsharegetinfo_1 },
|
|
{ 2, lm_data_resp_netsharegetinfo_2 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_netservergetinfo[] = {
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netservergetinfo[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_serverinfo_0[] = {
|
|
{ &hf_server_name, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_serverinfo_1[] = {
|
|
{ &hf_server_name, add_byte_param, PARAM_BYTES },
|
|
{ &hf_server_major, add_byte_param, PARAM_BYTES },
|
|
{ &hf_server_minor, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_server_type, PARAM_DWORD },
|
|
{ &hf_server_comment, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_serverinfo[] = {
|
|
{ 0, lm_data_serverinfo_0 },
|
|
{ 1, lm_data_serverinfo_1 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_netusergetinfo[] = {
|
|
{ &hf_user_name, add_string_param, PARAM_STRINGZ },
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netusergetinfo[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netusergetinfo_11[] = {
|
|
{ &hf_user_name, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_pad_param, PARAM_BYTES },
|
|
{ &hf_comment, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_user_comment, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_full_name, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_privilege_level, add_word_param, PARAM_WORD },
|
|
{ &hf_operator_privileges, add_dword_param, PARAM_DWORD },
|
|
{ &hf_password_age, add_reltime, PARAM_DWORD },
|
|
{ &hf_homedir, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_parameters, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
|
|
{ &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
|
|
{ &hf_bad_pw_count, add_word_param, PARAM_WORD },
|
|
{ &hf_num_logons, add_nlogons, PARAM_WORD },
|
|
{ &hf_logon_server, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_country_code, add_word_param, PARAM_WORD },
|
|
{ &hf_workstations, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_max_storage, add_max_storage, PARAM_DWORD },
|
|
{ &hf_units_per_week, add_word_param, PARAM_WORD },
|
|
{ &hf_logon_hours, add_logon_hours, PARAM_BYTES },
|
|
{ &hf_code_page, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netusergetinfo[] = {
|
|
{ 11, lm_data_resp_netusergetinfo_11 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_netusergetgroups[] = {
|
|
{ &hf_user_name, add_string_param, PARAM_STRINGZ },
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netusergetgroups[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netusergetgroups_0[] = {
|
|
{ &hf_group_name, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netusergetgroups[] = {
|
|
{ 0, lm_data_resp_netusergetgroups_0 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
/*
|
|
* Has no detail level; make it the default.
|
|
*/
|
|
static const item_t lm_data_resp_netremotetod_nolevel[] = {
|
|
{ &hf_current_time, add_abstime_absent_unknown, PARAM_DWORD },
|
|
{ &hf_msecs, add_dword_param, PARAM_DWORD },
|
|
{ &hf_hour, add_byte_param, PARAM_BYTES },
|
|
{ &hf_minute, add_byte_param, PARAM_BYTES },
|
|
{ &hf_second, add_byte_param, PARAM_BYTES },
|
|
{ &hf_hundredths, add_byte_param, PARAM_BYTES },
|
|
{ &hf_tzoffset, add_tzoffset, PARAM_WORD },
|
|
{ &hf_timeinterval, add_timeinterval, PARAM_WORD },
|
|
{ &hf_day, add_byte_param, PARAM_BYTES },
|
|
{ &hf_month, add_byte_param, PARAM_BYTES },
|
|
{ &hf_year, add_word_param, PARAM_WORD },
|
|
{ &hf_weekday, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netremotetod[] = {
|
|
{ -1, lm_data_resp_netremotetod_nolevel },
|
|
};
|
|
|
|
static const item_t lm_params_req_netserverenum2[] = {
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ &no_hf, add_server_type_info, PARAM_DWORD },
|
|
{ &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
/*
|
|
* Create a subtree for a server.
|
|
*/
|
|
static proto_item *
|
|
netserverenum2_server_entry(tvbuff_t *tvb, proto_tree *tree, int offset)
|
|
{
|
|
if (tree) {
|
|
return proto_tree_add_text(tree, tvb, offset, -1,
|
|
"Server %.16s", tvb_get_ptr(tvb, offset, 16));
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
static const item_t lm_params_resp_netserverenum2[] = {
|
|
{ &hf_acount, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
|
|
static const item_t lm_params_req_netserverenum3[] = {
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ &no_hf, add_server_type_info, PARAM_DWORD },
|
|
{ &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
|
|
{ &hf_last_entry, add_string_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
|
|
static const item_t lm_params_req_netwkstagetinfo[] = {
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netwkstagetinfo[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netwkstagetinfo_10[] = {
|
|
{ &hf_computer_name, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_user_name, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_workstation_domain, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_workstation_major, add_byte_param, PARAM_BYTES },
|
|
{ &hf_workstation_minor, add_byte_param, PARAM_BYTES },
|
|
{ &hf_logon_domain, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_other_domains, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netwkstagetinfo[] = {
|
|
{ 10, lm_data_resp_netwkstagetinfo_10 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_netwkstauserlogon[] = {
|
|
{ &no_hf, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &no_hf, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_detail_level, add_detail_level, PARAM_WORD },
|
|
{ &no_hf, add_logon_args, PARAM_BYTES },
|
|
{ &hf_ustruct_size, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netwkstauserlogon[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netwkstauserlogon_1[] = {
|
|
{ &hf_logon_code, add_word_param, PARAM_WORD },
|
|
{ &hf_user_name, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_pad_param, PARAM_BYTES },
|
|
{ &hf_privilege_level, add_word_param, PARAM_WORD },
|
|
{ &hf_operator_privileges, add_dword_param, PARAM_DWORD },
|
|
{ &hf_num_logons, add_nlogons, PARAM_WORD },
|
|
{ &hf_bad_pw_count, add_word_param, PARAM_WORD },
|
|
{ &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
|
|
{ &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
|
|
{ &hf_logoff_time, add_abstime_absent_never, PARAM_DWORD },
|
|
{ &hf_kickoff_time, add_abstime_absent_never, PARAM_DWORD },
|
|
{ &hf_password_age, add_reltime, PARAM_DWORD },
|
|
{ &hf_password_can_change, add_abstime_absent_never, PARAM_DWORD },
|
|
{ &hf_password_must_change, add_abstime_absent_never, PARAM_DWORD },
|
|
{ &hf_server_name, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_logon_domain, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_script_path, add_stringz_pointer_param, PARAM_STRINGZ },
|
|
{ &hf_reserved, add_dword_param, PARAM_DWORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netwkstauserlogon[] = {
|
|
{ 1, lm_data_resp_netwkstauserlogon_1 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_netwkstauserlogoff[] = {
|
|
{ &hf_user_name, add_byte_param, PARAM_BYTES },
|
|
{ &no_hf, add_pad_param, PARAM_BYTES },
|
|
{ &hf_workstation_name, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_params_resp_netwkstauserlogoff[] = {
|
|
{ &hf_abytes, add_word_param, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_resp_netwkstauserlogoff_1[] = {
|
|
{ &hf_logoff_code, add_word_param, PARAM_WORD },
|
|
{ &hf_duration, add_reltime, PARAM_DWORD },
|
|
{ &hf_num_logons, add_nlogons, PARAM_WORD },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_list_t lm_data_resp_netwkstauserlogoff[] = {
|
|
{ 1, lm_data_resp_netwkstauserlogoff_1 },
|
|
{ -1, lm_null }
|
|
};
|
|
|
|
static const item_t lm_params_req_samoemchangepassword[] = {
|
|
{ &hf_user_name, add_string_param, PARAM_STRINGZ },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
static const item_t lm_data_req_samoemchangepassword[] = {
|
|
{ &hf_new_password, add_byte_param, PARAM_BYTES },
|
|
{ &hf_old_password, add_byte_param, PARAM_BYTES },
|
|
{ NULL, NULL, PARAM_NONE }
|
|
};
|
|
|
|
#define API_NetShareEnum 0
|
|
#define API_NetShareGetInfo 1
|
|
#define API_NetShareSetInfo 2
|
|
#define API_NetShareAdd 3
|
|
#define API_NetShareDel 4
|
|
#define API_NetShareCheck 5
|
|
#define API_NetSessionEnum 6
|
|
#define API_NetSessionGetInfo 7
|
|
#define API_NetSessionDel 8
|
|
#define API_WconnectionEnum 9
|
|
#define API_NetFileEnum 10
|
|
#define API_NetFileGetInfo 11
|
|
#define API_NetFileClose 12
|
|
#define API_NetServerGetInfo 13
|
|
#define API_NetServerSetInfo 14
|
|
#define API_NetServerDiskEnum 15
|
|
#define API_NetServerAdminCommand 16
|
|
#define API_NetAuditOpen 17
|
|
#define API_NetAuditClear 18
|
|
#define API_NetErrorLogOpen 19
|
|
#define API_NetErrorLogClear 20
|
|
#define API_NetCharDevEnum 21
|
|
#define API_NetCharDevGetInfo 22
|
|
#define API_NetCharDevControl 23
|
|
#define API_NetCharDevQEnum 24
|
|
#define API_NetCharDevQGetInfo 25
|
|
#define API_NetCharDevQSetInfo 26
|
|
#define API_NetCharDevQPurge 27
|
|
#define API_NetCharDevQPurgeSelf 28
|
|
#define API_NetMessageNameEnum 29
|
|
#define API_NetMessageNameGetInfo 30
|
|
#define API_NetMessageNameAdd 31
|
|
#define API_NetMessageNameDel 32
|
|
#define API_NetMessageNameFwd 33
|
|
#define API_NetMessageNameUnFwd 34
|
|
#define API_NetMessageBufferSend 35
|
|
#define API_NetMessageFileSend 36
|
|
#define API_NetMessageLogFileSet 37
|
|
#define API_NetMessageLogFileGet 38
|
|
#define API_NetServiceEnum 39
|
|
#define API_NetServiceInstall 40
|
|
#define API_NetServiceControl 41
|
|
#define API_NetAccessEnum 42
|
|
#define API_NetAccessGetInfo 43
|
|
#define API_NetAccessSetInfo 44
|
|
#define API_NetAccessAdd 45
|
|
#define API_NetAccessDel 46
|
|
#define API_NetGroupEnum 47
|
|
#define API_NetGroupAdd 48
|
|
#define API_NetGroupDel 49
|
|
#define API_NetGroupAddUser 50
|
|
#define API_NetGroupDelUser 51
|
|
#define API_NetGroupGetUsers 52
|
|
#define API_NetUserEnum 53
|
|
#define API_NetUserAdd 54
|
|
#define API_NetUserDel 55
|
|
#define API_NetUserGetInfo 56
|
|
#define API_NetUserSetInfo 57
|
|
#define API_NetUserPasswordSet 58
|
|
#define API_NetUserGetGroups 59
|
|
/*This line and number replaced a Dead Entry for 60 */
|
|
/*This line and number replaced a Dead Entry for 61 */
|
|
#define API_NetWkstaSetUID 62
|
|
#define API_NetWkstaGetInfo 63
|
|
#define API_NetWkstaSetInfo 64
|
|
#define API_NetUseEnum 65
|
|
#define API_NetUseAdd 66
|
|
#define API_NetUseDel 67
|
|
#define API_NetUseGetInfo 68
|
|
#define API_WPrintQEnum 69
|
|
#define API_WPrintQGetInfo 70
|
|
#define API_WPrintQSetInfo 71
|
|
#define API_WPrintQAdd 72
|
|
#define API_WPrintQDel 73
|
|
#define API_WPrintQPause 74
|
|
#define API_WPrintQContinue 75
|
|
#define API_WPrintJobEnum 76
|
|
#define API_WPrintJobGetInfo 77
|
|
#define API_WPrintJobSetInfo_OLD 78
|
|
/* This line and number replaced a Dead Entry for 79 */
|
|
/* This line and number replaced a Dead Entry for 80 */
|
|
#define API_WPrintJobDel 81
|
|
#define API_WPrintJobPause 82
|
|
#define API_WPrintJobContinue 83
|
|
#define API_WPrintDestEnum 84
|
|
#define API_WPrintDestGetInfo 85
|
|
#define API_WPrintDestControl 86
|
|
#define API_NetProfileSave 87
|
|
#define API_NetProfileLoad 88
|
|
#define API_NetStatisticsGet 89
|
|
#define API_NetStatisticsClear 90
|
|
#define API_NetRemoteTOD 91
|
|
#define API_WNetBiosEnum 92
|
|
#define API_WNetBiosGetInfo 93
|
|
#define API_NetServerEnum 94
|
|
#define API_I_NetServerEnum 95
|
|
#define API_NetServiceGetInfo 96
|
|
/* This line and number replaced a Dead Entry for 97 */
|
|
/* This line and number replaced a Dead Entry for 98 */
|
|
/* This line and number replaced a Dead Entry for 99 */
|
|
/* This line and number replaced a Dead Entry for 100 */
|
|
/* This line and number replaced a Dead Entry for 101 */
|
|
/* This line and number replaced a Dead Entry for 102 */
|
|
#define API_WPrintQPurge 103
|
|
#define API_NetServerEnum2 104
|
|
#define API_NetAccessGetUserPerms 105
|
|
#define API_NetGroupGetInfo 106
|
|
#define API_NetGroupSetInfo 107
|
|
#define API_NetGroupSetUsers 108
|
|
#define API_NetUserSetGroups 109
|
|
#define API_NetUserModalsGet 110
|
|
#define API_NetUserModalsSet 111
|
|
#define API_NetFileEnum2 112
|
|
#define API_NetUserAdd2 113
|
|
#define API_NetUserSetInfo2 114
|
|
#define API_NetUserPasswordSet2 115
|
|
#define API_I_NetServerEnum2 116
|
|
#define API_NetConfigGet2 117
|
|
#define API_NetConfigGetAll2 118
|
|
#define API_NetGetDCName 119
|
|
#define API_NetHandleGetInfo 120
|
|
#define API_NetHandleSetInfo 121
|
|
#define API_NetStatisticsGet2 122
|
|
#define API_WBuildGetInfo 123
|
|
#define API_NetFileGetInfo2 124
|
|
#define API_NetFileClose2 125
|
|
#define API_NetServerReqChallenge 126
|
|
#define API_NetServerAuthenticate 127
|
|
#define API_NetServerPasswordSet 128
|
|
#define API_WNetAccountDeltas 129
|
|
#define API_WNetAccountSync 130
|
|
#define API_NetUserEnum2 131
|
|
#define API_NetWkstaUserLogon 132
|
|
#define API_NetWkstaUserLogoff 133
|
|
#define API_NetLogonEnum 134
|
|
#define API_NetErrorLogRead 135
|
|
#define API_I_NetPathType 136
|
|
#define API_I_NetPathCanonicalize 137
|
|
#define API_I_NetPathCompare 138
|
|
#define API_I_NetNameValidate 139
|
|
#define API_I_NetNameCanonicalize 140
|
|
#define API_I_NetNameCompare 141
|
|
#define API_NetAuditRead 142
|
|
#define API_WPrintDestAdd 143
|
|
#define API_WPrintDestSetInfo 144
|
|
#define API_WPrintDestDel 145
|
|
#define API_NetUserValidate2 146
|
|
#define API_WPrintJobSetInfo 147
|
|
#define API_TI_NetServerDiskEnum 148
|
|
#define API_TI_NetServerDiskGetInfo 149
|
|
#define API_TI_FTVerifyMirror 150
|
|
#define API_TI_FTAbortVerify 151
|
|
#define API_TI_FTGetInfo 152
|
|
#define API_TI_FTSetInfo 153
|
|
#define API_TI_FTLockDisk 154
|
|
#define API_TI_FTFixError 155
|
|
#define API_TI_FTAbortFix 156
|
|
#define API_TI_FTDiagnoseError 157
|
|
#define API_TI_FTGetDriveStats 158
|
|
/* This line and number replaced a Dead Entry for 159 */
|
|
#define API_TI_FTErrorGetInfo 160
|
|
/* This line and number replaced a Dead Entry for 161 */
|
|
/* This line and number replaced a Dead Entry for 162 */
|
|
#define API_NetAccessCheck 163
|
|
#define API_NetAlertRaise 164
|
|
#define API_NetAlertStart 165
|
|
#define API_NetAlertStop 166
|
|
#define API_NetAuditWrite 167
|
|
#define API_NetIRemoteAPI 168
|
|
#define API_NetServiceStatus 169
|
|
#define API_I_NetServerRegister 170
|
|
#define API_I_NetServerDeregister 171
|
|
#define API_I_NetSessionEntryMake 172
|
|
#define API_I_NetSessionEntryClear 173
|
|
#define API_I_NetSessionEntryGetInfo 174
|
|
#define API_I_NetSessionEntrySetInfo 175
|
|
#define API_I_NetConnectionEntryMake 176
|
|
#define API_I_NetConnectionEntryClear 177
|
|
#define API_I_NetConnectionEntrySetInfo 178
|
|
#define API_I_NetConnectionEntryGetInfo 179
|
|
#define API_I_NetFileEntryMake 180
|
|
#define API_I_NetFileEntryClear 181
|
|
#define API_I_NetFileEntrySetInfo 182
|
|
#define API_I_NetFileEntryGetInfo 183
|
|
#define API_AltSrvMessageBufferSend 184
|
|
#define API_AltSrvMessageFileSend 185
|
|
#define API_wI_NetRplWkstaEnum 186
|
|
#define API_wI_NetRplWkstaGetInfo 187
|
|
#define API_wI_NetRplWkstaSetInfo 188
|
|
#define API_wI_NetRplWkstaAdd 189
|
|
#define API_wI_NetRplWkstaDel 190
|
|
#define API_wI_NetRplProfileEnum 191
|
|
#define API_wI_NetRplProfileGetInfo 192
|
|
#define API_wI_NetRplProfileSetInfo 193
|
|
#define API_wI_NetRplProfileAdd 194
|
|
#define API_wI_NetRplProfileDel 195
|
|
#define API_wI_NetRplProfileClone 196
|
|
#define API_wI_NetRplBaseProfileEnum 197
|
|
/* This line and number replaced a Dead Entry for 198 */
|
|
/* This line and number replaced a Dead Entry for 199 */
|
|
/* This line and number replaced a Dead Entry for 200 */
|
|
#define API_WIServerSetInfo 201
|
|
/* This line and number replaced a Dead Entry for 202 */
|
|
/* This line and number replaced a Dead Entry for 203 */
|
|
/* This line and number replaced a Dead Entry for 204 */
|
|
#define API_WPrintDriverEnum 205
|
|
#define API_WPrintQProcessorEnum 206
|
|
#define API_WPrintPortEnum 207
|
|
#define API_WNetWriteUpdateLog 208
|
|
#define API_WNetAccountUpdate 209
|
|
#define API_WNetAccountConfirmUpdate 210
|
|
#define API_NetConfigSet 211
|
|
#define API_WAccountsReplicate 212
|
|
/* 213 is used by WfW */
|
|
#define API_SamOEMChgPasswordUser2_P 214
|
|
#define API_NetServerEnum3 215
|
|
/* XXX - what about 216 through 249? */
|
|
#define API_WPrintDriverGetInfo 250
|
|
#define API_WPrintDriverSetInfo 251
|
|
#define API_NetAliasAdd 252
|
|
#define API_NetAliasDel 253
|
|
#define API_NetAliasGetInfo 254
|
|
#define API_NetAliasSetInfo 255
|
|
#define API_NetAliasEnum 256
|
|
#define API_NetUserGetLogonAsn 257
|
|
#define API_NetUserSetLogonAsn 258
|
|
#define API_NetUserGetAppSel 259
|
|
#define API_NetUserSetAppSel 260
|
|
#define API_NetAppAdd 261
|
|
#define API_NetAppDel 262
|
|
#define API_NetAppGetInfo 263
|
|
#define API_NetAppSetInfo 264
|
|
#define API_NetAppEnum 265
|
|
#define API_NetUserDCDBInit 266
|
|
#define API_NetDASDAdd 267
|
|
#define API_NetDASDDel 268
|
|
#define API_NetDASDGetInfo 269
|
|
#define API_NetDASDSetInfo 270
|
|
#define API_NetDASDEnum 271
|
|
#define API_NetDASDCheck 272
|
|
#define API_NetDASDCtl 273
|
|
#define API_NetUserRemoteLogonCheck 274
|
|
#define API_NetUserPasswordSet3 275
|
|
#define API_NetCreateRIPLMachine 276
|
|
#define API_NetDeleteRIPLMachine 277
|
|
#define API_NetGetRIPLMachineInfo 278
|
|
#define API_NetSetRIPLMachineInfo 279
|
|
#define API_NetEnumRIPLMachine 280
|
|
#define API_I_ShareAdd 281
|
|
#define API_I_AliasEnum 282
|
|
#define API_NetAccessApply 283
|
|
#define API_WPrt16Query 284
|
|
#define API_WPrt16Set 285
|
|
#define API_NetUserDel100 286
|
|
#define API_NetUserRemoteLogonCheck2 287
|
|
#define API_WRemoteTODSet 294
|
|
#define API_WPrintJobMoveAll 295
|
|
#define API_W16AppParmAdd 296
|
|
#define API_W16AppParmDel 297
|
|
#define API_W16AppParmGet 298
|
|
#define API_W16AppParmSet 299
|
|
#define API_W16RIPLMachineCreate 300
|
|
#define API_W16RIPLMachineGetInfo 301
|
|
#define API_W16RIPLMachineSetInfo 302
|
|
#define API_W16RIPLMachineEnum 303
|
|
#define API_W16RIPLMachineListParmEnum 304
|
|
#define API_W16RIPLMachClassGetInfo 305
|
|
#define API_W16RIPLMachClassEnum 306
|
|
#define API_W16RIPLMachClassCreate 307
|
|
#define API_W16RIPLMachClassSetInfo 308
|
|
#define API_W16RIPLMachClassDelete 309
|
|
#define API_W16RIPLMachClassLPEnum 310
|
|
#define API_W16RIPLMachineDelete 311
|
|
#define API_W16WSLevelGetInfo 312
|
|
#define API_NetServerNameAdd 313
|
|
#define API_NetServerNameDel 314
|
|
#define API_NetServerNameEnum 315
|
|
#define API_I_WDASDEnum 316
|
|
#define API_I_WDASDEnumTerminate 317
|
|
#define API_I_WDASDSetInfo2 318
|
|
|
|
static const struct lanman_desc lmd[] = {
|
|
{ API_NetShareEnum,
|
|
lm_params_req_netshareenum,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netshareenum,
|
|
"Available Shares",
|
|
&ett_lanman_shares,
|
|
netshareenum_share_entry,
|
|
&ett_lanman_share,
|
|
lm_data_resp_netshareenum,
|
|
lm_null },
|
|
|
|
{ API_NetShareGetInfo,
|
|
lm_params_req_netsharegetinfo,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netsharegetinfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netsharegetinfo,
|
|
lm_null },
|
|
|
|
{ API_NetServerGetInfo,
|
|
lm_params_req_netservergetinfo,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netservergetinfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_serverinfo,
|
|
lm_null },
|
|
|
|
{ API_NetUserGetInfo,
|
|
lm_params_req_netusergetinfo,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netusergetinfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netusergetinfo,
|
|
lm_null },
|
|
|
|
{ API_NetUserGetGroups,
|
|
lm_params_req_netusergetgroups,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netusergetgroups,
|
|
"Groups",
|
|
&ett_lanman_groups,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netusergetgroups,
|
|
lm_null },
|
|
|
|
{ API_NetRemoteTOD,
|
|
lm_null,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_null,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netremotetod,
|
|
lm_null },
|
|
|
|
{ API_NetServerEnum2,
|
|
lm_params_req_netserverenum2,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netserverenum2,
|
|
"Servers",
|
|
&ett_lanman_servers,
|
|
netserverenum2_server_entry,
|
|
&ett_lanman_server,
|
|
lm_data_serverinfo,
|
|
lm_null },
|
|
|
|
{ API_NetWkstaGetInfo,
|
|
lm_params_req_netwkstagetinfo,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netwkstagetinfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netwkstagetinfo,
|
|
lm_null },
|
|
|
|
{ API_NetWkstaUserLogon,
|
|
lm_params_req_netwkstauserlogon,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netwkstauserlogon,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netwkstauserlogon,
|
|
lm_null },
|
|
|
|
{ API_NetWkstaUserLogoff,
|
|
lm_params_req_netwkstauserlogoff,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netwkstauserlogoff,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_data_resp_netwkstauserlogoff,
|
|
lm_null },
|
|
|
|
{ API_SamOEMChgPasswordUser2_P,
|
|
lm_params_req_samoemchangepassword,
|
|
NULL,
|
|
NULL,
|
|
lm_data_req_samoemchangepassword,
|
|
lm_null,
|
|
lm_null,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lm_null_list,
|
|
lm_null },
|
|
|
|
{ API_NetServerEnum3,
|
|
lm_params_req_netserverenum3,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_params_resp_netserverenum2,
|
|
"Servers",
|
|
&ett_lanman_servers,
|
|
netserverenum2_server_entry,
|
|
&ett_lanman_server,
|
|
lm_data_serverinfo,
|
|
lm_null },
|
|
|
|
{ -1,
|
|
lm_null,
|
|
NULL,
|
|
NULL,
|
|
lm_null,
|
|
lm_null,
|
|
lm_null,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ett_lanman_unknown_entry,
|
|
lm_null_list,
|
|
lm_null }
|
|
};
|
|
|
|
static const struct lanman_desc *
|
|
find_lanman(int lanman_num)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; lmd[i].lanman_num != -1; i++) {
|
|
if (lmd[i].lanman_num == lanman_num)
|
|
break;
|
|
}
|
|
return &lmd[i];
|
|
}
|
|
|
|
static const guchar *
|
|
get_count(const guchar *desc, int *countp)
|
|
{
|
|
int count = 0;
|
|
guchar c;
|
|
|
|
if (!isdigit(*desc)) {
|
|
*countp = 1; /* no count was supplied */
|
|
return desc;
|
|
}
|
|
|
|
while ((c = *desc) != '\0' && isdigit(c)) {
|
|
count = (count * 10) + c - '0';
|
|
desc++;
|
|
}
|
|
|
|
*countp = count; /* XXX - what if it's 0? */
|
|
return desc;
|
|
}
|
|
|
|
static int
|
|
dissect_request_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
|
|
proto_tree *tree, const guchar *desc, const item_t *items,
|
|
gboolean *has_data_p)
|
|
{
|
|
guint c;
|
|
guint16 WParam;
|
|
guint32 LParam;
|
|
guint string_len;
|
|
int count;
|
|
|
|
*has_data_p = FALSE;
|
|
while ((c = *desc++) != '\0') {
|
|
switch (c) {
|
|
|
|
case 'W':
|
|
/*
|
|
* A 16-bit word value in the request.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_word_param(tvb, offset, 0, pinfo,
|
|
tree, 0, -1);
|
|
} else if (items->type != PARAM_WORD) {
|
|
/*
|
|
* Descriptor character is 'W', but this
|
|
* isn't a word parameter.
|
|
*/
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: Value is %u (0x%04X), type is wrong (W)",
|
|
(*items->hf_index == -1) ?
|
|
"Word Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
WParam, WParam);
|
|
offset += 2;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0, pinfo,
|
|
tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
/*
|
|
* A 32-bit doubleword value in the request.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_dword_param(tvb, offset, 0, pinfo,
|
|
tree, 0, -1);
|
|
} else if (items->type != PARAM_DWORD) {
|
|
/*
|
|
* Descriptor character is 'D', but this
|
|
* isn't a doubleword parameter.
|
|
*/
|
|
LParam = tvb_get_letohl(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: Value is %u (0x%08X), type is wrong (D)",
|
|
(*items->hf_index == -1) ?
|
|
"Doubleword Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
LParam, LParam);
|
|
offset += 4;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0, pinfo,
|
|
tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
/*
|
|
* A byte or multi-byte value in the request.
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_byte_param(tvb, offset, count,
|
|
pinfo, tree, 0, -1);
|
|
} else if (items->type != PARAM_BYTES) {
|
|
/*
|
|
* Descriptor character is 'b', but this
|
|
* isn't a byte/bytes parameter.
|
|
*/
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"%s: Value is %s, type is wrong (b)",
|
|
(*items->hf_index == -1) ?
|
|
"Byte Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
tvb_bytes_to_str(tvb, offset, count));
|
|
offset += count;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, count,
|
|
pinfo, tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'O':
|
|
/*
|
|
* A null pointer.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
add_null_pointer_param(tvb, offset, 0,
|
|
pinfo, tree, 0, -1);
|
|
} else {
|
|
/*
|
|
* If "*items->hf_index" is -1, this is
|
|
* a reserved must-be-null field; don't
|
|
* clutter the protocol tree by putting
|
|
* it in.
|
|
*/
|
|
if (*items->hf_index != -1) {
|
|
add_null_pointer_param(tvb,
|
|
offset, 0, pinfo, tree, 0,
|
|
*items->hf_index);
|
|
}
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'z':
|
|
/*
|
|
* A null-terminated ASCII string.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_string_param(tvb, offset, 0,
|
|
pinfo, tree, 0, -1);
|
|
} else if (items->type != PARAM_STRINGZ) {
|
|
/*
|
|
* Descriptor character is 'z', but this
|
|
* isn't a string parameter.
|
|
*/
|
|
string_len = tvb_strsize(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, string_len,
|
|
"%s: Value is %s, type is wrong (z)",
|
|
(*items->hf_index == -1) ?
|
|
"String Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
tvb_format_text(tvb, offset, string_len));
|
|
offset += string_len;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0,
|
|
pinfo, tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'F':
|
|
/*
|
|
* One or more pad bytes.
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"%s", "Padding");
|
|
offset += count;
|
|
break;
|
|
|
|
case 'L':
|
|
/*
|
|
* 16-bit receive buffer length.
|
|
*/
|
|
proto_tree_add_item(tree, hf_recv_buf_len, tvb,
|
|
offset, 2, TRUE);
|
|
offset += 2;
|
|
break;
|
|
|
|
case 's':
|
|
/*
|
|
* 32-bit send buffer offset.
|
|
* This appears not to be sent over the wire.
|
|
*/
|
|
*has_data_p = TRUE;
|
|
break;
|
|
|
|
case 'T':
|
|
/*
|
|
* 16-bit send buffer length.
|
|
*/
|
|
proto_tree_add_item(tree, hf_send_buf_len, tvb,
|
|
offset, 2, TRUE);
|
|
offset += 2;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
dissect_response_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
|
|
proto_tree *tree, const guchar *desc, const item_t *items,
|
|
gboolean *has_data_p, gboolean *has_ent_count_p, guint16 *ent_count_p)
|
|
{
|
|
guint c;
|
|
guint16 WParam;
|
|
guint32 LParam;
|
|
int count;
|
|
|
|
*has_data_p = FALSE;
|
|
*has_ent_count_p = FALSE;
|
|
while ((c = *desc++) != '\0') {
|
|
switch (c) {
|
|
|
|
case 'r':
|
|
/*
|
|
* 32-bit receive buffer offset.
|
|
*/
|
|
*has_data_p = TRUE;
|
|
break;
|
|
|
|
case 'g':
|
|
/*
|
|
* A byte or series of bytes is returned.
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_byte_param(tvb, offset, count,
|
|
pinfo, tree, 0, -1);
|
|
} else if (items->type != PARAM_BYTES) {
|
|
/*
|
|
* Descriptor character is 'b', but this
|
|
* isn't a byte/bytes parameter.
|
|
*/
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"%s: Value is %s, type is wrong (g)",
|
|
(*items->hf_index == -1) ?
|
|
"Byte Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
tvb_bytes_to_str(tvb, offset, count));
|
|
offset += count;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, count,
|
|
pinfo, tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'h':
|
|
/*
|
|
* A 16-bit word is received.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_word_param(tvb, offset, 0, pinfo,
|
|
tree, 0, -1);
|
|
} else if (items->type != PARAM_WORD) {
|
|
/*
|
|
* Descriptor character is 'h', but this
|
|
* isn't a word parameter.
|
|
*/
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: Value is %u (0x%04X), type is wrong (W)",
|
|
(*items->hf_index == -1) ?
|
|
"Word Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
WParam, WParam);
|
|
offset += 2;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0, pinfo,
|
|
tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'i':
|
|
/*
|
|
* A 32-bit doubleword is received.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_dword_param(tvb, offset, 0, pinfo,
|
|
tree, 0, -1);
|
|
} else if (items->type != PARAM_DWORD) {
|
|
/*
|
|
* Descriptor character is 'i', but this
|
|
* isn't a doubleword parameter.
|
|
*/
|
|
LParam = tvb_get_letohl(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: Value is %u (0x%08X), type is wrong (i)",
|
|
(*items->hf_index == -1) ?
|
|
"Doubleword Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
LParam, LParam);
|
|
offset += 4;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0, pinfo,
|
|
tree, 0, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'e':
|
|
/*
|
|
* A 16-bit entry count is returned.
|
|
*/
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2,
|
|
WParam);
|
|
offset += 2;
|
|
*has_ent_count_p = TRUE;
|
|
*ent_count_p = WParam; /* Save this for later retrieval */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
static int
|
|
dissect_transact_data(tvbuff_t *tvb, int offset, int convert,
|
|
packet_info *pinfo, proto_tree *tree, const guchar *desc,
|
|
const item_t *items, guint16 *aux_count_p)
|
|
{
|
|
guint c;
|
|
guint16 WParam;
|
|
guint32 LParam;
|
|
int count;
|
|
int cptr;
|
|
const char *string;
|
|
gint string_len;
|
|
|
|
if (aux_count_p != NULL)
|
|
*aux_count_p = 0;
|
|
|
|
while ((c = *desc++) != '\0') {
|
|
switch (c) {
|
|
|
|
case 'W':
|
|
/*
|
|
* A 16-bit word value.
|
|
* XXX - handle the count?
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_word_param(tvb, offset, 0, pinfo,
|
|
tree, convert, -1);
|
|
} else if (items->type != PARAM_WORD) {
|
|
/*
|
|
* Descriptor character is 'W', but this
|
|
* isn't a word parameter.
|
|
*/
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: Value is %u (0x%04X), type is wrong (W)",
|
|
(*items->hf_index == -1) ?
|
|
"Word Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
WParam, WParam);
|
|
offset += 2;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0, pinfo,
|
|
tree, convert, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
/*
|
|
* A 32-bit doubleword value.
|
|
* XXX - handle the count?
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_dword_param(tvb, offset, 0, pinfo,
|
|
tree, convert, -1);
|
|
} else if (items->type != PARAM_DWORD) {
|
|
/*
|
|
* Descriptor character is 'D', but this
|
|
* isn't a doubleword parameter.
|
|
*/
|
|
LParam = tvb_get_letohl(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: Value is %u (0x%08X), type is wrong (D)",
|
|
(*items->hf_index == -1) ?
|
|
"Doubleword Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
LParam, LParam);
|
|
offset += 4;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0, pinfo,
|
|
tree, convert, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'B':
|
|
/*
|
|
* A byte or multi-byte value.
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_byte_param(tvb, offset, count,
|
|
pinfo, tree, convert, -1);
|
|
} else if (items->type != PARAM_BYTES) {
|
|
/*
|
|
* Descriptor character is 'B', but this
|
|
* isn't a byte/bytes parameter.
|
|
*/
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"%s: Value is %s, type is wrong (B)",
|
|
(*items->hf_index == -1) ?
|
|
"Byte Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
tvb_bytes_to_str(tvb, offset, count));
|
|
offset += count;
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, count,
|
|
pinfo, tree, convert, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'O':
|
|
/*
|
|
* A null pointer.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
add_null_pointer_param(tvb, offset, 0,
|
|
pinfo, tree, convert, -1);
|
|
} else {
|
|
/*
|
|
* If "*items->hf_index" is -1, this is
|
|
* a reserved must-be-null field; don't
|
|
* clutter the protocol tree by putting
|
|
* it in.
|
|
*/
|
|
if (*items->hf_index != -1) {
|
|
add_null_pointer_param(tvb,
|
|
offset, 0, pinfo, tree, convert,
|
|
*items->hf_index);
|
|
}
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'z':
|
|
/*
|
|
* A pointer to a null-terminated ASCII string.
|
|
*/
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_stringz_pointer_param(tvb, offset,
|
|
0, pinfo, tree, convert, -1);
|
|
} else if (items->type != PARAM_STRINGZ) {
|
|
/*
|
|
* Descriptor character is 'z', but this
|
|
* isn't a string parameter.
|
|
*/
|
|
string = get_stringz_pointer_value(tvb, offset,
|
|
convert, &cptr, &string_len);
|
|
offset += 4;
|
|
proto_tree_add_text(tree, tvb, cptr, string_len,
|
|
"%s: Value is %s, type is wrong (z)",
|
|
(*items->hf_index == -1) ?
|
|
"String Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
string);
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, 0,
|
|
pinfo, tree, convert, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
/*
|
|
* A pointer to a byte or multi-byte value.
|
|
*/
|
|
desc = get_count(desc, &count);
|
|
if (items->func == NULL) {
|
|
/*
|
|
* We've run out of items in the table;
|
|
* fall back on the default.
|
|
*/
|
|
offset = add_bytes_pointer_param(tvb, offset,
|
|
count, pinfo, tree, convert, -1);
|
|
} else if (items->type != PARAM_BYTES) {
|
|
/*
|
|
* Descriptor character is 'b', but this
|
|
* isn't a byte/bytes parameter.
|
|
*/
|
|
cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
|
|
offset += 4;
|
|
proto_tree_add_text(tree, tvb, offset, count,
|
|
"%s: Value is %s, type is wrong (b)",
|
|
(*items->hf_index == -1) ?
|
|
"Byte Param" :
|
|
proto_registrar_get_name(*items->hf_index),
|
|
tvb_bytes_to_str(tvb, cptr, count));
|
|
items++;
|
|
} else {
|
|
offset = (*items->func)(tvb, offset, count,
|
|
pinfo, tree, convert, *items->hf_index);
|
|
items++;
|
|
}
|
|
break;
|
|
|
|
case 'N':
|
|
/*
|
|
* 16-bit auxiliary data structure count.
|
|
* XXX - hf_acount?
|
|
*/
|
|
WParam = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_text(tree, tvb, offset, 2,
|
|
"%s: %u (0x%04X)",
|
|
"Auxiliary data structure count",
|
|
WParam, WParam);
|
|
offset += 2;
|
|
if (aux_count_p != NULL)
|
|
*aux_count_p = WParam; /* Save this for later retrieval */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
static const value_string commands[] = {
|
|
{API_NetShareEnum, "NetShareEnum"},
|
|
{API_NetShareGetInfo, "NetShareGetInfo"},
|
|
{API_NetShareSetInfo, "NetShareSetInfo"},
|
|
{API_NetShareAdd, "NetShareAdd"},
|
|
{API_NetShareDel, "NetShareDel"},
|
|
{API_NetShareCheck, "NetShareCheck"},
|
|
{API_NetSessionEnum, "NetSessionEnum"},
|
|
{API_NetSessionGetInfo, "NetSessionGetInfo"},
|
|
{API_NetSessionDel, "NetSessionDel"},
|
|
{API_WconnectionEnum, "NetConnectionEnum"},
|
|
{API_NetFileEnum, "NetFileEnum"},
|
|
{API_NetFileGetInfo, "NetFileGetInfo"},
|
|
{API_NetFileClose, "NetFileClose"},
|
|
{API_NetServerGetInfo, "NetServerGetInfo"},
|
|
{API_NetServerSetInfo, "NetServerSetInfo"},
|
|
{API_NetServerDiskEnum, "NetServerDiskEnum"},
|
|
{API_NetServerAdminCommand, "NetServerAdminCommand"},
|
|
{API_NetAuditOpen, "NetAuditOpen"},
|
|
{API_NetAuditClear, "NetAuditClear"},
|
|
{API_NetErrorLogOpen, "NetErrorLogOpen"},
|
|
{API_NetErrorLogClear, "NetErrorLogClear"},
|
|
{API_NetCharDevEnum, "NetCharDevEnum"},
|
|
{API_NetCharDevGetInfo, "NetCharDevGetInfo"},
|
|
{API_NetCharDevControl, "NetCharDevControl"},
|
|
{API_NetCharDevQEnum, "NetCharDevQEnum"},
|
|
{API_NetCharDevQGetInfo, "NetCharDevQGetInfo"},
|
|
{API_NetCharDevQSetInfo, "NetCharDevQSetInfo"},
|
|
{API_NetCharDevQPurge, "NetCharDevQPurge"},
|
|
{API_NetCharDevQPurgeSelf, "NetCharDevQPurgeSelf"},
|
|
{API_NetMessageNameEnum, "NetMessageNameEnum"},
|
|
{API_NetMessageNameGetInfo, "NetMessageNameGetInfo"},
|
|
{API_NetMessageNameAdd, "NetMessageNameAdd"},
|
|
{API_NetMessageNameDel, "NetMessageNameDel"},
|
|
{API_NetMessageNameFwd, "NetMessageNameFwd"},
|
|
{API_NetMessageNameUnFwd, "NetMessageNameUnFwd"},
|
|
{API_NetMessageBufferSend, "NetMessageBufferSend"},
|
|
{API_NetMessageFileSend, "NetMessageFileSend"},
|
|
{API_NetMessageLogFileSet, "NetMessageLogFileSet"},
|
|
{API_NetMessageLogFileGet, "NetMessageLogFileGet"},
|
|
{API_NetServiceEnum, "NetServiceEnum"},
|
|
{API_NetServiceInstall, "NetServiceInstall"},
|
|
{API_NetServiceControl, "NetServiceControl"},
|
|
{API_NetAccessEnum, "NetAccessEnum"},
|
|
{API_NetAccessGetInfo, "NetAccessGetInfo"},
|
|
{API_NetAccessSetInfo, "NetAccessSetInfo"},
|
|
{API_NetAccessAdd, "NetAccessAdd"},
|
|
{API_NetAccessDel, "NetAccessDel"},
|
|
{API_NetGroupEnum, "NetGroupEnum"},
|
|
{API_NetGroupAdd, "NetGroupAdd"},
|
|
{API_NetGroupDel, "NetGroupDel"},
|
|
{API_NetGroupAddUser, "NetGroupAddUser"},
|
|
{API_NetGroupDelUser, "NetGroupDelUser"},
|
|
{API_NetGroupGetUsers, "NetGroupGetUsers"},
|
|
{API_NetUserEnum, "NetUserEnum"},
|
|
{API_NetUserAdd, "NetUserAdd"},
|
|
{API_NetUserDel, "NetUserDel"},
|
|
{API_NetUserGetInfo, "NetUserGetInfo"},
|
|
{API_NetUserSetInfo, "NetUserSetInfo"},
|
|
{API_NetUserPasswordSet, "NetUserPasswordSet"},
|
|
{API_NetUserGetGroups, "NetUserGetGroups"},
|
|
{API_NetWkstaSetUID, "NetWkstaSetUID"},
|
|
{API_NetWkstaGetInfo, "NetWkstaGetInfo"},
|
|
{API_NetWkstaSetInfo, "NetWkstaSetInfo"},
|
|
{API_NetUseEnum, "NetUseEnum"},
|
|
{API_NetUseAdd, "NetUseAdd"},
|
|
{API_NetUseDel, "NetUseDel"},
|
|
{API_NetUseGetInfo, "NetUseGetInfo"},
|
|
{API_WPrintQEnum, "WPrintQEnum"},
|
|
{API_WPrintQGetInfo, "WPrintQGetInfo"},
|
|
{API_WPrintQSetInfo, "WPrintQSetInfo"},
|
|
{API_WPrintQAdd, "WPrintQAdd"},
|
|
{API_WPrintQDel, "WPrintQDel"},
|
|
{API_WPrintQPause, "WPrintQPause"},
|
|
{API_WPrintQContinue, "WPrintQContinue"},
|
|
{API_WPrintJobEnum, "WPrintJobEnum"},
|
|
{API_WPrintJobGetInfo, "WPrintJobGetInfo"},
|
|
{API_WPrintJobSetInfo_OLD, "WPrintJobSetInfo_OLD"},
|
|
{API_WPrintJobDel, "WPrintJobDel"},
|
|
{API_WPrintJobPause, "WPrintJobPause"},
|
|
{API_WPrintJobContinue, "WPrintJobContinue"},
|
|
{API_WPrintDestEnum, "WPrintDestEnum"},
|
|
{API_WPrintDestGetInfo, "WPrintDestGetInfo"},
|
|
{API_WPrintDestControl, "WPrintDestControl"},
|
|
{API_NetProfileSave, "NetProfileSave"},
|
|
{API_NetProfileLoad, "NetProfileLoad"},
|
|
{API_NetStatisticsGet, "NetStatisticsGet"},
|
|
{API_NetStatisticsClear, "NetStatisticsClear"},
|
|
{API_NetRemoteTOD, "NetRemoteTOD"},
|
|
{API_WNetBiosEnum, "WNetBiosEnum"},
|
|
{API_WNetBiosGetInfo, "WNetBiosGetInfo"},
|
|
{API_NetServerEnum, "NetServerEnum"},
|
|
{API_I_NetServerEnum, "I_NetServerEnum"},
|
|
{API_NetServiceGetInfo, "NetServiceGetInfo"},
|
|
{API_WPrintQPurge, "WPrintQPurge"},
|
|
{API_NetServerEnum2, "NetServerEnum2"},
|
|
{API_NetAccessGetUserPerms, "NetAccessGetUserPerms"},
|
|
{API_NetGroupGetInfo, "NetGroupGetInfo"},
|
|
{API_NetGroupSetInfo, "NetGroupSetInfo"},
|
|
{API_NetGroupSetUsers, "NetGroupSetUsers"},
|
|
{API_NetUserSetGroups, "NetUserSetGroups"},
|
|
{API_NetUserModalsGet, "NetUserModalsGet"},
|
|
{API_NetUserModalsSet, "NetUserModalsSet"},
|
|
{API_NetFileEnum2, "NetFileEnum2"},
|
|
{API_NetUserAdd2, "NetUserAdd2"},
|
|
{API_NetUserSetInfo2, "NetUserSetInfo2"},
|
|
{API_NetUserPasswordSet2, "SetUserPassword"},
|
|
{API_I_NetServerEnum2, "I_NetServerEnum2"},
|
|
{API_NetConfigGet2, "NetConfigGet2"},
|
|
{API_NetConfigGetAll2, "NetConfigGetAll2"},
|
|
{API_NetGetDCName, "NetGetDCName"},
|
|
{API_NetHandleGetInfo, "NetHandleGetInfo"},
|
|
{API_NetHandleSetInfo, "NetHandleSetInfo"},
|
|
{API_NetStatisticsGet2, "NetStatisticsGet2"},
|
|
{API_WBuildGetInfo, "WBuildGetInfo"},
|
|
{API_NetFileGetInfo2, "NetFileGetInfo2"},
|
|
{API_NetFileClose2, "NetFileClose2"},
|
|
{API_NetServerReqChallenge, "NetServerReqChallenge"},
|
|
{API_NetServerAuthenticate, "NetServerAuthenticate"},
|
|
{API_NetServerPasswordSet, "NetServerPasswordSet"},
|
|
{API_WNetAccountDeltas, "WNetAccountDeltas"},
|
|
{API_WNetAccountSync, "WNetAccountSync"},
|
|
{API_NetUserEnum2, "NetUserEnum2"},
|
|
{API_NetWkstaUserLogon, "NetWkstaUserLogon"},
|
|
{API_NetWkstaUserLogoff, "NetWkstaUserLogoff"},
|
|
{API_NetLogonEnum, "NetLogonEnum"},
|
|
{API_NetErrorLogRead, "NetErrorLogRead"},
|
|
{API_I_NetPathType, "I_NetPathType"},
|
|
{API_I_NetPathCanonicalize, "I_NetPathCanonicalize"},
|
|
{API_I_NetPathCompare, "I_NetPathCompare"},
|
|
{API_I_NetNameValidate, "I_NetNameValidate"},
|
|
{API_I_NetNameCanonicalize, "I_NetNameCanonicalize"},
|
|
{API_I_NetNameCompare, "I_NetNameCompare"},
|
|
{API_NetAuditRead, "NetAuditRead"},
|
|
{API_WPrintDestAdd, "WPrintDestAdd"},
|
|
{API_WPrintDestSetInfo, "WPrintDestSetInfo"},
|
|
{API_WPrintDestDel, "WPrintDestDel"},
|
|
{API_NetUserValidate2, "NetUserValidate2"},
|
|
{API_WPrintJobSetInfo, "WPrintJobSetInfo"},
|
|
{API_TI_NetServerDiskEnum, "TI_NetServerDiskEnum"},
|
|
{API_TI_NetServerDiskGetInfo, "TI_NetServerDiskGetInfo"},
|
|
{API_TI_FTVerifyMirror, "TI_FTVerifyMirror"},
|
|
{API_TI_FTAbortVerify, "TI_FTAbortVerify"},
|
|
{API_TI_FTGetInfo, "TI_FTGetInfo"},
|
|
{API_TI_FTSetInfo, "TI_FTSetInfo"},
|
|
{API_TI_FTLockDisk, "TI_FTLockDisk"},
|
|
{API_TI_FTFixError, "TI_FTFixError"},
|
|
{API_TI_FTAbortFix, "TI_FTAbortFix"},
|
|
{API_TI_FTDiagnoseError, "TI_FTDiagnoseError"},
|
|
{API_TI_FTGetDriveStats, "TI_FTGetDriveStats"},
|
|
{API_TI_FTErrorGetInfo, "TI_FTErrorGetInfo"},
|
|
{API_NetAccessCheck, "NetAccessCheck"},
|
|
{API_NetAlertRaise, "NetAlertRaise"},
|
|
{API_NetAlertStart, "NetAlertStart"},
|
|
{API_NetAlertStop, "NetAlertStop"},
|
|
{API_NetAuditWrite, "NetAuditWrite"},
|
|
{API_NetIRemoteAPI, "NetIRemoteAPI"},
|
|
{API_NetServiceStatus, "NetServiceStatus"},
|
|
{API_I_NetServerRegister, "I_NetServerRegister"},
|
|
{API_I_NetServerDeregister, "I_NetServerDeregister"},
|
|
{API_I_NetSessionEntryMake, "I_NetSessionEntryMake"},
|
|
{API_I_NetSessionEntryClear, "I_NetSessionEntryClear"},
|
|
{API_I_NetSessionEntryGetInfo, "I_NetSessionEntryGetInfo"},
|
|
{API_I_NetSessionEntrySetInfo, "I_NetSessionEntrySetInfo"},
|
|
{API_I_NetConnectionEntryMake, "I_NetConnectionEntryMake"},
|
|
{API_I_NetConnectionEntryClear, "I_NetConnectionEntryClear"},
|
|
{API_I_NetConnectionEntrySetInfo, "I_NetConnectionEntrySetInfo"},
|
|
{API_I_NetConnectionEntryGetInfo, "I_NetConnectionEntryGetInfo"},
|
|
{API_I_NetFileEntryMake, "I_NetFileEntryMake"},
|
|
{API_I_NetFileEntryClear, "I_NetFileEntryClear"},
|
|
{API_I_NetFileEntrySetInfo, "I_NetFileEntrySetInfo"},
|
|
{API_I_NetFileEntryGetInfo, "I_NetFileEntryGetInfo"},
|
|
{API_AltSrvMessageBufferSend, "AltSrvMessageBufferSend"},
|
|
{API_AltSrvMessageFileSend, "AltSrvMessageFileSend"},
|
|
{API_wI_NetRplWkstaEnum, "wI_NetRplWkstaEnum"},
|
|
{API_wI_NetRplWkstaGetInfo, "wI_NetRplWkstaGetInfo"},
|
|
{API_wI_NetRplWkstaSetInfo, "wI_NetRplWkstaSetInfo"},
|
|
{API_wI_NetRplWkstaAdd, "wI_NetRplWkstaAdd"},
|
|
{API_wI_NetRplWkstaDel, "wI_NetRplWkstaDel"},
|
|
{API_wI_NetRplProfileEnum, "wI_NetRplProfileEnum"},
|
|
{API_wI_NetRplProfileGetInfo, "wI_NetRplProfileGetInfo"},
|
|
{API_wI_NetRplProfileSetInfo, "wI_NetRplProfileSetInfo"},
|
|
{API_wI_NetRplProfileAdd, "wI_NetRplProfileAdd"},
|
|
{API_wI_NetRplProfileDel, "wI_NetRplProfileDel"},
|
|
{API_wI_NetRplProfileClone, "wI_NetRplProfileClone"},
|
|
{API_wI_NetRplBaseProfileEnum, "wI_NetRplBaseProfileEnum"},
|
|
{API_WIServerSetInfo, "WIServerSetInfo"},
|
|
{API_WPrintDriverEnum, "WPrintDriverEnum"},
|
|
{API_WPrintQProcessorEnum, "WPrintQProcessorEnum"},
|
|
{API_WPrintPortEnum, "WPrintPortEnum"},
|
|
{API_WNetWriteUpdateLog, "WNetWriteUpdateLog"},
|
|
{API_WNetAccountUpdate, "WNetAccountUpdate"},
|
|
{API_WNetAccountConfirmUpdate, "WNetAccountConfirmUpdate"},
|
|
{API_NetConfigSet, "NetConfigSet"},
|
|
{API_WAccountsReplicate, "WAccountsReplicate"},
|
|
{API_SamOEMChgPasswordUser2_P, "SamOEMChangePassword"},
|
|
{API_NetServerEnum3, "NetServerEnum3"},
|
|
{API_WPrintDriverGetInfo, "WPrintDriverGetInfo"},
|
|
{API_WPrintDriverSetInfo, "WPrintDriverSetInfo"},
|
|
{API_NetAliasAdd, "NetAliasAdd"},
|
|
{API_NetAliasDel, "NetAliasDel"},
|
|
{API_NetAliasGetInfo, "NetAliasGetInfo"},
|
|
{API_NetAliasSetInfo, "NetAliasSetInfo"},
|
|
{API_NetAliasEnum, "NetAliasEnum"},
|
|
{API_NetUserGetLogonAsn, "NetUserGetLogonAsn"},
|
|
{API_NetUserSetLogonAsn, "NetUserSetLogonAsn"},
|
|
{API_NetUserGetAppSel, "NetUserGetAppSel"},
|
|
{API_NetUserSetAppSel, "NetUserSetAppSel"},
|
|
{API_NetAppAdd, "NetAppAdd"},
|
|
{API_NetAppDel, "NetAppDel"},
|
|
{API_NetAppGetInfo, "NetAppGetInfo"},
|
|
{API_NetAppSetInfo, "NetAppSetInfo"},
|
|
{API_NetAppEnum, "NetAppEnum"},
|
|
{API_NetUserDCDBInit, "NetUserDCDBInit"},
|
|
{API_NetDASDAdd, "NetDASDAdd"},
|
|
{API_NetDASDDel, "NetDASDDel"},
|
|
{API_NetDASDGetInfo, "NetDASDGetInfo"},
|
|
{API_NetDASDSetInfo, "NetDASDSetInfo"},
|
|
{API_NetDASDEnum, "NetDASDEnum"},
|
|
{API_NetDASDCheck, "NetDASDCheck"},
|
|
{API_NetDASDCtl, "NetDASDCtl"},
|
|
{API_NetUserRemoteLogonCheck, "NetUserRemoteLogonCheck"},
|
|
{API_NetUserPasswordSet3, "NetUserPasswordSet3"},
|
|
{API_NetCreateRIPLMachine, "NetCreateRIPLMachine"},
|
|
{API_NetDeleteRIPLMachine, "NetDeleteRIPLMachine"},
|
|
{API_NetGetRIPLMachineInfo, "NetGetRIPLMachineInfo"},
|
|
{API_NetSetRIPLMachineInfo, "NetSetRIPLMachineInfo"},
|
|
{API_NetEnumRIPLMachine, "NetEnumRIPLMachine"},
|
|
{API_I_ShareAdd, "I_ShareAdd"},
|
|
{API_I_AliasEnum, "I_AliasEnum"},
|
|
{API_NetAccessApply, "NetAccessApply"},
|
|
{API_WPrt16Query, "WPrt16Query"},
|
|
{API_WPrt16Set, "WPrt16Set"},
|
|
{API_NetUserDel100, "NetUserDel100"},
|
|
{API_NetUserRemoteLogonCheck2, "NetUserRemoteLogonCheck2"},
|
|
{API_WRemoteTODSet, "WRemoteTODSet"},
|
|
{API_WPrintJobMoveAll, "WPrintJobMoveAll"},
|
|
{API_W16AppParmAdd, "W16AppParmAdd"},
|
|
{API_W16AppParmDel, "W16AppParmDel"},
|
|
{API_W16AppParmGet, "W16AppParmGet"},
|
|
{API_W16AppParmSet, "W16AppParmSet"},
|
|
{API_W16RIPLMachineCreate, "W16RIPLMachineCreate"},
|
|
{API_W16RIPLMachineGetInfo, "W16RIPLMachineGetInfo"},
|
|
{API_W16RIPLMachineSetInfo, "W16RIPLMachineSetInfo"},
|
|
{API_W16RIPLMachineEnum, "W16RIPLMachineEnum"},
|
|
{API_W16RIPLMachineListParmEnum, "W16RIPLMachineListParmEnum"},
|
|
{API_W16RIPLMachClassGetInfo, "W16RIPLMachClassGetInfo"},
|
|
{API_W16RIPLMachClassEnum, "W16RIPLMachClassEnum"},
|
|
{API_W16RIPLMachClassCreate, "W16RIPLMachClassCreate"},
|
|
{API_W16RIPLMachClassSetInfo, "W16RIPLMachClassSetInfo"},
|
|
{API_W16RIPLMachClassDelete, "W16RIPLMachClassDelete"},
|
|
{API_W16RIPLMachClassLPEnum, "W16RIPLMachClassLPEnum"},
|
|
{API_W16RIPLMachineDelete, "W16RIPLMachineDelete"},
|
|
{API_W16WSLevelGetInfo, "W16WSLevelGetInfo"},
|
|
{API_NetServerNameAdd, "NetServerNameAdd"},
|
|
{API_NetServerNameDel, "NetServerNameDel"},
|
|
{API_NetServerNameEnum, "NetServerNameEnum"},
|
|
{API_I_WDASDEnum, "I_WDASDEnum"},
|
|
{API_I_WDASDEnumTerminate, "I_WDASDEnumTerminate"},
|
|
{API_I_WDASDSetInfo2, "I_WDASDSetInfo2"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static void
|
|
dissect_response_data(tvbuff_t *tvb, packet_info *pinfo, int convert,
|
|
proto_tree *tree, struct smb_info *smb_info,
|
|
const struct lanman_desc *lanman, gboolean has_ent_count,
|
|
guint16 ent_count)
|
|
{
|
|
smb_transact_info_t *trp = smb_info->sip->extra_info;
|
|
const item_list_t *resp_data_list;
|
|
int offset, start_offset;
|
|
const char *label;
|
|
gint ett;
|
|
const item_t *resp_data;
|
|
proto_item *data_item;
|
|
proto_tree *data_tree;
|
|
proto_item *entry_item;
|
|
proto_tree *entry_tree;
|
|
guint i, j;
|
|
guint16 aux_count;
|
|
|
|
/*
|
|
* Find the item table for the matching request's detail level.
|
|
*/
|
|
for (resp_data_list = lanman->resp_data_list;
|
|
resp_data_list->level != -1; resp_data_list++) {
|
|
if (resp_data_list->level == trp->info_level)
|
|
break;
|
|
}
|
|
resp_data = resp_data_list->item_list;
|
|
|
|
offset = 0;
|
|
if (has_ent_count) {
|
|
/*
|
|
* The data is a list of entries; create a protocol tree item
|
|
* for it.
|
|
*/
|
|
if (tree) {
|
|
label = lanman->resp_data_entry_list_label;
|
|
if (label == NULL)
|
|
label = "Entries";
|
|
if (lanman->ett_data_entry_list != NULL)
|
|
ett = *lanman->ett_data_entry_list;
|
|
else
|
|
ett = ett_lanman_unknown_entries;
|
|
data_item = proto_tree_add_text(tree, tvb, offset, -1,
|
|
label);
|
|
data_tree = proto_item_add_subtree(data_item, ett);
|
|
} else {
|
|
data_item = NULL;
|
|
data_tree = NULL;
|
|
}
|
|
} else {
|
|
/*
|
|
* Just leave it at the top level.
|
|
*/
|
|
data_item = NULL;
|
|
data_tree = tree;
|
|
}
|
|
|
|
if (trp->data_descrip == NULL) {
|
|
/*
|
|
* This could happen if we only dissected
|
|
* part of the request to which this is a
|
|
* reply, e.g. if the request was split
|
|
* across TCP segments and we weren't doing
|
|
* TCP desegmentation, or if we had a snapshot
|
|
* length that was too short.
|
|
*
|
|
* We can't dissect the data; just show it as raw data or,
|
|
* if we've already created a top-level item, note that
|
|
* no descriptor is available.
|
|
*/
|
|
if (has_ent_count) {
|
|
if (data_item != NULL) {
|
|
proto_item_append_text(data_item,
|
|
" (No descriptor available)");
|
|
}
|
|
} else {
|
|
proto_tree_add_text(data_tree, tvb, offset, -1,
|
|
"Data (no descriptor available)");
|
|
}
|
|
offset += tvb_length_remaining(tvb, offset);
|
|
} else {
|
|
/*
|
|
* If we have an entry count, show all the entries,
|
|
* with each one having a protocol tree item.
|
|
*
|
|
* Otherwise, we just show one returned item, with
|
|
* no protocol tree item.
|
|
*/
|
|
if (!has_ent_count)
|
|
ent_count = 1;
|
|
for (i = 0; i < ent_count; i++) {
|
|
start_offset = offset;
|
|
if (has_ent_count &&
|
|
lanman->resp_data_element_item != NULL) {
|
|
/*
|
|
* Create a protocol tree item for the
|
|
* entry.
|
|
*/
|
|
entry_item =
|
|
(*lanman->resp_data_element_item)
|
|
(tvb, data_tree, offset);
|
|
entry_tree = proto_item_add_subtree(
|
|
entry_item,
|
|
*lanman->ett_resp_data_element_item);
|
|
} else {
|
|
/*
|
|
* Just leave it at the current
|
|
* level.
|
|
*/
|
|
entry_item = NULL;
|
|
entry_tree = data_tree;
|
|
}
|
|
|
|
offset = dissect_transact_data(tvb, offset,
|
|
convert, pinfo, entry_tree,
|
|
trp->data_descrip, resp_data, &aux_count);
|
|
|
|
/* auxiliary data */
|
|
if (trp->aux_data_descrip != NULL) {
|
|
for (j = 0; j < aux_count; j++) {
|
|
offset = dissect_transact_data(
|
|
tvb, offset, convert,
|
|
pinfo, entry_tree,
|
|
trp->data_descrip,
|
|
lanman->resp_aux_data, NULL);
|
|
}
|
|
}
|
|
|
|
if (entry_item != NULL) {
|
|
/*
|
|
* Set the length of the protocol tree
|
|
* item for the entry.
|
|
*/
|
|
proto_item_set_len(entry_item,
|
|
offset - start_offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data_item != NULL) {
|
|
/*
|
|
* Set the length of the protocol tree item
|
|
* for the data.
|
|
*/
|
|
proto_item_set_len(data_item, offset);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
dissect_pipe_lanman(tvbuff_t *pd_tvb, tvbuff_t *p_tvb, tvbuff_t *d_tvb,
|
|
packet_info *pinfo, proto_tree *parent_tree)
|
|
{
|
|
smb_info_t *smb_info = pinfo->private_data;
|
|
smb_transact_info_t *trp = smb_info->sip->extra_info;
|
|
int offset = 0, start_offset;
|
|
guint16 cmd;
|
|
guint16 status;
|
|
int convert;
|
|
const struct lanman_desc *lanman;
|
|
proto_item *item = NULL;
|
|
proto_tree *tree = NULL;
|
|
guint descriptor_len;
|
|
const gchar *param_descrip, *data_descrip, *aux_data_descrip = NULL;
|
|
gboolean has_data;
|
|
gboolean has_ent_count;
|
|
guint16 ent_count, aux_count;
|
|
guint i;
|
|
proto_item *data_item;
|
|
proto_tree *data_tree;
|
|
|
|
if (!proto_is_protocol_enabled(find_protocol_by_id(proto_smb_lanman)))
|
|
return FALSE;
|
|
if (smb_info->request && p_tvb == NULL) {
|
|
/*
|
|
* Requests must have parameters.
|
|
*/
|
|
return FALSE;
|
|
}
|
|
pinfo->current_proto = "LANMAN";
|
|
|
|
if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "LANMAN");
|
|
}
|
|
|
|
if (parent_tree) {
|
|
item = proto_tree_add_item(parent_tree, proto_smb_lanman,
|
|
pd_tvb, 0, -1, FALSE);
|
|
tree = proto_item_add_subtree(item, ett_lanman);
|
|
}
|
|
|
|
if (smb_info->request) { /* this is a request */
|
|
/* function code */
|
|
cmd = tvb_get_letohs(p_tvb, offset);
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command (%u)"));
|
|
}
|
|
proto_tree_add_uint(tree, hf_function_code, p_tvb, offset, 2,
|
|
cmd);
|
|
offset += 2;
|
|
|
|
/*
|
|
* If we haven't already done so, save the function code in
|
|
* the structure we were handed, so that it's available to
|
|
* the code parsing the reply, and initialize the detail
|
|
* level to -1, meaning "unknown".
|
|
*/
|
|
if (!pinfo->fd->flags.visited) {
|
|
trp->lanman_cmd = cmd;
|
|
trp->info_level = -1;
|
|
trp->param_descrip=NULL;
|
|
trp->data_descrip=NULL;
|
|
trp->aux_data_descrip=NULL;
|
|
}
|
|
|
|
/* parameter descriptor */
|
|
descriptor_len = tvb_strsize(p_tvb, offset);
|
|
proto_tree_add_item(tree, hf_param_desc, p_tvb, offset,
|
|
descriptor_len, TRUE);
|
|
param_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
|
|
if (!pinfo->fd->flags.visited) {
|
|
/*
|
|
* Save the parameter descriptor for future use.
|
|
*/
|
|
g_assert(trp->param_descrip == NULL);
|
|
trp->param_descrip = g_strdup(param_descrip);
|
|
}
|
|
offset += descriptor_len;
|
|
|
|
/* return descriptor */
|
|
descriptor_len = tvb_strsize(p_tvb, offset);
|
|
proto_tree_add_item(tree, hf_return_desc, p_tvb, offset,
|
|
descriptor_len, TRUE);
|
|
data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
|
|
if (!pinfo->fd->flags.visited) {
|
|
/*
|
|
* Save the return descriptor for future use.
|
|
*/
|
|
g_assert(trp->data_descrip == NULL);
|
|
trp->data_descrip = g_strdup(data_descrip);
|
|
}
|
|
offset += descriptor_len;
|
|
|
|
lanman = find_lanman(cmd);
|
|
|
|
/* request parameters */
|
|
start_offset = offset;
|
|
offset = dissect_request_parameters(p_tvb, offset, pinfo, tree,
|
|
param_descrip, lanman->req, &has_data);
|
|
|
|
/* auxiliary data descriptor */
|
|
if (tvb_reported_length_remaining(p_tvb, offset) > 0){
|
|
/*
|
|
* There are more parameters left, so the next
|
|
* item is the auxiliary data descriptor.
|
|
*/
|
|
descriptor_len = tvb_strsize(p_tvb, offset);
|
|
proto_tree_add_item(tree, hf_aux_data_desc, p_tvb, offset,
|
|
descriptor_len, TRUE);
|
|
aux_data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
|
|
if (!pinfo->fd->flags.visited) {
|
|
/*
|
|
* Save the auxiliary data descriptor for
|
|
* future use.
|
|
*/
|
|
g_assert(trp->aux_data_descrip == NULL);
|
|
trp->aux_data_descrip =
|
|
g_strdup(aux_data_descrip);
|
|
}
|
|
offset += descriptor_len;
|
|
}
|
|
|
|
/* reset offset, we now start dissecting the data area */
|
|
offset = 0;
|
|
if (has_data && d_tvb && tvb_reported_length(d_tvb) != 0) {
|
|
/*
|
|
* There's a send buffer item in the descriptor
|
|
* string, and the data count in the transaction
|
|
* is non-zero, so there's data to dissect.
|
|
*/
|
|
|
|
if (lanman->req_data_item != NULL) {
|
|
/*
|
|
* Create a protocol tree item for the data.
|
|
*/
|
|
data_item = (*lanman->req_data_item)(d_tvb,
|
|
pinfo, tree, offset);
|
|
data_tree = proto_item_add_subtree(data_item,
|
|
*lanman->ett_req_data);
|
|
} else {
|
|
/*
|
|
* Just leave it at the top level.
|
|
*/
|
|
data_item = NULL;
|
|
data_tree = tree;
|
|
}
|
|
|
|
/* data */
|
|
offset = dissect_transact_data(d_tvb, offset, -1,
|
|
pinfo, data_tree, data_descrip, lanman->req_data,
|
|
&aux_count); /* XXX - what about strings? */
|
|
|
|
/* auxiliary data */
|
|
if (aux_data_descrip != NULL) {
|
|
for (i = 0; i < aux_count; i++) {
|
|
offset = dissect_transact_data(d_tvb,
|
|
offset, -1, pinfo, data_tree,
|
|
aux_data_descrip,
|
|
lanman->req_aux_data, NULL);
|
|
}
|
|
}
|
|
|
|
if (data_item != NULL) {
|
|
/*
|
|
* Set the length of the protocol tree item
|
|
* for the data.
|
|
*/
|
|
proto_item_set_len(data_item, offset);
|
|
}
|
|
}
|
|
} else {
|
|
/*
|
|
* This is a response.
|
|
* Have we seen the request to which it's a response?
|
|
*/
|
|
if (trp == NULL)
|
|
return FALSE; /* no - can't dissect it */
|
|
|
|
/* ok we have seen this one before */
|
|
|
|
/* if it looks like an interim response, update COL_INFO and return */
|
|
if( ( (p_tvb==NULL) || (tvb_reported_length(p_tvb)==0) )
|
|
&& ( (d_tvb==NULL) || (tvb_reported_length(d_tvb)==0) ) ){
|
|
/* command */
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s Interim Response",
|
|
val_to_str(trp->lanman_cmd, commands, "Unknown Command (%u)"));
|
|
}
|
|
proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0, trp->lanman_cmd);
|
|
return TRUE;
|
|
}
|
|
|
|
/* command */
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s Response",
|
|
val_to_str(trp->lanman_cmd, commands, "Unknown Command (%u)"));
|
|
}
|
|
proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0,
|
|
trp->lanman_cmd);
|
|
|
|
lanman = find_lanman(trp->lanman_cmd);
|
|
|
|
/* response parameters */
|
|
|
|
/* status */
|
|
status = tvb_get_letohs(p_tvb, offset);
|
|
proto_tree_add_uint(tree, hf_status, p_tvb, offset, 2, status);
|
|
offset += 2;
|
|
|
|
/* convert */
|
|
convert = tvb_get_letohs(p_tvb, offset);
|
|
proto_tree_add_uint(tree, hf_convert, p_tvb, offset, 2, convert);
|
|
offset += 2;
|
|
|
|
if (trp->param_descrip == NULL) {
|
|
/*
|
|
* This could happen if we only dissected
|
|
* part of the request to which this is a
|
|
* reply, e.g. if the request was split
|
|
* across TCP segments and we weren't doing
|
|
* TCP desegmentation, or if we had a snapshot
|
|
* length that was too short.
|
|
*
|
|
* We can't dissect the parameters; just show them
|
|
* as raw data.
|
|
*/
|
|
proto_tree_add_text(tree, p_tvb, offset, -1,
|
|
"Parameters (no descriptor available)");
|
|
|
|
/*
|
|
* We don't know whether we have a receive buffer,
|
|
* as we don't have the descriptor; just show what
|
|
* bytes purport to be data.
|
|
*/
|
|
if (d_tvb && tvb_reported_length(d_tvb) > 0) {
|
|
proto_tree_add_text(tree, d_tvb, 0, -1,
|
|
"Data (no descriptor available)");
|
|
}
|
|
} else {
|
|
/* rest of the parameters */
|
|
offset = dissect_response_parameters(p_tvb, offset,
|
|
pinfo, tree, trp->param_descrip, lanman->resp,
|
|
&has_data, &has_ent_count, &ent_count);
|
|
|
|
/* reset offset, we now start dissecting the data area */
|
|
offset = 0;
|
|
/* data */
|
|
if (d_tvb && tvb_reported_length(d_tvb) > 0) {
|
|
/*
|
|
* Well, there are bytes that purport to
|
|
* be data, at least.
|
|
*/
|
|
if (has_data) {
|
|
/*
|
|
* There's a receive buffer item
|
|
* in the descriptor string, so
|
|
* dissect it as response data.
|
|
*/
|
|
dissect_response_data(d_tvb, pinfo,
|
|
convert, tree, smb_info, lanman,
|
|
has_ent_count, ent_count);
|
|
} else {
|
|
/*
|
|
* There's no receive buffer item,
|
|
* but we do have data, so just
|
|
* show what bytes are data.
|
|
*/
|
|
proto_tree_add_text(tree, d_tvb, 0, -1,
|
|
"Data (no receive buffer)");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
proto_register_pipe_lanman(void)
|
|
{
|
|
static hf_register_info hf[] = {
|
|
{ &hf_function_code,
|
|
{ "Function Code", "lanman.function_code", FT_UINT16, BASE_DEC,
|
|
VALS(commands), 0, "LANMAN Function Code/Command", HFILL }},
|
|
|
|
{ &hf_param_desc,
|
|
{ "Parameter Descriptor", "lanman.param_desc", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Parameter Descriptor", HFILL }},
|
|
|
|
{ &hf_return_desc,
|
|
{ "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Return Descriptor", HFILL }},
|
|
|
|
{ &hf_aux_data_desc,
|
|
{ "Auxiliary Data Descriptor", "lanman.aux_data_desc", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Auxiliary Data Descriptor", HFILL }},
|
|
|
|
{ &hf_detail_level,
|
|
{ "Detail Level", "lanman.level", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Detail Level", HFILL }},
|
|
|
|
{ &hf_recv_buf_len,
|
|
{ "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Receive Buffer Length", HFILL }},
|
|
|
|
{ &hf_send_buf_len,
|
|
{ "Send Buffer Length", "lanman.send_buf_len", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Send Buffer Length", HFILL }},
|
|
|
|
{ &hf_continuation_from,
|
|
{ "Continuation from message in frame", "lanman.continuation_from", FT_UINT32, BASE_DEC,
|
|
NULL, 0, "This is a LANMAN continuation from the message in the frame in question", HFILL }},
|
|
|
|
{ &hf_status,
|
|
{ "Status", "lanman.status", FT_UINT16, BASE_DEC,
|
|
VALS(status_vals), 0, "LANMAN Return status", HFILL }},
|
|
|
|
{ &hf_convert,
|
|
{ "Convert", "lanman.convert", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Convert", HFILL }},
|
|
|
|
{ &hf_ecount,
|
|
{ "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Number of Entries", HFILL }},
|
|
|
|
{ &hf_acount,
|
|
{ "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Number of Available Entries", HFILL }},
|
|
|
|
{ &hf_share_name,
|
|
{ "Share Name", "lanman.share.name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Name of Share", HFILL }},
|
|
|
|
{ &hf_share_type,
|
|
{ "Share Type", "lanman.share.type", FT_UINT16, BASE_DEC,
|
|
VALS(share_type_vals), 0, "LANMAN Type of Share", HFILL }},
|
|
|
|
{ &hf_share_comment,
|
|
{ "Share Comment", "lanman.share.comment", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Share Comment", HFILL }},
|
|
|
|
{ &hf_share_permissions,
|
|
{ "Share Permissions", "lanman.share.permissions", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Permissions on share", HFILL }},
|
|
|
|
{ &hf_share_max_uses,
|
|
{ "Share Max Uses", "lanman.share.max_uses", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Max connections allowed to share", HFILL }},
|
|
|
|
{ &hf_share_current_uses,
|
|
{ "Share Current Uses", "lanman.share.current_uses", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Current connections to share", HFILL }},
|
|
|
|
{ &hf_share_path,
|
|
{ "Share Path", "lanman.share.path", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Share Path", HFILL }},
|
|
|
|
{ &hf_share_password,
|
|
{ "Share Password", "lanman.share.password", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Share Password", HFILL }},
|
|
|
|
{ &hf_server_name,
|
|
{ "Server Name", "lanman.server.name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Name of Server", HFILL }},
|
|
|
|
{ &hf_server_major,
|
|
{ "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Server Major Version", HFILL }},
|
|
|
|
{ &hf_server_minor,
|
|
{ "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Server Minor Version", HFILL }},
|
|
|
|
{ &hf_server_comment,
|
|
{ "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Server Comment", HFILL }},
|
|
|
|
{ &hf_abytes,
|
|
{ "Available Bytes", "lanman.available_bytes", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Number of Available Bytes", HFILL }},
|
|
|
|
{ &hf_current_time,
|
|
{ "Current Date/Time", "lanman.current_time", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Current date and time, in seconds since 00:00:00, January 1, 1970", HFILL }},
|
|
|
|
{ &hf_msecs,
|
|
{ "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC,
|
|
NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }},
|
|
|
|
{ &hf_hour,
|
|
{ "Hour", "lanman.hour", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Current hour", HFILL }},
|
|
|
|
{ &hf_minute,
|
|
{ "Minute", "lanman.minute", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Current minute", HFILL }},
|
|
|
|
{ &hf_second,
|
|
{ "Second", "lanman.second", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Current second", HFILL }},
|
|
|
|
{ &hf_hundredths,
|
|
{ "Hundredths of a second", "lanman.hundredths", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Current hundredths of a second", HFILL }},
|
|
|
|
{ &hf_tzoffset,
|
|
{ "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }},
|
|
|
|
{ &hf_timeinterval,
|
|
{ "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }},
|
|
|
|
{ &hf_day,
|
|
{ "Day", "lanman.day", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Current day", HFILL }},
|
|
|
|
{ &hf_month,
|
|
{ "Month", "lanman.month", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Current month", HFILL }},
|
|
|
|
{ &hf_year,
|
|
{ "Year", "lanman.year", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Current year", HFILL }},
|
|
|
|
{ &hf_weekday,
|
|
{ "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC,
|
|
VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }},
|
|
|
|
{ &hf_enumeration_domain,
|
|
{ "Enumeration Domain", "lanman.enumeration_domain", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Domain in which to enumerate servers", HFILL }},
|
|
|
|
{ &hf_last_entry,
|
|
{ "Last Entry", "lanman.last_entry", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN last reported entry of the enumerated servers", HFILL }},
|
|
|
|
{ &hf_computer_name,
|
|
{ "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Computer Name", HFILL }},
|
|
|
|
{ &hf_user_name,
|
|
{ "User Name", "lanman.user_name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN User Name", HFILL }},
|
|
|
|
{ &hf_group_name,
|
|
{ "Group Name", "lanman.group_name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Group Name", HFILL }},
|
|
|
|
{ &hf_workstation_domain,
|
|
{ "Workstation Domain", "lanman.workstation_domain", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Workstation Domain", HFILL }},
|
|
|
|
{ &hf_workstation_major,
|
|
{ "Workstation Major Version", "lanman.workstation_major", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Workstation Major Version", HFILL }},
|
|
|
|
{ &hf_workstation_minor,
|
|
{ "Workstation Minor Version", "lanman.workstation_minor", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "LANMAN Workstation Minor Version", HFILL }},
|
|
|
|
{ &hf_logon_domain,
|
|
{ "Logon Domain", "lanman.logon_domain", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Logon Domain", HFILL }},
|
|
|
|
{ &hf_other_domains,
|
|
{ "Other Domains", "lanman.other_domains", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Other Domains", HFILL }},
|
|
|
|
{ &hf_password,
|
|
{ "Password", "lanman.password", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Password", HFILL }},
|
|
|
|
{ &hf_workstation_name,
|
|
{ "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Workstation Name", HFILL }},
|
|
|
|
{ &hf_ustruct_size,
|
|
{ "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN UStruct Length", HFILL }},
|
|
|
|
{ &hf_logon_code,
|
|
{ "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC,
|
|
VALS(status_vals), 0, "LANMAN Logon Code", HFILL }},
|
|
|
|
{ &hf_privilege_level,
|
|
{ "Privilege Level", "lanman.privilege_level", FT_UINT16, BASE_DEC,
|
|
VALS(privilege_vals), 0, "LANMAN Privilege Level", HFILL }},
|
|
|
|
{ &hf_operator_privileges,
|
|
{ "Operator Privileges", "lanman.operator_privileges", FT_UINT32, BASE_DEC,
|
|
VALS(op_privilege_vals), 0, "LANMAN Operator Privileges", HFILL }},
|
|
|
|
{ &hf_num_logons,
|
|
{ "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Number of Logons", HFILL }},
|
|
|
|
{ &hf_bad_pw_count,
|
|
{ "Bad Password Count", "lanman.bad_pw_count", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Number of incorrect passwords entered since last successful login", HFILL }},
|
|
|
|
{ &hf_last_logon,
|
|
{ "Last Logon Date/Time", "lanman.last_logon", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Date and time of last logon", HFILL }},
|
|
|
|
{ &hf_last_logoff,
|
|
{ "Last Logoff Date/Time", "lanman.last_logoff", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Date and time of last logoff", HFILL }},
|
|
|
|
{ &hf_logoff_time,
|
|
{ "Logoff Date/Time", "lanman.logoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Date and time when user should log off", HFILL }},
|
|
|
|
{ &hf_kickoff_time,
|
|
{ "Kickoff Date/Time", "lanman.kickoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Date and time when user will be logged off", HFILL }},
|
|
|
|
{ &hf_password_age,
|
|
{ "Password Age", "lanman.password_age", FT_RELATIVE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Time since user last changed his/her password", HFILL }},
|
|
|
|
{ &hf_password_can_change,
|
|
{ "Password Can Change", "lanman.password_can_change", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Date and time when user can change their password", HFILL }},
|
|
|
|
{ &hf_password_must_change,
|
|
{ "Password Must Change", "lanman.password_must_change", FT_ABSOLUTE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Date and time when user must change their password", HFILL }},
|
|
|
|
{ &hf_script_path,
|
|
{ "Script Path", "lanman.script_path", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Pathname of user's logon script", HFILL }},
|
|
|
|
{ &hf_logoff_code,
|
|
{ "Logoff Code", "lanman.logoff_code", FT_UINT16, BASE_DEC,
|
|
VALS(status_vals), 0, "LANMAN Logoff Code", HFILL }},
|
|
|
|
{ &hf_duration,
|
|
{ "Duration of Session", "lanman.duration", FT_RELATIVE_TIME, BASE_NONE,
|
|
NULL, 0, "LANMAN Number of seconds the user was logged on", HFILL }},
|
|
|
|
{ &hf_comment,
|
|
{ "Comment", "lanman.comment", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Comment", HFILL }},
|
|
|
|
{ &hf_user_comment,
|
|
{ "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN User Comment", HFILL }},
|
|
|
|
{ &hf_full_name,
|
|
{ "Full Name", "lanman.full_name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Full Name", HFILL }},
|
|
|
|
{ &hf_homedir,
|
|
{ "Home Directory", "lanman.homedir", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Home Directory", HFILL }},
|
|
|
|
{ &hf_parameters,
|
|
{ "Parameters", "lanman.parameters", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Parameters", HFILL }},
|
|
|
|
{ &hf_logon_server,
|
|
{ "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Logon Server", HFILL }},
|
|
|
|
/* XXX - we should have a value_string table for this */
|
|
{ &hf_country_code,
|
|
{ "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC,
|
|
VALS(ms_country_codes), 0, "LANMAN Country Code", HFILL }},
|
|
|
|
{ &hf_workstations,
|
|
{ "Workstations", "lanman.workstations", FT_STRING, BASE_NONE,
|
|
NULL, 0, "LANMAN Workstations", HFILL }},
|
|
|
|
{ &hf_max_storage,
|
|
{ "Max Storage", "lanman.max_storage", FT_UINT32, BASE_DEC,
|
|
NULL, 0, "LANMAN Max Storage", HFILL }},
|
|
|
|
{ &hf_units_per_week,
|
|
{ "Units Per Week", "lanman.units_per_week", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Units Per Week", HFILL }},
|
|
|
|
{ &hf_logon_hours,
|
|
{ "Logon Hours", "lanman.logon_hours", FT_BYTES, BASE_NONE,
|
|
NULL, 0, "LANMAN Logon Hours", HFILL }},
|
|
|
|
/* XXX - we should have a value_string table for this */
|
|
{ &hf_code_page,
|
|
{ "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "LANMAN Code Page", HFILL }},
|
|
|
|
{ &hf_new_password,
|
|
{ "New Password", "lanman.new_password", FT_BYTES, BASE_HEX,
|
|
NULL, 0, "LANMAN New Password (encrypted)", HFILL }},
|
|
|
|
{ &hf_old_password,
|
|
{ "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX,
|
|
NULL, 0, "LANMAN Old Password (encrypted)", HFILL }},
|
|
|
|
{ &hf_reserved,
|
|
{ "Reserved", "lanman.reserved", FT_UINT32, BASE_HEX,
|
|
NULL, 0, "LANMAN Reserved", HFILL }},
|
|
|
|
};
|
|
static gint *ett[] = {
|
|
&ett_lanman,
|
|
&ett_lanman_unknown_entries,
|
|
&ett_lanman_unknown_entry,
|
|
&ett_lanman_servers,
|
|
&ett_lanman_server,
|
|
&ett_lanman_groups,
|
|
&ett_lanman_shares,
|
|
&ett_lanman_share,
|
|
};
|
|
|
|
proto_smb_lanman = proto_register_protocol(
|
|
"Microsoft Windows Lanman Remote API Protocol", "LANMAN", "lanman");
|
|
proto_register_field_array(proto_smb_lanman, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
}
|
|
|
|
static heur_dissector_list_t smb_transact_heur_subdissector_list;
|
|
|
|
static GHashTable *dcerpc_fragment_table = NULL;
|
|
static GHashTable *dcerpc_reassembled_table = NULL;
|
|
|
|
static void
|
|
smb_dcerpc_reassembly_init(void)
|
|
{
|
|
fragment_table_init(&dcerpc_fragment_table);
|
|
reassembled_table_init(&dcerpc_reassembled_table);
|
|
}
|
|
|
|
gboolean
|
|
dissect_pipe_dcerpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
|
|
proto_tree *tree, guint32 fid)
|
|
{
|
|
dcerpc_private_info dcerpc_priv;
|
|
smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
|
|
gboolean result=0;
|
|
gboolean save_fragmented;
|
|
guint reported_len;
|
|
guint32 hash_key;
|
|
fragment_data *fd_head;
|
|
tvbuff_t *new_tvb;
|
|
|
|
dcerpc_priv.fid = fid;
|
|
|
|
pinfo->private_data = &dcerpc_priv;
|
|
|
|
|
|
/*
|
|
* Offer desegmentation service to DCERPC if we have all the
|
|
* data. Otherwise, reassembly is (probably) impossible.
|
|
*/
|
|
pinfo->can_desegment=0;
|
|
pinfo->desegment_offset = 0;
|
|
pinfo->desegment_len = 0;
|
|
reported_len = tvb_reported_length(d_tvb);
|
|
if(smb_dcerpc_reassembly && tvb_bytes_exist(d_tvb, 0, reported_len)){
|
|
pinfo->can_desegment=2;
|
|
}
|
|
|
|
save_fragmented = pinfo->fragmented;
|
|
|
|
|
|
/* if we are not offering desegmentation, just try the heuristics
|
|
and bail out
|
|
*/
|
|
if(!pinfo->can_desegment){
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
|
|
/* below this line, we know we are doing reassembly */
|
|
|
|
/*
|
|
* We have to keep track of reassemblies by FID, because
|
|
* we could have more than one pipe operation in a frame
|
|
* with NetBIOS-over-TCP.
|
|
*
|
|
* We also have to keep track of them by direction, as
|
|
* we might have reassemblies in progress in both directions.
|
|
*
|
|
* We do that by combining the FID and the direction and
|
|
* using that as the reassembly ID.
|
|
*
|
|
* The direction is indicated by the SMB request/reply flag - data
|
|
* from client to server is carried in requests, data from server
|
|
* to client is carried in replies.
|
|
*
|
|
* We know that the FID is only 16 bits long, so we put the
|
|
* direction in bit 17.
|
|
*/
|
|
hash_key = fid;
|
|
if (smb_priv->request)
|
|
hash_key |= 0x10000;
|
|
|
|
/* this is a new packet, see if we are already reassembling this
|
|
pdu and if not, check if the dissector wants us
|
|
to reassemble it
|
|
*/
|
|
if(!pinfo->fd->flags.visited){
|
|
/*
|
|
* This is the first pass.
|
|
*
|
|
* Check if we are already reassembling this PDU or not;
|
|
* we check for an in-progress reassembly for this FID
|
|
* in this direction, by searching for its reassembly
|
|
* structure.
|
|
*/
|
|
fd_head=fragment_get(pinfo, fid, dcerpc_fragment_table);
|
|
if(!fd_head){
|
|
/* No reassembly, so this is a new pdu. check if the
|
|
dissector wants us to reassemble it or if we
|
|
already got the full pdu in this tvb.
|
|
*/
|
|
|
|
/*
|
|
* First, just check if it looks like dcerpc or not.
|
|
*
|
|
* XXX - this assumes that the dissector is idempotent,
|
|
* as it's doing a "trial" dissection building no
|
|
* tree; that's not necessarily the case.
|
|
*/
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, NULL);
|
|
|
|
/* no this didnt look like something we know */
|
|
if(!result){
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
/* did the subdissector want us to reassemble any
|
|
more data ?
|
|
*/
|
|
if(pinfo->desegment_len){
|
|
fragment_add_check(d_tvb, 0, pinfo, fid,
|
|
dcerpc_fragment_table,
|
|
dcerpc_reassembled_table,
|
|
0, reported_len, TRUE);
|
|
fragment_set_tot_len(pinfo, fid,
|
|
dcerpc_fragment_table,
|
|
pinfo->desegment_len+reported_len);
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
/* guess we have the full pdu in this tvb then,
|
|
just dissect it and continue.
|
|
*/
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
/* OK, we're already doing a reassembly for this FID.
|
|
skip to last segment in the existing reassembly structure
|
|
and add this fragment there
|
|
|
|
XXX we might add code here to use any offset values
|
|
we might pick up from the Read/Write calls instead of
|
|
assuming we always get them in the correct order
|
|
*/
|
|
while(fd_head->next){
|
|
fd_head=fd_head->next;
|
|
}
|
|
fd_head=fragment_add_check(d_tvb, 0, pinfo, fid,
|
|
dcerpc_fragment_table, dcerpc_reassembled_table,
|
|
fd_head->offset+fd_head->len,
|
|
reported_len, TRUE);
|
|
|
|
/* if we completed reassembly */
|
|
if(fd_head){
|
|
new_tvb = tvb_new_real_data(fd_head->data,
|
|
fd_head->datalen, fd_head->datalen);
|
|
tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
|
|
add_new_data_source(pinfo, new_tvb,
|
|
"DCERPC over SMB");
|
|
pinfo->fragmented=FALSE;
|
|
|
|
d_tvb=new_tvb;
|
|
|
|
/* list what segments we have */
|
|
show_fragment_tree(fd_head, &smb_pipe_frag_items,
|
|
tree, pinfo, d_tvb);
|
|
|
|
/* dissect the full PDU */
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
|
|
}
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
/*
|
|
* This is not the first pass; see if it's in the table of
|
|
* reassembled packets.
|
|
*
|
|
* XXX - we know that several of the arguments aren't going to
|
|
* be used, so we pass bogus variables. Can we clean this
|
|
* up so that we don't have to distinguish between the first
|
|
* pass and subsequent passes?
|
|
*/
|
|
fd_head=fragment_add_check(d_tvb, 0, pinfo, fid, dcerpc_fragment_table,
|
|
dcerpc_reassembled_table, 0, 0, TRUE);
|
|
if(!fd_head){
|
|
/* we didnt find it, try any of the heuristic dissectors
|
|
and bail out
|
|
*/
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
|
|
goto clean_up_and_exit;
|
|
}
|
|
if(!fd_head->flags&FD_DEFRAGMENTED){
|
|
/* we dont have a fully reassembled frame */
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
/* it is reassembled but it was reassembled in a different frame */
|
|
if(pinfo->fd->num!=fd_head->reassembled_in){
|
|
proto_tree_add_uint(parent_tree, hf_pipe_reassembled_in, d_tvb, 0, 0, fd_head->reassembled_in);
|
|
goto clean_up_and_exit;
|
|
}
|
|
|
|
|
|
/* display the reassembled pdu */
|
|
new_tvb = tvb_new_real_data(fd_head->data,
|
|
fd_head->datalen, fd_head->datalen);
|
|
tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
|
|
add_new_data_source(pinfo, new_tvb,
|
|
"DCERPC over SMB");
|
|
pinfo->fragmented=FALSE;
|
|
|
|
d_tvb=new_tvb;
|
|
|
|
/* list what segments we have */
|
|
show_fragment_tree(fd_head, &smb_pipe_frag_items,
|
|
tree, pinfo, d_tvb);
|
|
|
|
/* dissect the full PDU */
|
|
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
|
|
|
|
|
|
|
|
clean_up_and_exit:
|
|
/* clear out the variables */
|
|
pinfo->private_data = smb_priv;
|
|
pinfo->can_desegment=0;
|
|
pinfo->desegment_offset = 0;
|
|
pinfo->desegment_len = 0;
|
|
|
|
if (!result)
|
|
call_dissector(data_handle, d_tvb, pinfo, parent_tree);
|
|
|
|
pinfo->fragmented = save_fragmented;
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
proto_register_pipe_dcerpc(void)
|
|
{
|
|
register_heur_dissector_list("smb_transact", &smb_transact_heur_subdissector_list);
|
|
register_init_routine(smb_dcerpc_reassembly_init);
|
|
}
|
|
|
|
#define CALL_NAMED_PIPE 0x54
|
|
#define WAIT_NAMED_PIPE 0x53
|
|
#define PEEK_NAMED_PIPE 0x23
|
|
#define Q_NM_P_HAND_STATE 0x21
|
|
#define SET_NM_P_HAND_STATE 0x01
|
|
#define Q_NM_PIPE_INFO 0x22
|
|
#define TRANSACT_NM_PIPE 0x26
|
|
#define RAW_READ_NM_PIPE 0x11
|
|
#define RAW_WRITE_NM_PIPE 0x31
|
|
|
|
static const value_string functions[] = {
|
|
{CALL_NAMED_PIPE, "CallNamedPipe"},
|
|
{WAIT_NAMED_PIPE, "WaitNamedPipe"},
|
|
{PEEK_NAMED_PIPE, "PeekNamedPipe"},
|
|
{Q_NM_P_HAND_STATE, "QNmPHandState"},
|
|
{SET_NM_P_HAND_STATE, "SetNmPHandState"},
|
|
{Q_NM_PIPE_INFO, "QNmPipeInfo"},
|
|
{TRANSACT_NM_PIPE, "TransactNmPipe"},
|
|
{RAW_READ_NM_PIPE, "RawReadNmPipe"},
|
|
{RAW_WRITE_NM_PIPE, "RawWriteNmPipe"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static const value_string pipe_status[] = {
|
|
{1, "Disconnected by server"},
|
|
{2, "Listening"},
|
|
{3, "Connection to server is OK"},
|
|
{4, "Server end of pipe is closed"},
|
|
{0, NULL}
|
|
};
|
|
|
|
#define PIPE_LANMAN 1
|
|
#define PIPE_DCERPC 2
|
|
|
|
/* decode the SMB pipe protocol
|
|
for requests
|
|
pipe is the name of the pipe, e.g. LANMAN
|
|
smb_info->trans_subcmd is set to the symbolic constant matching the mailslot name
|
|
for responses
|
|
pipe is NULL
|
|
smb_info->trans_subcmd gives us which pipe this response is for
|
|
*/
|
|
gboolean
|
|
dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb,
|
|
tvbuff_t *p_tvb, tvbuff_t *d_tvb, const char *pipe,
|
|
packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
smb_info_t *smb_info;
|
|
smb_transact_info_t *tri;
|
|
guint sp_len;
|
|
proto_item *pipe_item = NULL;
|
|
proto_tree *pipe_tree = NULL;
|
|
int offset;
|
|
int trans_subcmd;
|
|
int function;
|
|
int fid = -1;
|
|
guint16 info_level;
|
|
|
|
if (!proto_is_protocol_enabled(find_protocol_by_id(proto_smb_pipe)))
|
|
return FALSE;
|
|
pinfo->current_proto = "SMB Pipe";
|
|
|
|
smb_info = pinfo->private_data;
|
|
|
|
/*
|
|
* Set the columns.
|
|
*/
|
|
if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB Pipe");
|
|
}
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_set_str(pinfo->cinfo, COL_INFO,
|
|
smb_info->request ? "Request" : "Response");
|
|
}
|
|
|
|
if (smb_info->sip != NULL)
|
|
tri = smb_info->sip->extra_info;
|
|
else
|
|
tri = NULL;
|
|
|
|
/*
|
|
* Set up a subtree for the pipe protocol. (It might not contain
|
|
* anything.)
|
|
*/
|
|
if (sp_tvb != NULL)
|
|
sp_len = tvb_length(sp_tvb);
|
|
else
|
|
sp_len = 0;
|
|
if (tree) {
|
|
pipe_item = proto_tree_add_item(tree, proto_smb_pipe,
|
|
sp_tvb, 0, sp_len, FALSE);
|
|
pipe_tree = proto_item_add_subtree(pipe_item, ett_smb_pipe);
|
|
}
|
|
offset = 0;
|
|
|
|
/*
|
|
* Do we have any setup words at all?
|
|
*/
|
|
if (s_tvb != NULL && tvb_length(s_tvb) != 0) {
|
|
/*
|
|
* Yes. The first of them is the function.
|
|
*/
|
|
function = tvb_get_letohs(s_tvb, offset);
|
|
proto_tree_add_uint(pipe_tree, hf_pipe_function, s_tvb,
|
|
offset, 2, function);
|
|
offset += 2;
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
|
|
val_to_str(function, functions, "Unknown function (0x%04x)"),
|
|
smb_info->request ? "Request" : "Response");
|
|
}
|
|
if (tri != NULL)
|
|
tri->function = function;
|
|
|
|
/*
|
|
* The second of them depends on the function.
|
|
*/
|
|
switch (function) {
|
|
|
|
case CALL_NAMED_PIPE:
|
|
case WAIT_NAMED_PIPE:
|
|
/*
|
|
* It's a priority.
|
|
*/
|
|
proto_tree_add_item(pipe_tree, hf_pipe_priority, s_tvb,
|
|
offset, 2, TRUE);
|
|
break;
|
|
|
|
case PEEK_NAMED_PIPE:
|
|
case Q_NM_P_HAND_STATE:
|
|
case SET_NM_P_HAND_STATE:
|
|
case Q_NM_PIPE_INFO:
|
|
case TRANSACT_NM_PIPE:
|
|
case RAW_READ_NM_PIPE:
|
|
case RAW_WRITE_NM_PIPE:
|
|
/*
|
|
* It's a FID.
|
|
*/
|
|
fid = tvb_get_letohs(s_tvb, 2);
|
|
add_fid(s_tvb, pinfo, pipe_tree, offset, 2, (guint16) fid);
|
|
if (tri != NULL)
|
|
tri->fid = fid;
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* It's something unknown.
|
|
* XXX - put it into the tree?
|
|
*/
|
|
break;
|
|
}
|
|
offset += 2;
|
|
} else {
|
|
/*
|
|
* This is either a response or a pipe transaction with
|
|
* no setup information.
|
|
*
|
|
* In the former case, we can get that information from
|
|
* the matching request, if we saw it.
|
|
*
|
|
* In the latter case, there is no function or FID.
|
|
*/
|
|
if (tri != NULL && tri->function != -1) {
|
|
function = tri->function;
|
|
proto_tree_add_uint(pipe_tree, hf_pipe_function, NULL,
|
|
0, 0, function);
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
|
|
val_to_str(function, functions, "Unknown function (0x%04x)"),
|
|
smb_info->request ? "Request" : "Response");
|
|
}
|
|
fid = tri->fid;
|
|
if (fid != -1)
|
|
add_fid(NULL, pinfo, pipe_tree, 0, 0, (guint16) fid);
|
|
} else {
|
|
function = -1;
|
|
fid = -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* XXX - put the byte count and the pipe name into the tree as well;
|
|
* that requires us to fetch a possibly-Unicode string.
|
|
*/
|
|
|
|
if(smb_info->request){
|
|
if(strncmp(pipe,"LANMAN",6) == 0){
|
|
trans_subcmd=PIPE_LANMAN;
|
|
} else {
|
|
/* assume it is DCERPC */
|
|
trans_subcmd=PIPE_DCERPC;
|
|
}
|
|
|
|
if (!pinfo->fd->flags.visited)
|
|
tri->trans_subcmd = trans_subcmd;
|
|
} else
|
|
trans_subcmd = tri->trans_subcmd;
|
|
|
|
if (tri == NULL) {
|
|
/*
|
|
* We don't know what type of pipe transaction this
|
|
* was, so indicate that we didn't dissect it.
|
|
*/
|
|
return FALSE;
|
|
}
|
|
|
|
switch (function) {
|
|
|
|
case CALL_NAMED_PIPE:
|
|
case TRANSACT_NM_PIPE:
|
|
switch(trans_subcmd){
|
|
|
|
case PIPE_LANMAN:
|
|
return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
|
|
tree);
|
|
break;
|
|
|
|
case PIPE_DCERPC:
|
|
/*
|
|
* Only dissect this if we know the FID.
|
|
*/
|
|
if (fid != -1) {
|
|
if (d_tvb == NULL)
|
|
return FALSE;
|
|
return dissect_pipe_dcerpc(d_tvb, pinfo, tree,
|
|
pipe_tree, fid);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case -1:
|
|
/*
|
|
* We don't know the function; we dissect only LANMAN
|
|
* pipe messages, not RPC pipe messages, in that case.
|
|
*/
|
|
switch(trans_subcmd){
|
|
case PIPE_LANMAN:
|
|
return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
|
|
tree);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WAIT_NAMED_PIPE:
|
|
break;
|
|
|
|
case PEEK_NAMED_PIPE:
|
|
/*
|
|
* Request contains no parameters or data.
|
|
*/
|
|
if (!smb_info->request) {
|
|
if (p_tvb == NULL)
|
|
return FALSE;
|
|
offset = 0;
|
|
proto_tree_add_item(pipe_tree, hf_pipe_peek_available,
|
|
p_tvb, offset, 2, TRUE);
|
|
offset += 2;
|
|
proto_tree_add_item(pipe_tree, hf_pipe_peek_remaining,
|
|
p_tvb, offset, 2, TRUE);
|
|
offset += 2;
|
|
proto_tree_add_item(pipe_tree, hf_pipe_peek_status,
|
|
p_tvb, offset, 2, TRUE);
|
|
offset += 2;
|
|
}
|
|
break;
|
|
|
|
case Q_NM_P_HAND_STATE:
|
|
/*
|
|
* Request contains no parameters or data.
|
|
*/
|
|
if (!smb_info->request) {
|
|
if (p_tvb == NULL)
|
|
return FALSE;
|
|
offset = dissect_ipc_state(p_tvb, pipe_tree, 0, FALSE);
|
|
}
|
|
break;
|
|
|
|
case SET_NM_P_HAND_STATE:
|
|
/*
|
|
* Response contains no parameters or data.
|
|
*/
|
|
if (smb_info->request) {
|
|
if (p_tvb == NULL)
|
|
return FALSE;
|
|
offset = dissect_ipc_state(p_tvb, pipe_tree, 0, TRUE);
|
|
}
|
|
break;
|
|
|
|
case Q_NM_PIPE_INFO:
|
|
offset = 0;
|
|
if (smb_info->request) {
|
|
if (p_tvb == NULL)
|
|
return FALSE;
|
|
|
|
/*
|
|
* Request contains an information level.
|
|
*/
|
|
info_level = tvb_get_letohs(p_tvb, offset);
|
|
proto_tree_add_uint(pipe_tree, hf_pipe_getinfo_info_level,
|
|
p_tvb, offset, 2, info_level);
|
|
offset += 2;
|
|
if (!pinfo->fd->flags.visited)
|
|
tri->info_level = info_level;
|
|
} else {
|
|
guint8 pipe_namelen;
|
|
|
|
if (d_tvb == NULL)
|
|
return FALSE;
|
|
|
|
switch (tri->info_level) {
|
|
|
|
case 1:
|
|
proto_tree_add_item(pipe_tree,
|
|
hf_pipe_getinfo_output_buffer_size,
|
|
d_tvb, offset, 2, TRUE);
|
|
offset += 2;
|
|
proto_tree_add_item(pipe_tree,
|
|
hf_pipe_getinfo_input_buffer_size,
|
|
d_tvb, offset, 2, TRUE);
|
|
offset += 2;
|
|
proto_tree_add_item(pipe_tree,
|
|
hf_pipe_getinfo_maximum_instances,
|
|
d_tvb, offset, 1, TRUE);
|
|
offset += 1;
|
|
proto_tree_add_item(pipe_tree,
|
|
hf_pipe_getinfo_current_instances,
|
|
d_tvb, offset, 1, TRUE);
|
|
offset += 1;
|
|
pipe_namelen = tvb_get_guint8(d_tvb, offset);
|
|
proto_tree_add_uint(pipe_tree,
|
|
hf_pipe_getinfo_pipe_name_length,
|
|
d_tvb, offset, 1, pipe_namelen);
|
|
offset += 1;
|
|
/* XXX - can this be Unicode? */
|
|
proto_tree_add_item(pipe_tree,
|
|
hf_pipe_getinfo_pipe_name,
|
|
d_tvb, offset, pipe_namelen, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RAW_READ_NM_PIPE:
|
|
/*
|
|
* Request contains no parameters or data.
|
|
*/
|
|
if (!smb_info->request) {
|
|
if (d_tvb == NULL)
|
|
return FALSE;
|
|
|
|
offset = dissect_file_data(d_tvb, pipe_tree, 0,
|
|
(guint16) tvb_reported_length(d_tvb),
|
|
(guint16) tvb_reported_length(d_tvb));
|
|
}
|
|
break;
|
|
|
|
case RAW_WRITE_NM_PIPE:
|
|
offset = 0;
|
|
if (smb_info->request) {
|
|
if (d_tvb == NULL)
|
|
return FALSE;
|
|
|
|
offset = dissect_file_data(d_tvb, pipe_tree,
|
|
offset, (guint16) tvb_reported_length(d_tvb),
|
|
(guint16) tvb_reported_length(d_tvb));
|
|
} else {
|
|
if (p_tvb == NULL)
|
|
return FALSE;
|
|
proto_tree_add_item(pipe_tree,
|
|
hf_pipe_write_raw_bytes_written,
|
|
p_tvb, offset, 2, TRUE);
|
|
offset += 2;
|
|
}
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
proto_register_smb_pipe(void)
|
|
{
|
|
static hf_register_info hf[] = {
|
|
{ &hf_pipe_function,
|
|
{ "Function", "pipe.function", FT_UINT16, BASE_HEX,
|
|
VALS(functions), 0, "SMB Pipe Function Code", HFILL }},
|
|
{ &hf_pipe_priority,
|
|
{ "Priority", "pipe.priority", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "SMB Pipe Priority", HFILL }},
|
|
{ &hf_pipe_peek_available,
|
|
{ "Available Bytes", "pipe.peek.available_bytes", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "Total number of bytes available to be read from the pipe", HFILL }},
|
|
{ &hf_pipe_peek_remaining,
|
|
{ "Bytes Remaining", "pipe.peek.remaining_bytes", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "Total number of bytes remaining in the message at the head of the pipe", HFILL }},
|
|
{ &hf_pipe_peek_status,
|
|
{ "Pipe Status", "pipe.peek.status", FT_UINT16, BASE_DEC,
|
|
VALS(pipe_status), 0, "Pipe status", HFILL }},
|
|
{ &hf_pipe_getinfo_info_level,
|
|
{ "Information Level", "pipe.getinfo.info_level", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "Information level of information to return", HFILL }},
|
|
{ &hf_pipe_getinfo_output_buffer_size,
|
|
{ "Output Buffer Size", "pipe.getinfo.output_buffer_size", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "Actual size of buffer for outgoing (server) I/O", HFILL }},
|
|
{ &hf_pipe_getinfo_input_buffer_size,
|
|
{ "Input Buffer Size", "pipe.getinfo.input_buffer_size", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "Actual size of buffer for incoming (client) I/O", HFILL }},
|
|
{ &hf_pipe_getinfo_maximum_instances,
|
|
{ "Maximum Instances", "pipe.getinfo.maximum_instances", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "Maximum allowed number of instances", HFILL }},
|
|
{ &hf_pipe_getinfo_current_instances,
|
|
{ "Current Instances", "pipe.getinfo.current_instances", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "Current number of instances", HFILL }},
|
|
{ &hf_pipe_getinfo_pipe_name_length,
|
|
{ "Pipe Name Length", "pipe.getinfo.pipe_name_length", FT_UINT8, BASE_DEC,
|
|
NULL, 0, "Length of pipe name", HFILL }},
|
|
{ &hf_pipe_getinfo_pipe_name,
|
|
{ "Pipe Name", "pipe.getinfo.pipe_name", FT_STRING, BASE_NONE,
|
|
NULL, 0, "Name of pipe", HFILL }},
|
|
{ &hf_pipe_write_raw_bytes_written,
|
|
{ "Bytes Written", "pipe.write_raw.bytes_written", FT_UINT16, BASE_DEC,
|
|
NULL, 0, "Number of bytes written to the pipe", HFILL }},
|
|
{ &hf_pipe_fragment_overlap,
|
|
{ "Fragment overlap", "pipe.fragment.overlap", FT_BOOLEAN, BASE_NONE,
|
|
NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
|
|
{ &hf_pipe_fragment_overlap_conflict,
|
|
{ "Conflicting data in fragment overlap", "pipe.fragment.overlap.conflict", FT_BOOLEAN,
|
|
BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
|
|
{ &hf_pipe_fragment_multiple_tails,
|
|
{ "Multiple tail fragments found", "pipe.fragment.multipletails", FT_BOOLEAN,
|
|
BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
|
|
{ &hf_pipe_fragment_too_long_fragment,
|
|
{ "Fragment too long", "pipe.fragment.toolongfragment", FT_BOOLEAN,
|
|
BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
|
|
{ &hf_pipe_fragment_error,
|
|
{ "Defragmentation error", "pipe.fragment.error", FT_FRAMENUM,
|
|
BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
|
|
{ &hf_pipe_fragment,
|
|
{ "Fragment", "pipe.fragment", FT_FRAMENUM,
|
|
BASE_NONE, NULL, 0x0, "Pipe Fragment", HFILL }},
|
|
{ &hf_pipe_fragments,
|
|
{ "Fragments", "pipe.fragments", FT_NONE,
|
|
BASE_NONE, NULL, 0x0, "Pipe Fragments", HFILL }},
|
|
{ &hf_pipe_reassembled_in,
|
|
{ "This PDU is reassembled in", "pipe.reassembled_in", FT_FRAMENUM,
|
|
BASE_NONE, NULL, 0x0, "The DCE/RPC PDU is completely reassembled in this frame", HFILL }},
|
|
};
|
|
static gint *ett[] = {
|
|
&ett_smb_pipe,
|
|
&ett_smb_pipe_fragment,
|
|
&ett_smb_pipe_fragments,
|
|
};
|
|
|
|
proto_smb_pipe = proto_register_protocol(
|
|
"SMB Pipe Protocol", "SMB Pipe", "pipe");
|
|
|
|
proto_register_field_array(proto_smb_pipe, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_smb_pipe(void)
|
|
{
|
|
data_handle = find_dissector("data");
|
|
}
|