2000-02-14 04:02:21 +00:00
|
|
|
/* packet-smb-pipe.c
|
2001-03-18 03:23:30 +00:00
|
|
|
* Routines for SMB named pipe packet dissection
|
2000-02-14 04:02:21 +00:00
|
|
|
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
|
|
|
|
*
|
2001-03-22 00:50:44 +00:00
|
|
|
* $Id: packet-smb-pipe.c,v 1.21 2001/03/22 00:50:44 guy Exp $
|
2000-02-14 04:02:21 +00:00
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@zing.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* Copied from packet-pop.c
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
# include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
# include <netinet/in.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "packet.h"
|
|
|
|
#include "conversation.h"
|
|
|
|
#include "smb.h"
|
|
|
|
#include "alignment.h"
|
2000-09-11 16:16:13 +00:00
|
|
|
#include "strutil.h"
|
2001-03-18 03:23:30 +00:00
|
|
|
#include "packet-smb-pipe.h"
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
static int proto_smb_lanman = -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;
|
|
|
|
|
2000-05-14 20:50:03 +00:00
|
|
|
/*
|
|
|
|
* See
|
|
|
|
*
|
|
|
|
* ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
|
|
|
|
*
|
|
|
|
* among other documents.
|
|
|
|
*/
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 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},
|
2000-02-19 12:13:52 +00:00
|
|
|
{52, "NetGroupGetUsers", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
|
2000-02-14 04:02:21 +00:00
|
|
|
{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}
|
|
|
|
};
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
static struct lanman_desc *
|
2000-02-14 04:02:21 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define NETSHAREENUM 0x00 /* 00 */
|
|
|
|
#define NETSERVERENUM2 0x68 /* 104 */
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
static void
|
|
|
|
dissect_server_flags(proto_tree *tree, int offset, int length, int flags)
|
2000-02-14 04:02:21 +00:00
|
|
|
{
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0001, length*8, "Workstation", "Not Workstation"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0002, length*8, "Server", "Not Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0004, length*8, "SQL Server", "Not SQL Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0008, length*8, "Domain Controller", "Not Domain Controller"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0010, length*8, "Backup Controller", "Not Backup Controller"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, 4, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0020, length*8, "Time Source", "Not Time Source"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0040, length*8, "Apple Server", "Not Apple Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0080, length*8, "Novell Server", "Not Novell Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0100, length*8, "Domain Member Server", "Not Domain Member Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0200, length*8, "Print Queue Server", "Not Print Queue Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0400, length*8, "Dialin Server", "Not Dialin Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x0800, length*8, "Xenix Server", "Not Xenix Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x1000, length*8, "NT Workstation", "Not NT Workstation"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x2000, length*8, "Windows for Workgroups", "Not Windows for Workgroups"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x8000, length*8, "NT Server", "Not NT Server"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x10000, length*8, "Potential Browser", "Not Potential Browser"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x20000, length*8, "Backup Browser", "Not Backup Browser"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x40000, length*8, "Master Browser", "Not Master Browser"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x80000, length*8, "Domain Master Browser", "Not Domain Master Browser"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x100000, length*8, "OSF", "Not OSF"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x200000, length*8, "VMS", "Not VMS"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x400000, length*8, "Windows 95 or above", "Not Windows 95 or above"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x40000000, length*8, "Local List Only", "Not Local List Only"));
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, offset, length, "%s",
|
2000-02-14 04:02:21 +00:00
|
|
|
decode_boolean_bitfield(flags, 0x80000000, length*8, "Domain Enum", "Not Domain Enum"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 */
|
2001-03-18 03:23:30 +00:00
|
|
|
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)
|
2000-02-14 04:02:21 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_ent_count()
|
|
|
|
{
|
|
|
|
|
|
|
|
return lm_ent_count;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_act_count()
|
|
|
|
{
|
|
|
|
|
|
|
|
return lm_act_count;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
static int get_byte_count(const u_char *p_data)
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
int count = 0, off = 0;
|
|
|
|
|
|
|
|
while (p_data[off] && isdigit(p_data[off])) {
|
|
|
|
|
|
|
|
count = (count * 10) + (int)p_data[off++] - (int)'0';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
static int
|
|
|
|
dissect_transact_next(const u_char *pd, char *Name, int dirn, proto_tree *tree)
|
2000-02-14 04:02:21 +00:00
|
|
|
{
|
|
|
|
/* 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 (dirn == 0) { /* We need to process the data ... */
|
|
|
|
|
|
|
|
need_data = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h': /* A WORD parameter received */
|
|
|
|
|
|
|
|
if (dirn == 0) {
|
|
|
|
|
|
|
|
WParam = GSHORT(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Returned Word", WParam, WParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 2;
|
|
|
|
|
|
|
|
lm_act_count = WParam;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'e': /* An ent count .. */
|
|
|
|
|
|
|
|
if (dirn == 0) { /* Only relevant in a response */
|
|
|
|
|
|
|
|
WParam = GSHORT(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: (%04X)", (Name) ? Name : "Entry Count", WParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 2;
|
|
|
|
|
|
|
|
lm_ent_count = WParam; /* Save this for later retrieval */
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'W': /* Word Parameter */
|
|
|
|
|
|
|
|
if (dirn == 1) { /* A request ... */
|
|
|
|
|
|
|
|
/* Insert a word param */
|
|
|
|
|
|
|
|
WParam = GSHORT(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Word Param", WParam, WParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 2;
|
|
|
|
|
|
|
|
return 1; /* That's it here ... we have dissected a param */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'i': /* A long word is returned */
|
|
|
|
|
|
|
|
if (dirn == 0) {
|
|
|
|
|
|
|
|
LParam = GWORD(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "Returned Long Word", LParam, LParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 2;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D': /* Double Word parameter */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
LParam = GWORD(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "DWord Param", LParam, LParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 4;
|
|
|
|
|
|
|
|
return 1; /* That's it here */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'g': /* A byte or series of bytes is returned */
|
|
|
|
|
|
|
|
if (dirn == 0) {
|
|
|
|
|
|
|
|
bc = get_byte_count(p_desc + p_offset);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
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));
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += (bc) ? bc : 1;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'b': /* A byte or series of bytes */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
bc = get_byte_count(p_desc + p_offset); /* This is not clean */
|
|
|
|
|
|
|
|
/*Bytes = g_malloc(bc + 1); / * Is this needed ? */
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
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));
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += (bc) ? bc : 1;
|
|
|
|
|
|
|
|
return 1; /* That's it here ... */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'O': /* A null pointer */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 0, "%s: Null Pointer", (Name) ? Name : "Unknown");
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
return 1; /* That's it here */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'z': /* An AsciiZ string */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
AsciiZ = pd + pd_p_current;
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, strlen(AsciiZ) + 1, "%s: %s", (Name) ? Name : "AsciiZ", AsciiZ);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += strlen(AsciiZ) + 1;
|
|
|
|
|
|
|
|
return 1; /* That's it here ... */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F': /* One or more pad bytes */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
bc = get_byte_count(pd);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "Pad", bc, format_text(pd + pd_p_current, bc));
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += bc;
|
|
|
|
|
|
|
|
return 1; /* That's it here */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L': /* Receive buffer len: Short */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
WParam = GSHORT(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (0x%04X)", (Name) ? Name : "Receive Buffer Len", WParam, WParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 2;
|
|
|
|
|
|
|
|
return 1; /* That's it here ... */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 's': /* Send buf ... */
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
need_data = 1;
|
|
|
|
|
|
|
|
LParam = GWORD(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u", (Name) ? Name : "Send Buffer Ptr", LParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 4;
|
|
|
|
|
|
|
|
return 1; /* That's it here ... */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'T':
|
|
|
|
|
|
|
|
if (dirn == 1) {
|
|
|
|
|
|
|
|
WParam = GSHORT(pd, pd_p_current);
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u", (Name) ? Name : "Send Buffer Len", WParam);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
pd_p_current += 2;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* We are in the data area ... */
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2000-05-14 20:50:03 +00:00
|
|
|
static const value_string share_type_vals[] = {
|
|
|
|
{0, "Directory tree"},
|
|
|
|
{1, "Printer queue"},
|
|
|
|
{2, "Communications device"},
|
|
|
|
{3, "IPC"},
|
|
|
|
{0, NULL}
|
|
|
|
};
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
/*
|
|
|
|
* Per-frame data needed to dissect replies.
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
guint16 FunctionCode;
|
|
|
|
gboolean is_continuation;
|
|
|
|
} response_data;
|
|
|
|
|
|
|
|
static GMemChunk *lanman_proto_data;
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
gboolean
|
2000-02-14 04:02:21 +00:00
|
|
|
dissect_pipe_lanman(const u_char *pd, int offset, frame_data *fd,
|
|
|
|
proto_tree *parent, proto_tree *tree, struct smb_info si,
|
|
|
|
int max_data, int SMB_offset, int errcode, int dirn,
|
|
|
|
const u_char *command, int DataOffset, int DataCount,
|
2001-03-21 22:57:26 +00:00
|
|
|
int ParameterOffset, int ParameterCount)
|
|
|
|
{
|
2001-03-21 23:13:49 +00:00
|
|
|
gboolean is_interim_response;
|
2001-03-21 22:57:26 +00:00
|
|
|
guint32 loc_offset;
|
2000-02-14 04:02:21 +00:00
|
|
|
guint16 FunctionCode;
|
|
|
|
guint16 Level;
|
|
|
|
guint16 RecvBufLen;
|
2001-01-03 04:37:07 +00:00
|
|
|
guint32 Flags;
|
2000-02-14 04:02:21 +00:00
|
|
|
const char *ParameterDescriptor;
|
|
|
|
const char *ReturnDescriptor;
|
|
|
|
proto_tree *lanman_tree = NULL, *flags_tree = NULL;
|
|
|
|
proto_item *ti;
|
|
|
|
struct lanman_desc *lanman;
|
2000-05-14 04:00:48 +00:00
|
|
|
guint32 string_offset;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 22:57:26 +00:00
|
|
|
if (DataOffset < 0) {
|
|
|
|
|
|
|
|
/* Interim response; we weren't given any data. */
|
|
|
|
|
|
|
|
is_interim_response = TRUE;
|
2001-03-21 23:13:49 +00:00
|
|
|
loc_offset = SMB_offset;
|
2001-03-21 22:57:26 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* Offset of the data we should dissect. */
|
|
|
|
|
|
|
|
is_interim_response = FALSE;
|
|
|
|
loc_offset = SMB_offset + ParameterOffset;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2000-02-14 04:02:21 +00:00
|
|
|
if (check_col(fd, COL_PROTOCOL))
|
2001-03-18 03:23:30 +00:00
|
|
|
col_set_str(fd, COL_PROTOCOL, "LANMAN");
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
if (dirn == 1) { /* The request side */
|
|
|
|
|
|
|
|
FunctionCode = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
si.request_val -> last_lanman_cmd = FunctionCode;
|
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
lanman = find_lanman(FunctionCode);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
if (tree) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, ParameterCount, FALSE);
|
|
|
|
lanman_tree = proto_item_add_subtree(ti, ett_lanman);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
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);
|
2000-02-14 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
loc_offset += 2;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
ParameterDescriptor = pd + loc_offset;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
/* Now, save these for later */
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
si.request_val -> trans_response_seen = 0;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
if (si.request_val -> last_param_descrip)
|
|
|
|
g_free(si.request_val -> last_param_descrip);
|
|
|
|
si.request_val -> last_param_descrip = g_malloc(strlen(ParameterDescriptor) + 1);
|
|
|
|
if (si.request_val -> last_param_descrip)
|
|
|
|
strcpy(si.request_val -> last_param_descrip, ParameterDescriptor);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
if (tree) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ParameterDescriptor) + 1, "Parameter Descriptor: %s", ParameterDescriptor);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
loc_offset += strlen(ParameterDescriptor) + 1;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
ReturnDescriptor = pd + loc_offset;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
if (si.request_val -> last_data_descrip)
|
|
|
|
g_free(si.request_val -> last_data_descrip);
|
|
|
|
si.request_val -> last_data_descrip = g_malloc(strlen(ReturnDescriptor) + 1);
|
|
|
|
if (si.request_val -> last_data_descrip)
|
|
|
|
strcpy(si.request_val -> last_data_descrip, ReturnDescriptor);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
if (tree) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ReturnDescriptor) + 1, "Return Descriptor: %s", ReturnDescriptor);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
loc_offset += strlen(ReturnDescriptor) + 1;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
switch (FunctionCode) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
case NETSHAREENUM: /* Never decode this at the moment ... */
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
Level = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Detail Level: %u", Level);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
RecvBufLen = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NETSERVERENUM2: /* Process a NetServerEnum2 */
|
|
|
|
|
|
|
|
Level = GSHORT(pd, loc_offset);
|
|
|
|
si.request_val -> last_level = Level;
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Info Detail Level: %u", Level);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
RecvBufLen = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
Flags = GWORD(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 4, "Server Types Required: 0x%08X", Flags);
|
2000-02-14 04:02:21 +00:00
|
|
|
flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
|
|
|
|
dissect_server_flags(flags_tree, loc_offset, 4, Flags);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 4;
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
return TRUE;
|
2000-02-14 04:02:21 +00:00
|
|
|
break;
|
|
|
|
|
2001-03-21 23:30:54 +00:00
|
|
|
default: /* Just try to handle what is there ... */
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
|
|
|
int i = 0; /* Counter for names below */
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
dissect_transact_engine_init(pd, ParameterDescriptor, ReturnDescriptor,SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
|
|
|
|
|
|
|
|
if (lanman) name = lanman -> req[i]; /* Must be OK ... */
|
|
|
|
|
|
|
|
while (dissect_transact_next(pd, name, dirn, lanman_tree))
|
|
|
|
if (name) name = lanman -> req[++i];
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2001-03-21 23:13:49 +00:00
|
|
|
else { /* dirn == 0, response */
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
response_data *proto_data;
|
2000-02-14 04:02:21 +00:00
|
|
|
guint16 Status;
|
|
|
|
guint16 Convert;
|
|
|
|
guint16 EntCount;
|
|
|
|
guint16 AvailCount;
|
|
|
|
int i;
|
|
|
|
proto_tree *server_tree = NULL, *flags_tree = NULL, *share_tree = NULL;
|
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
/* 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 = si.request_val -> last_lanman_cmd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we've already seen a response to the request, this must
|
|
|
|
* be a continuation of that response.
|
|
|
|
*/
|
|
|
|
proto_data->is_continuation = si.request_val -> trans_response_seen;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attach it to the frame.
|
|
|
|
*/
|
|
|
|
p_add_proto_data(fd, proto_smb_lanman, proto_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionCode = proto_data->FunctionCode;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have already seen the response to this transact, simply
|
|
|
|
* record it as a continuation ...
|
|
|
|
*/
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
if (proto_data->is_continuation) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
if (check_col(fd, COL_INFO)) {
|
2001-03-18 03:23:30 +00:00
|
|
|
col_set_str(fd, COL_INFO, "Transact Continuation");
|
2000-02-14 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2001-03-22 00:50:44 +00:00
|
|
|
ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, END_OF_FRAME, FALSE);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
lanman_tree = proto_item_add_subtree(ti, ett_lanman);
|
|
|
|
|
2001-03-22 00:50:44 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, END_OF_FRAME, "Payload: %s", format_text(pd + loc_offset, END_OF_FRAME));
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
return TRUE;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
si.request_val -> trans_response_seen = 1;
|
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
lanman = find_lanman(FunctionCode);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
if (check_col(fd, COL_INFO)) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
if (lanman) {
|
|
|
|
col_add_fstr(fd, COL_INFO, "%s %sResponse", lanman -> lanman_name,
|
|
|
|
is_interim_response ? "Interim " : "");
|
2000-02-14 04:02:21 +00:00
|
|
|
}
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
else {
|
|
|
|
col_add_fstr(fd, COL_INFO, "Unknown LANMAN %sResponse: %u",
|
|
|
|
is_interim_response ? "Interim " : "", FunctionCode);
|
|
|
|
}
|
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
if (tree) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
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);
|
2000-02-14 04:02:21 +00:00
|
|
|
}
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
else {
|
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: Unknown LANMAN Response: %u", FunctionCode);
|
|
|
|
}
|
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
if (is_interim_response) {
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
return TRUE; /* no data to dissect */
|
2001-03-21 22:57:26 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
}
|
2001-03-21 22:57:26 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
switch (FunctionCode) {
|
|
|
|
|
|
|
|
case NETSHAREENUM:
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
Status = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
Convert = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
EntCount = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
AvailCount = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, AvailCount * 20, "Available Shares");
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
share_tree = proto_item_add_subtree(ti, ett_lanman_shares);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
ti = proto_tree_add_text(share_tree, NullTVB, loc_offset, 20, "Share %s", Share);
|
2000-02-14 04:02:21 +00:00
|
|
|
share = proto_item_add_subtree(ti, ett_lanman_share);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(share, NullTVB, loc_offset, 13, "Share Name: %s", Share);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 13;
|
|
|
|
|
2000-05-14 03:17:26 +00:00
|
|
|
loc_offset += 1; /* Pad byte ... */
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
Flags = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-14 20:50:03 +00:00
|
|
|
proto_tree_add_text(share, NullTVB, loc_offset, 2, "Share Type: %s",
|
|
|
|
val_to_str(Flags, share_type_vals, "Unknown (%u)"));
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
2000-05-14 04:00:48 +00:00
|
|
|
/* 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>";
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(share, NullTVB, loc_offset, 4, "Share Comment: %s", Comment);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 4;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NETSERVERENUM2:
|
|
|
|
|
|
|
|
Status = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
Convert = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
EntCount = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
AvailCount = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 26 * AvailCount, "Servers");
|
2000-02-14 04:02:21 +00:00
|
|
|
if (ti == NULL) {
|
|
|
|
|
|
|
|
printf("Null value returned from proto_tree_add_text\n");
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
server_tree = proto_item_add_subtree(ti, ett_lanman_servers);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure we don't go past the end of the capture buffer */
|
|
|
|
|
2001-01-01 01:44:46 +00:00
|
|
|
for (i = 1; (i <= EntCount) && ((pi.captured_len - loc_offset) >= 16); i++) {
|
2000-02-14 04:02:21 +00:00
|
|
|
const gchar *Server = pd + loc_offset;
|
|
|
|
gint8 ServerMajor;
|
|
|
|
guint ServerMinor;
|
|
|
|
guint32 ServerFlags;
|
|
|
|
const gchar *Comment;
|
|
|
|
proto_tree *server = NULL;
|
|
|
|
proto_item *ti;
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
ti = proto_tree_add_text(server_tree, NullTVB, loc_offset,
|
2000-02-14 04:02:21 +00:00
|
|
|
(si.request_val -> last_level) ? 26 : 16,
|
|
|
|
"Server %s", Server);
|
|
|
|
server = proto_item_add_subtree(ti, ett_lanman_server);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(server, NullTVB, loc_offset, 16, "Server Name: %s", Server);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 16;
|
|
|
|
|
|
|
|
if (si.request_val -> last_level) { /* Print out the rest of the info */
|
|
|
|
|
|
|
|
ServerMajor = GBYTE(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(server, NullTVB, loc_offset, 1, "Major Version: %u", ServerMajor);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 1;
|
|
|
|
|
|
|
|
ServerMinor = GBYTE(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(server, NullTVB, loc_offset, 1, "Minor Version: %u", ServerMinor);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 1;
|
|
|
|
|
|
|
|
ServerFlags = GWORD(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
ti = proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Type: 0x%08X", ServerFlags);
|
2000-02-14 04:02:21 +00:00
|
|
|
flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
|
|
|
|
dissect_server_flags(flags_tree, loc_offset, 4, ServerFlags);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 4;
|
|
|
|
|
2000-05-14 04:00:48 +00:00
|
|
|
/* 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>";
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Comment: %s", Comment);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 4;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
Status = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
Convert = GSHORT(pd, loc_offset);
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
2000-05-11 08:18:09 +00:00
|
|
|
proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
loc_offset += 2;
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
dissect_transact_engine_init(pd, si.request_val -> last_param_descrip, si.request_val -> last_data_descrip, SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
|
|
|
|
|
|
|
|
if (lanman) name = lanman -> resp[i];
|
|
|
|
|
|
|
|
while (dissect_transact_next(pd, name, dirn, lanman_tree))
|
|
|
|
if (name) name = lanman -> resp[++i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
return TRUE;
|
2000-02-14 04:02:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
return FALSE;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
gboolean
|
2000-02-14 04:02:21 +00:00
|
|
|
dissect_pipe_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn, const u_char *command, int DataOffset, int DataCount, int ParameterOffset, int ParameterCount)
|
|
|
|
{
|
|
|
|
|
Add the "Edit:Protocols..." feature which currently only implements
the following:
It is now possible to enable/disable a particular protocol decoding
(i.e. the protocol dissector is void or not). When a protocol
is disabled, it is displayed as Data and of course, all linked
sub-protocols are disabled as well.
Disabling a protocol could be interesting:
- in case of buggy dissectors
- in case of wrong heuristics
- for performance reasons
- to decode the data as another protocol (TODO)
Currently (if I am not wrong), all dissectors but NFS can be disabled
(and dissectors that do not register protocols :-)
I do not like the way the RPC sub-dissectors are disabled (in the
sub-dissectors) since this could be done in the RPC dissector itself,
knowing the sub-protocol hfinfo entry (this is why, I've not modified
the NFS one yet).
Two functions are added in proto.c :
gboolean proto_is_protocol_enabled(int n);
void proto_set_decoding(int n, gboolean enabled);
and two MACROs which can be used in dissectors:
OLD_CHECK_DISPLAY_AS_DATA(index, pd, offset, fd, tree)
CHECK_DISPLAY_AS_DATA(index, tvb, pinfo, tree)
See also the XXX in proto_dlg.c and proto.c around the new functions.
svn path=/trunk/; revision=2267
2000-08-13 14:09:15 +00:00
|
|
|
if (!proto_is_protocol_enabled(proto_smb_lanman))
|
2001-03-18 03:23:30 +00:00
|
|
|
return FALSE;
|
Add the "Edit:Protocols..." feature which currently only implements
the following:
It is now possible to enable/disable a particular protocol decoding
(i.e. the protocol dissector is void or not). When a protocol
is disabled, it is displayed as Data and of course, all linked
sub-protocols are disabled as well.
Disabling a protocol could be interesting:
- in case of buggy dissectors
- in case of wrong heuristics
- for performance reasons
- to decode the data as another protocol (TODO)
Currently (if I am not wrong), all dissectors but NFS can be disabled
(and dissectors that do not register protocols :-)
I do not like the way the RPC sub-dissectors are disabled (in the
sub-dissectors) since this could be done in the RPC dissector itself,
knowing the sub-protocol hfinfo entry (this is why, I've not modified
the NFS one yet).
Two functions are added in proto.c :
gboolean proto_is_protocol_enabled(int n);
void proto_set_decoding(int n, gboolean enabled);
and two MACROs which can be used in dissectors:
OLD_CHECK_DISPLAY_AS_DATA(index, pd, offset, fd, tree)
CHECK_DISPLAY_AS_DATA(index, tvb, pinfo, tree)
See also the XXX in proto_dlg.c and proto.c around the new functions.
svn path=/trunk/; revision=2267
2000-08-13 14:09:15 +00:00
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
if (command != NULL && strcmp(command, "LANMAN") == 0) {
|
|
|
|
/* Try to decode a LANMAN */
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
return dissect_pipe_lanman(pd, offset, fd, parent, tree, si, max_data,
|
|
|
|
SMB_offset, errcode, dirn, command, DataOffset,
|
|
|
|
DataCount, ParameterOffset, ParameterCount);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-03-18 03:23:30 +00:00
|
|
|
return FALSE;
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
static void
|
|
|
|
pipe_lanman_init_protocol(void)
|
|
|
|
{
|
|
|
|
if (lanman_proto_data != NULL)
|
|
|
|
g_mem_chunk_destroy(lanman_proto_data);
|
2000-02-14 04:02:21 +00:00
|
|
|
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
lanman_proto_data = g_mem_chunk_new("lanman_proto_data",
|
|
|
|
sizeof(response_data),
|
|
|
|
100 * sizeof(response_data),
|
|
|
|
G_ALLOC_AND_FREE);
|
|
|
|
}
|
2000-02-14 04:02:21 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
register_proto_smb_pipe( void){
|
|
|
|
|
|
|
|
|
|
|
|
static gint *ett[] = {
|
|
|
|
|
|
|
|
&ett_lanman,
|
|
|
|
&ett_lanman_servers,
|
|
|
|
&ett_lanman_server,
|
|
|
|
&ett_lanman_shares,
|
|
|
|
&ett_lanman_share,
|
|
|
|
&ett_lanman_flags
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
proto_smb_lanman = proto_register_protocol(
|
2001-01-03 06:56:03 +00:00
|
|
|
"Microsoft Windows Lanman Protocol", "LANMAN", "lanman");
|
2000-02-14 04:02:21 +00:00
|
|
|
|
2000-02-14 04:18:57 +00:00
|
|
|
proto_register_subtree_array(ett, array_length(ett));
|
When dissecting LANMAN pipe transaction replies, store with each reply
frame per-frame data indicating
1) what type of transaction it's a reply to
and
2) whether it's the first reply or a continuation reply
as the information supplied by the SMB dissector can only be trusted on
the first pass through the capture.
(If you have two different transactions in the *same* conversation with
the *same* MID, but different transaction types, only on the first pass
will the transaction type in the data structure pointed to by
"si.request_val" reflect the previous request - it reflects the last
request seen which, when the user is clicking on frames in the capture,
needn't be the request corresponding to the reply that they've just
clicked on.
If you have a reply that consists of multiple SMBs,
"si.request_val->trans_response_seen" will be set to 1 as soon as the
first reply is seen, and will *remain* 1 until the request is seen
again; if the user clicks on one of the SMBs in the reply, even if it's
the first SMB in the reply, without having first clicked on the request,
"si.request_val->trans_response_seen" will be 1, and the SMB will be
misdissected as a continuation.)
Use common code to handle the beginning of LANMAN replies, rather than
duplicating it in the code to handle each reply.
svn path=/trunk/; revision=3154
2001-03-22 00:28:35 +00:00
|
|
|
register_init_routine(&pipe_lanman_init_protocol);
|
2000-02-14 04:02:21 +00:00
|
|
|
}
|