diff options
-rw-r--r-- | packet-smb-browse.c | 32 | ||||
-rw-r--r-- | packet-smb-browse.h | 5 | ||||
-rw-r--r-- | packet-smb-pipe.c | 2383 | ||||
-rw-r--r-- | packet-smb-pipe.h | 15 | ||||
-rw-r--r-- | packet-smb.c | 128 | ||||
-rw-r--r-- | smb.h | 7 |
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 = π + + 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)); @@ -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 |