aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packet-smb-browse.c32
-rw-r--r--packet-smb-browse.h5
-rw-r--r--packet-smb-pipe.c2383
-rw-r--r--packet-smb-pipe.h15
-rw-r--r--packet-smb.c128
-rw-r--r--smb.h7
6 files changed, 1661 insertions, 909 deletions
diff --git a/packet-smb-browse.c b/packet-smb-browse.c
index dba926ac0d..7720d2cf6a 100644
--- a/packet-smb-browse.c
+++ b/packet-smb-browse.c
@@ -2,7 +2,7 @@
* Routines for SMB Browser packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: packet-smb-browse.c,v 1.16 2001/08/01 08:12:15 guy Exp $
+ * $Id: packet-smb-browse.c,v 1.17 2001/08/05 01:15:26 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -439,8 +439,12 @@ dissect_election_criterion(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent
}
-static void
-dissect_server_type_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
+/*
+ * XXX - this causes non-browser packets to have browser fields.
+ */
+void
+dissect_smb_server_type_flags(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *parent_tree, int offset, gboolean infoflag)
{
proto_tree *tree = NULL;
proto_item *item = NULL;
@@ -454,13 +458,15 @@ dissect_server_type_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_
tree = proto_item_add_subtree(item, ett_browse_flags);
}
- /* Append the type(s) of the system to the COL_INFO line ... */
- if (check_col(pinfo->fd, COL_INFO)) {
- for (i = 0; i < 32; i++) {
- if (flags & (1<<i)) {
- col_append_fstr(pinfo->fd, COL_INFO, ", %s",
- val_to_str(i, server_types,
- "Unknown server type:%d"));
+ if (infoflag) {
+ /* Append the type(s) of the system to the COL_INFO line ... */
+ if (check_col(pinfo->fd, COL_INFO)) {
+ for (i = 0; i < 32; i++) {
+ if (flags & (1<<i)) {
+ col_append_fstr(pinfo->fd, COL_INFO, ", %s",
+ val_to_str(i, server_types,
+ "Unknown server type:%d"));
+ }
}
}
}
@@ -516,6 +522,7 @@ dissect_server_type_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_
}
+
gboolean
dissect_mailslot_browse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
{
@@ -600,7 +607,7 @@ dissect_mailslot_browse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr
offset += 1;
/* server type flags */
- dissect_server_type_flags(tvb, pinfo, tree, offset);
+ dissect_smb_server_type_flags(tvb, pinfo, tree, offset, TRUE);
offset += 4;
if (cmd == BROWSE_DOMAIN_ANNOUNCEMENT) {
@@ -797,7 +804,8 @@ dissect_mailslot_lanman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr
offset += 1;
/* server type flags */
- dissect_server_type_flags(tvb, pinfo, tree, offset);
+ dissect_smb_server_type_flags(tvb, pinfo, tree, offset,
+ hf_server_type);
offset += 4;
/* OS major version */
diff --git a/packet-smb-browse.h b/packet-smb-browse.h
index bb7a50ea48..6c686050c8 100644
--- a/packet-smb-browse.h
+++ b/packet-smb-browse.h
@@ -2,7 +2,7 @@
* Declaration of routines for SMB Browser packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: packet-smb-browse.h,v 1.3 2001/08/01 03:47:00 guy Exp $
+ * $Id: packet-smb-browse.h,v 1.4 2001/08/05 01:15:26 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -32,4 +32,7 @@ dissect_mailslot_browse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr
gboolean
dissect_mailslot_lanman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree);
+void
+dissect_smb_server_type_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gboolean infoflag);
+
#endif
diff --git a/packet-smb-pipe.c b/packet-smb-pipe.c
index 73cda9f84b..542d9b8a8d 100644
--- a/packet-smb-pipe.c
+++ b/packet-smb-pipe.c
@@ -1,11 +1,18 @@
+/*
+XXX Fixme : continuation stuff removed, should be solved by smb reassembly
+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.23 2001/08/05 00:16:36 guy Exp $
+ * $Id: packet-smb-pipe.c,v 1.24 2001/08/05 01:15:26 guy Exp $
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* Copied from packet-pop.c
@@ -46,18 +53,88 @@
#include "packet.h"
#include "conversation.h"
#include "smb.h"
-#include "alignment.h"
-#include "strutil.h"
#include "packet-smb-pipe.h"
+#include "packet-smb-browse.h"
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_not_implemented = -1;
+static int hf_detail_level = -1;
+static int hf_recv_buf_len = -1;
+static int hf_response_to = -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_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_computer_name = -1;
+static int hf_user_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_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 gint ett_lanman = -1;
static gint ett_lanman_servers = -1;
static gint ett_lanman_server = -1;
static gint ett_lanman_shares = -1;
static gint ett_lanman_share = -1;
-static gint ett_lanman_flags = -1;
/*
* See
@@ -67,1120 +144,1689 @@ static gint ett_lanman_flags = -1;
* among other documents.
*/
-/*
- * The following data structure describes the LANMAN requests we understand
- *
- * Simply fill in the number, name, and parameter names if you know them
- * Try to keep them in order
- *
- * We will extend this data structure as we try to decode more ...
- */
-
-struct lanman_desc {
- int lanman_num;
- char *lanman_name;
- char **req;
- char **req_data; /* Hmmm, not flexible enough */
- char **resp;
- char **resp_data;
+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"},
+ {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 char *lm_params_req_0[] = {"Detail Level", "Return Buffer Size", NULL};
-static char *lm_params_req_1[] = {"Share Name", "Detail Level", "Receive Buffer Size", NULL};
-static char *lm_params_resp_1[] = {"Returned Data Len", NULL};
-static char *lm_params_req_13[] = {"Detail Level", "Receive Buffer Size", NULL};
-static char *lm_params_req_56[] = {"User Name", "Detail Level", "Receive Buffer Size", NULL};
-static char *lm_params_req_104[] = {"Detail Level", "Return Buffer Size", "Server Type", "Domain", NULL};
-static char *lm_params_req_132[] = {"Reserved1", "Reserved2", "Detail Level", "UserInfoStruct?", "Length of UStruct", "Receive Buffer Size", NULL};
-static char *lm_params_req_133[] = {"Reserved1", "Reserved2", "Detail Level", "UserInfoStruct?", "Length of UStruct", "Receive Buffer Size", NULL};
-
-static char *lm_null_params[] = {NULL};
-
-struct lanman_desc lmd[] = {
- {0, "NetShareEnum", lm_params_req_0, lm_null_params, lm_null_params, lm_null_params},
- {1, "NetShareGetInfo", lm_params_req_1, lm_null_params, lm_params_resp_1, lm_null_params},
- {13, "NetServerGetInfo", lm_params_req_13, lm_null_params, lm_null_params, lm_null_params},
- {52, "NetGroupGetUsers", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {56, "NetUserGetInfo", lm_params_req_56, lm_null_params, lm_null_params, lm_null_params},
- {59, "NetUserGetGroups", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {63, "NetWkstaGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {69, "DOSPrintQEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {70, "DOSPrintQGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {74, "WPrintQueuePause", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {75, "WPrintQueueResume", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {76, "WPrintJobEnumerate", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {77, "WPrintJobGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {81, "RDOSPrintJobDel", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {82, "RDOSPrintJobPause", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {83, "RDOSPrintJobResume", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {84, "WPrintDestEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {85, "WPrintDestGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {91, "NetRemoteTOD", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {103, "WPrintQueuePurge", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {104, "NetServerEnum2", lm_params_req_104, lm_null_params, lm_null_params, lm_null_params},
- {105, "WAccessGetUserPerms", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {115, "SetUserPassword", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {132, "NetWkstaUserLogon", lm_params_req_132, lm_null_params, lm_null_params, lm_null_params},
- {133, "NetWkstaUserLogoff", lm_params_req_133, lm_null_params, lm_null_params, lm_null_params},
- {147, "PrintJobInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {205, "WPrintDriverEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {206, "WPrintQProcEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {207, "WPrintPortEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {214, "SamOEMChangePassword", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
- {-1, NULL, NULL,NULL, NULL, NULL}
+static const value_string share_type_vals[] = {
+ {0, "Directory tree"},
+ {1, "Printer queue"},
+ {2, "Communications device"},
+ {3, "IPC"},
+ {0, NULL}
};
-static struct lanman_desc *
-find_lanman(int lanman_num)
-{
- int i = 0;
-
- /* FIXME, This could be more efficient */
-
- while (lmd[i].lanman_num != -1) {
-
- if (lmd[i].lanman_num == lanman_num) {
-
- return &lmd[i];
-
- }
-
- i++;
-
- }
-
- return 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}
+};
-#define NETSHAREENUM 0x00 /* 00 */
-#define NETSERVERENUM2 0x68 /* 104 */
+static const value_string weekday_vals[] = {
+ {0, "Sunday"},
+ {1, "Monday"},
+ {2, "Tuesday"},
+ {3, "Wednesday"},
+ {4, "Thursday"},
+ {5, "Friday"},
+ {6, "Saturday"},
+ {0, NULL}
+};
-static void
-dissect_server_flags(proto_tree *tree, int offset, int length, int flags)
+static int
+not_implemented(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
{
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0001, length*8, "Workstation", "Not Workstation"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0002, length*8, "Server", "Not Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0004, length*8, "SQL Server", "Not SQL Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0008, length*8, "Domain Controller", "Not Domain Controller"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0010, length*8, "Backup Controller", "Not Backup Controller"));
- proto_tree_add_text(tree, NullTVB, offset, 4, "%s",
- decode_boolean_bitfield(flags, 0x0020, length*8, "Time Source", "Not Time Source"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0040, length*8, "Apple Server", "Not Apple Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0080, length*8, "Novell Server", "Not Novell Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0100, length*8, "Domain Member Server", "Not Domain Member Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0200, length*8, "Print Queue Server", "Not Print Queue Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0400, length*8, "Dialin Server", "Not Dialin Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x0800, length*8, "Xenix Server", "Not Xenix Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x1000, length*8, "NT Workstation", "Not NT Workstation"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x2000, length*8, "Windows for Workgroups", "Not Windows for Workgroups"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x8000, length*8, "NT Server", "Not NT Server"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x10000, length*8, "Potential Browser", "Not Potential Browser"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x20000, length*8, "Backup Browser", "Not Backup Browser"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x40000, length*8, "Master Browser", "Not Master Browser"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x80000, length*8, "Domain Master Browser", "Not Domain Master Browser"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x100000, length*8, "OSF", "Not OSF"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x200000, length*8, "VMS", "Not VMS"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x400000, length*8, "Windows 95 or above", "Not Windows 95 or above"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x40000000, length*8, "Local List Only", "Not Local List Only"));
- proto_tree_add_text(tree, NullTVB, offset, length, "%s",
- decode_boolean_bitfield(flags, 0x80000000, length*8, "Domain Enum", "Not Domain Enum"));
+ proto_tree_add_item(tree, hf_not_implemented, tvb, offset, tvb_length_remaining(tvb, offset), TRUE);
+ return offset+tvb_length_remaining(tvb,offset);
}
-
-
-static char *p_desc = NULL, *d_desc = NULL, *data = NULL, *params = NULL;
-static int p_count, d_count, p_offset, d_offset, d_current = 0, p_current = 0;
-static int pd_p_current = 0, pd_d_current = 0, in_params = 0, need_data = 0;
-static int lm_ent_count = 0, lm_act_count = 0;
-
-/* Initialize the various data structure */
-static void
-dissect_transact_engine_init(const u_char *pd, const char *param_desc,
- const char *data_desc, int SMB_offset, int ParameterOffset,
- int ParameterCount, int DataOffset, int DataCount)
+static int
+add_string_pointer(tvbuff_t *tvb, proto_tree *tree, int offset, int convert,
+ int hf_index)
{
+ int cptr;
+ gint string_len;
+
+ /* pointer to string */
+ cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
+ offset += 4;
+
+ /* string */
+ if (tvb_offset_exists(tvb, cptr) &&
+ (string_len = tvb_strnlen(tvb, cptr, -1)) != -1) {
+ proto_tree_add_item(tree, hf_index, tvb, cptr,
+ string_len + 1, TRUE);
+ } else {
+ proto_tree_add_text(tree, tvb, 0, 0,
+ "%s: <String goes past end of frame>",
+ proto_registrar_get_name(hf_index));
+ }
- d_count = DataCount;
- p_count = ParameterCount;
- d_offset = 0;
- p_offset = 0;
- d_current = 0;
- p_current = 0;
- lm_ent_count = lm_act_count = 0;
- pd_d_current = DataOffset;
- pd_p_current = ParameterOffset;
- in_params = need_data = 0;
-
- if (p_desc) g_free(p_desc);
- p_desc = g_malloc(strlen(param_desc) + 1);
- strcpy(p_desc, param_desc);
-
- if (d_desc) g_free(d_desc);
- d_desc= g_malloc(strlen(data_desc) + 1);
- strcpy(d_desc, data_desc);
-
- if (params) g_free(params);
- params = g_malloc(p_count);
- memcpy(params, pd + ParameterOffset, ParameterCount);
-
- if (data) g_free(data);
- data = g_malloc(d_count);
- memcpy(data, pd + DataOffset, DataCount);
-
+ return offset;
}
-int get_ent_count()
+static int
+add_byte_array_pointer(tvbuff_t *tvb, proto_tree *tree, int offset, int len,
+ int convert, int hf_index)
{
+ int cptr;
- return lm_ent_count;
+ /* pointer to string */
+ cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
+ offset += 4;
+ /* string */
+ proto_tree_add_item(tree, hf_index, tvb, cptr, len, TRUE);
+
+ return offset;
}
-int get_act_count()
+/*
+ * Sigh. This is for handling Microsoft's annoying almost-UNIX-time-but-
+ * it's-local-time-not-UTC time.
+ */
+static time_t
+localtime_to_utc(time_t local)
{
-
- return lm_act_count;
-
+ struct tm *tmp;
+
+ /*
+ * Run it through "gmtime()" to break it down, and then run it
+ * through "mktime()" to put it back together as UTC.
+ */
+ tmp = gmtime(&local);
+ tmp->tm_isdst = -1; /* we don't know if it's DST or not */
+ return mktime(tmp);
}
-static int get_byte_count(const u_char *p_data)
-
+static int
+netshareenum_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
{
- int count = 0, off = 0;
-
- while (p_data[off] && isdigit(p_data[off])) {
-
- count = (count * 10) + (int)p_data[off++] - (int)'0';
+ /* detail level */
+ proto_tree_add_item(tree, hf_detail_level, tvb, offset, 2, TRUE);
+ offset += 2;
- }
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- return count;
+ return offset;
}
-
-/* Dissect the next item, if Name is null, call it by its data type */
-/* We pull out the next item in the appropriate place and display it */
-/* We display the parameters first, then the data, then any auxilliary data */
-
static int
-dissect_transact_next(const u_char *pd, char *Name, gboolean request, proto_tree *tree)
+netshareenum_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
{
- /* guint8 BParam; */
- guint16 WParam = 0;
- guint32 LParam = 0;
- const char /**Bytes,*/ *AsciiZ = NULL;
- int bc;
-
- while (1) {
-
- if (p_desc[p_offset] == 0) return 0; /* No more ... */
-
- switch (in_params) {
-
- case 0: /* We are in the params area ... */
-
- switch (p_desc[p_offset++]) {
-
- case 'r':
-
- if (!request) { /* We need to process the data ... */
-
- need_data = 1;
-
- }
-
- break;
-
- case 'h': /* A WORD parameter received */
-
- if (!request) {
+ struct smb_info *smb_info = pinfo->private;
+ proto_item *it = NULL;
+ proto_tree *tr = NULL;
+ guint16 acount, ecount;
+ int i;
- WParam = GSHORT(pd, pd_p_current);
+ /* entry count */
+ ecount = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2, ecount);
+ offset += 2;
- proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Returned Word", WParam, WParam);
+ /* available count */
+ acount = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_acount, tvb, offset, 2, acount);
+ offset += 2;
- pd_p_current += 2;
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
- lm_act_count = WParam;
-
- return 1;
-
- }
-
- break;
-
- case 'e': /* An ent count .. */
-
- if (!request) { /* Only relevant in a response */
-
- WParam = GSHORT(pd, pd_p_current);
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: (%04X)", (Name) ? Name : "Entry Count", WParam);
-
- pd_p_current += 2;
-
- lm_ent_count = WParam; /* Save this for later retrieval */
-
- return 1;
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
+ /* create a subtree for all available shares */
+ if (tree) {
+ it = proto_tree_add_text(tree, tvb, offset,
+ tvb_length_remaining(tvb, offset),
+ "Available Shares");
+ tr = proto_item_add_subtree(it, ett_lanman_shares);
}
- break;
+ for (i = 0; i < ecount; i++){
+ proto_item *si = NULL;
+ proto_tree *st = NULL;
+ char *share;
+ int start_offset = offset;
- case 'W': /* Word Parameter */
+ share = (char *)tvb_get_ptr(tvb, offset, 13);
- if (request) { /* A request ... */
-
- /* Insert a word param */
+ if (tree) {
+ si = proto_tree_add_text(tr, tvb, offset,
+ tvb_length_remaining(tvb, offset),
+ "Share %s", share);
+ st = proto_item_add_subtree(si, ett_lanman_shares);
+ }
- WParam = GSHORT(pd, pd_p_current);
+ /* share name */
+ proto_tree_add_item(st, hf_share_name, tvb, offset, 13, TRUE);
+ offset += 13;
- proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Word Param", WParam, WParam);
+ /* pad byte */
+ offset += 1;
- pd_p_current += 2;
+ /* share type */
+ proto_tree_add_item(st, hf_share_type, tvb, offset, 2, TRUE);
+ offset += 2;
- return 1; /* That's it here ... we have dissected a param */
+ /* share comment */
+ offset = add_string_pointer(tvb, st, offset, convert,
+ hf_share_comment);
+ proto_item_set_len(si, offset-start_offset);
}
- break;
-
- case 'i': /* A long word is returned */
-
- if (!request) {
-
- LParam = GWORD(pd, pd_p_current);
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "Returned Long Word", LParam, LParam);
-
- pd_p_current += 2;
+ return offset;
+}
- return 1;
+static int
+netsharegetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ guint share_name_len;
+ guint16 level;
+
+ /* share name */
+ share_name_len = tvb_strsize(tvb, offset);
+ proto_tree_add_item(tree, hf_share_name, tvb, offset, share_name_len,
+ TRUE);
+ offset += share_name_len;
+
+ /* detail level */
+ level = tvb_get_letohs(tvb, offset);
+ request_val->last_level = level; /* remember this for the response */
+ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level);
+ offset += 2;
+
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ return offset;
+}
+static int
+netsharegetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 abytes;
+ guint16 permissions;
+ guint16 max_uses;
+
+ /* available bytes */
+ abytes = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes);
+ offset += 2;
+
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
+
+ /* XXX - what is this field? */
+ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x",
+ tvb_get_letohs(tvb, offset));
+ offset += 2;
+
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
+
+ /* share name */
+ proto_tree_add_item(tree, hf_share_name, tvb, offset, 13, TRUE);
+ offset += 13;
+
+ if (request_val->last_level == 0)
+ return offset; /* that's it, at level 0 */
+
+ /* pad byte */
+ offset += 1;
+
+ /* share type */
+ proto_tree_add_item(tree, hf_share_type, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* share comment */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_share_comment);
+
+ if (request_val->last_level == 1)
+ return offset; /* that's it, at level 1 */
+
+ /* share permissions */
+ /* XXX - do as bit fields */
+ permissions = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_share_permissions, tvb, offset, 2,
+ permissions);
+ offset += 2;
+
+ /* max uses */
+ max_uses = tvb_get_letohs(tvb, offset);
+ if (max_uses == 0xffff) { /* -1 */
+ proto_tree_add_uint_format(tree, hf_share_max_uses, tvb,
+ offset, 2, max_uses, "Share Max Uses: No limit");
+ } else {
+ proto_tree_add_uint(tree, hf_share_max_uses, tvb, offset, 2,
+ max_uses);
}
+ offset += 2;
- break;
-
- case 'D': /* Double Word parameter */
+ /* current uses */
+ max_uses = tvb_get_letohs(tvb, offset);
+ proto_tree_add_item(tree, hf_share_current_uses, tvb, offset, 2, TRUE);
+ offset += 2;
- if (request) {
-
- LParam = GWORD(pd, pd_p_current);
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "DWord Param", LParam, LParam);
-
- pd_p_current += 4;
-
- return 1; /* That's it here */
+ return offset;
+}
+static int
+add_server_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ int offset, int convert, guint16 level)
+{
+ /* server name */
+ proto_tree_add_item(tree, hf_server_name, tvb, offset, 16, TRUE);
+ offset += 16;
+
+ if (level) {
+ /* major version */
+ proto_tree_add_item(tree, hf_server_major, tvb, offset, 1,
+ TRUE);
+ offset += 1;
+
+ /* minor version */
+ proto_tree_add_item(tree, hf_server_minor, tvb, offset, 1,
+ TRUE);
+ offset += 1;
+
+ /* server type flags */
+ dissect_smb_server_type_flags(tvb, pinfo, tree, offset, FALSE);
+ offset += 4;
+
+ /* server comment */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_server_comment);
}
- break;
-
- case 'g': /* A byte or series of bytes is returned */
-
- if (!request) {
-
- bc = get_byte_count(p_desc + p_offset);
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "B", (bc) ? bc : 1, format_text( pd + pd_p_current, (bc) ? bc : 1));
-
- pd_p_current += (bc) ? bc : 1;
-
- return 1;
+ return offset;
+}
- }
+static int
+netservergetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ guint16 level;
- break;
+ /* detail level */
+ level = tvb_get_letohs(tvb, offset);
+ request_val->last_level = level; /* remember this for the response */
+ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level);
+ offset += 2;
- case 'b': /* A byte or series of bytes */
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- if (request) {
+ return offset;
+}
- bc = get_byte_count(p_desc + p_offset); /* This is not clean */
+static int
+netservergetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 abytes;
- /*Bytes = g_malloc(bc + 1); / * Is this needed ? */
+ /* available bytes */
+ abytes = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes);
+ offset += 2;
- proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "B", (bc) ? bc : 1, format_text(pd + pd_p_current, (bc) ? bc : 1));
+ /* XXX - what is this field? */
+ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x",
+ tvb_get_letohs(tvb, offset));
+ offset += 2;
- pd_p_current += (bc) ? bc : 1;
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
- return 1; /* That's it here ... */
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
- }
+ offset = add_server_info(tvb, pinfo, tree, offset, convert,
+ request_val->last_level);
- break;
+ return offset;
+}
- case 'O': /* A null pointer */
+static int
+netusergetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ guint16 level;
- if (request) {
+ /* detail level */
+ level = tvb_get_letohs(tvb, offset);
+ request_val->last_level = level; /* remember this for the response */
+ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level);
+ offset += 2;
- proto_tree_add_text(tree, NullTVB, pd_p_current, 0, "%s: Null Pointer", (Name) ? Name : "Unknown");
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- return 1; /* That's it here */
+ return offset;
+}
+static int
+netusergetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 abytes;
+ struct timeval timeval;
+ guint16 nlogons;
+ guint32 max_storage;
+
+ /* available bytes */
+ abytes = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes);
+ offset += 2;
+
+ /* XXX - what is this field? */
+ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x",
+ tvb_get_letohs(tvb, offset));
+ offset += 2;
+
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
+
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
+
+ /* user name */
+ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
+ offset += 21;
+
+ /* pad1 */
+ offset += 1;
+
+ /* user comment */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_user_comment);
+
+ /* full name */
+ offset = add_string_pointer(tvb, tree, offset, convert, hf_full_name);
+
+ /* privilege level */
+ proto_tree_add_item(tree, hf_privilege_level, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* operator privileges */
+ proto_tree_add_item(tree, hf_operator_privileges, tvb, offset, 4, TRUE);
+ offset += 4;
+
+ /* password age */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ proto_tree_add_time_format(tree, hf_password_age, tvb, offset, 4,
+ &timeval, "Password Age: %s", time_secs_to_str(timeval.tv_sec));
+ offset += 4;
+
+ /* home directory */
+ offset = add_string_pointer(tvb, tree, offset, convert, hf_homedir);
+
+ /* parameters */
+ offset = add_string_pointer(tvb, tree, offset, convert, hf_parameters);
+
+ timeval.tv_usec = 0;
+
+ /* last logon time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_last_logon, tvb, offset, 4,
+ &timeval, "Last Logon Date/Time: Unknown");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_last_logon, tvb, offset, 4,
+ &timeval);
}
-
- break;
-
- case 'z': /* An AsciiZ string */
-
- if (request) {
-
- AsciiZ = pd + pd_p_current;
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, strlen(AsciiZ) + 1, "%s: %s", (Name) ? Name : "AsciiZ", AsciiZ);
-
- pd_p_current += strlen(AsciiZ) + 1;
-
- return 1; /* That's it here ... */
-
+ offset += 4;
+
+ /* last logoff time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_last_logoff, tvb, offset, 4,
+ &timeval, "Last Logoff Date/Time: Unknown");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_last_logoff, tvb, offset, 4,
+ &timeval);
}
+ offset += 4;
- break;
+ /* bad password count */
+ proto_tree_add_item(tree, hf_bad_pw_count, tvb, offset, 2, TRUE);
+ offset += 2;
- case 'F': /* One or more pad bytes */
-
- if (request) {
-
- bc = get_byte_count(pd);
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "Pad", bc, format_text(pd + pd_p_current, bc));
+ /* number of logons */
+ nlogons = tvb_get_letohs(tvb, offset);
+ if (nlogons == 0xffff) /* -1 */
+ proto_tree_add_uint_format(tree, hf_num_logons, tvb, offset, 2,
+ nlogons, "Number of Logons: Unknown");
+ else
+ proto_tree_add_uint(tree, hf_num_logons, tvb, offset, 2,
+ nlogons);
+ offset += 2;
+
+ /* logon server */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_logon_server);
+
+ /* country code */
+ /* XXX - we should have a value_string table for these */
+ proto_tree_add_item(tree, hf_country_code, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* workstations */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_workstations);
+
+ /* max storage */
+ max_storage = tvb_get_letohl(tvb, offset);
+ if (nlogons == 0xffffffff)
+ proto_tree_add_uint_format(tree, hf_max_storage, tvb, offset, 4,
+ max_storage, "Max Storage: No limit");
+ else
+ proto_tree_add_uint(tree, hf_max_storage, tvb, offset, 4,
+ max_storage);
+ offset += 4;
+
+ /* units per week */
+ proto_tree_add_item(tree, hf_units_per_week, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* logon hours */
+ /* XXX - should actually carve up the bits */
+ /* XXX - how do we recognize a null pointer? */
+ offset = add_byte_array_pointer(tvb, tree, offset, 21, convert,
+ hf_logon_hours);
+
+ /* code page */
+ /* XXX - we should have a value_string table for these */
+ proto_tree_add_item(tree, hf_code_page, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ return offset;
+}
- pd_p_current += bc;
+static int
+netremotetod_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- return 1; /* That's it here */
+ return offset;
+}
+static int
+netremotetod_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct timeval timeval;
+ gint16 tzoffset;
+ guint16 timeinterval;
+
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
+
+ /* current time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ timeval.tv_usec = 0;
+ proto_tree_add_time(tree, hf_current_time, tvb, offset, 4, &timeval);
+ offset += 4;
+
+ /* msecs since arbitrary point in the past */
+ timeval.tv_usec = tvb_get_letohl(tvb, offset);
+ offset += 4;
+
+ /* hour */
+ proto_tree_add_item(tree, hf_hour, tvb, offset, 1, TRUE);
+ offset += 1;
+
+ /* minute */
+ proto_tree_add_item(tree, hf_minute, tvb, offset, 1, TRUE);
+ offset += 1;
+
+ /* second */
+ proto_tree_add_item(tree, hf_second, tvb, offset, 1, TRUE);
+ offset += 1;
+
+ /* hundredths-of-second */
+ proto_tree_add_item(tree, hf_hundredths, tvb, offset, 1, TRUE);
+ offset += 1;
+
+ /* time zone offset, in minutes */
+ tzoffset = tvb_get_letohs(tvb, offset);
+ if (tzoffset < 0) {
+ proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
+ tzoffset, "Time Zone Offset: %s east of UTC",
+ time_secs_to_str(-tzoffset*60));
+ } else if (tzoffset > 0) {
+ proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
+ tzoffset, "Time Zone Offset: %s west of UTC",
+ time_secs_to_str(tzoffset*60));
+ } else {
+ proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
+ tzoffset, "Time Zone Offset: at UTC");
}
+ offset += 2;
- break;
+ /* timer resolution */
+ timeinterval = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2,
+ timeinterval, "Time Interval: %f seconds", timeinterval*.0001);
+ offset += 2;
- case 'L': /* Receive buffer len: Short */
+ /* day */
+ proto_tree_add_item(tree, hf_day, tvb, offset, 1, TRUE);
+ offset += 1;
- if (request) {
+ /* month */
+ proto_tree_add_item(tree, hf_month, tvb, offset, 1, TRUE);
+ offset += 1;
- WParam = GSHORT(pd, pd_p_current);
+ /* year */
+ proto_tree_add_item(tree, hf_year, tvb, offset, 2, TRUE);
+ offset += 2;
- proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (0x%04X)", (Name) ? Name : "Receive Buffer Len", WParam, WParam);
+ /* day of week */
+ proto_tree_add_item(tree, hf_weekday, tvb, offset, 1, TRUE);
+ offset += 1;
- pd_p_current += 2;
+ return offset;
+}
- return 1; /* That's it here ... */
+static int
+netserverenum2_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ guint16 level;
- }
+ /* detail level */
+ level = tvb_get_letohs(tvb, offset);
+ request_val->last_level = level; /* remember this for the response */
+ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level);
+ offset += 2;
- break;
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- case 's': /* Send buf ... */
+ /* server type flags */
+ dissect_smb_server_type_flags(tvb, pinfo, tree, offset, TRUE);
+ offset += 4;
- if (request) {
+ return offset;
+}
- need_data = 1;
+static int
+netserverenum2_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 ecount, acount;
+ proto_item *it = NULL;
+ proto_tree *tr = NULL;
+ int i;
- LParam = GWORD(pd, pd_p_current);
+ /* entry count */
+ ecount = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2, ecount);
+ offset += 2;
- proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u", (Name) ? Name : "Send Buffer Ptr", LParam);
+ /* available count */
+ acount = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_acount, tvb, offset, 2, acount);
+ offset += 2;
- pd_p_current += 4;
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
- return 1; /* That's it here ... */
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
+ if (tree) {
+ it = proto_tree_add_text(tree, tvb, offset,
+ tvb_length_remaining(tvb, offset), "Servers");
+ tr = proto_item_add_subtree(it, ett_lanman_servers);
}
- break;
+ for (i = 0; i < ecount; i++) {
+ proto_item *si = NULL;
+ proto_tree *st = NULL;
+ char *server;
+ int old_offset = offset;
- case 'T':
+ server = (char *)tvb_get_ptr(tvb, offset, 16);
+ if (tree) {
+ si = proto_tree_add_text(tr, tvb, offset,
+ request_val->last_level ? 26 : 16,
+ "Server %.16s", server);
+ st = proto_item_add_subtree(si, ett_lanman_server);
+ }
- if (request) {
-
- WParam = GSHORT(pd, pd_p_current);
-
- proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u", (Name) ? Name : "Send Buffer Len", WParam);
-
- pd_p_current += 2;
-
- return 1;
+ offset = add_server_info(tvb, pinfo, st, offset, convert,
+ request_val->last_level);
+ proto_item_set_len(si, offset-old_offset);
}
- break;
-
- default:
-
- break;
-
- }
-
- break;
-
- case 1: /* We are in the data area ... */
-
-
- break;
-
- }
- }
-
- return 0;
-
+ return offset;
}
-static const value_string share_type_vals[] = {
- {0, "Directory tree"},
- {1, "Printer queue"},
- {2, "Communications device"},
- {3, "IPC"},
- {0, NULL}
-};
-
-/*
- * Per-frame data needed to dissect replies.
- */
-typedef struct {
- guint16 FunctionCode;
- gboolean is_continuation;
-} response_data;
-
-static GMemChunk *lanman_proto_data;
-
-static gboolean
-dissect_pipe_lanman(const u_char *pd, int offset, frame_data *fd,
- proto_tree *parent, proto_tree *tree,
- int max_data, int SMB_offset, int errcode,
- const u_char *command, int DataOffset, int DataCount,
- int ParameterOffset, int ParameterCount)
+static int
+netwkstagetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
{
- struct smb_info *smb_info = pi.private;
- gboolean is_interim_response;
- guint32 loc_offset;
- guint16 FunctionCode;
- guint16 Level;
- guint16 RecvBufLen;
- guint32 Flags;
- const char *ParameterDescriptor;
- const char *ReturnDescriptor;
- proto_tree *lanman_tree = NULL, *flags_tree = NULL;
- proto_item *ti;
- struct lanman_desc *lanman;
- guint32 string_offset;
-
- if (DataOffset < 0) {
-
- /* Interim response; we weren't given any data. */
-
- is_interim_response = TRUE;
- loc_offset = SMB_offset;
-
- }
- else {
-
- /* Offset of the data we should dissect. */
-
- is_interim_response = FALSE;
- loc_offset = SMB_offset + ParameterOffset;
-
- }
-
- if (check_col(fd, COL_PROTOCOL))
- col_set_str(fd, COL_PROTOCOL, "LANMAN");
-
- if (smb_info->request) { /* The request side */
-
- FunctionCode = GSHORT(pd, loc_offset);
-
- smb_info->request_val -> last_lanman_cmd = FunctionCode;
-
- lanman = find_lanman(FunctionCode);
-
- if (check_col(fd, COL_INFO)) {
-
- if (lanman) {
- col_add_fstr(fd, COL_INFO, "%s Request", lanman -> lanman_name);
- }
- else {
- col_add_fstr(fd, COL_INFO, "Unknown LANMAN Request: %u", FunctionCode);
- }
- }
-
- if (tree) {
-
- ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, ParameterCount, FALSE);
- lanman_tree = proto_item_add_subtree(ti, ett_lanman);
-
- if (lanman) {
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: %s", lanman -> lanman_name);
- }
- else {
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: Unknown LANMAN Request: %u", FunctionCode);
- }
-
- }
-
- loc_offset += 2;
-
- ParameterDescriptor = pd + loc_offset;
-
- /* Now, save these for later */
-
- smb_info->request_val -> trans_response_seen = 0;
-
- if (smb_info->request_val -> last_param_descrip)
- g_free(smb_info->request_val -> last_param_descrip);
- smb_info->request_val -> last_param_descrip = g_malloc(strlen(ParameterDescriptor) + 1);
- if (smb_info->request_val -> last_param_descrip)
- strcpy(smb_info->request_val -> last_param_descrip, ParameterDescriptor);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ParameterDescriptor) + 1, "Parameter Descriptor: %s", ParameterDescriptor);
-
- }
-
- loc_offset += strlen(ParameterDescriptor) + 1;
-
- ReturnDescriptor = pd + loc_offset;
-
- if (smb_info->request_val -> last_data_descrip)
- g_free(smb_info->request_val -> last_data_descrip);
- smb_info->request_val -> last_data_descrip = g_malloc(strlen(ReturnDescriptor) + 1);
- if (smb_info->request_val -> last_data_descrip)
- strcpy(smb_info->request_val -> last_data_descrip, ReturnDescriptor);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ReturnDescriptor) + 1, "Return Descriptor: %s", ReturnDescriptor);
-
- }
+ guint16 level;
- loc_offset += strlen(ReturnDescriptor) + 1;
+ /* detail level */
+ level = tvb_get_letohs(tvb, offset);
+ request_val->last_level = level; /* remember this for the response */
+ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level);
+ offset += 2;
- switch (FunctionCode) {
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- case NETSHAREENUM: /* Never decode this at the moment ... */
-
- Level = GSHORT(pd, loc_offset);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Detail Level: %u", Level);
-
- }
-
- loc_offset += 2;
-
- RecvBufLen = GSHORT(pd, loc_offset);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
-
- }
-
- loc_offset += 2;
-
- break;
-
- case NETSERVERENUM2: /* Process a NetServerEnum2 */
-
- Level = GSHORT(pd, loc_offset);
- smb_info->request_val -> last_level = Level;
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Info Detail Level: %u", Level);
-
- }
-
- loc_offset += 2;
-
- RecvBufLen = GSHORT(pd, loc_offset);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
-
- }
-
- loc_offset += 2;
-
- Flags = GWORD(pd, loc_offset);
-
- if (tree) {
-
- ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 4, "Server Types Required: 0x%08X", Flags);
- flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
- dissect_server_flags(flags_tree, loc_offset, 4, Flags);
-
- }
-
- loc_offset += 4;
-
- return TRUE;
- break;
-
- default: /* Just try to handle what is there ... */
-
- if (tree) {
-
- int i = 0; /* Counter for names below */
- char *name = NULL;
+ return offset;
+}
- dissect_transact_engine_init(pd, ParameterDescriptor, ReturnDescriptor,SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
+static int
+netwkstagetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 abytes;
- if (lanman) name = lanman -> req[i]; /* Must be OK ... */
+ /* available bytes */
+ abytes = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes);
+ offset += 2;
- while (dissect_transact_next(pd, name, smb_info->request, lanman_tree))
- if (name) name = lanman -> req[++i];
- }
+ /* XXX - what is this field? */
+ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x",
+ tvb_get_letohs(tvb, offset));
+ offset += 2;
- break;
-
- }
- }
- else { /* response */
- response_data *proto_data;
- guint16 Status;
- guint16 Convert;
- guint16 EntCount;
- guint16 AvailCount;
- int i;
- proto_tree *server_tree = NULL, *flags_tree = NULL, *share_tree = NULL;
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
- /* Is there any per-frame LANMAN data for this frame? */
- proto_data = p_get_proto_data(fd, proto_smb_lanman);
- if (proto_data == NULL) {
- /* No. Allocate some, and set it up. */
- proto_data = g_mem_chunk_alloc(lanman_proto_data);
- proto_data->FunctionCode = smb_info->request_val -> last_lanman_cmd;
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
- /*
- * If we've already seen a response to the request, this must
- * be a continuation of that response.
- */
- proto_data->is_continuation = smb_info->request_val -> trans_response_seen;
+ /* computer name */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_computer_name);
- /*
- * Attach it to the frame.
- */
- p_add_proto_data(fd, proto_smb_lanman, proto_data);
- }
+ /* user name */
+ offset = add_string_pointer(tvb, tree, offset, convert, hf_user_name);
- FunctionCode = proto_data->FunctionCode;
+ /* workstation domain */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_workstation_domain);
- /*
- * If we have already seen the response to this transact, simply
- * record it as a continuation ...
- */
- if (proto_data->is_continuation) {
+ /* major version */
+ proto_tree_add_item(tree, hf_workstation_major, tvb, offset, 1, TRUE);
+ offset += 1;
- if (check_col(fd, COL_INFO)) {
- col_set_str(fd, COL_INFO, "Transact Continuation");
- }
-
- if (tree) {
+ /* minor version */
+ proto_tree_add_item(tree, hf_workstation_minor, tvb, offset, 1, TRUE);
+ offset += 1;
- ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, END_OF_FRAME, FALSE);
+ /* logon domain */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_logon_domain);
- lanman_tree = proto_item_add_subtree(ti, ett_lanman);
+ /* other domains */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_other_domains);
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, END_OF_FRAME, "Payload: %s", format_text(pd + loc_offset, END_OF_FRAME));
+ return offset;
+}
- }
+static int
+netwkstauserlogon_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ guint16 level;
- return TRUE;
+ /* detail level */
+ level = tvb_get_letohs(tvb, offset);
+ request_val->last_level = level; /* remember this for the response */
+ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level);
+ offset += 2;
- }
+ /* user name */
+ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
+ offset += 21;
- smb_info->request_val -> trans_response_seen = 1;
+ /* pad1 */
+ offset += 1;
- lanman = find_lanman(FunctionCode);
+ /* password */
+ proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE);
+ offset += 15;
- if (check_col(fd, COL_INFO)) {
+ /* pad2 */
+ offset += 1;
- if (lanman) {
- col_add_fstr(fd, COL_INFO, "%s %sResponse", lanman -> lanman_name,
- is_interim_response ? "Interim " : "");
- }
- else {
- col_add_fstr(fd, COL_INFO, "Unknown LANMAN %sResponse: %u",
- is_interim_response ? "Interim " : "", FunctionCode);
- }
- }
+ /* workstation name */
+ proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
+ offset += 16;
- if (tree) {
+ /* size of the above */
+ proto_tree_add_item(tree, hf_ustruct_size, tvb, offset, 2, TRUE);
+ offset += 2;
- ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, END_OF_FRAME, FALSE);
- lanman_tree = proto_item_add_subtree(ti, ett_lanman);
- if (lanman) {
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: %s", lanman -> lanman_name);
- }
- else {
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: Unknown LANMAN Response: %u", FunctionCode);
- }
- }
+ /* receiver buffer length */
+ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE);
+ offset += 2;
- if (is_interim_response) {
+ return offset;
+}
- return TRUE; /* no data to dissect */
+static int
+netwkstauserlogon_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 abytes;
+ guint16 nlogons;
+ struct timeval timeval;
+
+ /* available bytes */
+ abytes = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes);
+ offset += 2;
+
+ /* XXX - what is this field? */
+ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x",
+ tvb_get_letohs(tvb, offset));
+ offset += 2;
+
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
+
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
+
+ /* logon code */
+ proto_tree_add_item(tree, hf_logon_code, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* user name */
+ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
+ offset += 21;
+
+ /* pad1 */
+ offset += 1;
+
+ /* privilege level */
+ proto_tree_add_item(tree, hf_privilege_level, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* operator privileges */
+ proto_tree_add_item(tree, hf_operator_privileges, tvb, offset, 4, TRUE);
+ offset += 4;
+
+ /* number of logons */
+ nlogons = tvb_get_letohs(tvb, offset);
+ if (nlogons == 0xffff) /* -1 */
+ proto_tree_add_uint_format(tree, hf_num_logons, tvb, offset, 2,
+ nlogons, "Number of Logons: Unknown");
+ else
+ proto_tree_add_uint(tree, hf_num_logons, tvb, offset, 2,
+ nlogons);
+ offset += 2;
+
+ /* bad password count */
+ proto_tree_add_item(tree, hf_bad_pw_count, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ timeval.tv_usec = 0;
+
+ /* last logon time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_last_logon, tvb, offset, 4,
+ &timeval, "Last Logon Date/Time: Unknown");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_last_logon, tvb, offset, 4,
+ &timeval);
+ }
+ offset += 4;
+
+ /* last logoff time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_last_logoff, tvb, offset, 4,
+ &timeval, "Last Logoff Date/Time: Unknown");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_last_logoff, tvb, offset, 4,
+ &timeval);
+ }
+ offset += 4;
+
+ /* logoff time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_logoff_time, tvb, offset, 4,
+ &timeval, "Logoff Date/Time: None");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_logoff_time, tvb, offset, 4,
+ &timeval);
+ }
+ offset += 4;
+
+ /* kickoff time */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_kickoff_time, tvb, offset, 4,
+ &timeval, "Kickoff Date/Time: None");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_kickoff_time, tvb, offset, 4,
+ &timeval);
+ }
+ offset += 4;
+
+ /* password age */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ proto_tree_add_time_format(tree, hf_password_age, tvb, offset, 4,
+ &timeval, "Password Age: %s", time_secs_to_str(timeval.tv_sec));
+ offset += 4;
+
+ /* date/time when password can change */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_password_can_change, tvb, offset, 4,
+ &timeval, "Password Can Change: Never");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_password_can_change, tvb, offset, 4,
+ &timeval);
+ }
+ offset += 4;
+
+ /* date/time when password must change */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ if (timeval.tv_sec == -1) {
+ proto_tree_add_time_format(tree, hf_password_must_change, tvb, offset, 4,
+ &timeval, "Password Must Change: Never");
+ } else {
+ timeval.tv_sec = localtime_to_utc(timeval.tv_sec);
+ proto_tree_add_time(tree, hf_password_must_change, tvb, offset, 4,
+ &timeval);
+ }
+ offset += 4;
- }
+ /* computer where user is logged on */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_server_name);
- switch (FunctionCode) {
+ /* domain in which user is logged on */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_logon_domain);
- case NETSHAREENUM:
+ /* pathname of user's login script */
+ offset = add_string_pointer(tvb, tree, offset, convert,
+ hf_script_path);
- Status = GSHORT(pd, loc_offset);
+ /* reserved */
+ proto_tree_add_text(tree, tvb, offset, 4, "Reserved: %08x",
+ tvb_get_letohl(tvb, offset));
+ offset += 4;
- if (tree) {
+ return offset;
+}
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
+static int
+netwkstauserlogoff_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ /* user name */
+ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
+ offset += 21;
- }
+ /* pad1 */
+ offset += 1;
- loc_offset += 2;
+ /* workstation name */
+ proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
+ offset += 16;
- Convert = GSHORT(pd, loc_offset);
+ return offset;
+}
- if (tree) {
+static int
+netwkstauserlogoff_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint16 abytes;
+ guint16 nlogons;
+ struct timeval timeval;
+
+ /* available bytes */
+ abytes = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes);
+ offset += 2;
+
+ /* XXX - what is this field? */
+ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x",
+ tvb_get_letohs(tvb, offset));
+ offset += 2;
+
+ if (status != 0 && status != SMBE_moredata)
+ return offset;
+
+ /* The rest is in the data section. */
+ offset = smb_info->data_offset;
+
+ /* logoff code */
+ proto_tree_add_item(tree, hf_logoff_code, tvb, offset, 2, TRUE);
+ offset += 2;
+
+ /* duration */
+ timeval.tv_sec = tvb_get_letohl(tvb, offset);
+ timeval.tv_usec = 0;
+ proto_tree_add_time_format(tree, hf_duration, tvb, offset, 4,
+ &timeval, "Duration of Session: %s", time_secs_to_str(timeval.tv_sec));
+ offset += 4;
+
+ /* number of logons */
+ nlogons = tvb_get_letohs(tvb, offset);
+ if (nlogons == 0xffff) /* -1 */
+ proto_tree_add_uint_format(tree, hf_num_logons, tvb, offset, 2,
+ nlogons, "Number of Logons: Unknown");
+ else
+ proto_tree_add_uint(tree, hf_num_logons, tvb, offset, 2,
+ nlogons);
+ offset += 2;
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
+ return offset;
+}
- }
+static int
+samoemchangepassword_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset)
+{
+ struct smb_info *smb_info = pinfo->private;
+ guint user_name_len;
- loc_offset += 2;
+ /* user name */
+ user_name_len = tvb_strsize(tvb, offset);
+ proto_tree_add_item(tree, hf_user_name, tvb, offset, user_name_len,
+ TRUE);
+ offset += user_name_len;
- EntCount = GSHORT(pd, loc_offset);
+ /* new password */
+ proto_tree_add_item(tree, hf_new_password, tvb,
+ smb_info->data_offset, 516, TRUE);
- if (tree) {
+ /* old password */
+ proto_tree_add_item(tree, hf_old_password, tvb,
+ smb_info->data_offset + 516, 16, TRUE);
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
+ return offset;
+}
- }
+static int
+samoemchangepassword_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val, int offset, guint16 status,
+ int convert)
+{
+ /* nothing in this reply */
+ return offset;
+}
- loc_offset += 2;
+#define LANMAN_NETSHAREENUM 0
+#define LANMAN_NETSHAREGETINFO 1
+#define LANMAN_NETSERVERGETINFO 13
+#define LANMAN_NETGROUPGETUSERS 52
+#define LANMAN_NETUSERGETINFO 56
+#define LANMAN_NETUSERGETGROUPS 59
+#define LANMAN_NETWKSTAGETINFO 63
+#define LANMAN_DOSPRINTQENUM 69
+#define LANMAN_DOSPRINTQGETINFO 70
+#define LANMAN_WPRINTQUEUEPAUSE 74
+#define LANMAN_WPRINTQUEUERESUME 75
+#define LANMAN_WPRINTJOBENUMERATE 76
+#define LANMAN_WPRINTJOBGETINFO 77
+#define LANMAN_RDOSPRINTJOBDEL 81
+#define LANMAN_RDOSPRINTJOBPAUSE 82
+#define LANMAN_RDOSPRINTJOBRESUME 83
+#define LANMAN_WPRINTDESTENUM 84
+#define LANMAN_WPRINTDESTGETINFO 85
+#define LANMAN_NETREMOTETOD 91
+#define LANMAN_WPRINTQUEUEPURGE 103
+#define LANMAN_NETSERVERENUM2 104
+#define LANMAN_WACCESSGETUSERPERMS 105
+#define LANMAN_SETUSERPASSWORD 115
+#define LANMAN_NETWKSTAUSERLOGON 132
+#define LANMAN_NETWKSTAUSERLOGOFF 133
+#define LANMAN_PRINTJOBINFO 147
+#define LANMAN_WPRINTDRIVERENUM 205
+#define LANMAN_WPRINTQPROCENUM 206
+#define LANMAN_WPRINTPORTENUM 207
+#define LANMAN_SAMOEMCHANGEPASSWORD 214
+
+static const value_string commands[] = {
+ {LANMAN_NETSHAREENUM, "NetShareEnum"},
+ {LANMAN_NETSHAREGETINFO, "NetShareGetInfo"},
+ {LANMAN_NETSERVERGETINFO, "NetServerGetInfo"},
+ {LANMAN_NETGROUPGETUSERS, "NetGroupGetUsers"},
+ {LANMAN_NETUSERGETINFO, "NetUserGetInfo"},
+ {LANMAN_NETUSERGETGROUPS, "NetUserGetGroups"},
+ {LANMAN_NETWKSTAGETINFO, "NetWkstaGetInfo"},
+ {LANMAN_DOSPRINTQENUM, "DOSPrintQEnum"},
+ {LANMAN_DOSPRINTQGETINFO, "DOSPrintQGetInfo"},
+ {LANMAN_WPRINTQUEUEPAUSE, "WPrintQueuePause"},
+ {LANMAN_WPRINTQUEUERESUME, "WPrintQueueResume"},
+ {LANMAN_WPRINTJOBENUMERATE, "WPrintJobEnumerate"},
+ {LANMAN_WPRINTJOBGETINFO, "WPrintJobGetInfo"},
+ {LANMAN_RDOSPRINTJOBDEL, "RDOSPrintJobDel"},
+ {LANMAN_RDOSPRINTJOBPAUSE, "RDOSPrintJobPause"},
+ {LANMAN_RDOSPRINTJOBRESUME, "RDOSPrintJobResume"},
+ {LANMAN_WPRINTDESTENUM, "WPrintDestEnum"},
+ {LANMAN_WPRINTDESTGETINFO, "WPrintDestGetInfo"},
+ {LANMAN_NETREMOTETOD, "NetRemoteTOD"},
+ {LANMAN_WPRINTQUEUEPURGE, "WPrintQueuePurge"},
+ {LANMAN_NETSERVERENUM2, "NetServerEnum2"},
+ {LANMAN_WACCESSGETUSERPERMS, "WAccessGetUserPerms"},
+ {LANMAN_SETUSERPASSWORD, "SetUserPassword"},
+ {LANMAN_NETWKSTAUSERLOGON, "NetWkstaUserLogon"},
+ {LANMAN_NETWKSTAUSERLOGOFF, "NetWkstaUserLogoff"},
+ {LANMAN_PRINTJOBINFO, "PrintJobInfo"},
+ {LANMAN_WPRINTDRIVERENUM, "WPrintDriverEnum"},
+ {LANMAN_WPRINTQPROCENUM, "WPrintQProcEnum"},
+ {LANMAN_WPRINTPORTENUM, "WPrintPortEnum"},
+ {LANMAN_SAMOEMCHANGEPASSWORD, "SamOEMChangePassword"},
+ {0, NULL}
+};
- AvailCount = GSHORT(pd, loc_offset);
+struct lanman_dissector {
+ int command;
+ int (*request)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val,
+ int offset);
+ int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ struct smb_request_val *request_val,
+ int offset, guint16 status, int convert);
+};
- if (tree) {
+struct lanman_dissector lmd[] = {
+ { LANMAN_NETSHAREENUM,
+ netshareenum_request,
+ netshareenum_response },
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
+ { LANMAN_NETSHAREGETINFO,
+ netsharegetinfo_request,
+ netsharegetinfo_response },
- }
+ { LANMAN_NETSERVERGETINFO,
+ netservergetinfo_request,
+ netservergetinfo_response },
- loc_offset += 2;
+ { LANMAN_NETUSERGETINFO,
+ netusergetinfo_request,
+ netusergetinfo_response },
- if (tree) {
+ { LANMAN_NETREMOTETOD,
+ netremotetod_request,
+ netremotetod_response },
- ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, AvailCount * 20, "Available Shares");
+ { LANMAN_NETSERVERENUM2,
+ netserverenum2_request,
+ netserverenum2_response },
- share_tree = proto_item_add_subtree(ti, ett_lanman_shares);
+ { LANMAN_NETWKSTAGETINFO,
+ netwkstagetinfo_request,
+ netwkstagetinfo_response },
- }
+ { LANMAN_NETWKSTAUSERLOGON,
+ netwkstauserlogon_request,
+ netwkstauserlogon_response },
- for (i = 1; i <= EntCount; i++) {
- const gchar *Share = pd + loc_offset;
- guint32 Flags;
- const gchar *Comment;
- proto_tree *share = NULL;
- proto_item *ti = NULL;
+ { LANMAN_NETWKSTAUSERLOGOFF,
+ netwkstauserlogoff_request,
+ netwkstauserlogoff_response },
- if (tree) {
+ { LANMAN_SAMOEMCHANGEPASSWORD,
+ samoemchangepassword_request,
+ samoemchangepassword_response },
- ti = proto_tree_add_text(share_tree, NullTVB, loc_offset, 20, "Share %s", Share);
- share = proto_item_add_subtree(ti, ett_lanman_share);
+ { -1, NULL, NULL }
+};
+struct lanman_dissector *find_lanman_dissector(int cmd)
+{
+ int i;
+ for (i = 0; lmd[i].command != -1; i++) {
+ if (lmd[i].command == cmd)
+ return &lmd[i];
}
+ return NULL;
+}
- if (tree) {
-
- proto_tree_add_text(share, NullTVB, loc_offset, 13, "Share Name: %s", Share);
-
+static gboolean
+dissect_pipe_lanman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+{
+ struct smb_info *smb_info = pinfo->private;
+ struct smb_request_val *request_val = smb_info->request_val;
+ int offset = 0;
+ guint16 cmd;
+ guint16 status;
+ int convert;
+ proto_item *item = NULL;
+ proto_tree *tree = NULL;
+ struct lanman_dissector *dis;
+ guint param_descriptor_len, return_descriptor_len;
+
+ if (check_col(pinfo->fd, COL_PROTOCOL)) {
+ col_set_str(pinfo->fd, COL_PROTOCOL, "LANMAN");
}
- loc_offset += 13;
-
- loc_offset += 1; /* Pad byte ... */
-
- Flags = GSHORT(pd, loc_offset);
-
- if (tree) {
-
- proto_tree_add_text(share, NullTVB, loc_offset, 2, "Share Type: %s",
- val_to_str(Flags, share_type_vals, "Unknown (%u)"));
-
+ if (parent_tree) {
+ item = proto_tree_add_item(parent_tree, proto_smb_lanman,
+ tvb, 0, tvb_length(tvb), FALSE);
+ tree = proto_item_add_subtree(item, ett_lanman);
}
- loc_offset += 2;
-
- /* XXX - should check whether all of the string is within the
- frame. */
- string_offset = SMB_offset + DataOffset + (GWORD(pd, loc_offset) & 0xFFFF) - Convert;
- if (IS_DATA_IN_FRAME(string_offset))
- Comment = pd + string_offset;
- else
- Comment = "<String goes past end of frame>";
-
- if (tree) {
-
- proto_tree_add_text(share, NullTVB, loc_offset, 4, "Share Comment: %s", Comment);
-
+ /* continuation messages, dont try to decode them */
+ if (smb_info->ddisp) {
+ if (check_col(pinfo->fd, COL_INFO)) {
+ col_set_str(pinfo->fd, COL_INFO, "Transact Continuation");
+ }
+ return TRUE;
}
- loc_offset += 4;
-
- }
-
- break;
-
- case NETSERVERENUM2:
-
- Status = GSHORT(pd, loc_offset);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
-
- }
-
- loc_offset += 2;
-
- Convert = GSHORT(pd, loc_offset);
-
- if (tree) {
-
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
-
- }
-
- loc_offset += 2;
+ if (smb_info->request) { /* this is a request */
+ /* function code */
+ cmd = tvb_get_letohs(tvb, offset);
+ if (check_col(pinfo->fd, COL_INFO)) {
+ col_add_fstr(pinfo->fd, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command:0x%02x"));
+ }
+ proto_tree_add_uint(tree, hf_function_code, 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.
+ */
+ if (!pinfo->fd->flags.visited)
+ request_val->last_lanman_cmd = cmd;
+
+ /* parameter descriptor */
+ param_descriptor_len = tvb_strsize(tvb, offset);
+ proto_tree_add_item(tree, hf_param_desc, tvb, offset,
+ param_descriptor_len, TRUE);
+ if (pinfo->fd->flags.visited) {
+ /*
+ * Save the parameter descriptor for future use.
+ */
+ g_assert(request_val->last_param_descrip == NULL);
+ request_val->last_param_descrip =
+ g_malloc(param_descriptor_len);
+ strcpy(request_val->last_param_descrip,
+ tvb_get_ptr(tvb, offset, param_descriptor_len));
+ }
+ offset += param_descriptor_len;
+
+ /* return descriptor */
+ return_descriptor_len = tvb_strsize(tvb, offset);
+ proto_tree_add_item(tree, hf_return_desc, tvb, offset,
+ return_descriptor_len, TRUE);
+ if (pinfo->fd->flags.visited) {
+ /*
+ * Save the return descriptor for future use.
+ */
+ g_assert(request_val->last_data_descrip == NULL);
+ request_val->last_data_descrip =
+ g_malloc(return_descriptor_len);
+ strcpy(request_val->last_data_descrip,
+ tvb_get_ptr(tvb, offset, return_descriptor_len));
+ }
+ offset += return_descriptor_len;
+
+ /* command parameters */
+ dis = find_lanman_dissector(cmd);
+ if (dis == NULL) {
+ offset = not_implemented(tvb, pinfo, tree, offset);
+ return FALSE;
+ }
+ offset = (*(dis->request))(tvb, pinfo, tree, request_val,
+ offset);
+ } else {
+ /*
+ * This is a response.
+ * Have we seen the request to which it's a response?
+ */
+ if (request_val == NULL)
+ return FALSE; /* no - can't dissect it */
+
+ /* ok we have seen this one before */
+
+ /* response to the request in frame xx */
+ proto_tree_add_uint(tree, hf_response_to, tvb, 0, 0,
+ request_val->frame);
+ /* command */
+ if (check_col(pinfo->fd, COL_INFO)) {
+ col_add_fstr(pinfo->fd, COL_INFO, "%s %sResponse",
+ val_to_str(request_val->last_lanman_cmd, commands, "Unknown Command (0x%02x)"),
+ smb_info->is_interim_response ? "Interim " : "");
+ }
+ proto_tree_add_uint(tree, hf_function_code, tvb, 0, 0,
+ request_val->last_lanman_cmd);
+
+ if (smb_info->is_interim_response)
+ return TRUE; /* no data to dissect */
+
+ /* command parameters */
+
+ /* status */
+ status = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_status, tvb, offset, 2, status);
+ offset += 2;
+
+ /* convert */
+ convert = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_convert, tvb, offset, 2, convert);
+ offset += 2;
+
+ /*
+ * "convert" is relative to the beginning of the data
+ * area, but we're handed a tvbuff that starts at the
+ * beginning of the parameter area, so we need to
+ * add "smb_info->data_offset" to offsets after
+ * subtracting "convert"; subtract it from "convert"
+ * so that it gets added in for free.
+ */
+ convert -= smb_info->data_offset;
+
+ dis = find_lanman_dissector(request_val->last_lanman_cmd);
+ if (dis == NULL) {
+ offset = not_implemented(tvb, pinfo, tree, offset);
+ return FALSE;
+ }
+ offset = (*(dis->response))(tvb, pinfo, tree, request_val,
+ offset, status, convert);
+ }
- EntCount = GSHORT(pd, loc_offset);
+ return TRUE;
+}
- if (tree) {
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
- }
+gboolean
+dissect_pipe_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ char *command)
+{
+ if (!proto_is_protocol_enabled(proto_smb_lanman))
+ return FALSE;
+ pinfo->current_proto = "LANMAN";
- loc_offset += 2;
+ if (command != NULL && strcmp(command, "LANMAN") == 0) {
+ /* Try to decode a LANMAN */
- AvailCount = GSHORT(pd, loc_offset);
+ return dissect_pipe_lanman(tvb, pinfo, tree);
+ }
- if (tree) {
+ return FALSE;
+}
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
+void
+register_proto_smb_pipe(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 }},
- loc_offset += 2;
+ { &hf_return_desc,
+ { "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Return Descriptor", HFILL }},
- if (tree) {
+ { &hf_not_implemented,
+ { "Unknown Data", "lanman.not_implemented", FT_BYTES, BASE_HEX,
+ NULL, 0, "Decoding of this data is not implemented yet", HFILL }},
- ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 26 * AvailCount, "Servers");
- if (ti == NULL) {
+ { &hf_detail_level,
+ { "Detail Level", "lanman.level", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Detail Level", HFILL }},
- printf("Null value returned from proto_tree_add_text\n");
- exit(1);
+ { &hf_recv_buf_len,
+ { "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Receive Buffer Length", HFILL }},
- }
+ { &hf_response_to,
+ { "Response to request in frame", "lanman.response_to", FT_UINT32, BASE_DEC,
+ NULL, 0, "This is a LANMAN response to the request in frame", HFILL }},
- server_tree = proto_item_add_subtree(ti, ett_lanman_servers);
+ { &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 }},
- /* Make sure we don't go past the end of the capture buffer */
+ { &hf_ecount,
+ { "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Number of Entries", HFILL }},
- for (i = 1; (i <= EntCount) && ((pi.captured_len - loc_offset) >= 16); i++) {
- const gchar *Server = pd + loc_offset;
- gint8 ServerMajor;
- guint ServerMinor;
- guint32 ServerFlags;
- const gchar *Comment;
- proto_tree *server = NULL;
- proto_item *ti;
+ { &hf_acount,
+ { "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Number of Available Entries", HFILL }},
- if (tree) {
+ { &hf_share_name,
+ { "Share Name", "lanman.share.name", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Name of Share", HFILL }},
- ti = proto_tree_add_text(server_tree, NullTVB, loc_offset,
- (smb_info->request_val -> last_level) ? 26 : 16,
- "Server %s", Server);
- server = proto_item_add_subtree(ti, ett_lanman_server);
+ { &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 }},
- if (tree) {
-
- proto_tree_add_text(server, NullTVB, loc_offset, 16, "Server Name: %s", Server);
+ { &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 }},
- loc_offset += 16;
+ { &hf_server_name,
+ { "Server Name", "lanman.server.name", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Name of Server", HFILL }},
- if (smb_info->request_val -> last_level) { /* Print out the rest of the info */
+ { &hf_server_major,
+ { "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC,
+ NULL, 0, "LANMAN Server Major Version", HFILL }},
- ServerMajor = GBYTE(pd, loc_offset);
+ { &hf_server_minor,
+ { "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC,
+ NULL, 0, "LANMAN Server Minor Version", HFILL }},
- if (tree) {
+ { &hf_server_comment,
+ { "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Server Comment", HFILL }},
- proto_tree_add_text(server, NullTVB, loc_offset, 1, "Major Version: %u", ServerMajor);
+ { &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 }},
- loc_offset += 1;
+ { &hf_msecs,
+ { "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC,
+ NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }},
- ServerMinor = GBYTE(pd, loc_offset);
+ { &hf_hour,
+ { "Hour", "lanman.hour", FT_UINT8, BASE_DEC,
+ NULL, 0, "LANMAN Current hour", HFILL }},
- if (tree) {
+ { &hf_minute,
+ { "Minute", "lanman.minute", FT_UINT8, BASE_DEC,
+ NULL, 0, "LANMAN Current minute", HFILL }},
- proto_tree_add_text(server, NullTVB, loc_offset, 1, "Minor Version: %u", ServerMinor);
+ { &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 }},
- loc_offset += 1;
+ { &hf_tzoffset,
+ { "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC,
+ NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }},
- ServerFlags = GWORD(pd, loc_offset);
+ { &hf_timeinterval,
+ { "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }},
- if (tree) {
+ { &hf_day,
+ { "Day", "lanman.day", FT_UINT8, BASE_DEC,
+ NULL, 0, "LANMAN Current day", HFILL }},
- ti = proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Type: 0x%08X", ServerFlags);
- flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
- dissect_server_flags(flags_tree, loc_offset, 4, ServerFlags);
+ { &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 }},
- loc_offset += 4;
+ { &hf_weekday,
+ { "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC,
+ VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }},
- /* XXX - should check whether all of the string is within the
- frame. */
- string_offset = SMB_offset + DataOffset + (GWORD(pd, loc_offset) & 0xFFFF) - Convert;
- if (IS_DATA_IN_FRAME(string_offset))
- Comment = pd + string_offset;
- else
- Comment = "<String goes past end of frame>";
+ { &hf_computer_name,
+ { "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Computer Name", HFILL }},
- if (tree) {
+ { &hf_user_name,
+ { "User Name", "lanman.user_name", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN User Name", HFILL }},
- proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Comment: %s", Comment);
+ { &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 }},
- loc_offset += 4;
+ { &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 }},
- break;
+ { &hf_password,
+ { "Password", "lanman.password", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Password", HFILL }},
- default:
+ { &hf_workstation_name,
+ { "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Workstation Name", HFILL }},
- Status = GSHORT(pd, loc_offset);
+ { &hf_ustruct_size,
+ { "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN UStruct Length", HFILL }},
- if (tree) {
+ { &hf_logon_code,
+ { "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC,
+ VALS(status_vals), 0, "LANMAN Logon Code", HFILL }},
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
+ { &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 }},
- loc_offset += 2;
+ { &hf_num_logons,
+ { "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Number of Logons", HFILL }},
- Convert = GSHORT(pd, loc_offset);
+ { &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 }},
- if (tree) {
+ { &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 }},
- proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
+ { &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 }},
- loc_offset += 2;
+ { &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 }},
- if (tree) {
+ { &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 }},
- int i = 0;
- char *name = NULL;
+ { &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 }},
- dissect_transact_engine_init(pd, smb_info->request_val -> last_param_descrip, smb_info->request_val -> last_data_descrip, SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
+ { &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 }},
- if (lanman) name = lanman -> resp[i];
-
- while (dissect_transact_next(pd, name, smb_info->request, lanman_tree))
- if (name) name = lanman -> resp[++i];
-
- }
+ { &hf_script_path,
+ { "Script Path", "lanman.script_path", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Pathname of user's logon script", HFILL }},
- return TRUE;
- break;
+ { &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_user_comment,
+ { "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN User Comment", HFILL }},
- return FALSE;
+ { &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 }},
-gboolean
-dissect_pipe_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, int max_data, int SMB_offset, int errcode, const u_char *command, int DataOffset, int DataCount, int ParameterOffset, int ParameterCount)
-{
+ { &hf_parameters,
+ { "Parameters", "lanman.parameters", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Parameters", HFILL }},
- if (!proto_is_protocol_enabled(proto_smb_lanman))
- return FALSE;
+ { &hf_logon_server,
+ { "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE,
+ NULL, 0, "LANMAN Logon Server", HFILL }},
- if (command != NULL && strcmp(command, "LANMAN") == 0) {
- /* Try to decode a LANMAN */
+ { &hf_country_code,
+ { "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Country Code", HFILL }},
- return dissect_pipe_lanman(pd, offset, fd, parent, tree, max_data,
- SMB_offset, errcode, command, DataOffset,
- DataCount, ParameterOffset, ParameterCount);
+ { &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 }},
- return FALSE;
+ { &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 }},
-static void
-pipe_lanman_init_protocol(void)
-{
- if (lanman_proto_data != NULL)
- g_mem_chunk_destroy(lanman_proto_data);
+ { &hf_code_page,
+ { "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC,
+ NULL, 0, "LANMAN Code Page", HFILL }},
- lanman_proto_data = g_mem_chunk_new("lanman_proto_data",
- sizeof(response_data),
- 100 * sizeof(response_data),
- G_ALLOC_AND_FREE);
-}
+ { &hf_new_password,
+ { "New Password", "lanman.new_password", FT_BYTES, BASE_HEX,
+ NULL, 0, "LANMAN New Password (encrypted)", HFILL }},
-void
-register_proto_smb_pipe( void){
+ { &hf_old_password,
+ { "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX,
+ NULL, 0, "LANMAN Old Password (encrypted)", HFILL }},
+ };
static gint *ett[] = {
@@ -1189,13 +1835,12 @@ register_proto_smb_pipe( void){
&ett_lanman_server,
&ett_lanman_shares,
&ett_lanman_share,
- &ett_lanman_flags
};
proto_smb_lanman = proto_register_protocol(
"Microsoft Windows Lanman Protocol", "LANMAN", "lanman");
+ proto_register_field_array(proto_smb_lanman, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- register_init_routine(&pipe_lanman_init_protocol);
}
diff --git a/packet-smb-pipe.h b/packet-smb-pipe.h
index a0717aaf5a..db30e8bb74 100644
--- a/packet-smb-pipe.h
+++ b/packet-smb-pipe.h
@@ -2,10 +2,10 @@
* Declarations of routines for SMB named pipe packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: packet-smb-pipe.h,v 1.3 2001/08/05 00:16:36 guy Exp $
+ * $Id: packet-smb-pipe.h,v 1.4 2001/08/05 01:15:26 guy Exp $
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
@@ -23,8 +23,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef _PACKET_SMB_PIPE_H_
+#define _PACKET_SMB_PIPE_H_
+
gboolean
-dissect_pipe_smb(const u_char *pd, int offset, frame_data *fd,
- proto_tree *parent, proto_tree *tree, int max_data,
- int SMB_offset, int errcode, const u_char *command,
- int DataOffset, int DataCount, int ParameterOffset, int ParameterCount);
+dissect_pipe_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ char *command);
+
+#endif
diff --git a/packet-smb.c b/packet-smb.c
index 4c23d6ed5d..3475032ae1 100644
--- a/packet-smb.c
+++ b/packet-smb.c
@@ -2,7 +2,7 @@
* Routines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: packet-smb.c,v 1.94 2001/08/05 00:30:41 guy Exp $
+ * $Id: packet-smb.c,v 1.95 2001/08/05 01:15:26 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -8973,6 +8973,7 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
new_request_key -> pid = si.pid;
request_val = g_mem_chunk_alloc(smb_request_vals);
+ request_val -> frame = fd->num;
request_val -> last_transact2_command = -1; /* unknown */
request_val -> last_transact_command = NULL;
request_val -> last_param_descrip = NULL;
@@ -9114,6 +9115,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
/* Build display for: Parameter Count */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
ParameterCount = GSHORT(pd, offset);
if (tree) {
@@ -9126,6 +9130,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
/* Build display for: Parameter Offset */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
ParameterOffset = GSHORT(pd, offset);
if (tree) {
@@ -9138,6 +9145,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
/* Build display for: Data Count */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
DataCount = GSHORT(pd, offset);
if (tree) {
@@ -9150,6 +9160,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
/* Build display for: Data Offset */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
DataOffset = GSHORT(pd, offset);
if (tree) {
@@ -9162,6 +9175,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
/* Build display for: Setup Count */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
SetupCount = GBYTE(pd, offset);
if (tree) {
@@ -9190,6 +9206,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
int i;
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
/*
* First Setup word is transaction code.
*/
@@ -9215,6 +9234,9 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
for (i = 2; i <= SetupCount; i++) {
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
Setup = GSHORT(pd, offset);
if (tree) {
@@ -9318,11 +9340,11 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
if (check_col(fd, COL_INFO)) {
if (request_val == NULL)
- col_set_str(fd, COL_INFO, "Response to unknown message");
+ col_set_str(fd, COL_INFO, "Response to unknown message");
else if (request_val -> last_transact2_command == -1)
- col_set_str(fd, COL_INFO, "Response to message of unknown type");
+ col_set_str(fd, COL_INFO, "Response to message of unknown type");
else
- col_add_fstr(fd, COL_INFO, "%s Response",
+ col_add_fstr(fd, COL_INFO, "%s Response",
val_to_str(request_val -> last_transact2_command,
trans2_cmd_vals, "Unknown (0x%02X)"));
@@ -9438,7 +9460,11 @@ dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *
/* Build display for: Data Displacement */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
DataDisplacement = GSHORT(pd, offset);
+ si.ddisp = DataDisplacement;
if (tree) {
@@ -9583,6 +9609,8 @@ dissect_transact_params(const u_char *pd, int offset, frame_data *fd,
char *trans_type = NULL, *trans_cmd, *loc_of_slash = NULL;
int index;
const gchar *Data;
+ packet_info *pinfo;
+ tvbuff_t *next_tvb;
if (!TransactName)
return;
@@ -9604,10 +9632,45 @@ dissect_transact_params(const u_char *pd, int offset, frame_data *fd,
else
trans_cmd = NULL;
+ pinfo = &pi;
+
+ if (DataOffset < 0) {
+ /*
+ * This is an interim response, so there're no parameters or data
+ * to dissect.
+ */
+ si.is_interim_response = TRUE;
+
+ /*
+ * Create a zero-length tvbuff.
+ */
+ next_tvb = tvb_create_from_top(pi.captured_len);
+ } else {
+ /*
+ * This isn't an interim response.
+ */
+ si.is_interim_response = FALSE;
+
+ /*
+ * Create a tvbuff for the parameters and data.
+ */
+ next_tvb = tvb_create_from_top(SMB_offset + ParameterOffset);
+ }
+
+ /*
+ * Offset of beginning of data from beginning of next_tvb.
+ */
+ si.data_offset = DataOffset - ParameterOffset;
+
+ /*
+ * Number of bytes of data.
+ */
+ si.data_count = DataCount;
+
/*
* Pass "si" to the subdissector.
*/
- pi.private = &si;
+ pinfo->private = &si;
if ((trans_cmd == NULL) ||
(((trans_type == NULL || strcmp(trans_type, "MAILSLOT") != 0) ||
@@ -9616,9 +9679,7 @@ dissect_transact_params(const u_char *pd, int offset, frame_data *fd,
SMB_offset + DataOffset, DataCount,
SMB_offset + ParameterOffset, ParameterCount)) &&
((trans_type == NULL || strcmp(trans_type, "PIPE") != 0) ||
- !dissect_pipe_smb(pd, offset, fd, parent, tree, max_data,
- SMB_offset, errcode, trans_cmd, DataOffset,
- DataCount, ParameterOffset, ParameterCount)))) {
+ !dissect_pipe_smb(next_tvb, pinfo, parent, trans_cmd)))) {
if (ParameterCount > 0) {
@@ -9743,6 +9804,7 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
new_request_key -> pid = si.pid;
request_val = g_mem_chunk_alloc(smb_request_vals);
+ request_val -> frame = fd->num;
request_val -> last_transact2_command = -1; /* unknown */
request_val -> last_transact_command = NULL;
request_val -> last_param_descrip = NULL;
@@ -9887,6 +9949,9 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
/* Build display for: Parameter Count */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
ParameterCount = GSHORT(pd, offset);
if (tree) {
@@ -9899,6 +9964,9 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
/* Build display for: Parameter Offset */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
ParameterOffset = GSHORT(pd, offset);
if (tree) {
@@ -9911,6 +9979,9 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
/* Build display for: Data Count */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
DataCount = GSHORT(pd, offset);
if (tree) {
@@ -9923,6 +9994,9 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
/* Build display for: Data Offset */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
DataOffset = GSHORT(pd, offset);
if (tree) {
@@ -9935,6 +10009,9 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
/* Build display for: Setup Count */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
SetupCount = GBYTE(pd, offset);
if (tree) {
@@ -9964,10 +10041,16 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
int i = SetupCount;
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
Setup = GSHORT(pd, offset);
for (i = 1; i <= SetupCount; i++) {
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
Setup = GSHORT(pd, offset);
if (tree) {
@@ -10081,11 +10164,11 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
if (check_col(fd, COL_INFO)) {
if ( request_val == NULL )
- col_set_str(fd, COL_INFO, "Response to unknown message");
+ col_set_str(fd, COL_INFO, "Response to unknown message");
else if (request_val -> last_transact_command == NULL)
- col_set_str(fd, COL_INFO, "Response to message of unknown type");
+ col_set_str(fd, COL_INFO, "Response to message of unknown type");
else
- col_add_fstr(fd, COL_INFO, "%s Response",
+ col_add_fstr(fd, COL_INFO, "%s Response",
request_val -> last_transact_command);
}
@@ -10113,7 +10196,7 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
if (tree) {
- proto_tree_add_text(tree, NullTVB, offset, 2, "Byte Count (BCC): %u", ByteCount);
+ proto_tree_add_text(tree, NullTVB, offset, 2, "Byte Count (BCC): %u", ByteCount);
}
@@ -10229,7 +10312,11 @@ dissect_transact_smb(const u_char *pd, int offset, frame_data *fd,
/* Build display for: Data Displacement */
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
+
DataDisplacement = GSHORT(pd, offset);
+ si.ddisp = DataDisplacement;
if (tree) {
@@ -10752,7 +10839,7 @@ char *decode_smb_error(guint8 errcls, guint16 errcode)
void
dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
{
- proto_tree *smb_tree = tree, *flags_tree, *flags2_tree;
+ proto_tree *smb_tree = tree, *flags_tree, *flags2_tree;
proto_item *ti, *tf;
guint8 cmd, errcls, errcode1, flags;
guint16 flags2, errcode, tid, pid, uid, mid;
@@ -10763,6 +10850,7 @@ dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
OLD_CHECK_DISPLAY_AS_DATA(proto_smb, pd, offset, fd, tree);
si.unicode = FALSE;
+ si.ddisp = 0;
cmd = pd[offset + SMB_hdr_com_offset];
@@ -10803,8 +10891,8 @@ dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
/* Handle error code */
- if (!BYTES_ARE_IN_FRAME(SMB_offset + 10, 2))
- return;
+ if (!BYTES_ARE_IN_FRAME(SMB_offset + 10, 2))
+ return;
if (GSHORT(pd, SMB_offset + 10) & 0x4000) {
@@ -10904,8 +10992,8 @@ dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
offset += 1;
- if (!BYTES_ARE_IN_FRAME(offset, 2))
- return;
+ if (!BYTES_ARE_IN_FRAME(offset, 2))
+ return;
flags2 = GSHORT(pd, offset);
@@ -11021,7 +11109,7 @@ dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
offset += 2;
- /* Now the UID, User ID */
+ /* Now the UID, User ID */
uid = GSHORT(pd, offset);
si.uid = uid;
@@ -11034,7 +11122,7 @@ dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
offset += 2;
- /* Now the MID, Multiplex ID */
+ /* Now the MID, Multiplex ID */
mid = GSHORT(pd, offset);
si.mid = mid;
@@ -11090,7 +11178,7 @@ proto_register_smb(void)
&ett_smb_lock_type,
};
- proto_smb = proto_register_protocol("SMB (Server Message Block Protocol)",
+ proto_smb = proto_register_protocol("SMB (Server Message Block Protocol)",
"SMB", "smb");
proto_register_subtree_array(ett, array_length(ett));
diff --git a/smb.h b/smb.h
index 7163a6203b..7217d9549b 100644
--- a/smb.h
+++ b/smb.h
@@ -2,7 +2,7 @@
* Defines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
- * $Id: smb.h,v 1.9 2001/08/05 00:16:36 guy Exp $
+ * $Id: smb.h,v 1.10 2001/08/05 01:15:27 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -628,6 +628,7 @@
#define SMB_LMapi_UserPasswordSet 0x0073
struct smb_request_val {
+ int frame; /* Frame in which this request appeared */
int last_transact2_command;
gchar *last_transact_command;
guint16 last_lanman_cmd;
@@ -643,6 +644,10 @@ struct smb_info {
struct smb_request_val *request_val;
gboolean unicode; /* Are strings in this SMB Unicode? */
gboolean request; /* Is this a request? */
+ gboolean is_interim_response; /* Is this an interim transaction response? */
+ int data_offset; /* Offset from parameter to data in transaction */
+ int data_count; /* Number of bytes of data in transaction */
+ guint16 ddisp; /* Data displacement for transaction commands */
};
#endif