diff --git a/AUTHORS b/AUTHORS index 6903a61704..7c6bd8f60f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3082,6 +3082,10 @@ Holger Freyther { NexusWare C7 MTP over UDP dissector } +Jose Pico jose.pico@telefonica.net { + Routines for exporting SMB objects +} + and by: Pavel Roskin diff --git a/epan/dissectors/packet-smb.c b/epan/dissectors/packet-smb.c index ee71c3156f..a16f965ae5 100644 --- a/epan/dissectors/packet-smb.c +++ b/epan/dissectors/packet-smb.c @@ -30,6 +30,8 @@ # include "config.h" #endif +#include + #include #include #include @@ -765,6 +767,7 @@ static gint ett_smb_posic_ace = -1; static gint ett_smb_posix_ace_perms = -1; static int smb_tap = -1; +static int smb_eo_tap = -1; static dissector_handle_t gssapi_handle; static dissector_handle_t ntlmssp_handle; @@ -884,6 +887,13 @@ static int dissect_smb_command(tvbuff_t *tvb, packet_info *pinfo, int offset, pr gboolean sid_name_snooping = FALSE; +/* Compare funtion to maintain the GSL_fid_info ordered + Order criteria: packet where the fid was opened */ +gint fid_cmp(smb_fid_info_t *fida, smb_fid_info_t *fidb) +{ + return (fida->opened_in - fidb->opened_in); +} + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX These are needed by the reassembly of SMB Transaction payload and DCERPC over SMB XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ @@ -3444,6 +3454,10 @@ dissect_smb_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_item *it; proto_tree *tr; smb_fid_info_t *fid_info=NULL; + smb_fid_info_t *suspect_fid_info=NULL; + /* We need this to use an array-accessed tree */ + GSList *GSL_iterator; + int found=0; DISSECTOR_ASSERT(si); @@ -3460,17 +3474,38 @@ dissect_smb_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, fid_info->opened_in=pinfo->fd->num; fid_info->closed_in=0; fid_info->type=SMB_FID_TYPE_UNKNOWN; + fid_info->fid=fid; + fid_info->tid=si->tid; if(si->sip && (si->sip->extra_info_type==SMB_EI_FILEDATA)){ fid_info->fsi=si->sip->extra_info; } else { fid_info->fsi=NULL; } - - se_tree_insert32(si->ct->fid_tree, fid, fid_info); + /* We don't use the fid_tree anymore to access and + maintain the fid information of analized files. + (was se_tree_insert32(si->ct->fid_tree, fid, fid_info);) + We'll use a single list instead to keep track of the + files (fid) opened. + Note that the insert_sorted function allows to insert duplicates + but being inside this if section should prevent it */ + si->ct->GSL_fid_info=g_slist_insert_sorted( + si->ct->GSL_fid_info, + fid_info, + (GCompareFunc)fid_cmp); } if(!fid_info){ - fid_info=se_tree_lookup32(si->ct->fid_tree, fid); + /* we use the single linked list to access this fid_info + (was fid_info=se_tree_lookup32(si->ct->fid_tree, fid);) */ + GSL_iterator = si->ct->GSL_fid_info; + while (GSL_iterator) { + suspect_fid_info=GSL_iterator->data; + if(suspect_fid_info->opened_in > pinfo->fd->num) break; + if(suspect_fid_info->tid==si->tid && suspect_fid_info->fid==fid) + fid_info=suspect_fid_info; + GSL_iterator=g_slist_next(GSL_iterator); + found+=1; + } } if(!fid_info){ return NULL; @@ -6014,6 +6049,18 @@ dissect_open_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i fn); COUNT_BYTES(fn_len); + /* Copied this portion of code from create_andx_request + to guarantee that fsi and si->sip are always correctly filled out */ + if((!pinfo->fd->flags.visited) && si->sip && fn){ + smb_fid_saved_info_t *fsi; + + fsi=se_alloc(sizeof(smb_fid_saved_info_t)); + fsi->filename=se_strdup(fn); + + si->sip->extra_info_type=SMB_EI_FILEDATA; + si->sip->extra_info=fsi; + } + if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", format_text(fn, strlen(fn))); @@ -6092,6 +6139,10 @@ dissect_open_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 wc, cmd=0xff; guint16 andxoffset=0, bc; guint16 fid; + guint16 ftype; + guint16 fattr; + smb_fid_info_t *fid_info=NULL; + gboolean isdir=FALSE; WORD_COUNT; @@ -6115,16 +6166,22 @@ dissect_open_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* fid */ fid = tvb_get_letohs(tvb, offset); - dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE); + /* we add fid_info= to this call so that we save the result */ + fid_info=dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE); + offset += 2; /* File Attributes */ + fattr = tvb_get_letohs(tvb, offset); + isdir = fattr & 0x10; offset = dissect_file_attributes(tvb, tree, offset, 2); /* last write time */ offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); /* File Size */ + /* We store the file_size in the fid_info */ + fid_info->end_of_file=(guint64) tvb_get_letohl(tvb, offset); proto_tree_add_item(tree, hf_smb_file_size, tvb, offset, 4, TRUE); offset += 4; @@ -6132,8 +6189,30 @@ dissect_open_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset = dissect_access(tvb, tree, offset, "Granted"); /* File Type */ + ftype=tvb_get_letohs(tvb, offset); proto_tree_add_item(tree, hf_smb_file_type, tvb, offset, 2, TRUE); offset += 2; + /* Copied from dissect_nt_create_andx_response + Try to remember the type of this fid so that we can dissect + any future security descriptor (access mask) properly + */ + fid_info->type=SMB_FID_TYPE_UNKNOWN; + if(ftype==0){ + if(isdir==0){ + if(fid_info){ + fid_info->type=SMB_FID_TYPE_FILE; + } + } else { + if(fid_info){ + fid_info->type=SMB_FID_TYPE_DIR; + } + } + } + if(ftype==2 || ftype==1){ + if(fid_info){ + fid_info->type=SMB_FID_TYPE_PIPE; + } + } /* IPC State */ offset = dissect_ipc_state(tvb, tree, offset, FALSE); @@ -6303,6 +6382,15 @@ dissect_read_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i return offset; } +/* Strings that describes the SMB object type */ +const value_string smb_fid_types[] = { + {SMB_FID_TYPE_UNKNOWN,"UNKNOWN"}, + {SMB_FID_TYPE_FILE,"FILE"}, + {SMB_FID_TYPE_DIR,"DIRECTORY (Not Implemented)"}, + {SMB_FID_TYPE_PIPE,"PIPE (Not Implemented)"}, + {0, NULL} +}; + static int dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree) { @@ -6310,8 +6398,18 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 andxoffset=0, bc, datalen_low, dataoffset=0; guint32 datalen=0, datalen_high; smb_info_t *si = (smb_info_t *)pinfo->private_data; - int fid=0; rw_info_t *rwi=NULL; + guint16 fid=0; /* was int fid=0; */ + + smb_eo_t *eo_info; /* eo_info variable to pass info. to + export object and aux */ + smb_tid_info_t *tid_info=NULL; + smb_fid_info_t *fid_info=NULL; + smb_fid_info_t *suspect_fid_info=NULL; + guint32 tvblen,packet_number; + tvbuff_t *data_tvb; + GSList *GSL_iterator; + int found=0; DISSECTOR_ASSERT(si); @@ -6413,6 +6511,51 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bc = 0; } + /* feed the export object tap listener */ + tvblen = tvb_length_remaining(tvb, dataoffset); + if(have_tap_listener(smb_eo_tap) && datalen==tvblen && rwi) { + packet_number=pinfo->fd->num; + /* Create a new tvb to point to the payload data */ + data_tvb = tvb_new_subset(tvb, dataoffset, datalen, tvblen); + /* Create the eo_info to pass to the listener */ + eo_info = ep_alloc(sizeof(smb_eo_t)); + + /* Try to get fid_info and tid_info */ + if (fid_info==NULL) { + GSL_iterator = si->ct->GSL_fid_info; + while (GSL_iterator) { + suspect_fid_info=GSL_iterator->data; + if(suspect_fid_info->opened_in > pinfo->fd->num) break; + if(suspect_fid_info->tid==si->tid && suspect_fid_info->fid==fid) + fid_info=suspect_fid_info; + GSL_iterator=g_slist_next(GSL_iterator); + found+=1; + } + } + tid_info = se_tree_lookup32(si->ct->tid_tree, si->tid); + + /* Construct the eo_info structure */ + if (tid_info) eo_info->hostname = tid_info->filename; + else eo_info->hostname = ep_strdup_printf("\\\\TREEID_%i",si->tid); + if (fid_info) { + eo_info->filename=NULL; + if (fid_info->fsi) + if (fid_info->fsi->filename) + eo_info->filename = (gchar *) fid_info->fsi->filename; + if(!eo_info->filename) eo_info->filename = ep_strdup_printf("\\FILEID_%i",fid); + eo_info->fid_type = fid_info->type; eo_info->end_of_file = fid_info->end_of_file; + } else { eo_info->fid_type=SMB_FID_TYPE_UNKNOWN; + eo_info->filename = ep_strdup_printf("\\FILEID_%i",fid); eo_info->end_of_file = 0; + } eo_info->fid=fid; + eo_info->tid=si->tid; eo_info->uid=si->uid; + eo_info->payload_len = datalen; eo_info->payload_data = data_tvb->real_data; + eo_info->smb_file_offset=rwi->offset; eo_info->smb_chunk_len=rwi->len; + eo_info->cmd=SMB_COM_READ_ANDX; + /* Queue data to the listener */ + + tap_queue_packet(smb_eo_tap, pinfo, eo_info); + } + END_OF_SMB if (cmd != 0xff) { /* there is an andX command */ @@ -6432,10 +6575,19 @@ dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 andxoffset=0, bc, dataoffset=0, datalen_low, datalen_high; guint32 datalen=0; smb_info_t *si = (smb_info_t *)pinfo->private_data; - unsigned int fid=0; + guint16 fid=0; /* was unsigned int fid=0; */ guint16 mode = 0; rw_info_t *rwi=NULL; - + /* eo_info variables to pass info. to export object and + other aux */ + smb_eo_t *eo_info; + smb_tid_info_t *tid_info=NULL; + smb_fid_info_t *fid_info=NULL; + smb_fid_info_t *suspect_fid_info=NULL; + guint32 tvblen,packet_number; + tvbuff_t *data_tvb; + GSList *GSL_iterator; + int found=0; DISSECTOR_ASSERT(si); @@ -6575,6 +6727,65 @@ dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bc = 0; } + /* feed the export object tap listener */ + tvblen = tvb_length_remaining(tvb, dataoffset); + if(have_tap_listener(smb_eo_tap) && datalen==tvblen && rwi) { + packet_number=pinfo->fd->num; + /* Create a new tvb to point to the payload data */ + data_tvb = tvb_new_subset(tvb, dataoffset, datalen, tvblen); + /* Create the eo_info to pass to the listener */ + eo_info = ep_alloc(sizeof(smb_eo_t)); + + /* Try to get fid_info and tid_info */ + if (fid_info==NULL) { + /* We'll use a GSL instead */ + /* (was fid_info = se_tree_lookup32(si->ct->fid_tree, fi +d);) */ + GSL_iterator = si->ct->GSL_fid_info; + while (GSL_iterator) { + suspect_fid_info=GSL_iterator->data; + if(suspect_fid_info->opened_in > pinfo->fd->num) + break; + if(suspect_fid_info->tid==si->tid && suspect_fid_info->fid==fid) + fid_info=suspect_fid_info; + GSL_iterator=g_slist_next(GSL_iterator); + found+=1; + } + } + tid_info = se_tree_lookup32(si->ct->tid_tree, si->tid); + + /* Construct the eo_info structure */ + if (tid_info) eo_info->hostname = tid_info->filename; + else eo_info->hostname = ep_strdup_printf("\\\\TREEID_%i",si->tid); + if (fid_info) { + eo_info->filename=NULL; + if (fid_info->fsi) { + if (fid_info->fsi->filename) { + eo_info->filename = (gchar *) fid_info->fsi->filename; + } + } + if(!eo_info->filename) eo_info->filename = ep_strdup_printf("\\FILEID_%i",fid); + eo_info->fid_type = fid_info->type; + eo_info->end_of_file = fid_info->end_of_file; + } else { + eo_info->fid_type=SMB_FID_TYPE_UNKNOWN; + eo_info->filename = ep_strdup_printf("\\FILEID_%i",fid); + eo_info->end_of_file = 0; + } + eo_info->fid=fid; + eo_info->tid=si->tid; + eo_info->uid=si->uid; + eo_info->payload_len = datalen; + eo_info->payload_data = data_tvb->real_data; + eo_info->smb_file_offset=rwi->offset; + eo_info->smb_chunk_len=rwi->len; + eo_info->cmd=SMB_COM_WRITE_ANDX; + + /* Queue data to the listener */ + + tap_queue_packet(smb_eo_tap, pinfo, eo_info); + } + END_OF_SMB if (cmd != 0xff) { /* there is an andX command */ @@ -9911,6 +10122,8 @@ dissect_nt_create_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t offset += 8; /* end of file */ + /* We store the end of file */ + fid_info->end_of_file=tvb_get_letoh64(tvb, offset); proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, TRUE); offset += 8; @@ -16735,6 +16948,8 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) si->ct->fid_tree=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "SMB fid_tree"); si->ct->tid_tree=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "SMB tid_tree"); si->ct->uid_tree=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "SMB uid_tree"); + /* Initialize the GSL_fid_info for this ct */ + si->ct->GSL_fid_info=NULL; conversation_add_proto_data(conversation, proto_smb, si->ct); } @@ -19650,6 +19865,9 @@ proto_register_smb(void) register_init_routine(smb_trans_reassembly_init); smb_tap = register_tap("smb"); + /* Register the tap for the "Export Object" function */ + smb_eo_tap = register_tap("smb_eo"); /* SMB Export Object tap */ + register_dissector("smb", dissect_smb, proto_smb); } diff --git a/epan/dissectors/packet-smb.h b/epan/dissectors/packet-smb.h index 11b9432458..dea3c0cb67 100644 --- a/epan/dissectors/packet-smb.h +++ b/epan/dissectors/packet-smb.h @@ -177,6 +177,25 @@ WS_VAR_IMPORT const value_string nt_cmd_vals[]; #define SMBE_sharebufexc 36 /* A sharing buffer has been exceeded */ #define SMBE_diskfull 39 +/* Used for SMB Export Object feature */ +typedef struct _smb_eo_t { + guint8 cmd; + int tid,uid,fid; + guint32 pkt_num; + gchar *hostname; + gchar *filename; + int fid_type; + gint64 end_of_file; + gchar *content_type; + guint32 payload_len; + const guint8 *payload_data; + guint64 smb_file_offset; + guint32 smb_chunk_len; +} smb_eo_t; + +/* Strings that describes the SMB object type */ +WS_VAR_IMPORT const value_string smb_fid_types[]; + /* the information we need to keep around for NT transatcion commands */ typedef struct { int subcmd; @@ -238,7 +257,8 @@ typedef struct { int subcmd; int trans_subcmd; int function; - int fid; + /* Unification of fid variable type (was int) */ + guint16 fid; guint16 lanman_cmd; guchar *param_descrip; /* Keep these descriptors around */ guchar *data_descrip; @@ -269,6 +289,8 @@ typedef struct conv_tables { /* track fid to fidstruct (filename/openframe/closeframe */ emem_tree_t *fid_tree; + /* We'll use a GSL list instead */ + GSList *GSL_fid_info; /* track tid to fidstruct (sharename/shareframe/unshareframe */ emem_tree_t *tid_tree; @@ -334,8 +356,13 @@ typedef struct _smb_fid_saved_info_t { guint32 create_disposition; } smb_fid_saved_info_t; struct _smb_fid_into_t { - int opened_in; - int closed_in; + guint16 tid,fid; + /* The end_of_file will store the last registered offset or + the reported end_of_file from the SMB protocol */ + gint64 end_of_file; + /* These two were int */ + guint opened_in; + guint closed_in; int type; smb_fid_saved_info_t *fsi; }; diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index e573007540..4a21cc3a46 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -45,6 +45,7 @@ set(WIRESHARK_GTK_SRC export_object.c export_object_dicom.c export_object_http.c + export_object_smb.c filter_autocomplete.c file_dlg.c fileset_dlg.c diff --git a/gtk/Makefile.common b/gtk/Makefile.common index 27fed0bec3..3f59204d8c 100644 --- a/gtk/Makefile.common +++ b/gtk/Makefile.common @@ -57,6 +57,7 @@ WIRESHARK_GTK_SRC = \ export_object.c \ export_object_dicom.c \ export_object_http.c \ + export_object_smb.c \ filter_autocomplete.c \ file_dlg.c \ fileset_dlg.c \ diff --git a/gtk/export_object.c b/gtk/export_object.c index cde07a8ac8..8cf8ee6b0b 100644 --- a/gtk/export_object.c +++ b/gtk/export_object.c @@ -318,7 +318,9 @@ export_object_window(const gchar *tapname, const gchar *name, tap_packet_cb tap_ object_list->store = gtk_tree_store_new(EO_NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_INT, + /* we need a UINT64 + (was G_TYPE_STRING, G_TYPE_INT,) */ + G_TYPE_STRING, G_TYPE_INT64, G_TYPE_STRING); object_list->tree = tree_view_new(GTK_TREE_MODEL(object_list->store)); @@ -376,7 +378,6 @@ export_object_window(const gchar *tapname, const gchar *name, tap_packet_cb tap_ selection = gtk_tree_view_get_selection(object_list->tree_view); g_signal_connect(selection, "changed", G_CALLBACK(eo_remember_row_num), object_list); - bbox = dlg_button_row_new(GTK_STOCK_HELP, WIRESHARK_STOCK_SAVE_ALL, GTK_STOCK_SAVE_AS, GTK_STOCK_CANCEL, NULL); /* Help button */ diff --git a/gtk/export_object.h b/gtk/export_object.h index 2ad4bd0dcc..f1e6e873aa 100644 --- a/gtk/export_object.h +++ b/gtk/export_object.h @@ -42,7 +42,9 @@ typedef struct _export_object_entry_t { gchar *hostname; gchar *content_type; gchar *filename; - guint payload_len; + /* We need to store a 64 bit integer to hold a file length + (was guint payload_len;) */ + gint64 payload_len; guint8 *payload_data; } export_object_entry_t; @@ -52,5 +54,6 @@ void export_object_window(const gchar *tapname, const gchar *name, /* Protocol specific */ void eo_http_cb(GtkWidget *widget _U_, gpointer data _U_); void eo_dicom_cb(GtkWidget *widget _U_, gpointer data _U_); +void eo_smb_cb(GtkWidget *widget _U_, gpointer data _U_); #endif /* __EXPORT_OBJECT_H__ */ diff --git a/gtk/export_object_smb.c b/gtk/export_object_smb.c new file mode 100644 index 0000000000..292865470b --- /dev/null +++ b/gtk/export_object_smb.c @@ -0,0 +1,453 @@ +/* export_object_smb.c + * Routines for tracking & saving objects (files) found in SMB streams + * See also: export_object.c / export_object.h for common code + * Initial file, prototypes and general structure initially copied + * from export_object_http.c + * + * Copyright 2010, David Perez & Jose Pico from TADDONG S.L. + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include + +#include "gtk/export_object.h" + + +/* These flags show what kind of data the object contains + (designed to be or'ed) */ +#define SMB_EO_CONTAINS_NOTHING 0x00 +#define SMB_EO_CONTAINS_READS 0x01 +#define SMB_EO_CONTAINS_WRITES 0x02 +#define SMB_EO_CONTAINS_READSANDWRITES 0x03 +#define LEGAL_FILENAME_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ1234567890_." + +const value_string smb_eo_contains_string[]={ + {SMB_EO_CONTAINS_NOTHING, ""}, + {SMB_EO_CONTAINS_READS, "R"}, + {SMB_EO_CONTAINS_WRITES, "W"}, + {SMB_EO_CONTAINS_READSANDWRITES, "R&W"}, + {0, NULL} + }; + + +/* This struct contains the relationship between + the row# in the export_object window and the file beeing captured; + the row# in this GSList will match the row# in the entry list */ + +typedef struct _active_file { + guint16 tid,uid,fid; + guint64 file_length; /* The last free reported offset */ + /* We treat it as the file length */ + guint64 data_gathered; /* The actual total of data gathered */ + guint8 flag_contains; /* What kind of data it contains */ + GSList *free_chunk_list; + /* A list of virtual "holes" in the */ + /* file stream stored in memory */ + gboolean is_out_of_memory; + /* TRUE if we cannot allocate memory */ + /* memory for this file */ + } active_file ; + +/* This is the GSList that will contain all the files that we are tracking */ +static GSList *GSL_active_files; + +/* This is the binary tree that will contain all the packets already processed + We want to process each smb packet only once */ +static GTree *btree_visited_packet; + +/* The comparison function for the btree_visited_packet */ +gint btree_visited_packet_cmpkey(gconstpointer keya, gconstpointer keyb, gpointer user_data) { + gint nop_value; + guint32 *a = (guint32 *)keya; + guint32 *b = (guint32 *)keyb; + gboolean *data = (gboolean *)user_data; + + if (*data == TRUE) nop_value=0; + + if (*a == *b) { return 0; } + else if (*a > *b) { return 1; } + else { return -1; } +} + +/* We define a free chunk in a file as an start offset and end offset + Consider a free chunk as a "hole" in a file that we are capturing */ +typedef struct _free_chunk { + guint64 start_offset; + guint64 end_offset; +} free_chunk; + +/* insert_chunk function will recalculate the free_chunk_list, the data_size, + the end_of_file, and the data_gathered as appropriate. + It will also insert the data chunk that is coming in the right + place of the file in memory. + HINTS: + file->data_gathered contains the real data gathered independently + from the file length + file->file_length contains the length of the file in memory, i.e., + the last offset captured. In most cases, the real + file length would be different. +*/ +void insert_chunk(active_file *file, export_object_entry_t *entry, const smb_eo_t *eo_info) +{ + guint nfreechunks = g_slist_length(file->free_chunk_list); + guint i; + free_chunk *current_free_chunk; + free_chunk *new_free_chunk; + guint64 chunk_offset=eo_info->smb_file_offset; + guint64 chunk_length=eo_info->payload_len; + guint64 chunk_end_offset = chunk_offset+chunk_length-1; + /* Size of file in memory */ + guint64 calculated_size = chunk_offset+chunk_length; + gpointer dest_memory_addr; + + /* Let's recalculate the file length and data gathered */ + if (file->data_gathered==0 && nfreechunks==0) { + /* If this is the first entry for this file, we first + create an initial free chunk */ + new_free_chunk=g_malloc(sizeof(free_chunk)); + new_free_chunk->start_offset=0; + new_free_chunk->end_offset=MAX(file->file_length,chunk_end_offset+1)-1; + file->free_chunk_list=NULL; + file->free_chunk_list=g_slist_append(file->free_chunk_list,new_free_chunk); + nfreechunks+=1; + } else { + if (chunk_end_offset > file->file_length-1) { + new_free_chunk=g_malloc(sizeof(free_chunk)); + new_free_chunk->start_offset=file->file_length; + new_free_chunk->end_offset=chunk_end_offset; + file->free_chunk_list=g_slist_append(file->free_chunk_list,new_free_chunk); + nfreechunks+=1; + } + } + file->file_length = MAX(file->file_length,chunk_end_offset+1); + + for (i=0;ifree_chunk_list,i); + if (chunk_offset <= current_free_chunk->start_offset ) { + if (chunk_end_offset >= current_free_chunk->start_offset) { + if (chunk_end_offset < current_free_chunk->end_offset) { + file->data_gathered+= + (chunk_end_offset-current_free_chunk->start_offset+1); + current_free_chunk->start_offset=chunk_end_offset+1; + } else { + file->data_gathered+= + (current_free_chunk->end_offset-current_free_chunk->start_offset+1); + file->free_chunk_list = + g_slist_remove(file->free_chunk_list,current_free_chunk); + nfreechunks-=1; + if (nfreechunks==0) { /* The free chunk list is empty */ + g_slist_free(file->free_chunk_list); + file->free_chunk_list=NULL; + break; + } + } + } else { + break; + } + } else { + if (chunk_offset <= current_free_chunk->end_offset) { + if (chunk_end_offset < current_free_chunk->end_offset) { + new_free_chunk=g_malloc(sizeof(free_chunk)); + new_free_chunk->start_offset=chunk_end_offset+1; + new_free_chunk->end_offset=current_free_chunk->end_offset; + current_free_chunk->end_offset=chunk_offset-1; + file->free_chunk_list = + g_slist_insert(file->free_chunk_list,new_free_chunk,i+1); + file->data_gathered+=chunk_length; + } else { + file->data_gathered+=current_free_chunk->end_offset-chunk_offset+1; + current_free_chunk->end_offset=chunk_offset-1; + } + } + } + } + + /* Now, let's insert the data chunk into memory + ...first, we shall be able to allocate the memory */ + if (!entry->payload_data) { + /* This is a New file */ + entry->payload_data = g_try_malloc(calculated_size); + if (!entry->payload_data) { + /* Memory error */ + file->is_out_of_memory=TRUE; + } + } else { + /* This is an existing file in memory */ + if (calculated_size > (guint64) entry->payload_len && + !file->is_out_of_memory) { + /* We need more memory */ + dest_memory_addr=g_try_realloc( + entry->payload_data, + calculated_size); + if(!dest_memory_addr) { + /* Memory error */ + file->is_out_of_memory=TRUE; + /* We don have memory for this file. + Free the current file content from memory */ + g_free(entry->payload_data); + entry->payload_data=NULL; + entry->payload_len=0; + } else { + entry->payload_data=dest_memory_addr; + entry->payload_len=calculated_size; + } + } + } + /* ...then, put the chunk of the file in the right place */ + if(!file->is_out_of_memory) { + dest_memory_addr=entry->payload_data+chunk_offset; + g_memmove(dest_memory_addr,eo_info->payload_data,eo_info->payload_len); + } +} + +/* We use this function to obtain the index in the GSL of a given file */ +int find_incoming_file(GSList *GSL_active_files,active_file *incoming_file) +{ + int i,row,last; + active_file *in_list_file; + + row=-1; + i=0; + last=g_slist_length(GSL_active_files)-1; + + /* We lookup in reverse order because it is more likely that the file + is one of the latest */ + for (i=last;i>=0;i--) { + in_list_file=g_slist_nth_data(GSL_active_files, i); + /* The best-working criteria of two identical files is that the file + that is the same of the file that we are analyzing is the last one + in the list that has the same tid and the same fid */ + /* note that we have excluded in_list_file->uid == incoming_file->uid + from the comparison, because a file can be opened by different + SMB users and it is still the same file */ + if (in_list_file->tid == incoming_file->tid && + in_list_file->fid == incoming_file->fid) { + row=i; + break; + } + } + + return row; +} + +/* This is the function answering to the registered tap listener call */ +static int +eo_smb_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, + const void *data) +{ + extern GSList *GSL_active_files; + extern GTree *btree_visited_packet; + + export_object_list_t *object_list = tapdata; + const smb_eo_t *eo_info = data; + + export_object_entry_t *entry; + export_object_entry_t *current_entry; + active_file incoming_file; + gint active_row; + active_file *new_file; + active_file *current_file; + guint8 contains; + gboolean is_supported_filetype; + + guint32 *packetnum; + gboolean *visited_packet; + gboolean new_packet; + gfloat percent; + + gchar **aux_string_v; + + + /* Obtain the packet number that originates the analysis */ + packetnum=g_malloc(sizeof(guint32)); + *packetnum=pinfo->fd->num; + + /* Lets look for that packet number */ + #ifdef SMB_DEBUG + printf("\tbtree_visited_packet: Looking for packet %u\n",*packetnum); + #endif + visited_packet = g_tree_lookup(btree_visited_packet, packetnum); + if (visited_packet==NULL) { + new_packet=TRUE; + visited_packet=g_malloc(sizeof(gboolean)); + *visited_packet=TRUE; + g_tree_insert(btree_visited_packet,packetnum,visited_packet); + } else { + new_packet=FALSE; + } + + if(eo_info && new_packet) { /* We have new data waiting for us */ + /* Is a eo_smb supported file_type? (right now we only support FILE */ + is_supported_filetype = (eo_info->fid_type==SMB_FID_TYPE_FILE); + + /* What kind of data this packet contains? */ + switch(eo_info->cmd) { + case SMB_COM_READ_ANDX: + contains=SMB_EO_CONTAINS_READS; + break; + case SMB_COM_WRITE_ANDX: + contains=SMB_EO_CONTAINS_WRITES; + break; + default: + contains=SMB_EO_CONTAINS_NOTHING; + break; + } + + /* Is this data from an already tracked file or not? */ + incoming_file.tid=eo_info->tid; + incoming_file.uid=eo_info->uid; + incoming_file.fid=eo_info->fid; + active_row=find_incoming_file(GSL_active_files, &incoming_file); + + if (active_row==-1) { /* This is a new-tracked file */ + + /* Construct the entry in the list of active files */ + entry = g_malloc(sizeof(export_object_entry_t)); + entry->payload_data=NULL; + entry->payload_len=0; + new_file = g_malloc(sizeof(active_file)); + new_file->tid=incoming_file.tid; + new_file->uid=incoming_file.uid; + new_file->fid=incoming_file.fid; + new_file->file_length = eo_info->end_of_file; + new_file->flag_contains=contains; + new_file->free_chunk_list=NULL; + new_file->data_gathered=0; + new_file->is_out_of_memory=FALSE; + entry->pkt_num = pinfo->fd->num; + entry->hostname = g_strdup(eo_info->hostname); + if (g_str_has_prefix(eo_info->filename,"\\")) { + aux_string_v = g_strsplit(eo_info->filename, "\\", -1); + entry->filename = g_strdup(aux_string_v[1]); + g_strfreev(aux_string_v); + } else { + entry->filename = g_strdup(eo_info->filename); + } + + /* Insert the first chunk in the chunk list of this file */ + if (is_supported_filetype) { + insert_chunk(new_file, entry, eo_info); + } + + if(new_file->is_out_of_memory) { + entry->content_type = + g_strdup_printf("%s (%"G_GUINT64_FORMAT"?/%"G_GUINT64_FORMAT") %s [mem!!]", + match_strval(eo_info->fid_type, smb_fid_types), + new_file->data_gathered, + new_file->file_length, + match_strval(contains, smb_eo_contains_string)); + } else { + percent=(gfloat) 100*new_file->data_gathered/new_file->file_length; + entry->content_type = + g_strdup_printf("%s (%"G_GUINT64_FORMAT"/%"G_GUINT64_FORMAT") %s [%5.2f%%]", + match_strval(eo_info->fid_type, smb_fid_types), + new_file->data_gathered, + new_file->file_length, + match_strval(contains, smb_eo_contains_string), + percent); + } + + object_list->entries = + g_slist_append(object_list->entries, entry); + GSL_active_files = + g_slist_append(GSL_active_files, new_file); + } + else if (is_supported_filetype) { + current_file=g_slist_nth_data(GSL_active_files,active_row); + /* Recalculate the current file flags */ + current_file->flag_contains=current_file->flag_contains|contains; + current_entry=g_slist_nth_data(object_list->entries,active_row); + + insert_chunk(current_file, current_entry, eo_info); + + /* Modify the current_entry object_type string */ + if(current_file->is_out_of_memory) { + current_entry->content_type = + g_strdup_printf("%s (%"G_GUINT64_FORMAT"?/%"G_GUINT64_FORMAT") %s [mem!!]", + match_strval(eo_info->fid_type, smb_fid_types), + current_file->data_gathered, + current_file->file_length, + match_strval(current_file->flag_contains, smb_eo_contains_string)); + } else { + percent=(gfloat) 100*current_file->data_gathered/current_file->file_length; + current_entry->content_type = + g_strdup_printf("%s (%"G_GUINT64_FORMAT"/%"G_GUINT64_FORMAT") %s [%5.2f%%]", + match_strval(eo_info->fid_type, smb_fid_types), + current_file->data_gathered, + current_file->file_length, + match_strval(current_file->flag_contains, smb_eo_contains_string), + percent); + } + } + return 1; /* State changed - window should be redrawn */ + } + else { + return 0; /* State unchanged - no window updates needed */ + } +} + +void +eo_smb_cb(GtkWidget *widget _U_, gpointer data _U_) +{ + extern GSList *GSL_active_files; + extern GTree *btree_visited_packet; + int i=0,last; + active_file *in_list_file; + + /* Free any previous data structures used in previous invocation to the + export_object_smb function */ + last=g_slist_length(GSL_active_files); + if (GSL_active_files) { + for (i=last-1;i>=0;i--) { + in_list_file=g_slist_nth_data(GSL_active_files, i); + if (in_list_file->free_chunk_list) { + g_slist_free(in_list_file->free_chunk_list); + in_list_file->free_chunk_list=NULL; + } + g_free(in_list_file); + } + g_slist_free(GSL_active_files); + GSL_active_files=NULL; + i=g_slist_length(GSL_active_files); + } + + /* Initialize the tree */ + if (btree_visited_packet) { + g_tree_destroy(btree_visited_packet); + btree_visited_packet=NULL; + } + btree_visited_packet=g_tree_new_full(btree_visited_packet_cmpkey,NULL,g_free,g_free); + + /* Then call the export_object window */ + export_object_window("smb_eo", "SMB", eo_smb_packet); +} diff --git a/gtk/menus.c b/gtk/menus.c index 4a83d3fbc9..81ddc33d97 100644 --- a/gtk/menus.c +++ b/gtk/menus.c @@ -483,7 +483,7 @@ static GtkItemFactoryEntry menu_items[] = 0, NULL, NULL,}, {"/File/Export/_Objects/_HTTP", NULL, GTK_MENU_FUNC(eo_http_cb), 0, NULL, NULL,}, {"/File/Export/_Objects/_DICOM", NULL, GTK_MENU_FUNC(eo_dicom_cb), 0, NULL, NULL,}, - + {"/File/Export/_Objects/_SMB", NULL, GTK_MENU_FUNC(eo_smb_cb), 0, NULL, NULL,}, {"/File/", NULL, NULL, 0, "", NULL,}, {"/File/_Print...", "P", GTK_MENU_FUNC(file_print_cmd_cb), 0, "", GTK_STOCK_PRINT,},