diff options
-rw-r--r-- | epan/dissectors/packet-smb.c | 378 | ||||
-rw-r--r-- | epan/dissectors/packet-smb.h | 36 | ||||
-rw-r--r-- | epan/dissectors/packet-smb2.c | 269 | ||||
-rw-r--r-- | epan/dissectors/packet-smb2.h | 64 | ||||
-rw-r--r-- | ui/export_object.h | 4 | ||||
-rw-r--r-- | ui/export_object_smb.c | 652 | ||||
-rw-r--r-- | ui/gtk/export_object_dlg.c | 36 | ||||
-rw-r--r-- | ui/gtk/main_menubar.c | 2 |
8 files changed, 984 insertions, 457 deletions
diff --git a/epan/dissectors/packet-smb.c b/epan/dissectors/packet-smb.c index 1c2683ceac..4f608c5aa9 100644 --- a/epan/dissectors/packet-smb.c +++ b/epan/dissectors/packet-smb.c @@ -924,6 +924,107 @@ static int dissect_smb_command(tvbuff_t *tvb, packet_info *pinfo, int offset, pr gboolean sid_display_hex = FALSE; gboolean sid_name_snooping = FALSE; +/* ExportObject preferences variable */ +gboolean eosmb_take_name_as_fid = FALSE ; +/* Utility to get an str reprensenting ipv4 or ipv6 address */ +const gchar *tree_ip_str(packet_info *pinfo, guint16 cmd) { + const gchar *buf; + + if (pinfo->src.type==AT_IPv4) { + if ( cmd==SMB_COM_READ_ANDX || + cmd==SMB_COM_READ || + cmd==SMB2_COM_READ) { + buf=(gchar *)ip_to_str(pinfo->src.data); + } else { + buf=(gchar *)ip_to_str(pinfo->dst.data); + } + } else { + if ( cmd==SMB_COM_READ_ANDX || + cmd==SMB_COM_READ || + cmd==SMB2_COM_READ) { + buf=(gchar *)ip6_to_str(pinfo->src.data); + } else { + buf=(gchar *)ip6_to_str(pinfo->dst.data); + } + } + + return buf; +} + + +/* ExportObject feed function*/ +static void +feed_eo_smb(guint16 cmd, guint16 fid, tvbuff_t * tvb,packet_info *pinfo,guint16 dataoffset,guint32 datalen, guint32 chunk_len, guint64 file_offset) { + 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; + tvbuff_t *data_tvb; + GSList *GSL_iterator; + + smb_info_t *si = (smb_info_t *)pinfo->private_data; + + /* Create a new tvb to point to the payload data */ + data_tvb = tvb_new_subset(tvb, dataoffset, datalen, datalen); + /* 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); + } + } + + + tid_info = se_tree_lookup32(si->ct->tid_tree, si->tid); + + /* Construct the eo_info structure */ + eo_info->smbversion=1; + if (tid_info) { + if (tid_info->filename) { + eo_info->hostname = tid_info->filename; + } else { + eo_info->hostname = ep_strdup_printf("\\\\%s\\TREEID_UNKNOWN",tree_ip_str(pinfo,cmd)); + } + } + else eo_info->hostname = ep_strdup_printf("\\\\%s\\TREEID_%i",tree_ip_str(pinfo,cmd),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; + } + if (eosmb_take_name_as_fid) { + eo_info->fid = g_str_hash(eo_info->filename); + } else { + eo_info->fid = fid; + } + eo_info->tid = si->tid; + eo_info->uid = si->uid; + eo_info->payload_len = datalen; + eo_info->payload_data = tvb_get_ptr(data_tvb, 0, datalen); + eo_info->smb_file_offset = file_offset; + eo_info->smb_chunk_len = chunk_len; + eo_info->cmd = cmd; + /* Queue data to the listener */ + + tap_queue_packet(smb_eo_tap, pinfo, eo_info); +} /* feed_eo_smb */ + /* Compare funtion to maintain the GSL_fid_info ordered Order criteria: packet where the fid was opened */ static gint @@ -3172,6 +3273,7 @@ dissect_open_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i const char *fn; guint8 wc; guint16 bc; + smb_fid_saved_info_t *fsi; /* eo_smb needs to track this info */ DISSECTOR_ASSERT(si); @@ -3199,6 +3301,23 @@ dissect_open_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i fn); COUNT_BYTES(fn_len); + /* store it for the fid->name/openframe/closeframe matching in + * dissect_smb_fid() called from the response. + */ + if ((!pinfo->fd->flags.visited) && si->sip && fn) { + fsi = se_alloc(sizeof(smb_fid_saved_info_t)); + fsi->filename = se_strdup(fn); + fsi->create_flags = 0; + fsi->access_mask = 0; + fsi->file_attributes = 0; + fsi->share_access = 0; + fsi->create_options = 0; + fsi->create_disposition = 0; + + 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))); @@ -3572,12 +3691,31 @@ dissect_open_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 wc; guint16 bc; guint16 fid; + smb_fid_info_t *fid_info = NULL; /* eo_smb needs to track this info */ + guint16 fattr; + gboolean isdir = FALSE; WORD_COUNT; /* fid */ fid = tvb_get_letohs(tvb, offset); - dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE); + + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE); + if (fid_info) { + /* This command is used to create and open a new file or open + and truncate an existing file to zero length */ + fid_info->end_of_file = 0; + /* File Type */ + fattr=fid_info->fsi->file_attributes; + /* XXX Volumes considered as directories */ + isdir = (fattr & SMB_FILE_ATTRIBUTE_DIRECTORY) || (fattr & SMB_FILE_ATTRIBUTE_VOLUME); + if (isdir == 0) { + fid_info->type = SMB_FID_TYPE_FILE; + } else { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + offset += 2; /* File Attributes */ @@ -3711,12 +3849,30 @@ dissect_create_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree guint8 wc; guint16 bc; guint16 fid; + smb_fid_info_t *fid_info = NULL; /* eo_smb needs to track this info */ + guint16 fattr; + gboolean isdir = FALSE; WORD_COUNT; /* fid */ fid = tvb_get_letohs(tvb, offset); - dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE); + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE); + if (fid_info) { + /* This command is used to create and open a new file or open + and truncate an existing file to zero length */ + fid_info->end_of_file = 0; + /* File Type */ + fattr=fid_info->fsi->file_attributes; + /* XXX Volumes considered as directories */ + isdir = (fattr & SMB_FILE_ATTRIBUTE_DIRECTORY) || (fattr & SMB_FILE_ATTRIBUTE_VOLUME); + if (isdir == 0) { + fid_info->type = SMB_FID_TYPE_FILE; + } else { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + offset += 2; BYTE_COUNT; @@ -3734,12 +3890,16 @@ dissect_create_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const char *fn; guint8 wc; guint16 bc; + smb_fid_saved_info_t *fsi; /* eo_smb needs to track this info */ + guint32 file_attributes = 0; DISSECTOR_ASSERT(si); WORD_COUNT; /* file attributes */ + /* We read the two lower bytes into the four-bytes file-attributes, because they are compatible */ + file_attributes = tvb_get_letohs(tvb, offset); offset = dissect_file_attributes(tvb, tree, offset); /* creation time */ @@ -3761,6 +3921,24 @@ dissect_create_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, fn); COUNT_BYTES(fn_len); + /* store it for the fid->name/openframe/closeframe matching in + * dissect_smb_fid() called from the response. + */ + if ((!pinfo->fd->flags.visited) && si->sip && fn) { + fsi = se_alloc(sizeof(smb_fid_saved_info_t)); + fsi->filename = se_strdup(fn); + fsi->create_flags = 0; + fsi->access_mask = 0; + fsi->file_attributes = file_attributes; + fsi->share_access = 0; + fsi->create_options = 0; + fsi->create_disposition = 0; + + 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))); @@ -4101,6 +4279,12 @@ dissect_set_information_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t return offset; } +typedef struct _rw_info_t { + guint64 offset; + guint32 len; + guint16 fid; +} rw_info_t; + static int dissect_read_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_) { @@ -4108,6 +4292,8 @@ dissect_read_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i guint16 cnt = 0, bc; guint32 ofs = 0; unsigned int fid; + rw_info_t *rwi = NULL; + smb_info_t *si = (smb_info_t *)pinfo->private_data; WORD_COUNT; @@ -4135,6 +4321,16 @@ dissect_read_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; + /* save the offset/len for this transaction */ + if (si->sip && !pinfo->fd->flags.visited) { + rwi = se_alloc(sizeof(rw_info_t)); + rwi->offset = ofs; + rwi->len = cnt; + rwi->fid = fid; + si->sip->extra_info_type = SMB_EI_RWINFO; + si->sip->extra_info = rwi; + } + BYTE_COUNT; END_OF_SMB @@ -4225,6 +4421,9 @@ dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 wc; smb_info_t *si = (smb_info_t *)pinfo->private_data; int fid = 0; + guint32 datalen=0,dataoffset=0; + guint32 tvblen; + rw_info_t *rwi = NULL; DISSECTOR_ASSERT(si); @@ -4248,7 +4447,9 @@ dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* data len */ CHECK_BYTE_COUNT(2); proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + datalen = tvb_get_letohs(tvb, offset); COUNT_BYTES(2); + dataoffset=offset; /* file data, might be DCERPC on a pipe */ if (bc) { @@ -4257,6 +4458,33 @@ dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bc = 0; } + /* If we have seen the request, then print which FID this refers to */ + if ((si->sip != NULL) && (si->sip->frame_req > 0) && (si->sip->extra_info_type == SMB_EI_FID)) { + fid = GPOINTER_TO_INT(si->sip->extra_info); + } + + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + PROTO_ITEM_SET_GENERATED(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + PROTO_ITEM_SET_GENERATED(it); + + /* we need the fid for the call to dcerpc below */ + fid = rwi->fid; + } + + /* feed the export object tap listener */ + tvblen = tvb_length_remaining(tvb, dataoffset); + if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { + feed_eo_smb(SMB_COM_READ,fid,tvb,pinfo,dataoffset,datalen,rwi->len,rwi->offset); + } + END_OF_SMB return offset; @@ -4296,11 +4524,6 @@ dissect_lock_and_read_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree return offset; } -typedef struct _rw_info_t { - guint64 offset; - guint32 len; - guint16 fid; -} rw_info_t; static int @@ -4311,6 +4534,8 @@ dissect_write_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 wc; smb_info_t *si = (smb_info_t *)pinfo->private_data; rw_info_t *rwi = NULL; + guint32 datalen=0,dataoffset=0; + guint32 tvblen; DISSECTOR_ASSERT(si); @@ -4323,6 +4548,7 @@ dissect_write_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* write count */ cnt = tvb_get_letohs(tvb, offset); + datalen = cnt; proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, cnt); offset += 2; @@ -4374,6 +4600,7 @@ dissect_write_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, CHECK_BYTE_COUNT(2); proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); COUNT_BYTES(2); + dataoffset=offset; /* file data, might be DCERPC on a pipe */ if (bc != 0) { @@ -4382,6 +4609,12 @@ dissect_write_file_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) { + feed_eo_smb(SMB_COM_WRITE,fid,tvb,pinfo,dataoffset,datalen,rwi->len,rwi->offset); + } + END_OF_SMB return offset; @@ -6424,15 +6657,6 @@ 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) { @@ -6443,14 +6667,7 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 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; - tvbuff_t *data_tvb; - GSList *GSL_iterator; DISSECTOR_ASSERT(si); @@ -6562,51 +6779,7 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* feed the export object tap listener */ tvblen = tvb_length_remaining(tvb, dataoffset); if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { - /* 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 = (smb_eo_t *)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 = (smb_fid_info_t *)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); - } - } - tid_info = (smb_tid_info_t *)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 = tvb_get_ptr(data_tvb, 0, datalen); - 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); + feed_eo_smb(SMB_COM_READ_ANDX,fid,tvb,pinfo,dataoffset,datalen,rwi->len,rwi->offset); } END_OF_SMB @@ -6633,15 +6806,8 @@ dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 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; - tvbuff_t *data_tvb; - GSList *GSL_iterator; + + guint32 tvblen; DISSECTOR_ASSERT(si); @@ -6791,57 +6957,7 @@ dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* feed the export object tap listener */ tvblen = tvb_length_remaining(tvb, dataoffset); if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { - /* 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 = (smb_eo_t *)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, fid);) */ - GSL_iterator = si->ct->GSL_fid_info; - while (GSL_iterator) { - suspect_fid_info = (smb_fid_info_t *)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); - } - } - tid_info = (smb_tid_info_t *)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 = tvb_get_ptr(data_tvb, 0, datalen); - 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); + feed_eo_smb(SMB_COM_WRITE_ANDX,fid,tvb,pinfo,dataoffset,datalen,rwi->len,rwi->offset); } END_OF_SMB @@ -20921,6 +21037,12 @@ proto_register_smb(void) "Whether the dissector should display SIDs and RIDs in hexadecimal rather than decimal", &sid_display_hex); + /* Will Export Object take name as fid ? */ + prefs_register_bool_preference(smb_module, "eosmb_take_name_as_fid", + "Use the full file name as File ID when exporting an SMB object", + "Whether the export object functionality will take the full path file name as file identifier", + &eosmb_take_name_as_fid); + register_init_routine(smb_trans_reassembly_init); smb_tap = register_tap("smb"); diff --git a/epan/dissectors/packet-smb.h b/epan/dissectors/packet-smb.h index 074526f6b0..a048e92a06 100644 --- a/epan/dissectors/packet-smb.h +++ b/epan/dissectors/packet-smb.h @@ -28,7 +28,6 @@ #include "ws_symbol_export.h" - WS_DLL_PUBLIC gboolean sid_name_snooping; /* SMB command codes, from the SNIA CIFS spec. With MSVC and a @@ -38,7 +37,6 @@ WS_DLL_PUBLIC value_string_ext smb_cmd_vals_ext; WS_DLL_PUBLIC value_string_ext trans2_cmd_vals_ext; WS_DLL_PUBLIC value_string_ext nt_cmd_vals_ext; - #define SMB_COM_CREATE_DIRECTORY 0x00 #define SMB_COM_DELETE_DIRECTORY 0x01 #define SMB_COM_OPEN 0x02 @@ -179,25 +177,24 @@ WS_DLL_PUBLIC value_string_ext nt_cmd_vals_ext; #define SMBE_sharebufexc 36 /* A sharing buffer has been exceeded */ #define SMBE_diskfull 39 -/* Used for SMB Export Object feature */ +/* used for SMB export object functionality */ 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; + guint smbversion; + guint16 cmd; + int tid,uid; + guint 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_DLL_PUBLIC const value_string smb_fid_types[]; - /* the information we need to keep around for NT transatcion commands */ typedef struct { int subcmd; @@ -437,4 +434,7 @@ extern int dissect_sfi_SMB_FILE_PIPE_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, extern int dissect_get_dfs_request_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint16 *bcp); extern int dissect_get_dfs_referral_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint16 *bcp); +/* Returns an IP (v4 or v6) of the server in a SMB/SMB2 conversation */ +extern const gchar *tree_ip_str(packet_info *pinfo, guint16 cmd); + #endif diff --git a/epan/dissectors/packet-smb2.c b/epan/dissectors/packet-smb2.c index 48e55eed07..2132c61b9d 100644 --- a/epan/dissectors/packet-smb2.c +++ b/epan/dissectors/packet-smb2.c @@ -46,6 +46,7 @@ #include "packet-smb.h" #include "packet-dcerpc-nt.h" #include <string.h> +#include <epan/prefs.h> #include <glib.h> /* Use libgcrypt for cipher libraries. */ @@ -402,6 +403,7 @@ static gint ett_smb2_transform_enc_alg = -1; static gint ett_smb2_buffercode = -1; static int smb2_tap = -1; +static int smb2_eo_tap = -1; static dissector_handle_t gssapi_handle = NULL; static dissector_handle_t ntlmssp_handle = NULL; @@ -517,6 +519,9 @@ static const value_string smb2_find_info_levels[] = { { 0, NULL } }; +/* ExportObject preferences variable */ +gboolean eosmb2_take_name_as_fid = FALSE ; + /* unmatched smb_saved_info structures. For unmatched smb_saved_info structures we store the smb_saved_info structure using the SEQNUM field. @@ -644,6 +649,149 @@ static void smb2_key_derivation(const guint8 *KI _U_, guint32 KI_len _U_, #endif } +/* for export-object-smb2 */ +static gchar *policy_hnd_to_file_id(const e_ctx_hnd *hnd) { +gchar *file_id; + file_id = ep_strdup_printf( + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + hnd->uuid.Data1, + hnd->uuid.Data2, + hnd->uuid.Data3, + hnd->uuid.Data4[0], + hnd->uuid.Data4[1], + hnd->uuid.Data4[2], + hnd->uuid.Data4[3], + hnd->uuid.Data4[4], + hnd->uuid.Data4[5], + hnd->uuid.Data4[6], + hnd->uuid.Data4[7]); + return file_id; +} +static guint smb2_eo_files_hash(gconstpointer k) { + return g_str_hash(policy_hnd_to_file_id((const e_ctx_hnd *)k)); +} +static gint smb2_eo_files_equal(gconstpointer k1, gconstpointer k2) { +int are_equal; + const e_ctx_hnd *key1 = (const e_ctx_hnd *)k1; + const e_ctx_hnd *key2 = (const e_ctx_hnd *)k2; + + are_equal = (key1->uuid.Data1==key2->uuid.Data1 && + key1->uuid.Data2==key2->uuid.Data2 && + key1->uuid.Data3==key2->uuid.Data3 && + key1->uuid.Data4[0]==key2->uuid.Data4[0] && + key1->uuid.Data4[1]==key2->uuid.Data4[1] && + key1->uuid.Data4[2]==key2->uuid.Data4[2] && + key1->uuid.Data4[3]==key2->uuid.Data4[3] && + key1->uuid.Data4[4]==key2->uuid.Data4[4] && + key1->uuid.Data4[5]==key2->uuid.Data4[5] && + key1->uuid.Data4[6]==key2->uuid.Data4[6] && + key1->uuid.Data4[7]==key2->uuid.Data4[7]); + + return are_equal; +} + +static void +feed_eo_smb2(tvbuff_t * tvb,packet_info *pinfo,smb2_info_t * si, guint16 dataoffset,guint32 length, guint64 file_offset) { + + char *fid_name = NULL; + guint32 open_frame = 0, close_frame = 0; + tvbuff_t *data_tvb = NULL; + smb_eo_t *eo_info; + gchar *file_id; + gchar *auxstring; + gchar **aux_string_v; + + /* Create a new tvb to point to the payload data */ + data_tvb = tvb_new_subset(tvb, dataoffset, length, length); + /* Create the eo_info to pass to the listener */ + eo_info = ep_alloc(sizeof(smb_eo_t)); + /* Fill in eo_info */ + eo_info->smbversion=2; + /* cmd == opcode */ + eo_info->cmd=si->opcode; + /* We don't keep track of uid in SMB v2 */ + eo_info->uid=0; + + /* Try to get file id and filename */ + file_id=policy_hnd_to_file_id(&si->saved->policy_hnd); + dcerpc_fetch_polhnd_data(&si->saved->policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->fd->num); + if (fid_name && g_strcmp0(fid_name,"File: ")!=0) { + auxstring=fid_name; + /* Remove "File: " from filename */ + if (g_str_has_prefix(auxstring, "File: ")) { + aux_string_v = g_strsplit(auxstring, "File: ", -1); + eo_info->filename = ep_strdup_printf("\\%s",aux_string_v[g_strv_length(aux_string_v)-1]); + g_strfreev(aux_string_v); + } else { + if (g_str_has_prefix(auxstring, "\\")) { + eo_info->filename = ep_strdup(auxstring); + } else { + eo_info->filename = ep_strdup_printf("\\%s",auxstring); + } + } + } else { + auxstring=ep_strdup_printf("File_Id_%s", file_id); + eo_info->filename=auxstring; + } + + + + if (eosmb2_take_name_as_fid) { + eo_info->fid = g_str_hash(eo_info->filename); + } else { + eo_info->fid = g_str_hash(file_id); + } + + /* tid, hostname, tree_id */ + if (si->tree) { + eo_info->tid=si->tree->tid; + if (strlen(si->tree->name)>0 && strlen(si->tree->name)<=256) { + eo_info->hostname = ep_strdup(si->tree->name); + } else { + eo_info->hostname = ep_strdup_printf("\\\\%s\\TREEID_%i",tree_ip_str(pinfo,si->opcode),si->tree->tid); + } + } else { + eo_info->tid=0; + eo_info->hostname = ep_strdup_printf("\\\\%s\\TREEID_UNKNOWN",tree_ip_str(pinfo,si->opcode)); + } + + /* packet number */ + eo_info->pkt_num = pinfo->fd->num; + + /* fid type */ + if (si->eo_file_info->attr_mask & SMB2_FLAGS_ATTR_DIRECTORY) { + eo_info->fid_type=SMB2_FID_TYPE_DIR; + } else { + if (si->eo_file_info->attr_mask & + (SMB2_FLAGS_ATTR_ARCHIVE | SMB2_FLAGS_ATTR_NORMAL | + SMB2_FLAGS_ATTR_HIDDEN | SMB2_FLAGS_ATTR_READONLY | + SMB2_FLAGS_ATTR_SYSTEM) ) { + eo_info->fid_type=SMB2_FID_TYPE_FILE; + } else { + eo_info->fid_type=SMB2_FID_TYPE_OTHER; + } + } + + /* end_of_file */ + eo_info->end_of_file=si->eo_file_info->end_of_file; + + /* data offset and chunk length */ + eo_info->smb_file_offset=file_offset; + eo_info->smb_chunk_len=length; + /* XXX is this right? */ + if (length<si->saved->bytes_moved) { + si->saved->file_offset=si->saved->file_offset+length; + si->saved->bytes_moved=si->saved->bytes_moved-length; + } + + /* Payload */ + eo_info->payload_len = length; + eo_info->payload_data = tvb_get_ptr(data_tvb, 0, length); + + tap_queue_packet(smb2_eo_tap, pinfo, eo_info); + +} + static int dissect_smb2_file_full_ea_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, smb2_info_t *si); @@ -1198,9 +1346,11 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset static dcerpc_call_value call_data; void *old_private_data; e_ctx_hnd policy_hnd; + e_ctx_hnd *policy_hnd_hashtablekey; proto_item *hnd_item = NULL; char *fid_name; guint32 open_frame = 0, close_frame = 0; + smb2_eo_file_info_t *eo_file_info; di.conformant_run = 0; /* we need di->call_data->flags.NDR64 == 0 */ @@ -1219,6 +1369,21 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset } dcerpc_store_polhnd_name(&policy_hnd, pinfo, fid_name); + + /* If needed, create the file entry and save the policy hnd */ + if (si->saved) { si->saved->policy_hnd = policy_hnd; } + + if (si->conv) { + eo_file_info = g_hash_table_lookup(si->conv->files,&policy_hnd); + if (!eo_file_info) { + eo_file_info = se_alloc(sizeof(smb2_eo_file_info_t)); + policy_hnd_hashtablekey = se_alloc(sizeof(e_ctx_hnd)); + memcpy(policy_hnd_hashtablekey, &policy_hnd, sizeof(e_ctx_hnd)); + eo_file_info->end_of_file=0; + g_hash_table_insert(si->conv->files,policy_hnd_hashtablekey,eo_file_info); + } + si->eo_file_info=eo_file_info; + } } break; case FID_MODE_CLOSE: @@ -1234,8 +1399,8 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset pinfo->private_data = old_private_data; - /* put the filename in col_info */ if (dcerpc_fetch_polhnd_data(&policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->fd->num)) { + /* put the filename in col_info */ if (fid_name) { if (hnd_item) { proto_item_append_text(hnd_item, " %s", fid_name); @@ -1244,6 +1409,25 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset col_append_fstr(pinfo->cinfo, COL_INFO, " %s", fid_name); } } + + /* look for the eo_file_info */ + if (!si->eo_file_info) { + if (si->saved) { si->saved->policy_hnd = policy_hnd; } + if (si->conv) { + eo_file_info = g_hash_table_lookup(si->conv->files,&policy_hnd); + if (eo_file_info) { + si->eo_file_info=eo_file_info; + } else { /* XXX This should never happen */ + //assert(1==0); + eo_file_info = se_alloc(sizeof(smb2_eo_file_info_t)); + policy_hnd_hashtablekey = se_alloc(sizeof(e_ctx_hnd)); + memcpy(policy_hnd_hashtablekey, &policy_hnd, sizeof(e_ctx_hnd)); + eo_file_info->end_of_file=0; + g_hash_table_insert(si->conv->files,policy_hnd_hashtablekey,eo_file_info); + } + } + + } } return offset; @@ -3844,6 +4028,8 @@ dissect_file_data_dcerpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_ static int dissect_smb2_write_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si) { + guint16 dataoffset = 0; + guint32 data_tvb_len; guint32 length; guint64 off; static const int *f_fields[] = { @@ -3855,6 +4041,7 @@ dissect_smb2_write_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); /* data offset */ + dataoffset=tvb_get_letohl(tvb,offset); proto_tree_add_item(tree, hf_smb2_data_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -3865,6 +4052,7 @@ dissect_smb2_write_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* offset */ off = tvb_get_letoh64(tvb, offset); + if (si->saved) si->saved->file_offset=off; proto_tree_add_item(tree, hf_smb2_file_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN); offset += 8; @@ -3903,8 +4091,17 @@ dissect_smb2_write_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* just ordinary data */ proto_tree_add_item(tree, hf_smb2_write_data, tvb, offset, length, ENC_NA); + + data_tvb_len=(guint32)tvb_length_remaining(tvb, offset); + offset += MIN(length,(guint32)tvb_length_remaining(tvb, offset)); + if (have_tap_listener(smb2_eo_tap) && (data_tvb_len == length)) { + if (si->saved && si->eo_file_info) { /* without this data we don't know wich file this belongs to */ + feed_eo_smb2(tvb,pinfo,si,dataoffset,length,off); + } + } + return offset; } @@ -4675,6 +4872,12 @@ dissect_smb2_read_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i /* there is a buffer here but it is never used (yet) */ + /* Store len and offset */ + if (si->saved) { + si->saved->file_offset=off; + si->saved->bytes_moved=len; + } + return offset; } @@ -4682,8 +4885,9 @@ dissect_smb2_read_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i static int dissect_smb2_read_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si _U_) { + guint16 dataoffset = 0; + guint32 data_tvb_len; guint32 length; - switch (si->status) { case 0x00000000: break; default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si); @@ -4693,6 +4897,7 @@ dissect_smb2_read_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); /* data offset */ + dataoffset=tvb_get_letohl(tvb,offset); proto_tree_add_item(tree, hf_smb2_data_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -4719,7 +4924,16 @@ dissect_smb2_read_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* data */ proto_tree_add_item(tree, hf_smb2_read_data, tvb, offset, length, ENC_NA); - offset += MIN(length,(guint32)tvb_length_remaining(tvb, offset)); + + data_tvb_len=(guint32)tvb_length_remaining(tvb, offset); + + offset += MIN(length,data_tvb_len); + + if (have_tap_listener(smb2_eo_tap) && (data_tvb_len == length)) { + if (si->saved && si->eo_file_info) { /* without this data we don't know wich file this belongs to */ + feed_eo_smb2(tvb,pinfo,si,dataoffset,length,si->saved->file_offset); + } + } return offset; } @@ -5388,6 +5602,8 @@ dissect_smb2_create_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, static int dissect_smb2_create_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si) { + guint64 end_of_file; + guint32 attr_mask; offset_length_buffer_t e_olb; static const int *create_rep_flags_fields[] = { &hf_smb2_create_rep_flags_reparse_point, @@ -5431,10 +5647,15 @@ dissect_smb2_create_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree offset += 8; /* end of file */ + end_of_file = tvb_get_letoh64(tvb, offset); + if (si->eo_file_info) { + si->eo_file_info->end_of_file = tvb_get_letoh64(tvb, offset); + } proto_tree_add_item(tree, hf_smb2_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); offset += 8; /* File Attributes */ + attr_mask=tvb_get_letohl(tvb, offset); offset = dissect_file_ext_attr(tvb, tree, offset); /* reserved */ @@ -5443,6 +5664,15 @@ dissect_smb2_create_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree /* fid */ offset = dissect_smb2_fid(tvb, pinfo, tree, offset, si, FID_MODE_OPEN); + /* We save this after dissect_smb2_fid just because it would be + possible to have this response without having the mathing request. + In that case the entry in the file info hash table has been created + in dissect_smb2_fid */ + if (si->eo_file_info) { + si->eo_file_info->end_of_file = end_of_file; + si->eo_file_info->attr_mask = attr_mask; + } + /* extrainfo offset */ offset = dissect_smb2_olb_length_offset(tvb, offset, &e_olb, OLB_O_UINT32_S_UINT32, hf_smb2_extrainfo); @@ -6557,9 +6787,14 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea smb2_saved_info_t *ssi = NULL, ssi_key; smb2_info_t *si; smb2_transform_info_t *sti; + char *fid_name; + guint32 open_frame,close_frame; + smb2_eo_file_info_t *eo_file_info; + e_ctx_hnd *policy_hnd_hashtablekey; sti = ep_alloc(sizeof(smb2_transform_info_t)); si = ep_alloc(sizeof(smb2_info_t)); + si->eo_file_info = NULL; si->conv = NULL; si->saved = NULL; si->tree = NULL; @@ -6587,6 +6822,7 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea smb2_saved_info_equal_unmatched); si->conv->sesids = g_hash_table_new(smb2_sesid_info_hash, smb2_sesid_info_equal); + si->conv->files = g_hash_table_new(smb2_eo_files_hash,smb2_eo_files_equal); conversation_add_proto_data(conversation, proto_smb2, si->conv); } @@ -6762,6 +6998,24 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea } if (ssi) { + if (dcerpc_fetch_polhnd_data(&ssi->policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->fd->num)) { + /* If needed, create the file entry and save the policy hnd */ + if (!si->eo_file_info) { + if (si->conv) { + eo_file_info = g_hash_table_lookup(si->conv->files,&ssi->policy_hnd); + if (!eo_file_info) { /* XXX This should never happen */ + /* assert(1==0); */ + eo_file_info = se_alloc(sizeof(smb2_eo_file_info_t)); + policy_hnd_hashtablekey = se_alloc(sizeof(e_ctx_hnd)); + memcpy(policy_hnd_hashtablekey, &ssi->policy_hnd, sizeof(e_ctx_hnd)); + eo_file_info->end_of_file=0; + g_hash_table_insert(si->conv->files,policy_hnd_hashtablekey,eo_file_info); + } + si->eo_file_info=eo_file_info; + } + } + } + if (!(si->flags & SMB2_FLAGS_RESPONSE)) { if (ssi->frame_res) { proto_item *tmp_item; @@ -6855,6 +7109,7 @@ dissect_smb2_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, vo void proto_register_smb2(void) { + module_t *smb2_module; static hf_register_info hf[] = { { &hf_smb2_cmd, { "Command", "smb2.cmd", FT_UINT16, BASE_DEC|BASE_EXT_STRING, @@ -7995,8 +8250,16 @@ proto_register_smb2(void) proto_register_subtree_array(ett, array_length(ett)); proto_register_field_array(proto_smb2, hf, array_length(hf)); + smb2_module = prefs_register_protocol(proto_smb2, NULL); + prefs_register_bool_preference(smb2_module, "eosmb2_take_name_as_fid", + "Use the full file name as File ID when exporting an SMB2 object", + "Whether the export object functionality will take the full path file name as file identifier", + &eosmb2_take_name_as_fid); + register_heur_dissector_list("smb2_heur_subdissectors", &smb2_heur_subdissector_list); smb2_tap = register_tap("smb2"); + smb2_eo_tap = register_tap("smb_eo"); /* SMB Export Object tap */ + } void diff --git a/epan/dissectors/packet-smb2.h b/epan/dissectors/packet-smb2.h index 61c9e440fb..919e99b407 100644 --- a/epan/dissectors/packet-smb2.h +++ b/epan/dissectors/packet-smb2.h @@ -25,6 +25,9 @@ #ifndef __PACKET_SMB2_H__ #define __PACKET_SMB2_H__ +#include "packet-dcerpc.h" +#include "packet-smb.h" + /* SMB2 command codes. With MSVC and a * libwireshark.dll, we need a special declaration. */ @@ -41,6 +44,13 @@ WS_DLL_PUBLIC value_string_ext smb2_cmd_vals_ext; * private data is set to NULL when the structure is created. It is used * for communications between the Request and the Response packets. */ + +/* extra info needed by export object smb */ +typedef struct _smb2_eo_file_info_t { + guint32 attr_mask; + gint64 end_of_file; +} smb2_eo_file_info_t; + typedef enum { SMB2_EI_NONE, /* Unassigned / NULL */ SMB2_EI_TREENAME, /* tid tracking char * */ @@ -53,6 +63,10 @@ typedef struct _smb2_saved_info_t { guint64 seqnum; guint32 frame_req, frame_res; nstime_t req_time; + e_ctx_hnd policy_hnd; /* for eo_smb tracking */ + smb_eo_t *eo_info_t; /* for storing eo_smb infos */ + guint64 file_offset; /* needed file_offset for eo_smb */ + guint32 bytes_moved; /* needed for eo_smb */ void *extra_info; smb2_extra_info_t extra_info_type; } smb2_saved_info_t; @@ -84,8 +98,11 @@ typedef struct _smb2_conv_info_t { GHashTable *unmatched; GHashTable *matched; GHashTable *sesids; + /* table to store some infos for smb export object */ + GHashTable *files; } smb2_conv_info_t; + /* This structure contains information from the SMB2 header * as well as pointers to the conversation and the transaction specific * structures. @@ -96,6 +113,52 @@ typedef struct _smb2_conv_info_t { #define SMB2_FLAGS_SIGNATURE 0x00000008 #define SMB2_FLAGS_DFS_OP 0x10000000 #define SMB2_FLAGS_REPLAY_OPERATION 0x20000000 + +/* SMB2 FLAG MASKS */ +#define SMB2_FLAGS_ATTR_ENCRYPTED 0x00004000 +#define SMB2_FLAGS_ATTR_INDEXED 0x00002000 +#define SMB2_FLAGS_ATTR_OFFLINE 0x00001000 +#define SMB2_FLAGS_ATTR_COMPRESSED 0x00000800 +#define SMB2_FLAGS_ATTR_REPARSEPOINT 0x00000400 +#define SMB2_FLAGS_ATTR_SPARSE 0x00000200 +#define SMB2_FLAGS_ATTR_TEMPORARY 0x00000100 +#define SMB2_FLAGS_ATTR_NORMAL 0x00000080 +#define SMB2_FLAGS_ATTR_DEVICE 0x00000040 +#define SMB2_FLAGS_ATTR_ARCHIVE 0x00000020 +#define SMB2_FLAGS_ATTR_DIRECTORY 0x00000010 +#define SMB2_FLAGS_ATTR_VOLUMEID 0x00000008 +#define SMB2_FLAGS_ATTR_SYSTEM 0x00000004 +#define SMB2_FLAGS_ATTR_HIDDEN 0x00000002 +#define SMB2_FLAGS_ATTR_READONLY 0x00000001 + +/* SMB2 FILE TYPES ASIGNED TO EXPORT OBJECTS */ +#define SMB2_FID_TYPE_UNKNOWN 0 +#define SMB2_FID_TYPE_FILE 1 +#define SMB2_FID_TYPE_DIR 2 +#define SMB2_FID_TYPE_PIPE 3 +#define SMB2_FID_TYPE_OTHER 4 + +/* SMB2 COMMAND CODES */ +#define SMB2_COM_NEGOTIATE_PROTOCOL 0x00 +#define SMB2_COM_SESSION_SETUP 0x01 +#define SMB2_COM_SESSION_LOGOFF 0x02 +#define SMB2_COM_TREE_CONNECT 0x03 +#define SMB2_COM_TREE_DISCONNECT 0x04 +#define SMB2_COM_CREATE 0x05 +#define SMB2_COM_CLOSE 0x06 +#define SMB2_COM_FLUSH 0x07 +#define SMB2_COM_READ 0x08 +#define SMB2_COM_WRITE 0x09 +#define SMB2_COM_LOCK 0x0A +#define SMB2_COM_IOCTL 0x0B +#define SMB2_COM_CANCEL 0x0C +#define SMB2_COM_KEEPALIVE 0x0D +#define SMB2_COM_FIND 0x0E +#define SMB2_COM_NOTIFY 0x0F +#define SMB2_COM_GETINFO 0x10 +#define SMB2_COM_SETINFO 0x11 +#define SMB2_COM_BREAK 0x12 + typedef struct _smb2_info_t { guint16 opcode; guint32 ioctl_function; @@ -104,6 +167,7 @@ typedef struct _smb2_info_t { guint64 sesid; gint64 seqnum; guint32 flags; + smb2_eo_file_info_t *eo_file_info; /* eo_smb extra info */ smb2_conv_info_t *conv; smb2_saved_info_t *saved; smb2_tid_info_t *tree; diff --git a/ui/export_object.h b/ui/export_object.h index ba73361224..c42d8524ff 100644 --- a/ui/export_object.h +++ b/ui/export_object.h @@ -59,9 +59,9 @@ const char *ct2ext(const char *content_type); gboolean eo_dicom_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data); gboolean eo_http_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, - const void *data); + const void *data); gboolean eo_smb_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, - const void *data); + const void *data); void eo_smb_cleanup(void); diff --git a/ui/export_object_smb.c b/ui/export_object_smb.c index 9153b70787..2e15795a47 100644 --- a/ui/export_object_smb.c +++ b/ui/export_object_smb.c @@ -34,6 +34,7 @@ #include <epan/packet.h> #include <epan/dissectors/packet-smb.h> +#include <epan/dissectors/packet-smb2.h> #include <epan/tap.h> #include "export_object.h" @@ -45,16 +46,33 @@ #define SMB_EO_CONTAINS_READS 0x01 #define SMB_EO_CONTAINS_WRITES 0x02 #define SMB_EO_CONTAINS_READSANDWRITES 0x03 -#define LEGAL_FILENAME_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ1234567890_." +#define LEGAL_FILENAME_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.- /\\{}[]=()&%$!,;.+&%$~#@" static 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} - }; - + {SMB_EO_CONTAINS_NOTHING, "" }, + {SMB_EO_CONTAINS_READS, "R" }, + {SMB_EO_CONTAINS_WRITES, "W" }, + {SMB_EO_CONTAINS_READSANDWRITES, "R&W"}, + {0, NULL} +}; + +/* Strings that describes the SMB object type */ +static 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 const value_string smb2_fid_types[] = { + {SMB2_FID_TYPE_UNKNOWN,"UNKNOWN"}, + {SMB2_FID_TYPE_FILE,"FILE"}, + {SMB2_FID_TYPE_DIR,"DIRECTORY (Not Implemented)"}, + {SMB2_FID_TYPE_PIPE,"PIPE (Not Implemented)"}, + {SMB2_FID_TYPE_OTHER,"OTHER (Not Implemented)"}, + {0, NULL} +}; /* This struct contains the relationship between the row# in the export_object window and the file being captured; @@ -96,318 +114,350 @@ typedef struct _free_chunk { static 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; i<nfreechunks; i++) { - current_free_chunk = g_slist_nth_data(file->free_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 */ - if (calculated_size > G_MAXSIZE) { - /* - * The argument to g_try_malloc() is - * a gsize, the maximum value of which is - * G_MAXSIZE. If the calculated size is - * bigger than that, we just say the attempt - * to allocate memory failed. - */ - entry->payload_data = NULL; - } else { - entry->payload_data = g_try_malloc((gsize)calculated_size); - entry->payload_len = 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 */ - if (calculated_size > G_MAXSIZE) { - /* - * As for g_try_malloc(), so for - * g_try_realloc(). - */ - dest_memory_addr = NULL; - } else { - dest_memory_addr = g_try_realloc( - entry->payload_data, - (gsize)calculated_size); - } - if (!dest_memory_addr) { - /* Memory error */ - file->is_out_of_memory = TRUE; - /* We don't 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); - } +gint nfreechunks = g_slist_length(file->free_chunk_list); +gint 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); + + /* Recalculate each free chunk according with the incoming data chunk */ + for (i=0; i<nfreechunks; i++) { + current_free_chunk = g_slist_nth_data(file->free_chunk_list, i); + /* 1. data chunk before the free chunk? */ + /* -> free chunk is not altered and no new data gathered */ + if (chunk_end_offset<current_free_chunk->start_offset) { + continue; + } + /* 2. data chunk overlaps the first part of free_chunk */ + /* -> free chunk shrinks from the beggining */ + if (chunk_offset<=current_free_chunk->start_offset && chunk_end_offset>=current_free_chunk->start_offset && 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; + continue; + } + /* 3. data chunk overlaps completely the free chunk */ + /* -> free chunk is removed */ + if (chunk_offset<=current_free_chunk->start_offset && chunk_end_offset>=current_free_chunk->end_offset) { + 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; + } + i--; + continue; + } + /* 4. data chunk is inside the free chunk */ + /* -> free chunk is splitted into two */ + if (chunk_offset>current_free_chunk->start_offset && 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; + continue; + } + /* 5.- data chunk overlaps the end part of free chunk */ + /* -> free chunk shrinks from the end */ + if (chunk_offset>current_free_chunk->start_offset && chunk_offset<=current_free_chunk->end_offset && chunk_end_offset>=current_free_chunk->end_offset) { + file->data_gathered += current_free_chunk->end_offset-chunk_offset+1; + current_free_chunk->end_offset = chunk_offset-1; + continue; + } + /* 6.- data chunk is after the free chunk */ + /* -> free chunk is not altered and no new data gathered */ + if (chunk_offset>current_free_chunk->end_offset) { + continue; + } + } + + /* 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 */ + if (calculated_size > G_MAXSIZE) { + /* + * The argument to g_try_malloc() is + * a gsize, the maximum value of which is + * G_MAXSIZE. If the calculated size is + * bigger than that, we just say the attempt + * to allocate memory failed. + */ + entry->payload_data = NULL; + } else { + entry->payload_data = g_try_malloc((gsize)calculated_size); + entry->payload_len = 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 */ + if (calculated_size > G_MAXSIZE) { + /* + * As for g_try_malloc(), so for + * g_try_realloc(). + */ + dest_memory_addr = NULL; + } else { + dest_memory_addr = g_try_realloc( + entry->payload_data, + (gsize)calculated_size); + } + if (!dest_memory_addr) { + /* Memory error */ + file->is_out_of_memory = TRUE; + /* We don't 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 */ static int find_incoming_file(GSList *GSL_active_files_p, active_file *incoming_file) { - int i, row, last; - active_file *in_list_file; - - row = -1; - last = g_slist_length(GSL_active_files_p) - 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_p, 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; + int i, row, last; + active_file *in_list_file; + + row = -1; + last = g_slist_length(GSL_active_files_p) - 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_p, 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 */ gboolean eo_smb_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data) { - 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; - gfloat percent; - - gchar **aux_string_v; - - /* Is this an 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[g_strv_length(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 { - if (new_file->file_length > 0) { - percent = (gfloat) (100*new_file->data_gathered/new_file->file_length); - } else { - percent = 0.0f; - } - - 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_add_entry(object_list, 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 = object_list_get_entry(object_list, 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 TRUE; /* State changed - window should be redrawn */ +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; +gfloat percent; + +gchar *aux_smb_fid_type_string; + + if (eo_info->smbversion==1) { + /* Is this an eo_smb supported file_type? (right now we only support FILE) */ + is_supported_filetype = (eo_info->fid_type == SMB_FID_TYPE_FILE); + aux_smb_fid_type_string=g_strdup(match_strval(eo_info->fid_type, smb_fid_types)); + + /* What kind of data this packet contains? */ + switch(eo_info->cmd) { + case SMB_COM_READ_ANDX: + case SMB_COM_READ: + contains = SMB_EO_CONTAINS_READS; + break; + case SMB_COM_WRITE_ANDX: + case SMB_COM_WRITE: + contains = SMB_EO_CONTAINS_WRITES; + break; + default: + contains = SMB_EO_CONTAINS_NOTHING; + break; + } + } else { + /* Is this an eo_smb supported file_type? (right now we only support FILE) */ + is_supported_filetype = (eo_info->fid_type == SMB2_FID_TYPE_FILE ); + aux_smb_fid_type_string=g_strdup(match_strval(eo_info->fid_type, smb2_fid_types)); + + /* What kind of data this packet contains? */ + switch(eo_info->cmd) { + case SMB2_COM_READ: + contains = SMB_EO_CONTAINS_READS; + break; + case SMB2_COM_WRITE: + 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_filename_display_name(g_strcanon(eo_info->hostname,LEGAL_FILENAME_CHARS,'?')); + entry->filename=g_filename_display_name(g_strcanon(eo_info->filename,LEGAL_FILENAME_CHARS,'?')); + + /* 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!!]", + aux_smb_fid_type_string, + new_file->data_gathered, + new_file->file_length, + match_strval(contains, smb_eo_contains_string)); + } else { + if (new_file->file_length > 0) { + percent = (gfloat) (100*new_file->data_gathered/new_file->file_length); + } else { + percent = 0.0f; + } + + entry->content_type = + g_strdup_printf("%s (%"G_GUINT64_FORMAT"/%"G_GUINT64_FORMAT") %s [%5.2f%%]", + aux_smb_fid_type_string, + new_file->data_gathered, + new_file->file_length, + match_strval(contains, smb_eo_contains_string), + percent); + } + + object_list_add_entry(object_list, 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 = object_list_get_entry(object_list, 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!!]", + aux_smb_fid_type_string, + 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%%]", + aux_smb_fid_type_string, + current_file->data_gathered, + current_file->file_length, + match_strval(current_file->flag_contains, smb_eo_contains_string), + percent); + } + } + + return TRUE; /* State changed - window should be redrawn */ } + + /* This is the eo_protocoldata_reset function that is used in the export_object module to cleanup any previous private data of the export object functionality before perform the eo_reset function or when the window closes */ void eo_smb_cleanup(void) { - int i, 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; - } +int i, 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; + } } /* diff --git a/ui/gtk/export_object_dlg.c b/ui/gtk/export_object_dlg.c index 6b49bbb943..27afb762b9 100644 --- a/ui/gtk/export_object_dlg.c +++ b/ui/gtk/export_object_dlg.c @@ -132,6 +132,26 @@ eo_win_destroy_cb(GtkWindow *win _U_, gpointer data) if (eo_protocoldata_reset != NULL) eo_protocoldata_reset(); } +static gchar *eo_saveable_pathname(gchar *filename) { +gchar **splitted_pathname; +gchar *auxstring, *saveable_pathname; +guint nparts,i; + + saveable_pathname = NULL; + splitted_pathname = g_strsplit_set(filename,"\\",-1); + nparts = g_strv_length(splitted_pathname); + if (nparts>0) { + saveable_pathname=g_strdup(splitted_pathname[0]); + } + for (i=1;i<nparts;i++) { + auxstring = g_strconcat(saveable_pathname,"__",splitted_pathname[i],NULL); + g_free(saveable_pathname); + saveable_pathname = auxstring; + } + + return saveable_pathname; +} + static void eo_save_clicked_cb(GtkWidget *widget _U_, gpointer arg) { @@ -139,6 +159,7 @@ eo_save_clicked_cb(GtkWidget *widget _U_, gpointer arg) export_object_list_t *object_list = arg; export_object_entry_t *entry; gchar *filename = NULL; + gchar *auxfilename = NULL; entry = g_slist_nth_data(object_list->entries, object_list->row_selected); @@ -154,14 +175,18 @@ eo_save_clicked_cb(GtkWidget *widget _U_, gpointer arg) gtk_window_set_transient_for(GTK_WINDOW(save_as_w), GTK_WINDOW(object_list->dlg)); + auxfilename = eo_saveable_pathname(entry->filename); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_as_w), - entry->filename); + auxfilename); + if(gtk_dialog_run(GTK_DIALOG(save_as_w)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_as_w)); eo_save_entry(filename, entry, TRUE); } + g_free(auxfilename); g_free(filename); window_destroy(save_as_w); } @@ -178,6 +203,7 @@ eo_save_all_clicked_cb(GtkWidget *widget _U_, gpointer arg) gboolean all_saved = TRUE; gchar *save_in_path; GString *safe_filename; + gchar *auxfilename = NULL; int count = 0; save_in_w = file_selection_new("Wireshark: Save All Objects In ...", @@ -194,10 +220,12 @@ eo_save_all_clicked_cb(GtkWidget *widget _U_, gpointer arg) if ((strlen(save_in_path) < MAXFILELEN)) { do { g_free(save_as_fullpath); - if (entry->filename) - safe_filename = eo_massage_str(entry->filename, + if (entry->filename) { + auxfilename = eo_saveable_pathname(entry->filename); + safe_filename = eo_massage_str(auxfilename, MAXFILELEN - strlen(save_in_path), count); - else { + g_free(auxfilename); + } else { char generic_name[256]; const char *ext; ext = ct2ext(entry->content_type); diff --git a/ui/gtk/main_menubar.c b/ui/gtk/main_menubar.c index 4f53ba667f..37c4c7b3e5 100644 --- a/ui/gtk/main_menubar.c +++ b/ui/gtk/main_menubar.c @@ -1448,7 +1448,7 @@ static const GtkActionEntry main_menu_bar_entries[] = { NULL, NULL, G_CALLBACK(export_pdml_cmd_cb) }, { "/File/ExportObjects/HTTP", NULL, "_HTTP", NULL, NULL, G_CALLBACK(eo_http_cb) }, { "/File/ExportObjects/DICOM", NULL, "_DICOM", NULL, NULL, G_CALLBACK(eo_dicom_cb) }, - { "/File/ExportObjects/SMB", NULL, "_SMB", NULL, NULL, G_CALLBACK(eo_smb_cb) }, + { "/File/ExportObjects/SMB", NULL, "_SMB/SMB2", NULL, NULL, G_CALLBACK(eo_smb_cb) }, { "/Edit/Copy", NULL, "Copy", NULL, NULL, NULL }, |