]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2737 in SNORT/snort3 from ~DIPANDIT/snort3:classify to master
authorLokesh Bevinamarad (lbevinam) <lbevinam@cisco.com>
Tue, 16 Mar 2021 07:55:49 +0000 (07:55 +0000)
committerLokesh Bevinamarad (lbevinam) <lbevinam@cisco.com>
Tue, 16 Mar 2021 07:55:49 +0000 (07:55 +0000)
Squashed commit of the following:

commit 85f29b509d5b53795caffbd55a44991929bac49c
Author: Dipto Pandit <dipandit@cisco.com>
Date:   Thu Oct 8 06:55:59 2020 -0400

    dce_rpc: refactoring smb code

    Changed old C style code to C++ code. Created classes for appropriate
    structures and encapsulated the methods. maintained data boundary as
    much as possible. Changed file structure to reduce clutter.

37 files changed:
src/service_inspectors/dce_rpc/CMakeLists.txt
src/service_inspectors/dce_rpc/dce_co.cc
src/service_inspectors/dce_rpc/dce_common.cc
src/service_inspectors/dce_rpc/dce_common.h
src/service_inspectors/dce_rpc/dce_db.h [deleted file]
src/service_inspectors/dce_rpc/dce_smb.h [deleted file]
src/service_inspectors/dce_rpc/dce_smb1.cc [moved from src/service_inspectors/dce_rpc/dce_smb.cc with 68% similarity]
src/service_inspectors/dce_rpc/dce_smb1.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2.cc
src/service_inspectors/dce_rpc/dce_smb2.h
src/service_inspectors/dce_rpc/dce_smb2_commands.cc [deleted file]
src/service_inspectors/dce_rpc/dce_smb2_commands.h [deleted file]
src/service_inspectors/dce_rpc/dce_smb2_file.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_file.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_request.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_session.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_session.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_session_cache.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_tree.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_tree.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb2_utils.cc [deleted file]
src/service_inspectors/dce_rpc/dce_smb2_utils.h [deleted file]
src/service_inspectors/dce_rpc/dce_smb_commands.cc
src/service_inspectors/dce_rpc/dce_smb_common.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb_common.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb_inspector.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb_inspector.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_smb_module.cc
src/service_inspectors/dce_rpc/dce_smb_module.h
src/service_inspectors/dce_rpc/dce_smb_paf.cc
src/service_inspectors/dce_rpc/dce_smb_transaction.cc
src/service_inspectors/dce_rpc/dce_smb_transaction_utils.h
src/service_inspectors/dce_rpc/dce_smb_utils.cc
src/service_inspectors/dce_rpc/dce_smb_utils.h
src/service_inspectors/dce_rpc/dev_notes.txt
src/service_inspectors/dce_rpc/smb_message.cc
src/service_inspectors/dce_rpc/smb_message.h

index a8b19ad043b47e18da80ea08fb42068eb1649d7e..3f4ca4b094e3948bdd8518b5092fcfe51b790708 100644 (file)
@@ -6,7 +6,6 @@ set( FILE_LIST
     dce_common.h
     dce_context_data.cc
     dce_context_data.h
-    dce_db.h
     dce_expected_session.cc
     dce_expected_session.h
     dce_http_proxy.cc
@@ -19,18 +18,25 @@ set( FILE_LIST
     dce_http_server_module.h
     dce_http_server_splitter.cc
     dce_http_server_splitter.h
-    dce_list.h
     dce_list.cc
-    dce_smb.cc
-    dce_smb.h
+    dce_list.h
+    dce_smb1.cc
+    dce_smb1.h
     dce_smb2.cc
     dce_smb2.h
-    dce_smb2_commands.cc
-    dce_smb2_commands.h
-    dce_smb2_utils.cc
-    dce_smb2_utils.h
+    dce_smb2_file.cc
+    dce_smb2_file.h
+    dce_smb2_request.h
+    dce_smb2_session.cc
+    dce_smb2_session.h
+    dce_smb2_tree.cc
+    dce_smb2_tree.h
     dce_smb_commands.cc
     dce_smb_commands.h
+    dce_smb_common.cc
+    dce_smb_common.h
+    dce_smb_inspector.cc
+    dce_smb_inspector.h
     dce_smb_module.cc
     dce_smb_module.h
     dce_smb_paf.cc
index ac8b121fe86686aa8a113798668cecf21ad3aa00..1bca583d37f29fc9c2e20ec514c4ced63c28cf37 100644 (file)
@@ -28,7 +28,7 @@
 #include "utils/util.h"
 
 #include "dce_expected_session.h"
-#include "dce_smb.h"
+#include "dce_smb1.h"
 #include "dce_smb_module.h"
 #include "dce_smb_utils.h"
 #include "dce_tcp.h"
index c56a74b1b6afd111fe5a3f5c4474dfe3417f4fe7..99ea498dd11733ac5e38b6ad4be55b5e006bfa5d 100644 (file)
@@ -32,6 +32,8 @@
 #include "dce_context_data.h"
 #include "dce_http_proxy_module.h"
 #include "dce_http_server_module.h"
+#include "dce_smb1.h"
+#include "dce_smb_common.h"
 #include "dce_smb_utils.h"
 #include "dce_tcp.h"
 #include "dce_udp.h"
@@ -141,6 +143,7 @@ bool dce2_paf_abort(DCE2_SsnData* sd)
 
 void DCE2_Detect(DCE2_SsnData* sd)
 {
+    if (!sd) return ;
     DceContextData::set_current_ropts(sd);
     if ( using_rpkt )
     {
index 90d8c19d84bc5ea10a31c945493088841252ca34..0e8ebf5b417c57ba7ba0e7a05c4ce9dc59f31cf9 100644 (file)
@@ -224,7 +224,7 @@ public:
     void reset();
 };
 
-inline void DCE2_ResetRopts(DCE2_SsnData* sd, snort::Packet* p)
+inline void DCE2_ResetRopts(DCE2_SsnData* sd, const snort::Packet* p)
 {
     sd->ropts.first_frag = DCE2_SENTINEL;
     sd->ropts.opnum = DCE2_SENTINEL;
diff --git a/src/service_inspectors/dce_rpc/dce_db.h b/src/service_inspectors/dce_rpc/dce_db.h
deleted file mode 100644 (file)
index 091fb1d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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.
-//--------------------------------------------------------------------------
-// dce_db.h author Neha Sharma <nehash4@cisco.com>
-
-// This implementation provides interface that can be extended for map, list, etc.
-// Currently only map has been implemented to handle multiple smb sessions
-// in single tcp connection. This database will modify/change to handle
-// single smb session spread across multiple tcp connections.
-
-#ifndef DCE_DB_H
-#define DCE_DB_H
-
-#include <unordered_map>
-#include <vector>
-#include "dce_utils.h"
-
-#include "main/snort_types.h"
-
-template<typename Key, typename Value, typename Hash>
-class DCE2_Db
-{
-public:
-
-    virtual void SetDoNotFree() = 0;
-    virtual bool Insert(const Key& key, Value data) = 0;
-    virtual Value Find(const Key& key) = 0;
-    virtual void Remove(const Key& key) = 0;
-    virtual int GetSize() = 0;
-    virtual std::vector< std::pair<Key, Value> > get_all_entry() = 0;
-};
-
-template<typename Key, typename Value, typename Hash>
-class DCE2_DbMap : public DCE2_Db<Key, Value, Hash>
-{
-public:
-
-    DCE2_DbMap() = default;
-
-    ~DCE2_DbMap()
-    {
-        auto it = Map.cbegin();
-        while (it != Map.cend())
-        {
-            if (!do_not_free)
-                delete it->second;
-            it = Map.erase(it);
-        }
-    }
-
-    void SetDoNotFree() override;
-    bool Insert(const Key& key, Value data) override;
-    Value Find(const Key& key) override;
-    void Remove(const Key& key) override;
-    int GetSize() override
-    {
-        return Map.size();
-    }
-
-    std::vector< std::pair<Key, Value> > get_all_entry() override;
-
-private:
-    std::unordered_map<Key, Value, Hash> Map;
-    bool do_not_free = false;
-};
-
-template<typename Key, typename Value, typename Hash>
-void DCE2_DbMap<Key, Value, Hash>::SetDoNotFree()
-{
-    do_not_free = true;
-}
-
-template<typename Key, typename Value, typename Hash>
-bool DCE2_DbMap<Key, Value, Hash>::Insert(const Key& key, Value data)
-{
-    return Map.insert(std::make_pair(key,data)).second;
-}
-
-template<typename Key, typename Value, typename Hash>
-Value DCE2_DbMap<Key, Value, Hash>::Find(const Key& key)
-{
-    auto elem = Map.find(key);
-    if (elem != Map.end())
-        return elem->second;
-    return nullptr;
-}
-
-template<typename Key, typename Value, typename Hash>
-void DCE2_DbMap<Key, Value, Hash>::Remove(const Key& key)
-{
-    auto elem = Map.find(key);
-    if (elem != Map.end())
-    {
-        if (!do_not_free)
-            delete elem->second;
-
-        Map.erase(elem->first);
-    }
-}
-
-template<typename Key, typename Value, typename Hash>
-std::vector< std::pair<Key, Value> >DCE2_DbMap<Key, Value, Hash>::get_all_entry()
-{
-    std::vector<std::pair<Key, Value> > vec;
-
-    for (auto& entry : Map )
-    {
-        vec.emplace_back(entry);
-    }
-
-    return vec;
-}
-
-#endif
-
diff --git a/src/service_inspectors/dce_rpc/dce_smb.h b/src/service_inspectors/dce_rpc/dce_smb.h
deleted file mode 100644 (file)
index 51899c7..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2020 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// dce_smb.h author Rashmi Pitre <rrp@cisco.com>
-// based on work by Todd Wease
-
-#ifndef DCE_SMB_H
-#define DCE_SMB_H
-
-#include "dce_co.h"
-#include "protocols/packet.h"
-#include "profiler/profiler_defs.h"
-#include "smb_common.h"
-#include "smb_message.h"
-
-#define DCE2_SMB_NAME "dce_smb"
-#define DCE2_SMB_HELP "dce over smb inspection"
-#define DCE2_SMB_RPKT_TYPE_MAX 4
-#define DCE2_SMB_RPKT_TYPE_START 1
-
-#define DCE2_SMB_BAD_NBSS_TYPE 2
-#define DCE2_SMB_BAD_TYPE 3
-#define DCE2_SMB_BAD_ID 4
-#define DCE2_SMB_BAD_WCT 5
-#define DCE2_SMB_BAD_BCC 6
-#define DCE2_SMB_BAD_FORM 7
-#define DCE2_SMB_BAD_OFF 8
-#define DCE2_SMB_TDCNT_ZE 9
-#define DCE2_SMB_NB_LT_SMBHDR 10
-#define DCE2_SMB_NB_LT_COM 11
-#define DCE2_SMB_NB_LT_BCC 12
-#define DCE2_SMB_NB_LT_DSIZE 13
-#define DCE2_SMB_TDCNT_LT_DSIZE 14
-#define DCE2_SMB_DSENT_GT_TDCNT 15
-#define DCE2_SMB_BCC_LT_DSIZE 16
-#define DCE2_SMB_INVALID_DSIZE 17
-#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS 18
-#define DCE2_SMB_EXCESSIVE_READS 19
-#define DCE2_SMB_EXCESSIVE_CHAINING 20
-#define DCE2_SMB_MULT_CHAIN_SS 21
-#define DCE2_SMB_MULT_CHAIN_TC 22
-#define DCE2_SMB_CHAIN_SS_LOGOFF 23
-#define DCE2_SMB_CHAIN_TC_TDIS 24
-#define DCE2_SMB_CHAIN_OPEN_CLOSE 25
-#define DCE2_SMB_INVALID_SHARE 26
-
-#define DCE2_SMB_V1 44
-#define DCE2_SMB_V2 45
-#define DCE2_SMB_INVALID_BINDING 46
-#define DCE2_SMB2_EXCESSIVE_COMPOUNDING 47
-#define DCE2_SMB_DCNT_ZERO 48
-#define DCE2_SMB_DCNT_MISMATCH 49
-#define DCE2_SMB_MAX_REQS_EXCEEDED 50
-#define DCE2_SMB_REQS_SAME_MID 51
-#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED 52
-#define DCE2_SMB_DEPR_COMMAND_USED 53
-#define DCE2_SMB_UNUSUAL_COMMAND_USED 54
-#define DCE2_SMB_INVALID_SETUP_COUNT 55
-#define DCE2_SMB_MULTIPLE_NEGOTIATIONS 56
-#define DCE2_SMB_EVASIVE_FILE_ATTRS 57
-#define DCE2_SMB_INVALID_FILE_OFFSET 58
-#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET 59
-
-#define DCE2_SMB_BAD_NBSS_TYPE_STR "SMB - bad NetBIOS session service session type"
-#define DCE2_SMB_BAD_TYPE_STR  "SMB - bad SMB message type"
-#define DCE2_SMB_BAD_ID_STR "SMB - bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)"
-#define DCE2_SMB_BAD_WCT_STR "SMB - bad word count or structure size"
-#define DCE2_SMB_BAD_BCC_STR  "SMB - bad byte count"
-#define DCE2_SMB_BAD_FORM_STR  "SMB - bad format type"
-#define DCE2_SMB_BAD_OFF_STR  "SMB - bad offset"
-#define DCE2_SMB_TDCNT_ZE_STR  "SMB - zero total data count"
-#define DCE2_SMB_NB_LT_SMBHDR_STR "SMB - NetBIOS data length less than SMB header length"
-#define DCE2_SMB_NB_LT_COM_STR   "SMB - remaining NetBIOS data length less than command length"
-#define DCE2_SMB_NB_LT_BCC_STR  "SMB - remaining NetBIOS data length less than command byte count"
-#define DCE2_SMB_NB_LT_DSIZE_STR \
-    "SMB - remaining NetBIOS data length less than command data size"
-#define DCE2_SMB_TDCNT_LT_DSIZE_STR \
-    "SMB - remaining total data count less than this command data size"
-#define DCE2_SMB_DSENT_GT_TDCNT_STR \
-    "SMB - total data sent (STDu64) greater than command total data expected"
-#define DCE2_SMB_BCC_LT_DSIZE_STR   "SMB - byte count less than command data size (STDu64)"
-#define DCE2_SMB_INVALID_DSIZE_STR  "SMB - invalid command data size for byte count"
-#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS_STR \
-    "SMB - excessive tree connect requests with pending tree connect responses"
-#define DCE2_SMB_EXCESSIVE_READS_STR  "SMB - excessive read requests with pending read responses"
-#define DCE2_SMB_EXCESSIVE_CHAINING_STR  "SMB - excessive command chaining"
-#define DCE2_SMB_MULT_CHAIN_SS_STR   "SMB - multiple chained tree connect requests"
-#define DCE2_SMB_MULT_CHAIN_TC_STR   "SMB - multiple chained tree connect requests"
-#define DCE2_SMB_CHAIN_SS_LOGOFF_STR   "SMB - chained/compounded login followed by logoff"
-#define DCE2_SMB_CHAIN_TC_TDIS_STR \
-    "SMB - chained/compounded tree connect followed by tree disconnect"
-#define DCE2_SMB_CHAIN_OPEN_CLOSE_STR \
-    "SMB - chained/compounded open pipe followed by close pipe"
-#define DCE2_SMB_INVALID_SHARE_STR   "SMB - invalid share access"
-
-#define DCE2_SMB_V1_STR  "SMB - invalid SMB version 1 seen"
-#define DCE2_SMB_V2_STR  "SMB - invalid SMB version 2 seen"
-#define DCE2_SMB_INVALID_BINDING_STR "SMB - invalid user, tree connect, file binding"
-#define DCE2_SMB2_EXCESSIVE_COMPOUNDING_STR  "SMB - excessive command compounding"
-#define DCE2_SMB_DCNT_ZERO_STR   "SMB - zero data count"
-#define DCE2_SMB_DCNT_MISMATCH_STR "SMB - data count mismatch in command and format"
-#define DCE2_SMB_MAX_REQS_EXCEEDED_STR  "SMB - maximum number of outstanding requests exceeded"
-#define DCE2_SMB_REQS_SAME_MID_STR "SMB - outstanding requests with same MID"
-#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED_STR  "SMB - deprecated dialect negotiated"
-#define DCE2_SMB_DEPR_COMMAND_USED_STR   "SMB - deprecated command used"
-#define DCE2_SMB_UNUSUAL_COMMAND_USED_STR "SMB - unusual command used"
-#define DCE2_SMB_INVALID_SETUP_COUNT_STR  "SMB - invalid setup count for command"
-#define DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR \
-    "SMB - client attempted multiple dialect negotiations on session"
-#define DCE2_SMB_EVASIVE_FILE_ATTRS_STR \
-    "SMB - client attempted to create or set a file's attributes to readonly/hidden/system"
-#define DCE2_SMB_INVALID_FILE_OFFSET_STR \
-    "SMB - file offset provided is greater than file size specified"
-#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \
-    "SMB - next command specified in SMB2 header is beyond payload boundary"
-
-struct dce2SmbStats
-{
-    PegCount events;
-
-    PegCount co_pdus;
-    PegCount co_bind;
-    PegCount co_bind_ack;
-    PegCount co_alter_ctx;
-    PegCount co_alter_ctx_resp;
-    PegCount co_bind_nack;
-    PegCount co_request;
-    PegCount co_response;
-    PegCount co_cancel;
-    PegCount co_orphaned;
-    PegCount co_fault;
-    PegCount co_auth3;
-    PegCount co_shutdown;
-    PegCount co_reject;
-    PegCount co_ms_pdu;
-    PegCount co_other_req;
-    PegCount co_other_resp;
-    PegCount co_req_fragments;
-    PegCount co_resp_fragments;
-    PegCount co_cli_max_frag_size;
-    PegCount co_cli_min_frag_size;
-    PegCount co_cli_seg_reassembled;
-    PegCount co_cli_frag_reassembled;
-    PegCount co_srv_max_frag_size;
-    PegCount co_srv_min_frag_size;
-    PegCount co_srv_seg_reassembled;
-    PegCount co_srv_frag_reassembled;
-
-    PegCount smb_sessions;
-    PegCount smb_pkts;
-    PegCount smb_ignored_bytes;
-    PegCount smb_cli_seg_reassembled;
-    PegCount smb_srv_seg_reassembled;
-    PegCount smb_max_outstanding_requests;
-    //  FIXIT-M more peg count foo
-    /*uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS];
-    uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS];
-    // The +1 is for codes beyond the range of the highest valid subcommand code
-    // Indicates a bogus subcommand
-    uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1];
-    uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1];
-    uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1];
-    */
-    PegCount smb_files_processed;
-    /* SMB2 stats */
-    PegCount v2_setup;
-    PegCount v2_setup_err_resp;
-    PegCount v2_setup_inv_str_sz;
-    PegCount v2_setup_resp_hdr_err;
-    PegCount v2_tree_cnct;
-    PegCount v2_tree_cnct_err_resp;
-    PegCount v2_tree_cnct_ignored;
-    PegCount v2_tree_cnct_inv_str_sz;
-    PegCount v2_tree_cnct_resp_hdr_err;
-    PegCount v2_crt;
-    PegCount v2_crt_err_resp;
-    PegCount v2_crt_inv_file_data;
-    PegCount v2_crt_inv_str_sz;
-    PegCount v2_crt_resp_hdr_err;
-    PegCount v2_crt_req_hdr_err;
-    PegCount v2_crt_rtrkr_misng;
-    PegCount v2_crt_req_ipc;
-    PegCount v2_crt_tree_trkr_misng;
-    PegCount v2_wrt;
-    PegCount v2_wrt_err_resp;
-    PegCount v2_wrt_ignored;
-    PegCount v2_wrt_inv_str_sz;
-    PegCount v2_wrt_req_hdr_err;
-    PegCount v2_read;
-    PegCount v2_read_err_resp;
-    PegCount v2_read_ignored;
-    PegCount v2_read_inv_str_sz;
-    PegCount v2_read_rtrkr_misng;
-    PegCount v2_read_resp_hdr_err;
-    PegCount v2_read_req_hdr_err;
-    PegCount v2_stinf;
-    PegCount v2_stinf_err_resp;
-    PegCount v2_stinf_ignored;
-    PegCount v2_stinf_inv_str_sz;
-    PegCount v2_stinf_req_ftrkr_misng;
-    PegCount v2_stinf_req_hdr_err;
-    PegCount v2_cls;
-    PegCount v2_cls_err_resp;
-    PegCount v2_cls_ignored;
-    PegCount v2_cls_inv_str_sz;
-    PegCount v2_cls_req_ftrkr_misng;
-    PegCount v2_cls_req_hdr_err;
-    PegCount v2_tree_discn;
-    PegCount v2_tree_discn_ignored;
-    PegCount v2_tree_discn_inv_str_sz;
-    PegCount v2_tree_discn_req_hdr_err;
-    PegCount v2_logoff;
-    PegCount v2_logoff_inv_str_sz;
-    PegCount v2_hdr_err;
-    PegCount v2_bad_next_cmd_offset;
-    PegCount v2_extra_file_data_err;
-    PegCount v2_inv_file_ctx_err;
-    PegCount v2_msgs_uninspected;
-    PegCount v2_cmpnd_req_lt_crossed;
-    PegCount concurrent_sessions;
-    PegCount max_concurrent_sessions;
-};
-
-extern THREAD_LOCAL dce2SmbStats dce2_smb_stats;
-extern THREAD_LOCAL snort::ProfileStats dce2_smb_pstat_main;
-
-enum DCE2_SmbSsnState
-{
-    DCE2_SMB_SSN_STATE__START         = 0x00,
-    DCE2_SMB_SSN_STATE__NEGOTIATED    = 0x01,
-    DCE2_SMB_SSN_STATE__FP_CLIENT     = 0x02,  // Fingerprinted client
-    DCE2_SMB_SSN_STATE__FP_SERVER     = 0x04   // Fingerprinted server
-};
-
-enum DCE2_SmbDataState
-{
-    DCE2_SMB_DATA_STATE__NETBIOS_HEADER,
-    DCE2_SMB_DATA_STATE__SMB_HEADER,
-    DCE2_SMB_DATA_STATE__NETBIOS_PDU
-};
-
-enum DCE2_SmbPduState
-{
-    DCE2_SMB_PDU_STATE__COMMAND,
-    DCE2_SMB_PDU_STATE__RAW_DATA
-};
-
-enum DCE2_SmbFileDirection
-{
-    DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0,
-    DCE2_SMB_FILE_DIRECTION__UPLOAD,
-    DCE2_SMB_FILE_DIRECTION__DOWNLOAD
-};
-
-enum SmbAndXCom
-{
-    SMB_ANDX_COM__NONE,
-    SMB_ANDX_COM__OPEN_ANDX,
-    SMB_ANDX_COM__READ_ANDX,
-    SMB_ANDX_COM__WRITE_ANDX,
-    SMB_ANDX_COM__TREE_CONNECT_ANDX,
-    SMB_ANDX_COM__SESSION_SETUP_ANDX,
-    SMB_ANDX_COM__LOGOFF_ANDX,
-    SMB_ANDX_COM__NT_CREATE_ANDX,
-    SMB_ANDX_COM__MAX
-};
-
-struct DCE2_SmbWriteAndXRaw
-{
-    int remaining;  // A signed integer so it can be negative
-    DCE2_Buffer* buf;
-};
-
-struct DCE2_SmbFileChunk
-{
-    uint64_t offset;
-    uint32_t length;
-    uint8_t* data;
-};
-
-enum DCE2_SmbVersion
-{
-    DCE2_SMB_VERSION_NULL,
-    DCE2_SMB_VERSION_1,
-    DCE2_SMB_VERSION_2
-};
-
-struct DCE2_SmbFileTracker
-{
-    union
-    {
-        struct
-        {
-            int file_id;   // A signed integer so it can be set to sentinel
-            uint16_t u_id;
-            uint16_t tree_id;
-        } id_smb1;
-
-        struct
-        {
-            uint64_t file_id;
-        } id_smb2;
-    } file_key;
-
-    bool is_ipc;
-    bool is_smb2;
-    char* file_name;
-    uint16_t file_name_size;
-    uint64_t file_name_hash;
-
-    union
-    {
-        struct
-        {
-            // If pipe has been set to byte mode via TRANS_SET_NMPIPE_STATE
-            bool byte_mode;
-
-            // For Windows 2000
-            bool used;
-
-            // For WriteAndX requests that use raw mode flag
-            // Windows only
-            DCE2_SmbWriteAndXRaw* writex_raw;
-
-            // Connection-oriented DCE/RPC tracker
-            DCE2_CoTracker* co_tracker;
-        } nmpipe;
-
-        struct
-        {
-            uint64_t file_size;
-            uint64_t file_offset;
-            uint64_t bytes_processed;
-            DCE2_List* file_chunks;
-            uint32_t bytes_queued;
-            DCE2_SmbFileDirection file_direction;
-            bool sequential_only;
-        } file;
-    } tracker;
-
-    DCE2_SmbPduState smb2_pdu_state;
-
-#define fid_v1                file_key.id_smb1.file_id
-#define uid_v1                file_key.id_smb1.u_id
-#define tid_v1                file_key.id_smb1.tree_id
-#define fid_v2                file_key.id_smb2.file_id
-#define fp_byte_mode   tracker.nmpipe.byte_mode
-#define fp_used        tracker.nmpipe.used
-#define fp_writex_raw  tracker.nmpipe.writex_raw
-#define fp_co_tracker  tracker.nmpipe.co_tracker
-#define ff_file_size          tracker.file.file_size
-#define ff_file_offset        tracker.file.file_offset
-#define ff_bytes_processed    tracker.file.bytes_processed
-#define ff_file_direction     tracker.file.file_direction
-#define ff_file_chunks        tracker.file.file_chunks
-#define ff_bytes_queued       tracker.file.bytes_queued
-#define ff_sequential_only    tracker.file.sequential_only
-};
-
-struct Smb2Request
-{
-    uint64_t message_id;   /* identifies a message uniquely on connection */
-    uint64_t offset;       /* data offset */
-    uint64_t file_id;      /* file id */
-    struct Smb2Request* next;
-    struct Smb2Request* previous;
-};
-
-struct DCE2_SmbTransactionTracker
-{
-    int smb_type;
-    uint8_t subcom;
-    bool one_way;
-    bool disconnect_tid;
-    bool pipe_byte_mode;
-    uint32_t tdcnt;
-    uint32_t dsent;
-    DCE2_Buffer* dbuf;
-    uint32_t tpcnt;
-    uint32_t psent;
-    DCE2_Buffer* pbuf;
-    // For Transaction2/Query File Information
-    uint16_t info_level;
-};
-
-struct DCE2_SmbRequestTracker
-{
-    int smb_com;
-
-    int mid;   // A signed integer so it can be set to sentinel
-    uint16_t uid;
-    uint16_t tid;
-    uint16_t pid;
-
-    // For WriteRaw
-    bool writeraw_writethrough;
-    uint32_t writeraw_remaining;
-
-    // For Transaction/Transaction2/NtTransact
-    DCE2_SmbTransactionTracker ttracker;
-
-    // Client can chain a write to an open.  Need to write data, but also
-    // need to associate tracker with fid returned from server
-    DCE2_Queue* ft_queue;
-
-    // This is a reference to an existing file tracker
-    DCE2_SmbFileTracker* ftracker;
-
-    // Used for requests to cache data that will ultimately end up in
-    // the file tracker upon response.
-    char* file_name;
-    uint16_t file_name_size;
-    uint64_t file_size;
-    uint64_t file_offset;
-    bool sequential_only;
-
-    // For TreeConnect to know whether it's to IPC
-    bool is_ipc;
-};
-
-struct DCE2_SmbSsnData
-{
-    DCE2_SsnData sd;  // This member must be first
-    DCE2_Policy policy;
-
-    int dialect_index;
-    int ssn_state_flags;
-
-    DCE2_SmbDataState cli_data_state;
-    DCE2_SmbDataState srv_data_state;
-
-    DCE2_SmbPduState pdu_state;
-
-    int uid;   // A signed integer so it can be set to sentinel
-    int tid;   // A signed integer so it can be set to sentinel
-    DCE2_List* uids;
-    DCE2_List* tids;
-
-    // For tracking files and named pipes
-    DCE2_SmbFileTracker ftracker;
-    DCE2_List* ftrackers;  // List of DCE2_SmbFileTracker
-
-    // For tracking requests / responses
-    DCE2_SmbRequestTracker rtracker;
-    DCE2_Queue* rtrackers;
-    uint16_t max_outstanding_requests;
-    uint16_t outstanding_requests;
-
-    // The current pid/mid node for this request/response
-    DCE2_SmbRequestTracker* cur_rtracker;
-
-    // Used for TCP segmentation to get full PDU
-    DCE2_Buffer* cli_seg;
-    DCE2_Buffer* srv_seg;
-
-    // These are used for commands we don't need to process
-    uint32_t cli_ignore_bytes;
-    uint32_t srv_ignore_bytes;
-
-    // The file API supports one concurrent upload/download per session.
-    // This is a reference to a file tracker so shouldn't be freed.
-    DCE2_SmbFileTracker* fapi_ftracker;
-
-    DCE2_SmbFileTracker* fb_ftracker;
-    bool block_pdus;
-
-    // Maximum file depth as returned from file API
-    int64_t max_file_depth;
-};
-
-struct DCE2_SmbFsm
-{
-    char input;
-    int next_state;
-    int fail_state;
-};
-
-class Dce2SmbFlowData : public snort::FlowData
-{
-public:
-    Dce2SmbFlowData();
-    ~Dce2SmbFlowData() override;
-
-    static void init()
-    { inspector_id = snort::FlowData::create_flow_data_id(); }
-
-    size_t size_of() override
-    { return sizeof(*this); }
-
-public:
-    static unsigned inspector_id;
-    DCE2_SmbVersion smb_version;
-    void* dce2_smb_session_data;
-};
-
-// Used for reassembled packets
-#define DCE2_MOCK_HDR_LEN__SMB_CLI \
-    ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq)))
-#define DCE2_MOCK_HDR_LEN__SMB_SRV \
-    ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp)))
-
-DCE2_SsnData* get_dce2_session_data(snort::Flow*);
-
-const char* get_smb_com_string(uint8_t);
-#endif
-
similarity index 68%
rename from src/service_inspectors/dce_rpc/dce_smb.cc
rename to src/service_inspectors/dce_rpc/dce_smb1.cc
index 10584f9ca9506832ad0cf3a93ec341d7f28a8971..f4396e3a35b8de495da68bfc0e3c1d4ea5c292fa 100644 (file)
@@ -1,5 +1,5 @@
 //--------------------------------------------------------------------------
-// Copyright (C) 2016-2020 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License Version 2 as published
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 
-// dce_smb.cc author Rashmi Pitre <rrp@cisco.com>
+// dce_smb1.cc author Bhargava Jandhyala <bjandhya@cisco.com>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "dce_smb.h"
-
-#include "detection/detection_engine.h"
-#include "file_api/file_service.h"
-#include "main/snort_debug.h"
-#include "managers/inspector_manager.h"
-#include "protocols/packet.h"
-
-#include "dce_context_data.h"
-#include "dce_smb_commands.h"
-#include "dce_smb_module.h"
-#include "dce_smb_paf.h"
-#include "dce_smb_transaction.h"
-#include "dce_smb2.h"
-#include "dce_smb2_utils.h"
+#include "dce_smb1.h"
 
 using namespace snort;
 
-THREAD_LOCAL dce2SmbStats dce2_smb_stats;
-THREAD_LOCAL ProfileStats dce2_smb_pstat_main;
-
 //-------------------------------------------------------------------------
 // debug stuff
 //-------------------------------------------------------------------------
@@ -312,205 +295,27 @@ const char* get_smb_com_string(uint8_t b)
 { return smb_com_strings[b]; }
 #endif
 
-//-------------------------------------------------------------------------
-// class stuff
-//-------------------------------------------------------------------------
-
-class Dce2Smb : public Inspector
-{
-public:
-    Dce2Smb(const dce2SmbProtoConf&);
-    ~Dce2Smb() override;
-
-    void show(const SnortConfig*) const override;
-    void eval(Packet*) override;
-    void clear(Packet*) override;
-
-    StreamSplitter* get_splitter(bool c2s) override
-    { return new Dce2SmbSplitter(c2s); }
-
-    bool can_carve_files() const override
-    { return true; }
-
-private:
-    dce2SmbProtoConf config;
-};
-
-Dce2Smb::Dce2Smb(const dce2SmbProtoConf& pc)
-{
-    config = pc;
-}
-
-Dce2Smb::~Dce2Smb()
-{
-    if (config.smb_invalid_shares)
-    {
-        DCE2_ListDestroy(config.smb_invalid_shares);
-    }
-}
-
-void Dce2Smb::show(const SnortConfig*) const
-{
-    print_dce2_smb_conf(config);
-}
-
-void Dce2Smb::eval(Packet* p)
-{
-    DCE2_SmbSsnData* dce2_smb_sess = nullptr;
-    DCE2_Smb2SsnData* dce2_smb2_sess = nullptr;
-    DCE2_SmbVersion smb_version = DCE2_SMB_VERSION_NULL;
-    Profile profile(dce2_smb_pstat_main);
-
-    assert(p->has_tcp_data());
-    assert(p->flow);
-
-    Dce2SmbFlowData *smb_flowdata = (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id);
-    if (smb_flowdata and smb_flowdata->dce2_smb_session_data)
-    {
-        smb_version = smb_flowdata->smb_version;
-        if (DCE2_SMB_VERSION_1 == smb_version)
-            dce2_smb_sess = (DCE2_SmbSsnData*)smb_flowdata->dce2_smb_session_data;
-        else
-            dce2_smb2_sess = (DCE2_Smb2SsnData*)smb_flowdata->dce2_smb_session_data;
-    }
-    else
-    {
-        smb_version = DCE2_Smb2Version(p);
-
-        if (DCE2_SMB_VERSION_1 == smb_version)
-        {
-            //1st packet of flow in smb1 session, create smb1 session and flowdata
-            dce2_smb_sess = dce2_create_new_smb_session(p, &config);
-            debug_logf(dce_smb_trace, p, "smb1 session created\n");
-        }
-        else if (DCE2_SMB_VERSION_2 == smb_version)
-        {
-            //1st packet of flow in smb2 session, create smb2 session and flowdata
-            dce2_smb2_sess = dce2_create_new_smb2_session(p, &config);
-            debug_logf(dce_smb_trace, p, "smb2 session created\n");
-        }
-        else
-        {
-            //smb_version is DCE2_SMB_VERSION_NULL
-            //This means there is no flow data and this is not an SMB packet
-            //if it is a TCP packet for smb data, the flow must have been
-            //already identified with version.
-            debug_logf(dce_smb_trace, p, "non-smb packet detected\n");
-            return;
-        }
-    }
-
-    //  By this time we must know the smb version, have correct smb session data and created flowdata
-    p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
-    dce2_detected = 0;
-    p->endianness = new DceEndianness();
-
-    if (DCE2_SMB_VERSION_1 == smb_version)
-    {
-        DCE2_Smb1Process(dce2_smb_sess);
-        if (!dce2_detected)
-            DCE2_Detect(&dce2_smb_sess->sd);
-    }
-    else
-    {
-        DCE2_Smb2Process(dce2_smb2_sess);
-        if (!dce2_detected)
-            DCE2_Detect(&dce2_smb2_sess->sd);
-    }
-
-    delete(p->endianness);
-    p->endianness = nullptr;
-}
-
-void Dce2Smb::clear(Packet* p)
-{
-    DCE2_SsnData* sd = get_dce2_session_data(p->flow);
-    if ( sd )
-        DCE2_ResetRopts(sd, p);
-}
-
-//-------------------------------------------------------------------------
-// api stuff
-//-------------------------------------------------------------------------
-
-static Module* mod_ctor()
-{
-    return new Dce2SmbModule;
-}
-
-static void mod_dtor(Module* m)
-{
-    delete m;
-}
-
-static void dce2_smb_init()
-{
-    Dce2SmbFlowData::init();
-    DCE2_SmbInitGlobals();
-    DCE2_SmbInitDeletePdu();
-    DceContextData::init(DCE2_TRANS_TYPE__SMB);
-}
-
-static void dce2_smb_thread_int()
-{
-    DCE2_SmbSessionCacheInit(session_cache_size);
-}
-
-static void dce_smb_thread_term()
+Dce2Smb1SessionData::Dce2Smb1SessionData(const Packet* p,
+    const dce2SmbProtoConf* proto) : Dce2SmbSessionData(p, proto)
 {
-    delete smb2_session_cache;
+    ssd = { };
+    ssd.max_outstanding_requests = 10;  // Until Negotiate/SessionSetupAndX
+    ssd.cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+    ssd.srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+    ssd.pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
+    ssd.uid = DCE2_SENTINEL;
+    ssd.tid = DCE2_SENTINEL;
+    ssd.ftracker.fid_v1 = DCE2_SENTINEL;
+    ssd.rtracker.mid = DCE2_SENTINEL;
+    ssd.dialect_index = dialect_index;
+    ssd.max_file_depth = max_file_depth;
+    ssd.sd = sd;
+    ssd.policy = policy;
+    debug_logf(dce_smb_trace, p, "smb1 session created\n");
 }
 
-static size_t get_max_smb_session(dce2SmbProtoConf* config)
+void Dce2Smb1SessionData::process()
 {
-    size_t smb_sess_storage_req = (sizeof(DCE2_Smb2SessionTracker) +
-        sizeof(DCE2_Smb2TreeTracker) +  sizeof(DCE2_Smb2RequestTracker) +
-        (sizeof(DCE2_Smb2FileTracker) * SMB_AVG_FILES_PER_SESSION));
-
-    size_t max_smb_sess = DCE2_ScSmbMemcap(config);
-
-    return (max_smb_sess/smb_sess_storage_req);
+    DCE2_Smb1Process(&ssd);
 }
 
-static Inspector* dce2_smb_ctor(Module* m)
-{
-    Dce2SmbModule* mod = (Dce2SmbModule*)m;
-    dce2SmbProtoConf config;
-    mod->get_data(config);
-    session_cache_size = get_max_smb_session(&config);
-    return new Dce2Smb(config);
-}
-
-static void dce2_smb_dtor(Inspector* p)
-{
-    delete p;
-}
-
-const InspectApi dce2_smb_api =
-{
-    {
-        PT_INSPECTOR,
-        sizeof(InspectApi),
-        INSAPI_VERSION,
-        0,
-        API_RESERVED,
-        API_OPTIONS,
-        DCE2_SMB_NAME,
-        DCE2_SMB_HELP,
-        mod_ctor,
-        mod_dtor
-    },
-    IT_SERVICE,
-    PROTO_BIT__PDU,
-    nullptr,  // buffers
-    "netbios-ssn",
-    dce2_smb_init,
-    nullptr, // pterm
-    dce2_smb_thread_int, // tinit
-    dce_smb_thread_term, // tterm
-    dce2_smb_ctor,
-    dce2_smb_dtor,
-    nullptr, // ssn
-    nullptr  // reset
-};
-
diff --git a/src/service_inspectors/dce_rpc/dce_smb1.h b/src/service_inspectors/dce_rpc/dce_smb1.h
new file mode 100644 (file)
index 0000000..716923e
--- /dev/null
@@ -0,0 +1,286 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb1.h author Bhargava Jandhyala <bjandhya@cisco.com>
+
+#ifndef DCE_SMB1_H
+#define DCE_SMB1_H
+
+// This provides smb session data and SMBv1 specific trackers
+
+#include "protocols/packet.h"
+#include "profiler/profiler_defs.h"
+
+#include "dce_co.h"
+#include "dce_smb_common.h"
+#include "dce_smb_module.h"
+#include "smb_message.h"
+
+enum DCE2_SmbSsnState
+{
+    DCE2_SMB_SSN_STATE__START         = 0x00,
+    DCE2_SMB_SSN_STATE__NEGOTIATED    = 0x01,
+    DCE2_SMB_SSN_STATE__FP_CLIENT     = 0x02,  // Fingerprinted client
+    DCE2_SMB_SSN_STATE__FP_SERVER     = 0x04   // Fingerprinted server
+};
+
+enum DCE2_SmbDataState
+{
+    DCE2_SMB_DATA_STATE__NETBIOS_HEADER,
+    DCE2_SMB_DATA_STATE__SMB_HEADER,
+    DCE2_SMB_DATA_STATE__NETBIOS_PDU
+};
+
+enum DCE2_SmbFileDirection
+{
+    DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0,
+    DCE2_SMB_FILE_DIRECTION__UPLOAD,
+    DCE2_SMB_FILE_DIRECTION__DOWNLOAD
+};
+
+enum SmbAndXCom
+{
+    SMB_ANDX_COM__NONE,
+    SMB_ANDX_COM__OPEN_ANDX,
+    SMB_ANDX_COM__READ_ANDX,
+    SMB_ANDX_COM__WRITE_ANDX,
+    SMB_ANDX_COM__TREE_CONNECT_ANDX,
+    SMB_ANDX_COM__SESSION_SETUP_ANDX,
+    SMB_ANDX_COM__LOGOFF_ANDX,
+    SMB_ANDX_COM__NT_CREATE_ANDX,
+    SMB_ANDX_COM__MAX
+};
+
+struct DCE2_SmbWriteAndXRaw
+{
+    int remaining;  // A signed integer so it can be negative
+    DCE2_Buffer* buf;
+};
+
+struct DCE2_SmbFileChunk
+{
+    uint64_t offset;
+    uint32_t length;
+    uint8_t* data;
+};
+
+struct DCE2_SmbFileTracker
+{
+    struct
+    {
+        int file_id;   // A signed integer so it can be set to sentinel
+        uint16_t u_id;
+        uint16_t tree_id;
+    } file_key;
+
+    bool is_ipc;
+    bool is_smb2;
+    char* file_name;
+    uint16_t file_name_size;
+    uint64_t file_name_hash;
+
+    union
+    {
+        struct
+        {
+            // If pipe has been set to byte mode via TRANS_SET_NMPIPE_STATE
+            bool byte_mode;
+
+            // For Windows 2000
+            bool used;
+
+            // For WriteAndX requests that use raw mode flag
+            // Windows only
+            DCE2_SmbWriteAndXRaw* writex_raw;
+
+            // Connection-oriented DCE/RPC tracker
+            DCE2_CoTracker* co_tracker;
+        } nmpipe;
+
+        struct
+        {
+            uint64_t file_size;
+            uint64_t file_offset;
+            uint64_t bytes_processed;
+            DCE2_List* file_chunks;
+            uint32_t bytes_queued;
+            DCE2_SmbFileDirection file_direction;
+            bool sequential_only;
+        } file;
+    } tracker;
+
+#define fid_v1                file_key.file_id
+#define uid_v1                file_key.u_id
+#define tid_v1                file_key.tree_id
+#define fp_byte_mode   tracker.nmpipe.byte_mode
+#define fp_used        tracker.nmpipe.used
+#define fp_writex_raw  tracker.nmpipe.writex_raw
+#define fp_co_tracker  tracker.nmpipe.co_tracker
+#define ff_file_size          tracker.file.file_size
+#define ff_file_offset        tracker.file.file_offset
+#define ff_bytes_processed    tracker.file.bytes_processed
+#define ff_file_direction     tracker.file.file_direction
+#define ff_file_chunks        tracker.file.file_chunks
+#define ff_bytes_queued       tracker.file.bytes_queued
+#define ff_sequential_only    tracker.file.sequential_only
+};
+
+struct Smb2Request
+{
+    uint64_t message_id;   /* identifies a message uniquely on connection */
+    uint64_t offset;       /* data offset */
+    uint64_t file_id;      /* file id */
+    struct Smb2Request* next;
+    struct Smb2Request* previous;
+};
+
+struct DCE2_SmbTransactionTracker
+{
+    int smb_type;
+    uint8_t subcom;
+    bool one_way;
+    bool disconnect_tid;
+    bool pipe_byte_mode;
+    uint32_t tdcnt;
+    uint32_t dsent;
+    DCE2_Buffer* dbuf;
+    uint32_t tpcnt;
+    uint32_t psent;
+    DCE2_Buffer* pbuf;
+    // For Transaction2/Query File Information
+    uint16_t info_level;
+};
+
+struct DCE2_SmbRequestTracker
+{
+    int smb_com;
+
+    int mid;   // A signed integer so it can be set to sentinel
+    uint16_t uid;
+    uint16_t tid;
+    uint16_t pid;
+
+    // For WriteRaw
+    bool writeraw_writethrough;
+    uint32_t writeraw_remaining;
+
+    // For Transaction/Transaction2/NtTransact
+    DCE2_SmbTransactionTracker ttracker;
+
+    // Client can chain a write to an open.  Need to write data, but also
+    // need to associate tracker with fid returned from server
+    DCE2_Queue* ft_queue;
+
+    // This is a reference to an existing file tracker
+    DCE2_SmbFileTracker* ftracker;
+
+    // Used for requests to cache data that will ultimately end up in
+    // the file tracker upon response.
+    char* file_name;
+    uint16_t file_name_size;
+    uint64_t file_size;
+    uint64_t file_offset;
+    bool sequential_only;
+
+    // For TreeConnect to know whether it's to IPC
+    bool is_ipc;
+};
+
+struct DCE2_SmbSsnData
+{
+    DCE2_SsnData sd;  // This member must be first
+    DCE2_Policy policy;
+
+    int dialect_index;
+    int ssn_state_flags;
+
+    DCE2_SmbDataState cli_data_state;
+    DCE2_SmbDataState srv_data_state;
+
+    Dce2SmbPduState pdu_state;
+
+    int uid;   // A signed integer so it can be set to sentinel
+    int tid;   // A signed integer so it can be set to sentinel
+    DCE2_List* uids;
+    DCE2_List* tids;
+
+    // For tracking files and named pipes
+    DCE2_SmbFileTracker ftracker;
+    DCE2_List* ftrackers;  // List of DCE2_SmbFileTracker
+
+    // For tracking requests / responses
+    DCE2_SmbRequestTracker rtracker;
+    DCE2_Queue* rtrackers;
+    uint16_t max_outstanding_requests;
+    uint16_t outstanding_requests;
+
+    // The current pid/mid node for this request/response
+    DCE2_SmbRequestTracker* cur_rtracker;
+
+    // Used for TCP segmentation to get full PDU
+    DCE2_Buffer* cli_seg;
+    DCE2_Buffer* srv_seg;
+
+    // These are used for commands we don't need to process
+    uint32_t cli_ignore_bytes;
+    uint32_t srv_ignore_bytes;
+
+    // The file API supports one concurrent upload/download per session.
+    // This is a reference to a file tracker so shouldn't be freed.
+    DCE2_SmbFileTracker* fapi_ftracker;
+
+    DCE2_SmbFileTracker* fb_ftracker;
+    bool block_pdus;
+
+    // Maximum file depth as returned from file API
+    int64_t max_file_depth;
+};
+
+struct DCE2_SmbFsm
+{
+    char input;
+    int next_state;
+    int fail_state;
+};
+
+// Used for reassembled packets
+#define DCE2_MOCK_HDR_LEN__SMB_CLI \
+    ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq)))
+#define DCE2_MOCK_HDR_LEN__SMB_SRV \
+    ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp)))
+
+DCE2_SsnData* get_dce2_session_data(snort::Flow*);
+
+const char* get_smb_com_string(uint8_t);
+
+class Dce2Smb1SessionData : public Dce2SmbSessionData
+{
+public:
+    Dce2Smb1SessionData() = delete;
+    Dce2Smb1SessionData(const snort::Packet*, const dce2SmbProtoConf* proto);
+    ~Dce2Smb1SessionData() override
+    { DCE2_SmbDataFree(&ssd); }
+    void process() override;
+    void handle_retransmit(FilePosition, FileVerdict) override { }
+
+private:
+    DCE2_SmbSsnData ssd;
+};
+
+#endif
+
index 9b3f3db74bf6bb3179a485c301ab1ca4b7f88108..553f17122b0967aa67065b858a14363dcd1d943a 100644 (file)
@@ -1,5 +1,5 @@
 //--------------------------------------------------------------------------
-// Copyright (C) 2015-2020 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2015-2021 Cisco and/or its affiliates. All rights reserved.
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License Version 2 as published
 #endif
 
 #include "dce_smb2.h"
-#include "dce_smb2_commands.h"
+
 #include "detection/detection_util.h"
 #include "flow/flow_key.h"
-#include "main/snort_debug.h"
+
+#include "dce_smb2_file.h"
+#include "dce_smb2_session.h"
+#include "dce_smb2_session_cache.h"
+#include "dce_smb2_tree.h"
 
 using namespace snort;
 
+THREAD_LOCAL Dce2Smb2SessionCache* smb2_session_cache;
+
 const char* smb2_command_string[SMB2_COM_MAX] = {
     "SMB2_COM_NEGOTIATE",
     "SMB2_COM_SESSION_SETUP",
@@ -50,11 +56,22 @@ const char* smb2_command_string[SMB2_COM_MAX] = {
     "SMB2_COM_CHANGE_NOTIFY",
     "SMB2_COM_QUERY_INFO",
     "SMB2_COM_SET_INFO",
-    "SMB2_COM_OPLOCK_BREAK"};
+    "SMB2_COM_OPLOCK_BREAK"
+};
+
+static inline uint64_t Smb2Sid(const Smb2Hdr* hdr)
+{
+    return alignedNtohq(&(hdr->session_id));
+}
+
+static inline bool Smb2Error(const Smb2Hdr* hdr)
+{
+    return (SMB_NT_STATUS_SEVERITY__ERROR == (uint8_t)(hdr->status >> 30));
+}
 
-static inline SmbFlowKey get_flow_key()
+Smb2FlowKey get_smb2_flow_key(void)
 {
-    SmbFlowKey key;
+    Smb2FlowKey key;
     const FlowKey* flow_key = DetectionEngine::get_current_packet()->flow->key;
 
     key.ip_l[0] = flow_key->ip_l[0];
@@ -80,227 +97,308 @@ static inline SmbFlowKey get_flow_key()
     return key;
 }
 
-DCE2_Smb2RequestTracker::DCE2_Smb2RequestTracker(uint64_t file_id_v,
-    uint64_t offset_v) : file_id(file_id_v), offset(offset_v)
+//Dce2Smb2SessionData member functions
+
+Dce2Smb2SessionData::Dce2Smb2SessionData(const Packet* p,
+    const dce2SmbProtoConf* proto) : Dce2SmbSessionData(p, proto)
 {
-    debug_logf(dce_smb_trace, nullptr, "request tracker created\n");
-    memory::MemoryCap::update_allocations(sizeof(*this));
+    tcp_file_tracker = nullptr;
+    flow_key = get_smb2_flow_key();
+    debug_logf(dce_smb_trace, p, "smb2 session created\n");
 }
 
-DCE2_Smb2RequestTracker::DCE2_Smb2RequestTracker(char* fname_v,
-    uint16_t fname_len_v) : fname(fname_v), fname_len(fname_len_v)
+Dce2Smb2SessionData::~Dce2Smb2SessionData(void)
 {
-    debug_logf(dce_smb_trace, nullptr, "request tracker created\n");
-    memory::MemoryCap::update_allocations(sizeof(*this));
+    for (auto it_session : connected_sessions)
+    {
+        if (it_session.second->detach_flow(flow_key))
+            smb2_session_cache->remove(it_session.second->get_key());
+    }
 }
 
-DCE2_Smb2RequestTracker::~DCE2_Smb2RequestTracker()
+void Dce2Smb2SessionData::reset_matching_tcp_file_tracker(
+    Dce2Smb2FileTracker* file_tracker)
 {
-    debug_logf(dce_smb_trace, nullptr, "request tracker terminating\n");
-    if (!file_id and fname)
-        snort_free(fname);
-    memory::MemoryCap::update_deallocations(sizeof(*this));
+    if (tcp_file_tracker == file_tracker)
+        tcp_file_tracker = nullptr;
 }
 
-DCE2_Smb2FileTracker::DCE2_Smb2FileTracker(uint64_t file_id_v, DCE2_Smb2TreeTracker* ttr_v,
-    DCE2_Smb2SessionTracker* str_v, Flow* flow_v) : file_id(file_id_v), ttr(ttr_v),
-    str(str_v), flow(flow_v)
+Smb2SessionKey Dce2Smb2SessionData::get_session_key(uint64_t session_id)
 {
-    debug_logf(dce_smb_trace, nullptr, "file tracker %" PRIu64 " created\n", file_id);
-    memory::MemoryCap::update_allocations(sizeof(*this));
+    Smb2SessionKey key;
+    Flow* flow = DetectionEngine::get_current_packet()->flow;
+    memcpy(key.cip, flow->client_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
+    memcpy(key.sip, flow->server_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
+    key.sid = session_id;
+    key.cgroup = flow->client_group;
+    key.sgroup = flow->server_group;
+    key.asid = flow->key->addressSpaceId;
+    key.padding = 0;
+    return key;
 }
 
-DCE2_Smb2FileTracker::~DCE2_Smb2FileTracker()
+Dce2Smb2SessionTracker* Dce2Smb2SessionData::find_session(uint64_t session_id)
 {
-    debug_logf(dce_smb_trace, nullptr,
-        "file tracker %" PRIu64 " file name hash %" PRIu64 " terminating\n",
-         file_id, file_name_hash);
-
-    FileFlows* file_flows = FileFlows::get_file_flows(flow, false);
-    if (file_flows)
+    auto it_session = connected_sessions.find(session_id);
+    if (it_session != connected_sessions.end())
     {
-        file_flows->remove_processed_file_context(file_name_hash, file_id);
+        Dce2Smb2SessionTracker* session = it_session->second;
+        //we already have the session, but call find to update the LRU
+        smb2_session_cache->find_session(session->get_key());
+        return session;
     }
-
-    if (file_name)
-        snort_free((void*)file_name);
-
-    memory::MemoryCap::update_deallocations(sizeof(*this));
-}
-
-DCE2_Smb2TreeTracker::DCE2_Smb2TreeTracker (uint32_t tid_v, uint8_t share_type_v) :
-    share_type(share_type_v), tid(tid_v)
-{
-    debug_logf(dce_smb_trace, nullptr, "tree tracker %" PRIu32 " created\n", tid);
-    memory::MemoryCap::update_allocations(sizeof(*this));
-}
-
-DCE2_Smb2TreeTracker::~DCE2_Smb2TreeTracker()
-{
-    debug_logf(dce_smb_trace, nullptr, "tree tracker %" PRIu32 " terminating\n", tid);
-
-    auto all_req_trackers = req_trackers.get_all_entry();
-    if (all_req_trackers.size())
+    else
     {
-        debug_logf(dce_smb_trace, nullptr, "cleanup pending requests for below MIDs:\n");
-        for ( auto& h : all_req_trackers )
+        Dce2Smb2SessionTracker* session = smb2_session_cache->find_session(
+            get_session_key(session_id));
+        if (session)
         {
-            debug_logf(dce_smb_trace, nullptr, "mid %" PRIu64 "\n", h.first);
-            removeRtracker(h.first);
+            session->attach_flow(flow_key, this);
+            connected_sessions.insert(std::make_pair(session_id,session));
         }
+        return session;
     }
-    memory::MemoryCap::update_deallocations(sizeof(*this));
 }
 
-DCE2_Smb2SessionTracker::DCE2_Smb2SessionTracker()
+// Caller must ensure that the session is not already present in flow
+Dce2Smb2SessionTracker* Dce2Smb2SessionData::create_session(uint64_t session_id)
 {
-    debug_logf(dce_smb_trace, nullptr, "session tracker %" PRIu64 " created\n", session_id);
-    memory::MemoryCap::update_allocations(sizeof(*this));
+    Smb2SessionKey session_key = get_session_key(session_id);
+    Dce2Smb2SessionTracker* session = smb2_session_cache->find_else_create_session(session_key);
+    session->init(session_id, session_key);
+    session->attach_flow(flow_key, this);
+    connected_sessions.insert(std::make_pair(session_id, session));
+    return session;
 }
 
-DCE2_Smb2SessionTracker::~DCE2_Smb2SessionTracker()
+void Dce2Smb2SessionData::remove_session(uint64_t session_id)
 {
-    debug_logf(dce_smb_trace, nullptr, "session tracker %" PRIu64 " terminating\n", session_id);
-    removeSessionFromAllConnection();
-    memory::MemoryCap::update_deallocations(sizeof(*this));
+    connected_sessions.erase(session_id);
+    smb2_session_cache->remove(get_session_key(session_id));
 }
 
-void DCE2_Smb2SessionTracker::removeSessionFromAllConnection()
+void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr,
+    const uint8_t* end)
 {
-    auto all_conn_trackers = conn_trackers.get_all_entry();
-    auto all_tree_trackers = tree_trackers.get_all_entry();
-    for ( auto& h : all_conn_trackers )
-    {
-        if (h.second->ftracker_tcp)
-        {
-            for (auto& t : all_tree_trackers)
-            {
-                DCE2_Smb2FileTracker* ftr = t.second->findFtracker(
-                    h.second->ftracker_tcp->file_id);
-                if (ftr and ftr == h.second->ftracker_tcp)
-                {
-                    h.second->ftracker_tcp = nullptr;
-                    break;
-                }
-            }
-        }
-        DCE2_Smb2RemoveSidInSsd(h.second, session_id);
+    const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
+    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
+
+// Macro and shorthand to save some repetitive code
+// Should only be used in this function
+#define SMB2_COMMAND_TYPE(cmd, type) \
+    (structure_size == SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE)
+
+#define SMB2_GET_COMMAND_TYPE(cmd) \
+    (SMB2_COMMAND_TYPE(ERROR,RESPONSE) and Smb2Error(smb_hdr)) ? \
+    SMB2_CMD_TYPE_ERROR_RESPONSE : (SMB2_COMMAND_TYPE(cmd, REQUEST) ? \
+    SMB2_CMD_TYPE_REQUEST : (SMB2_COMMAND_TYPE(cmd, RESPONSE) ? \
+    SMB2_CMD_TYPE_RESPONSE : SMB2_CMD_TYPE_INVALID))
+
+#define SMB2_HANDLE_HEADER_ERROR(cmd, type, counter) \
+    { \
+        if (smb_data + SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE - 1 > end) \
+        { \
+            dce2_smb_stats.v2_ ## counter ## _hdr_err++; \
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET, \
+                "%s : smb data beyond end detected\n", \
+                smb2_command_string[command]); \
+            return; \
+        } \
     }
-}
-
-static inline bool DCE2_Smb2FindSidTid(DCE2_Smb2SsnData* ssd, const uint64_t sid,
-    const uint32_t tid, const uint32_t mid, DCE2_Smb2SessionTracker** str, DCE2_Smb2TreeTracker** ttr)
-{
-    *str = DCE2_Smb2FindSidInSsd(ssd, sid);
-    if (!*str)
-        return false;
-    
-    if(!tid)
-        *ttr = find_tree_for_message(*str, mid);
-    else
-        *ttr = (*str)->findTtracker(tid);
-        
-    if(!*ttr)
-        return false;
 
-    return true;
-}
+#define SMB2_HANDLE_ERROR_RESPONSE(counter) \
+    { \
+        if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr)) \
+        { \
+            dce2_smb_stats.v2_ ## counter ## _err_resp++; \
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_RESP: error\n", \
+                smb2_command_string[command]); \
+            return; \
+        } \
+    }
 
-// FIXIT-L port fileCache related code along with
-// DCE2_Smb2Init, DCE2_Smb2Close and DCE2_Smb2UpdateStats
+#define SMB2_HANDLE_INVALID_STRUC_SIZE(counter) \
+    { \
+        dce2_smb_stats.v2_ ## counter ## _inv_str_sz++; \
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s: invalid struct size\n", \
+            smb2_command_string[command]); \
+        return; \
+    }
 
-static void DCE2_Smb2Inspect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const uint8_t* end)
-{
-    const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
     uint16_t command = alignedNtohs(&(smb_hdr->command));
-    DCE2_Smb2SessionTracker* str = nullptr;
-    DCE2_Smb2TreeTracker* ttr = nullptr;
-
-    uint64_t mid = Smb2Mid(smb_hdr);
-    uint64_t sid = Smb2Sid(smb_hdr);
-    uint32_t tid = Smb2Tid(smb_hdr);
-
-    debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
+    uint64_t session_id = Smb2Sid(smb_hdr);
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
         "%s : mid %" PRIu64 " sid %" PRIu64 " tid %" PRIu32 "\n",
-        (command <= SMB2_COM_OPLOCK_BREAK ? smb2_command_string[command] : "unknown"),
-        mid, sid, tid);
+        (command < SMB2_COM_MAX ? smb2_command_string[command] : "unknown"),
+        Smb2Mid(smb_hdr), session_id, Smb2Tid(smb_hdr));
+    // Try to find the session.
+    // The case when session is not available will be handled per command.
+    Dce2Smb2SessionTracker* session = find_session(session_id);
+
     switch (command)
     {
-    case SMB2_COM_CREATE:
-        dce2_smb_stats.v2_crt++;
-        DCE2_Smb2Create(ssd, smb_hdr, smb_data, end, mid, sid, tid);
-        break;
-    case SMB2_COM_READ:
-        dce2_smb_stats.v2_read++;
-        if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
-            SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+    //commands processed by flow
+    case SMB2_COM_SESSION_SETUP:
+        dce2_smb_stats.v2_setup++;
+        SMB2_HANDLE_ERROR_RESPONSE(setup)
+        if (SMB2_COMMAND_TYPE(SETUP, RESPONSE))
         {
-            dce2_smb_stats.v2_read_ignored++;
-            return;
+            SMB2_HANDLE_HEADER_ERROR(SETUP, RESPONSE, setup_resp)
+            if (!session)
+                create_session(session_id);
         }
+        else if (!SMB2_COMMAND_TYPE(SETUP, REQUEST))
+            SMB2_HANDLE_INVALID_STRUC_SIZE(setup)
+        break;
 
-        DCE2_Smb2Read(ssd, smb_hdr, smb_data, end, str, ttr, mid);
+    case SMB2_COM_LOGOFF:
+        dce2_smb_stats.v2_logoff++;
+        if (SMB2_COMMAND_TYPE(LOGOFF, REQUEST))
+            remove_session(session_id);
+        else
+            SMB2_HANDLE_INVALID_STRUC_SIZE(logoff)
         break;
-    case SMB2_COM_WRITE:
-        dce2_smb_stats.v2_wrt++;
-        if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
-            SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+    //commands processed by session
+    case SMB2_COM_TREE_CONNECT:
+        dce2_smb_stats.v2_tree_cnct++;
+
+        SMB2_HANDLE_ERROR_RESPONSE(tree_cnct)
+        if (SMB2_COMMAND_TYPE(TREE_CONNECT, RESPONSE))
         {
-            dce2_smb_stats.v2_wrt_ignored++;
-            return;
+            SMB2_HANDLE_HEADER_ERROR(TREE_CONNECT, RESPONSE, tree_cnct_resp)
+            if (!session)
+                session = create_session(session_id);
+            session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end);
         }
-
-        DCE2_Smb2Write(ssd, smb_hdr, smb_data, end, str, ttr, mid);
+        else if (!SMB2_COMMAND_TYPE(TREE_CONNECT,REQUEST))
+            SMB2_HANDLE_INVALID_STRUC_SIZE(tree_cnct)
         break;
-    case SMB2_COM_SET_INFO:
-        dce2_smb_stats.v2_stinf++;
-        if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
-            SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+
+    case SMB2_COM_TREE_DISCONNECT:
+        dce2_smb_stats.v2_tree_discn++;
+
+        if (session)
         {
-            dce2_smb_stats.v2_stinf_ignored++;
-            return;
+            if (SMB2_COMMAND_TYPE(TREE_DISCONNECT, REQUEST))
+            {
+                SMB2_HANDLE_HEADER_ERROR(TREE_DISCONNECT, REQUEST, tree_discn_req)
+                session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+            }
+            else
+            {
+                SMB2_HANDLE_INVALID_STRUC_SIZE(tree_discn)
+            }
         }
+        else
+            dce2_smb_stats.v2_session_ignored++;
+        break;
+    //commands processed by tree
+    case SMB2_COM_CREATE:
+    {
+        dce2_smb_stats.v2_crt++;
 
-        DCE2_Smb2SetInfo(ssd, smb_hdr, smb_data, end, ttr);
+        uint8_t command_type = SMB2_GET_COMMAND_TYPE(CREATE);
+        if (SMB2_CMD_TYPE_INVALID == command_type)
+            SMB2_HANDLE_INVALID_STRUC_SIZE(crt)
+        else if (SMB2_COMMAND_TYPE(CREATE, REQUEST))
+            SMB2_HANDLE_HEADER_ERROR(CREATE, REQUEST, crt_req)
+        else if (SMB2_COMMAND_TYPE(CREATE, RESPONSE))
+            SMB2_HANDLE_HEADER_ERROR(CREATE, RESPONSE, crt_resp)
+
+        if (!session)
+            session = create_session(session_id);
+        session->process(command, command_type, smb_hdr, end);
+    }
         break;
+
     case SMB2_COM_CLOSE:
         dce2_smb_stats.v2_cls++;
-        if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
-            SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+        SMB2_HANDLE_ERROR_RESPONSE(cls)
+        if (session)
         {
-            dce2_smb_stats.v2_cls_ignored++;
-            return;
+            if (SMB2_COMMAND_TYPE(CLOSE, REQUEST))
+            {
+                SMB2_HANDLE_HEADER_ERROR(CLOSE, REQUEST, cls_req)
+                session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+            }
+            else if (!SMB2_COMMAND_TYPE(CLOSE, RESPONSE))
+            {
+                SMB2_HANDLE_INVALID_STRUC_SIZE(cls)
+            }
         }
-
-        DCE2_Smb2CloseCmd(ssd, smb_hdr, smb_data, end, ttr, str);
+        else
+            dce2_smb_stats.v2_session_ignored++;
         break;
-    case SMB2_COM_TREE_CONNECT:
-        dce2_smb_stats.v2_tree_cnct++;
-        // This will always return session tracker
-        str = DCE2_Smb2FindElseCreateSid(ssd, sid);
-        if (str)
+
+    case SMB2_COM_SET_INFO:
+        dce2_smb_stats.v2_setinfo++;
+        SMB2_HANDLE_ERROR_RESPONSE(stinf)
+        if (session)
         {
-            DCE2_Smb2TreeConnect(ssd, smb_hdr, smb_data, end, str, tid);
+            if (SMB2_COMMAND_TYPE(SET_INFO, REQUEST))
+            {
+                SMB2_HANDLE_HEADER_ERROR(SET_INFO, REQUEST, stinf_req)
+                session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+            }
+            else if (!SMB2_COMMAND_TYPE(SET_INFO, RESPONSE))
+            {
+                SMB2_HANDLE_INVALID_STRUC_SIZE(stinf)
+            }
         }
+        else
+            dce2_smb_stats.v2_session_ignored++;
         break;
-    case SMB2_COM_TREE_DISCONNECT:
-        dce2_smb_stats.v2_tree_discn++;
-        if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr))
+
+    case SMB2_COM_READ:
+        dce2_smb_stats.v2_read++;
+        if (session)
         {
-            dce2_smb_stats.v2_tree_discn_ignored++;
-            return;
+            uint8_t command_type;
+            if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr))
+                command_type = SMB2_CMD_TYPE_ERROR_RESPONSE;
+            else if (SMB2_COMMAND_TYPE(READ, REQUEST))
+            {
+                SMB2_HANDLE_HEADER_ERROR(READ, REQUEST, read_req)
+                command_type = SMB2_CMD_TYPE_REQUEST;
+            }
+            else if (SMB2_COMMAND_TYPE(READ, RESPONSE))
+            {
+                SMB2_HANDLE_HEADER_ERROR(READ, RESPONSE, read_resp)
+                command_type = SMB2_CMD_TYPE_RESPONSE;
+            }
+            else
+                SMB2_HANDLE_INVALID_STRUC_SIZE(read)
+            session->process(command, command_type, smb_hdr, end);
         }
-        DCE2_Smb2TreeDisconnect(ssd, smb_data, end, str, tid);
-        break;
-    case SMB2_COM_SESSION_SETUP:
-        dce2_smb_stats.v2_setup++;
-        DCE2_Smb2Setup(ssd, smb_hdr, sid, smb_data, end);
+        else
+            dce2_smb_stats.v2_session_ignored++;
         break;
-    case SMB2_COM_LOGOFF:
-        dce2_smb_stats.v2_logoff++;
-        DCE2_Smb2Logoff(ssd, smb_data, sid);
+
+    case SMB2_COM_WRITE:
+        dce2_smb_stats.v2_wrt++;
+        if (session)
+        {
+            uint8_t command_type;
+            if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr))
+                command_type = SMB2_CMD_TYPE_ERROR_RESPONSE;
+            else if (SMB2_COMMAND_TYPE(WRITE, REQUEST))
+            {
+                SMB2_HANDLE_HEADER_ERROR(WRITE, REQUEST, wrt_req)
+                command_type = SMB2_CMD_TYPE_REQUEST;
+            }
+            else if (SMB2_COMMAND_TYPE(WRITE, RESPONSE))
+            {
+                SMB2_HANDLE_HEADER_ERROR(WRITE, RESPONSE, wrt_resp)
+                command_type = SMB2_CMD_TYPE_RESPONSE;
+            }
+            else
+                SMB2_HANDLE_INVALID_STRUC_SIZE(wrt)
+            session->process(command, command_type, smb_hdr, end);
+        }
+        else
+            dce2_smb_stats.v2_session_ignored++;
         break;
+
     default:
         dce2_smb_stats.v2_msgs_uninspected++;
         break;
@@ -308,7 +406,7 @@ static void DCE2_Smb2Inspect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
 }
 
 // This is the main entry point for SMB2 processing.
-void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd)
+void Dce2Smb2SessionData::process()
 {
     Packet* p = DetectionEngine::get_current_packet();
     const uint8_t* data_ptr = p->data;
@@ -317,8 +415,8 @@ void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd)
     // Check header length
     if (data_len < sizeof(NbssHdr) + SMB2_HEADER_LENGTH)
     {
-        dce2_smb_stats.v2_hdr_err++;
         debug_logf(dce_smb_trace, p, "Header error with data length %d\n",data_len);
+        dce2_smb_stats.v2_hdr_err++;
         return;
     }
 
@@ -338,13 +436,14 @@ void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd)
         // multiple requests up to the maximum size<88> that is supported by the transport."
         do
         {
-            DCE2_Smb2Inspect(ssd, smb_hdr, data_ptr +  data_len);
+            process_command(smb_hdr, data_ptr +  data_len);
+
             // In case of message compounding, find the offset of the next smb command
             next_command_offset = alignedNtohl(&(smb_hdr->next_command));
             if (next_command_offset + (const uint8_t*)smb_hdr > (data_ptr + data_len))
             {
                 dce_alert(GID_DCE2, DCE2_SMB_BAD_NEXT_COMMAND_OFFSET,
-                    (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
+                    (dce2CommonStats*)&dce2_smb_stats, sd);
                 debug_logf(dce_smb_trace, p, "bad next command offset\n");
                 dce2_smb_stats.v2_bad_next_cmd_offset++;
                 return;
@@ -355,59 +454,23 @@ void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd)
                 compound_request_index++;
             }
 
-            if (compound_request_index > DCE2_ScSmbMaxCompound((dce2SmbProtoConf*)ssd->sd.config))
+            if (compound_request_index > get_smb_max_compound())
             {
                 dce2_smb_stats.v2_cmpnd_req_lt_crossed++;
-                debug_logf(dce_smb_trace, p, "compound req limit reached %" PRIu8 "\n",
-                    compound_request_index);
+                debug_logf(dce_smb_trace, p, "compound request limit"
+                    " reached %" PRIu8 "\n",compound_request_index);
                 return;
             }
         }
         while (next_command_offset and smb_hdr);
     }
-    else if ( ssd->ftracker_tcp and (ssd->ftracker_tcp->smb2_pdu_state ==
-        DCE2_SMB_PDU_STATE__RAW_DATA))
-    {
-        debug_logf(dce_smb_trace, p,
-            "raw data file_name_hash %" PRIu64 " fid %" PRIu64 " dir %s\n",
-            ssd->ftracker_tcp->file_name_hash, ssd->ftracker_tcp->file_id,
-            ssd->ftracker_tcp->upload ? "upload" : "download");
-
-        if (!DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len))
-            return;
-        ssd->ftracker_tcp->file_offset += data_len;
-    }
-}
-
-DCE2_Ret DCE2_Smb2InitData(DCE2_Smb2SsnData* ssd)
-{
-    memset(&ssd->sd, 0, sizeof(DCE2_SsnData));
-    ssd->session_trackers.SetDoNotFree();
-    memset(&ssd->policy, 0, sizeof(DCE2_Policy));
-    ssd->dialect_index = 0;
-    ssd->ssn_state_flags = 0;
-    ssd->ftracker_tcp = nullptr;
-    ssd->max_file_depth = FileService::get_max_file_depth();
-    ssd->flow_key = get_flow_key();
-    return DCE2_RET__SUCCESS;
-}
-
-// Check whether the packet is smb2
-DCE2_SmbVersion DCE2_Smb2Version(const Packet* p)
-{
-    // Only check reassembled SMB2 packet
-    if ( p->has_paf_payload() and
-            (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE) ) // DCE2_SMB_ID is u32
+    else if ( tcp_file_tracker and tcp_file_tracker->accepting_raw_data())
     {
-        const Smb2Hdr* smb_hdr = (const Smb2Hdr*)(p->data + sizeof(NbssHdr));
-        uint32_t smb_version_id = SmbId((const SmbNtHdr*)smb_hdr);
-
-        if (smb_version_id == DCE2_SMB_ID)
-            return DCE2_SMB_VERSION_1;
-        else if (smb_version_id == DCE2_SMB2_ID)
-            return DCE2_SMB_VERSION_2;
+        debug_logf(dce_smb_trace, p, "processing raw data for file id %" PRIu64 "\n",
+            tcp_file_tracker->get_file_id());
+        
+        if (!tcp_file_tracker->process_data(data_ptr, data_len))
+            tcp_file_tracker->get_parent()->close_file(tcp_file_tracker->get_file_id());
     }
-
-    return DCE2_SMB_VERSION_NULL;
 }
 
index 490d7f8acda879421a4872c39b53520bd1a41b1d..642a53e691600f0a5f4d9976ce4e91c2c964cdfe 100644 (file)
 #ifndef DCE_SMB2_H
 #define DCE_SMB2_H
 
-#include "dce_db.h"
-#include "dce_smb.h"
-#include "hash/lru_cache_shared.h"
+// This implements smb session data for SMBv2
+// Also provides SMBv2 related header structures
+
 #include "main/thread_config.h"
 #include "memory/memory_cap.h"
 #include "utils/util.h"
 
+#include "dce_smb_common.h"
+
+/* SMB2 command codes */
+#define SMB2_COM_NEGOTIATE        0x00
+#define SMB2_COM_SESSION_SETUP    0x01
+#define SMB2_COM_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_ECHO             0x0D
+#define SMB2_COM_QUERY_DIRECTORY  0x0E
+#define SMB2_COM_CHANGE_NOTIFY    0x0F
+#define SMB2_COM_QUERY_INFO       0x10
+#define SMB2_COM_SET_INFO         0x11
+#define SMB2_COM_OPLOCK_BREAK     0x12
+#define SMB2_COM_MAX              0x13
+
+extern const char* smb2_command_string[SMB2_COM_MAX];
+
+// file attribute for create response
+#define SMB2_CREATE_RESPONSE_DIRECTORY 0x10
 #define SMB_AVG_FILES_PER_SESSION 5
 
+#define SMB2_SHARE_TYPE_DISK  0x01
+#define SMB2_SHARE_TYPE_PIPE  0x02
+#define SMB2_SHARE_TYPE_PRINT 0x03
+
+#define SMB2_CMD_TYPE_ERROR_RESPONSE 0
+#define SMB2_CMD_TYPE_REQUEST        1
+#define SMB2_CMD_TYPE_RESPONSE       2
+#define SMB2_CMD_TYPE_INVALID        3
+
 struct Smb2Hdr
 {
     uint8_t smb_idf[4];       /* contains 0xFE,’SMB’ */
@@ -47,22 +84,6 @@ struct Smb2Hdr
     uint8_t signature[16];    /* signature of the message */
 };
 
-struct Smb2ASyncHdr
-{
-    uint8_t smb_idf[4];       /* contains 0xFE,’SMB’ */
-    uint16_t structure_size;  /* This MUST be set to 64 */
-    uint16_t credit_charge;   /* # of credits that this request consumes */
-    uint32_t status;          /* depends */
-    uint16_t command;         /* command code  */
-    uint16_t credit;          /* # of credits requesting/granted */
-    uint32_t flags;           /* flags */
-    uint32_t next_command;    /* used for compounded request */
-    uint64_t message_id;      /* identifies a message uniquely on connection */
-    uint64_t async_id;        /* handle operations asynchronously */
-    uint64_t session_id;      /* identifies the established session for the command*/
-    uint8_t signature[16];    /* signature of the message */
-};
-
 struct Smb2SyncHdr
 {
     uint8_t smb_idf[4];       /* contains 0xFE,’SMB’ */
@@ -80,392 +101,6 @@ struct Smb2SyncHdr
     uint8_t signature[16];    /* signature of the message */
 };
 
-struct Smb2ErrorResponseHdr
-{
-    uint16_t structure_size;  /* This MUST be set to 9 */
-    uint16_t reserved;        /* reserved */
-    uint32_t byte_count;      /* The number of bytes of error_data */
-    uint8_t error_data[1];    /* If byte_count is 0, this MUST be 0*/
-};
-
-class DCE2_Smb2TreeTracker;
-
-class DCE2_Smb2RequestTracker
-{
-public:
-
-    DCE2_Smb2RequestTracker() = delete;
-    DCE2_Smb2RequestTracker(const DCE2_Smb2RequestTracker& arg) = delete;
-    DCE2_Smb2RequestTracker& operator=(const DCE2_Smb2RequestTracker& arg) = delete;
-
-    DCE2_Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0);
-    DCE2_Smb2RequestTracker(char* fname_v, uint16_t fname_len_v);
-    ~DCE2_Smb2RequestTracker();
-
-    uint64_t get_offset()
-    {
-        return offset;
-    }
-
-    uint64_t get_file_id()
-    {
-        return file_id;
-    }
-
-    void set_file_id(uint64_t fid)
-    {
-        file_id = fid;
-    }
-
-    char* fname = nullptr;
-    uint16_t fname_len = 0;
-
-private:
-
-    uint64_t file_id = 0;
-    uint64_t offset = 0;
-};
-
-struct DCE2_Smb2SsnData;
-class DCE2_Smb2SessionTracker;
-
-class DCE2_Smb2FileTracker
-{
-public:
-
-    DCE2_Smb2FileTracker() = delete;
-    DCE2_Smb2FileTracker(const DCE2_Smb2FileTracker& arg) = delete;
-    DCE2_Smb2FileTracker& operator=(const DCE2_Smb2FileTracker& arg) = delete;
-
-    DCE2_Smb2FileTracker(uint64_t file_id_v, DCE2_Smb2TreeTracker* ttr_v,
-         DCE2_Smb2SessionTracker* str_v, snort::Flow* flow_v);
-    ~DCE2_Smb2FileTracker();
-
-    bool ignore = false;
-    bool upload = false;
-    uint16_t file_name_len = 0;
-    uint64_t bytes_processed = 0;
-    uint64_t file_offset = 0;
-    uint64_t file_id = 0;
-    uint64_t file_size = 0;
-    uint64_t file_name_hash = 0;
-    char* file_name = nullptr;
-    DCE2_SmbPduState smb2_pdu_state;
-    DCE2_Smb2TreeTracker* ttr = nullptr;
-    DCE2_Smb2SessionTracker* str = nullptr;
-    snort::Flow *flow = nullptr;
-};
-
-typedef DCE2_DbMap<uint64_t, DCE2_Smb2FileTracker*, std::hash<uint64_t> > DCE2_DbMapFtracker;
-typedef DCE2_DbMap<uint64_t, DCE2_Smb2RequestTracker*, std::hash<uint64_t> > DCE2_DbMapRtracker;
-class DCE2_Smb2TreeTracker
-{
-public:
-
-    DCE2_Smb2TreeTracker() = delete;
-    DCE2_Smb2TreeTracker(const DCE2_Smb2TreeTracker& arg) = delete;
-    DCE2_Smb2TreeTracker& operator=(const DCE2_Smb2TreeTracker& arg) = delete;
-
-    DCE2_Smb2TreeTracker (uint32_t tid_v, uint8_t share_type_v);
-    ~DCE2_Smb2TreeTracker();
-
-    // File Tracker
-    DCE2_Smb2FileTracker* findFtracker(uint64_t file_id)
-    {
-        return file_trackers.Find(file_id);
-    }
-
-    bool insertFtracker(uint64_t file_id, DCE2_Smb2FileTracker* ftracker)
-    {
-        return file_trackers.Insert(file_id, ftracker);
-    }
-
-    void removeFtracker(uint64_t file_id)
-    {
-        file_trackers.Remove(file_id);
-    }
-
-    // Request Tracker
-    DCE2_Smb2RequestTracker* findRtracker(uint64_t mid)
-    {
-        return req_trackers.Find(mid);
-    }
-
-    bool insertRtracker(uint64_t message_id, DCE2_Smb2RequestTracker* rtracker)
-    {
-        return req_trackers.Insert(message_id, rtracker);
-    }
-
-    void removeRtracker(uint64_t message_id)
-    {
-        req_trackers.Remove(message_id);
-    }
-
-    int getRtrackerSize()
-    {
-        return req_trackers.GetSize();
-    }
-
-    // common methods
-    uint8_t get_share_type()
-    {
-        return share_type;
-    }
-
-    uint32_t get_tid()
-    {
-        return tid;
-    }
-
-private:
-    uint8_t share_type = 0;
-    uint32_t tid = 0;
-
-    DCE2_DbMapRtracker req_trackers;
-    DCE2_DbMapFtracker file_trackers;
-};
-
-PADDING_GUARD_BEGIN
-struct Smb2SidHashKey
-{
-    //must be of size 3*x*sizeof(uint32_t)
-    uint32_t cip[4];
-    uint32_t sip[4];
-    uint64_t sid;
-    int16_t cgroup;
-    int16_t sgroup;
-    uint16_t asid;
-    uint16_t padding;
-
-    bool operator== (const Smb2SidHashKey &other) const
-    {
-        return( sid == other.sid and
-                cip[0] == other.cip[0] and
-                cip[1] == other.cip[1] and
-                cip[2] == other.cip[2] and
-                cip[3] == other.cip[3] and
-                sip[0] == other.sip[0] and
-                sip[1] == other.sip[1] and
-                sip[2] == other.sip[2] and
-                sip[3] == other.sip[3] and
-                cgroup == other.cgroup and
-                sgroup == other.sgroup and
-                asid == other.asid);
-    }
-};
-
-struct SmbFlowKey
-{
-    uint32_t ip_l[4];   /* Low IP */
-    uint32_t ip_h[4];   /* High IP */
-    uint32_t mplsLabel;
-    uint16_t port_l;    /* Low Port - 0 if ICMP */
-    uint16_t port_h;    /* High Port - 0 if ICMP */
-    int16_t group_l;
-    int16_t group_h;
-    uint16_t vlan_tag;
-    uint16_t addressSpaceId;
-    uint8_t ip_protocol;
-    uint8_t pkt_type;
-    uint8_t version;
-    uint8_t padding;
-
-    bool operator==(const SmbFlowKey& other) const
-    {
-        return (ip_l[0] == other.ip_l[0] and
-               ip_l[1] == other.ip_l[1] and
-               ip_l[2] == other.ip_l[2] and
-               ip_l[3] == other.ip_l[3] and
-               ip_h[0] == other.ip_h[0] and
-               ip_l[1] == other.ip_l[1] and
-               ip_l[2] == other.ip_l[2] and
-               ip_l[3] == other.ip_l[3] and
-               mplsLabel == other.mplsLabel and
-               port_l == other.port_l and
-               port_h == other.port_h and
-               group_l == other.group_l and
-               group_h == other.group_h and
-               vlan_tag == other.vlan_tag and
-               addressSpaceId == other.addressSpaceId and
-               ip_protocol == other.ip_protocol and
-               pkt_type == other.pkt_type and
-               version == other.version);
-    }
-};
-PADDING_GUARD_END
-
-//The below value is taken from Hash Key class static hash hardener
-#define SMB_KEY_HASH_HARDENER 133824503
-
-struct SmbKeyHash
-{
-    size_t operator() (const SmbFlowKey& key) const
-    {
-        return  do_hash_flow_key((const uint32_t*)&key);
-    }
-
-    size_t operator() (const Smb2SidHashKey& key) const
-    {
-        return do_hash((const uint32_t*)&key);
-    }
-
-private:
-    size_t do_hash(const uint32_t* d) const
-    {
-        uint32_t a, b, c;
-        a = b = c = SMB_KEY_HASH_HARDENER;
-        a += d[0]; b += d[1];  c += d[2];  mix(a, b, c);
-        a += d[3]; b += d[4];  c += d[5];  mix(a, b, c);
-        a += d[6]; b += d[7];  c += d[8];  mix(a, b, c);
-        a += d[9]; b += d[10]; c += d[11]; finalize(a, b, c);
-        return c;
-    }
-
-    size_t do_hash_flow_key(const uint32_t* d) const
-    {
-        uint32_t a, b, c;
-        a = b = c = SMB_KEY_HASH_HARDENER;
-        a += d[0]; b += d[1];  c += d[2];  mix(a, b, c);
-        a += d[3]; b += d[4];  c += d[5];  mix(a, b, c);
-        a += d[6]; b += d[7];  c += d[8];  mix(a, b, c);
-        a += d[9]; b += d[10]; c += d[11]; mix(a, b, c);
-        a += d[12]; finalize(a, b, c);
-        return c;
-    }
-
-    inline uint32_t rot(uint32_t x, unsigned k) const
-    { return (x << k) | (x >> (32 - k)); }
-
-    inline void mix(uint32_t& a, uint32_t& b, uint32_t& c) const
-    {
-        a -= c; a ^= rot(c, 4); c += b;
-        b -= a; b ^= rot(a, 6); a += c;
-        c -= b; c ^= rot(b, 8); b += a;
-        a -= c; a ^= rot(c,16); c += b;
-        b -= a; b ^= rot(a,19); a += c;
-        c -= b; c ^= rot(b, 4); b += a;
-    }
-
-    inline void finalize(uint32_t& a, uint32_t& b, uint32_t& c) const
-    {
-        c ^= b; c -= rot(b,14);
-        a ^= c; a -= rot(c,11);
-        b ^= a; b -= rot(a,25);
-        c ^= b; c -= rot(b,16);
-        a ^= c; a -= rot(c,4);
-        b ^= a; b -= rot(a,14);
-        c ^= b; c -= rot(b,24);
-    }
-};
-
-typedef DCE2_DbMap<uint32_t, DCE2_Smb2TreeTracker*, std::hash<uint32_t> > DCE2_DbMapTtracker;
-typedef DCE2_DbMap<struct SmbFlowKey, DCE2_Smb2SsnData*, SmbKeyHash> DCE2_DbMapConntracker;
-class DCE2_Smb2SessionTracker
-{
-public:
-
-    DCE2_Smb2SessionTracker();
-    ~DCE2_Smb2SessionTracker();
-
-    void removeSessionFromAllConnection();
-
-    // tree tracker
-    bool insertTtracker(uint32_t tree_id, DCE2_Smb2TreeTracker* ttr)
-    {
-        return tree_trackers.Insert(tree_id, ttr);
-    }
-
-    DCE2_Smb2TreeTracker* findTtracker(uint32_t tree_id)
-    {
-        return tree_trackers.Find(tree_id);
-    }
-
-    void removeTtracker(uint32_t tree_id)
-    {
-        tree_trackers.Remove(tree_id);
-    }
-
-    // ssd tracker
-    bool insertConnTracker(SmbFlowKey key, DCE2_Smb2SsnData* ssd)
-    {
-        return conn_trackers.Insert(key, ssd);
-    }
-
-    DCE2_Smb2SsnData* findConnTracker(SmbFlowKey key)
-    {
-        return conn_trackers.Find(key);
-    }
-
-    void removeConnTracker(SmbFlowKey key)
-    {
-        conn_trackers.Remove(key);
-    }
-
-    int getConnTrackerSize()
-    {
-        return conn_trackers.GetSize();
-    }
-
-    uint16_t getTotalRequestsPending()
-    {
-        uint16_t total_count = 0;
-        auto all_tree_trackers = tree_trackers.get_all_entry();
-        for ( auto& h : all_tree_trackers )
-        {
-            total_count += h.second->getRtrackerSize();
-        }
-        return total_count;
-    }
-
-    void set_session_id(uint64_t sid)
-    {
-        session_id = sid;
-        conn_trackers.SetDoNotFree();
-    }
-
-    DCE2_DbMapConntracker conn_trackers;
-    DCE2_DbMapTtracker tree_trackers;
-    Smb2SidHashKey session_key;
-    uint64_t session_id = 0;
-};
-
-typedef DCE2_DbMap<uint64_t, DCE2_Smb2SessionTracker*, std::hash<uint64_t> > DCE2_DbMapStracker;
-struct DCE2_Smb2SsnData
-{
-    DCE2_SsnData sd;  // This member must be first
-    uint8_t smb_id;
-    DCE2_Policy policy;
-    int dialect_index;
-    int ssn_state_flags;
-    int64_t max_file_depth; // Maximum file depth as returned from file API
-    int16_t max_outstanding_requests; // Maximum number of request that can stay pending
-    DCE2_DbMapStracker session_trackers;
-    DCE2_Smb2FileTracker* ftracker_tcp; //To keep tab of current file being transferred over TCP
-    SmbFlowKey flow_key;
-};
-
-/* SMB2 command codes */
-#define SMB2_COM_NEGOTIATE        0x00
-#define SMB2_COM_SESSION_SETUP    0x01
-#define SMB2_COM_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_ECHO             0x0D
-#define SMB2_COM_QUERY_DIRECTORY  0x0E
-#define SMB2_COM_CHANGE_NOTIFY    0x0F
-#define SMB2_COM_QUERY_INFO       0x10
-#define SMB2_COM_SET_INFO         0x11
-#define SMB2_COM_OPLOCK_BREAK     0x12
-#define SMB2_COM_MAX              0x13
-
 struct Smb2WriteRequestHdr
 {
     uint16_t structure_size;  /* This MUST be set to 49 */
@@ -549,9 +184,6 @@ struct Smb2CreateRequestHdr
     uint32_t create_contexts_length;  /* length of contexts */
 };
 
-// file attribute for create response
-#define SMB2_CREATE_RESPONSE_DIRECTORY 0x10
-
 struct Smb2CreateResponseHdr
 {
     uint16_t structure_size;          /* This MUST be set to 89 */
@@ -572,6 +204,16 @@ struct Smb2CreateResponseHdr
     uint32_t create_contexts_length;  /*  */
 };
 
+struct Smb2CreateContextHdr
+{
+    uint32_t next;            /* next context header*/
+    uint16_t name_offset;     /* name offset */
+    uint16_t name_length;     /* name length */
+    uint16_t reserved;        /* reserved */
+    uint16_t data_offset;     /* data offset */
+    uint32_t data_length;     /* data length */
+};
+
 struct Smb2CloseRequestHdr
 {
     uint16_t structure_size;          /* This MUST be set to 24 */
@@ -581,10 +223,6 @@ struct Smb2CloseRequestHdr
     uint64_t fileId_volatile;         /* fileId that is volatile */
 };
 
-#define SMB2_SHARE_TYPE_DISK  0x01
-#define SMB2_SHARE_TYPE_PIPE  0x02
-#define SMB2_SHARE_TYPE_PRINT 0x03
-
 struct Smb2TreeConnectResponseHdr
 {
     uint16_t structure_size;          /* This MUST be set to 16 */
@@ -595,39 +233,12 @@ struct Smb2TreeConnectResponseHdr
     uint32_t maximal_access;          /* maximal access for the user */
 };
 
-struct Smb2TreeDisConnectHdr
-{
-    uint16_t structure_size;          /* This MUST be set to 4 */
-    uint16_t reserved;                 /* reserved */
-};
-
-struct  Smb2SetupRequestHdr
-{
-    uint16_t structure_size;            /* This MUST be set to 25 (0x19) bytes */
-    uint8_t flags;
-    uint8_t security_mode;
-    uint32_t capabilities;
-    uint32_t channel;
-    uint16_t secblob_ofs;
-    uint16_t secblob_size;
-    uint64_t previous_sessionid;
-};
-
-struct Smb2SetupResponseHdr
-{
-    uint16_t structure_size;            /* This MUST be set to 9 (0x09) bytes */
-    uint16_t session_flags;
-    uint16_t secblob_ofs;
-    uint16_t secblob_size;
-};
-
 #define SMB2_HEADER_LENGTH 64
 
 #define SMB2_ERROR_RESPONSE_STRUC_SIZE 9
 
 #define SMB2_CREATE_REQUEST_STRUC_SIZE 57
 #define SMB2_CREATE_RESPONSE_STRUC_SIZE 89
-#define SMB2_CREATE_REQUEST_DATA_OFFSET 120
 
 #define SMB2_CLOSE_REQUEST_STRUC_SIZE 24
 #define SMB2_CLOSE_RESPONSE_STRUC_SIZE 60
@@ -644,6 +255,7 @@ struct Smb2SetupResponseHdr
 #define SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE 9
 #define SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE 16
 #define SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE 4
+#define SMB2_TREE_DISCONNECT_RESPONSE_STRUC_SIZE 4
 
 #define SMB2_FILE_ENDOFFILE_INFO 0x14
 
@@ -651,13 +263,176 @@ struct Smb2SetupResponseHdr
 #define SMB2_SETUP_RESPONSE_STRUC_SIZE 9
 
 #define SMB2_LOGOFF_REQUEST_STRUC_SIZE 4
+#define SMB2_LOGOFF_RESPONSE_STRUC_SIZE 4
 
-extern const char* smb2_command_string[SMB2_COM_MAX];
-/* Process smb2 message */
-void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd);
+#define GET_CURRENT_PACKET snort::DetectionEngine::get_current_packet()
+
+class Dce2Smb2FileTracker;
+class Dce2Smb2SessionTracker;
+
+using Dce2Smb2SessionTrackerMap =
+    std::unordered_map<uint64_t, Dce2Smb2SessionTracker*, std::hash<uint64_t> >;
+
+PADDING_GUARD_BEGIN
+struct Smb2SessionKey
+{
+    uint32_t cip[4];
+    uint32_t sip[4];
+    uint64_t sid;
+    int16_t cgroup;
+    int16_t sgroup;
+    uint16_t asid;
+    uint16_t padding;
+
+    bool operator==(const Smb2SessionKey& other) const
+    {
+        return( sid == other.sid and
+               cip[0] == other.cip[0] and
+               cip[1] == other.cip[1] and
+               cip[2] == other.cip[2] and
+               cip[3] == other.cip[3] and
+               sip[0] == other.sip[0] and
+               sip[1] == other.sip[1] and
+               sip[2] == other.sip[2] and
+               sip[3] == other.sip[3] and
+               cgroup == other.cgroup and
+               sgroup == other.sgroup and
+               asid == other.asid );
+    }
+};
+
+struct Smb2FlowKey
+{
+    uint32_t ip_l[4];   // Low IP
+    uint32_t ip_h[4];   // High IP
+    uint32_t mplsLabel;
+    uint16_t port_l;    // Low Port - 0 if ICMP
+    uint16_t port_h;    // High Port - 0 if ICMP
+    int16_t group_l;
+    int16_t group_h;
+    uint16_t vlan_tag;
+    uint16_t addressSpaceId;
+    uint8_t ip_protocol;
+    uint8_t pkt_type;
+    uint8_t version;
+    uint8_t padding;
+
+    bool operator==(const Smb2FlowKey& other) const
+    {
+        return (ip_l[0] == other.ip_l[0] and
+               ip_l[1] == other.ip_l[1] and
+               ip_l[2] == other.ip_l[2] and
+               ip_l[3] == other.ip_l[3] and
+               ip_h[0] == other.ip_h[0] and
+               ip_l[1] == other.ip_l[1] and
+               ip_l[2] == other.ip_l[2] and
+               ip_l[3] == other.ip_l[3] and
+               mplsLabel == other.mplsLabel and
+               port_l == other.port_l and
+               port_h == other.port_h and
+               group_l == other.group_l and
+               group_h == other.group_h and
+               vlan_tag == other.vlan_tag and
+               addressSpaceId == other.addressSpaceId and
+               ip_protocol == other.ip_protocol and
+               pkt_type == other.pkt_type and
+               version == other.version);
+    }
+};
+PADDING_GUARD_END
+
+//The below value is taken from Hash Key class static hash hardener
+#define SMB_KEY_HASH_HARDENER 133824503
+
+struct Smb2KeyHash
+{
+    size_t operator()(const Smb2FlowKey& key) const
+    {
+        return do_hash_flow_key((const uint32_t*)&key);
+    }
+
+    size_t operator()(const Smb2SessionKey& key) const
+    {
+        return do_hash_session_key((const uint32_t*)&key);
+    }
+
+private:
+    size_t do_hash_flow_key(const uint32_t* d) const
+    {
+        uint32_t a, b, c;
+        a = b = c = SMB_KEY_HASH_HARDENER;
+        a += d[0]; b += d[1];  c += d[2];  mix(a, b, c);
+        a += d[3]; b += d[4];  c += d[5];  mix(a, b, c);
+        a += d[6]; b += d[7];  c += d[8];  mix(a, b, c);
+        a += d[9]; b += d[10]; c += d[11]; mix(a, b, c);
+        a += d[12]; finalize(a, b, c);
+        return c;
+    }
+
+    size_t do_hash_session_key(const uint32_t* d) const
+    {
+        uint32_t a, b, c;
+        a = b = c = SMB_KEY_HASH_HARDENER;
+        a += d[0]; b += d[1];  c += d[2];  mix(a, b, c);
+        a += d[3]; b += d[4];  c += d[5];  mix(a, b, c);
+        a += d[6]; b += d[7];  c += d[8];  mix(a, b, c);
+        a += d[9]; b += d[10]; c += d[11]; finalize(a, b, c);
+        return c;
+    }
+
+    inline uint32_t rot(uint32_t x, unsigned k) const
+    { return (x << k) | (x >> (32 - k)); }
+
+    inline void mix(uint32_t& a, uint32_t& b, uint32_t& c) const
+    {
+        a -= c; a ^= rot(c, 4); c += b;
+        b -= a; b ^= rot(a, 6); a += c;
+        c -= b; c ^= rot(b, 8); b += a;
+        a -= c; a ^= rot(c,16); c += b;
+        b -= a; b ^= rot(a,19); a += c;
+        c -= b; c ^= rot(b, 4); b += a;
+    }
+
+    inline void finalize(uint32_t& a, uint32_t& b, uint32_t& c) const
+    {
+        c ^= b; c -= rot(b,14);
+        a ^= c; a -= rot(c,11);
+        b ^= a; b -= rot(a,25);
+        c ^= b; c -= rot(b,16);
+        a ^= c; a -= rot(c,4);
+        b ^= a; b -= rot(a,14);
+        c ^= b; c -= rot(b,24);
+    }
+};
+
+Smb2FlowKey get_smb2_flow_key(void);
+
+class Dce2Smb2SessionData : public Dce2SmbSessionData
+{
+public:
+    Dce2Smb2SessionData() = delete;
+    Dce2Smb2SessionData(const snort::Packet*, const dce2SmbProtoConf* proto);
+    ~Dce2Smb2SessionData() override;
+    void process() override;
+    void remove_session(uint64_t);
+    void handle_retransmit(FilePosition, FileVerdict) override { }
+    void reset_matching_tcp_file_tracker(Dce2Smb2FileTracker*);
+    void set_tcp_file_tracker(Dce2Smb2FileTracker* file_tracker)
+    { tcp_file_tracker = file_tracker; }
+
+private:
+    void process_command(const Smb2Hdr*, const uint8_t*);
+    Smb2SessionKey get_session_key(uint64_t);
+    Dce2Smb2SessionTracker* create_session(uint64_t);
+    Dce2Smb2SessionTracker* find_session(uint64_t);
+
+    Smb2FlowKey flow_key;
+    Dce2Smb2FileTracker* tcp_file_tracker;
+    Dce2Smb2SessionTrackerMap connected_sessions;
+};
 
-/* Check smb version based on smb header */
-DCE2_SmbVersion DCE2_Smb2Version(const snort::Packet* p);
+using Dce2Smb2SessionDataMap =
+    std::unordered_map<Smb2FlowKey, Dce2Smb2SessionData*, Smb2KeyHash>;
 
 #endif  /* _DCE_SMB2_H_ */
 
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_commands.cc b/src/service_inspectors/dce_rpc/dce_smb2_commands.cc
deleted file mode 100644 (file)
index 50b60d1..0000000
+++ /dev/null
@@ -1,869 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2019 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// dce_smb2_commands.cc author Bhargava Jandhyala <bjandhya@cisco.com>
-// based on work by Todd Wease
-
-// Smb commands processing
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "dce_smb2_commands.h"
-#include "hash/hash_key_operations.h"
-#include "log/messages.h"
-#include "main/snort_debug.h"
-#include "packet_io/active.h"
-#include "protocols/packet.h"
-
-using namespace snort;
-#define UNKNOWN_FILE_SIZE (~0)
-
-#define SMB2_CHECK_HDR_ERROR(smb_data, end, strcuture_size, counter, cmd) \
-    { \
-        if ((smb_data + (strcuture_size)) > end) \
-        { \
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(), \
-                "%s : smb data beyond end detected\n", smb2_command_string[cmd]); \
-            counter ++; \
-            return; \
-        } \
-    }
-
-static inline FileContext* get_smb_file_context(uint64_t file_id, uint64_t
-    multi_file_processing_id,
-    bool to_create = false)
-{
-    FileFlows* file_flows = FileFlows::get_file_flows(DetectionEngine::get_current_packet()->flow);
-
-    if ( !file_flows )
-    {
-        dce2_smb_stats.v2_inv_file_ctx_err++;
-        return nullptr;
-    }
-
-    return file_flows->get_file_context(file_id, to_create, multi_file_processing_id);
-}
-
-static void DCE2_Smb2CleanFtrackerTcpRef(DCE2_Smb2SessionTracker* str, uint64_t file_id)
-{
-    debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-        "updating conn for fid %" PRIu64 "\n", file_id);
-    auto all_conn_trackers = str->conn_trackers.get_all_entry();
-    for ( auto& h : all_conn_trackers )
-    {
-        if (h.second->ftracker_tcp)
-        {
-            if (h.second->ftracker_tcp->file_id == file_id)
-            {
-                h.second->ftracker_tcp = nullptr;
-            }
-        }
-    }
-}
-
-DCE2_Smb2TreeTracker *find_tree_for_message(DCE2_Smb2SessionTracker *str, const uint64_t mid)
-{
-    auto all_tree_trackers = str->tree_trackers.get_all_entry();
-    for ( auto& h : all_tree_trackers )
-    {
-        if(h.second->findRtracker(mid))
-            return h.second;
-    }
-    return nullptr;
-}
-
-bool DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData* ssd, const uint8_t* file_data,
-    uint32_t data_size)
-{
-    int64_t file_detection_depth = DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config);
-    int64_t detection_size = 0;
-
-    if (file_detection_depth == 0)
-        detection_size = data_size;
-    else if ( ssd->ftracker_tcp->file_offset < (uint64_t)file_detection_depth)
-    {
-        if ( file_detection_depth - ssd->ftracker_tcp->file_offset < data_size )
-            detection_size = file_detection_depth - ssd->ftracker_tcp->file_offset;
-        else
-            detection_size = data_size;
-    }
-
-    if (detection_size)
-    {
-        set_file_data(file_data,
-            (detection_size > UINT16_MAX) ? UINT16_MAX : (uint16_t)detection_size);
-
-        DCE2_FileDetect();
-    }
-
-    Packet* p = DetectionEngine::get_current_packet();
-    ssd->ftracker_tcp->bytes_processed += detection_size;
-    FileDirection dir = ssd->ftracker_tcp->upload ? FILE_UPLOAD : FILE_DOWNLOAD;
-
-    debug_logf(dce_smb_trace, p, "file_process fid %" PRIu64 " data_size %" PRIu32 ""
-        " offset %" PRIu64 " bytes processed %" PRIu64 "\n", ssd->ftracker_tcp->file_id,
-        data_size, ssd->ftracker_tcp->file_offset, ssd->ftracker_tcp->bytes_processed);
-
-    // Do not process data beyond file size if file size is known.
-    FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
-    if ( !file_flows or (ssd->ftracker_tcp->file_size and
-        ssd->ftracker_tcp->bytes_processed > ssd->ftracker_tcp->file_size) )
-    {
-        dce2_smb_stats.v2_extra_file_data_err++;
-        debug_logf(dce_smb_trace, p, "extra file data\n");
-
-        DCE2_Smb2TreeTracker* ttr = ssd->ftracker_tcp->ttr;
-        uint64_t file_id = ssd->ftracker_tcp->file_id;
-        DCE2_Smb2CleanFtrackerTcpRef(ssd->ftracker_tcp->str, file_id);
-        ttr->removeFtracker(file_id);
-
-        return false;
-    }
-
-    if (!file_flows->file_process(p, ssd->ftracker_tcp->file_name_hash, file_data, data_size,
-        ssd->ftracker_tcp->file_offset, dir, ssd->ftracker_tcp->file_id) and detection_size)
-    {
-        debug_logf(dce_smb_trace, p, "file_process completed\n");
-
-        DCE2_Smb2TreeTracker* ttr = ssd->ftracker_tcp->ttr;
-        uint64_t file_id = ssd->ftracker_tcp->file_id;
-        DCE2_Smb2CleanFtrackerTcpRef(ssd->ftracker_tcp->str, file_id);
-        ttr->removeFtracker(file_id);
-
-        return false;
-    }
-    return true;
-}
-
-//-------------------------------------------------------------------------
-// Process session setup response to find/create session tracker
-//-------------------------------------------------------------------------
-void DCE2_Smb2Setup(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, const uint64_t sid,
-    const uint8_t* smb_data, const uint8_t* end)
-{
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: error\n", smb2_command_string[SMB2_COM_SESSION_SETUP]);
-        dce2_smb_stats.v2_setup_err_resp++;
-    }
-    else if (structure_size == SMB2_SETUP_RESPONSE_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_SETUP_RESPONSE_STRUC_SIZE - 1,
-            dce2_smb_stats.v2_setup_resp_hdr_err, SMB2_COM_SESSION_SETUP)
-        DCE2_Smb2FindElseCreateSid(ssd, sid);
-    }
-    else if (structure_size != SMB2_SETUP_REQUEST_STRUC_SIZE)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_SESSION_SETUP]);
-        dce2_smb_stats.v2_setup_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process tree connect response to find/create tree tracker
-//-------------------------------------------------------------------------
-void DCE2_Smb2TreeConnect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid)
-{
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
-    {
-        dce2_smb_stats.v2_tree_cnct_err_resp++;
-    }
-    else if (structure_size == SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE,
-            dce2_smb_stats.v2_tree_cnct_resp_hdr_err, SMB2_COM_TREE_CONNECT)
-
-        if (!DCE2_Smb2InsertTid(ssd, tid,
-            ((const Smb2TreeConnectResponseHdr*)smb_data)->share_type, str))
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s: ignored %d\n", smb2_command_string[SMB2_COM_TREE_CONNECT], tid);
-            dce2_smb_stats.v2_tree_cnct_ignored++;
-        }
-    }
-    else if (structure_size != SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_TREE_CONNECT]);
-        dce2_smb_stats.v2_tree_cnct_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process tree disconnect request to cleanup tree tracker and its
-// corresponding request trackers and file trackers
-//-------------------------------------------------------------------------
-void DCE2_Smb2TreeDisconnect(DCE2_Smb2SsnData*, const uint8_t* smb_data,
-    const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid)
-{
-    if (SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE == alignedNtohs((const uint16_t*)smb_data))
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE,
-            dce2_smb_stats.v2_tree_discn_req_hdr_err, SMB2_COM_TREE_DISCONNECT)
-        str->removeTtracker(tid);
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_TREE_DISCONNECT]);
-        dce2_smb_stats.v2_tree_discn_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process create request to get file name and save it in request tracker
-//-------------------------------------------------------------------------
-static void DCE2_Smb2CreateRequest(DCE2_Smb2SsnData* ssd,
-    const Smb2CreateRequestHdr* smb_create_hdr,const uint8_t* end,
-    DCE2_Smb2SessionTracker* str, DCE2_Smb2TreeTracker* ttr, uint64_t mid)
-{
-    uint16_t name_offset = alignedNtohs(&(smb_create_hdr->name_offset));
-
-    if (name_offset > SMB2_HEADER_LENGTH)
-    {
-        uint16_t name_len  = 0;
-
-        const uint8_t* file_data =  (const uint8_t*)smb_create_hdr + smb_create_hdr->name_offset -
-            SMB2_HEADER_LENGTH;
-        if (file_data >= end)
-        {
-            dce2_smb_stats.v2_crt_inv_file_data++;
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: invalid file data seen\n", smb2_command_string[SMB2_COM_CREATE]);
-            return;
-        }
-
-        uint16_t size = alignedNtohs(&(smb_create_hdr->name_length));
-        if (!size or (file_data + size > end))
-        {
-            dce2_smb_stats.v2_crt_inv_file_data++;
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: invalid file data seen with size %" PRIu16 "\n",
-                smb2_command_string[SMB2_COM_CREATE], size);
-
-            return;
-        }
-
-        if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
-        {
-            DCE2_Smb2RequestTracker* rtracker = ttr->findRtracker(mid);
-            if (rtracker) // Cleanup existing tracker
-                ttr->removeRtracker(mid);
-
-            char* file_name = DCE2_SmbGetFileName(file_data, size, true, &name_len);
-
-            rtracker = new DCE2_Smb2RequestTracker(file_name, name_len);
-            ttr->insertRtracker(mid, rtracker);
-        }
-        else
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: max req exceeded\n", smb2_command_string[SMB2_COM_CREATE]);
-            dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
-                ssd->sd);
-        }
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_REQ: name_offset %" PRIu16 "\n", smb2_command_string[SMB2_COM_CREATE], name_offset);
-        dce2_smb_stats.v2_crt_req_hdr_err++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process create response to create file tracker with file id and file
-// size. Request tracker is cleaned after updating file name in file tracker
-//-------------------------------------------------------------------------
-static void DCE2_Smb2CreateResponse(DCE2_Smb2SsnData*,
-    const Smb2CreateResponseHdr* smb_create_hdr, DCE2_Smb2RequestTracker* rtracker,
-    DCE2_Smb2TreeTracker* ttr, DCE2_Smb2SessionTracker* str, uint64_t fileId_persistent)
-{
-    uint64_t file_size = 0;
-
-    if (smb_create_hdr->end_of_file)
-    {
-        file_size = alignedNtohq((const uint64_t*)(&(smb_create_hdr->end_of_file)));
-    }
-
-    DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
-    if (!ftracker)
-    {
-        ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow);
-        ttr->insertFtracker(fileId_persistent, ftracker);
-    }
-    ftracker->file_name = rtracker->fname;
-    ftracker->file_name_len = rtracker->fname_len;
-    ftracker->file_size = file_size;
-
-    if (rtracker->fname and rtracker->fname_len)
-    {
-        ftracker->file_name_hash = str_to_hash(
-            (const uint8_t*)rtracker->fname, rtracker->fname_len);
-
-        FileContext* file = get_smb_file_context(ftracker->file_name_hash, fileId_persistent,
-            true);
-
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: file size %" PRIu64 " fid %" PRIu64 ""
-            "file_name_hash %" PRIu64 " file context %s\n", smb2_command_string[SMB2_COM_CREATE],
-            file_size, fileId_persistent, ftracker->file_name_hash, (file ? "found" : "not found"));
-
-        if (file)
-        {
-            if (file->verdict == FILE_VERDICT_UNKNOWN)
-            {
-                file->set_file_size(!file_size ? UNKNOWN_FILE_SIZE : file_size);
-                file->set_file_name(ftracker->file_name, ftracker->file_name_len);
-            }
-        }
-        else
-        {
-            ftracker->ignore = true; // could not create file context, hence this file transfer
-                                     // cant be inspected
-        }
-        rtracker->set_file_id(fileId_persistent); // to ensure file tracker will free file name
-    }
-    else
-    {
-        ftracker->ignore = true; // file can not be inspected as file name is null
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process create request to handle mid stream sessions by adding tree
-// tracker if not already present. Process create response for only disk
-// share type.
-//-------------------------------------------------------------------------
-void DCE2_Smb2Create(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const uint8_t* smb_data, const uint8_t* end, uint64_t mid, uint64_t sid, uint32_t tid)
-{
-    DCE2_Smb2SessionTracker* str = DCE2_Smb2FindElseCreateSid(ssd, sid);
-    DCE2_Smb2TreeTracker* ttr = str->findTtracker(tid);
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
-    {
-        if (ttr)
-            ttr->removeRtracker(mid);
-
-        dce2_smb_stats.v2_crt_err_resp++;
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: error\n", smb2_command_string[SMB2_COM_CREATE]);
-    }
-    // Using structure size to decide whether it is response or request
-    else if (structure_size == SMB2_CREATE_REQUEST_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_CREATE_REQUEST_STRUC_SIZE - 1,
-            dce2_smb_stats.v2_crt_req_hdr_err, SMB2_COM_CREATE)
-
-        if (!ttr)
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: mid stream session detected\n", smb2_command_string[SMB2_COM_CREATE]);
-            ttr = DCE2_Smb2InsertTid(ssd, tid, SMB2_SHARE_TYPE_DISK, str);
-            if (!ttr)
-            {
-                debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                    "%s_REQ: insert tree tracker failed\n", smb2_command_string[SMB2_COM_CREATE]);
-                return;
-            }
-        }
-        else if (SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
-        {
-            dce2_smb_stats.v2_crt_req_ipc++;
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: ignored for ipc share\n", smb2_command_string[SMB2_COM_CREATE]);
-            return;
-        }
-        DCE2_Smb2CreateRequest(ssd, (const Smb2CreateRequestHdr*)smb_data, end, str, ttr, mid);
-    }
-    else if (structure_size == SMB2_CREATE_RESPONSE_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_CREATE_RESPONSE_STRUC_SIZE - 1,
-            dce2_smb_stats.v2_crt_resp_hdr_err, SMB2_COM_CREATE)
-
-        if(!tid)
-            ttr = find_tree_for_message(str, mid);
-        if (!ttr)
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                 "%s_RESP: tree tracker missing\n", smb2_command_string[SMB2_COM_CREATE]);
-            dce2_smb_stats.v2_crt_tree_trkr_misng++;
-            return;
-        }
-
-        DCE2_Smb2RequestTracker* rtr = ttr->findRtracker(mid);
-        if (!rtr)
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                 "%s_RESP: req tracker missing\n", smb2_command_string[SMB2_COM_CREATE]);
-            dce2_smb_stats.v2_crt_rtrkr_misng++;
-            return;
-        }
-
-        uint64_t fileId_persistent = alignedNtohq((const uint64_t*)(
-                &(((const Smb2CreateResponseHdr*)smb_data)->fileId_persistent)));
-
-        if (((const Smb2CreateResponseHdr*)smb_data)->file_attributes &
-            SMB2_CREATE_RESPONSE_DIRECTORY)
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                 "%s_RESP: not processing for directory\n", smb2_command_string[SMB2_COM_CREATE]);
-            ttr->removeRtracker(mid);
-            DCE2_Smb2CleanFtrackerTcpRef(str, fileId_persistent);
-            ttr->removeFtracker(fileId_persistent);
-            return;
-        }
-
-        DCE2_Smb2CreateResponse(ssd, (const Smb2CreateResponseHdr*)smb_data, rtr, ttr,
-            str, fileId_persistent);
-        ttr->removeRtracker(mid);
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_CREATE]);
-        dce2_smb_stats.v2_crt_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process close command request to do file processing for an upload or
-// download request with unknown size.
-//-------------------------------------------------------------------------
-void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr,
-    DCE2_Smb2SessionTracker* str)
-{
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: error\n", smb2_command_string[SMB2_COM_CLOSE]);
-        dce2_smb_stats.v2_cls_err_resp++;
-    }
-    // Using structure size to decide whether it is response or request
-    else if (structure_size == SMB2_CLOSE_REQUEST_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_CLOSE_REQUEST_STRUC_SIZE,
-            dce2_smb_stats.v2_cls_req_hdr_err, SMB2_COM_CLOSE)
-
-        uint64_t fileId_persistent = alignedNtohq(&(((const
-            Smb2CloseRequestHdr*)smb_data)->fileId_persistent));
-        DCE2_Smb2FileTracker* ftracker =  ttr->findFtracker(fileId_persistent);
-        if (!ftracker)
-        {
-            dce2_smb_stats.v2_cls_req_ftrkr_misng++;
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: ftracker missing %" PRIu64 "\n",
-                smb2_command_string[SMB2_COM_CLOSE], fileId_persistent);
-            return;
-        }
-
-        if (!ftracker->ignore and !ftracker->file_size and ftracker->file_offset)
-        {
-            ftracker->file_size = ftracker->file_offset;
-            FileContext* file = get_smb_file_context(ftracker->file_name_hash, fileId_persistent);
-            if (file)
-            {
-                file->set_file_size(ftracker->file_size);
-            }
-
-            ssd->ftracker_tcp = ftracker;
-
-            // In case of upload/download of file with UNKNOWN size, we will not be able to
-            // detect malicious file during write request or read response. Once the close
-            // command request comes, we will go for file inspection and block an subsequent
-            // upload/download request for this file even with unknown size
-            DCE2_Smb2ProcessFileData(ssd, nullptr, 0);
-        }
-        else
-        {
-            DCE2_Smb2CleanFtrackerTcpRef(str, fileId_persistent);
-            ttr->removeFtracker(fileId_persistent);
-        }
-    }
-    else if (structure_size != SMB2_CLOSE_RESPONSE_STRUC_SIZE)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_CLOSE]);
-        dce2_smb_stats.v2_cls_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process set info request to update file size
-//-------------------------------------------------------------------------
-void DCE2_Smb2SetInfo(DCE2_Smb2SsnData*, const Smb2Hdr* smb_hdr,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr)
-{
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    // Using structure size to decide whether it is response or request
-    if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: error resp\n", smb2_command_string[SMB2_COM_SET_INFO]);
-        dce2_smb_stats.v2_stinf_err_resp++;
-    }
-    else if (structure_size == SMB2_SET_INFO_REQUEST_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_SET_INFO_REQUEST_STRUC_SIZE,
-            dce2_smb_stats.v2_stinf_req_hdr_err, SMB2_COM_SET_INFO)
-
-        const Smb2SetInfoRequestHdr* smb_set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data;
-        const uint8_t* file_data =  (const uint8_t*)smb_set_info_hdr +
-            SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1;
-
-        if (smb_set_info_hdr->file_info_class == SMB2_FILE_ENDOFFILE_INFO)
-        {
-            uint64_t file_size = alignedNtohq((const uint64_t*)file_data);
-            uint64_t fileId_persistent = alignedNtohq(&(smb_set_info_hdr->fileId_persistent));
-            DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
-            if (ftracker and !ftracker->ignore)
-            {
-                ftracker->file_size = file_size;
-                FileContext* file = get_smb_file_context(ftracker->file_name_hash,
-                    fileId_persistent);
-                debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                    "%s_REQ: set file size %" PRIu64 " fid %" PRIu64 " file context %s\n",
-                    smb2_command_string[SMB2_COM_SET_INFO], file_size, fileId_persistent,
-                    file ? "found" : "not found");
-                if (file)
-                {
-                    file->set_file_size(ftracker->file_size);
-                }
-            }
-            else
-            {
-                dce2_smb_stats.v2_stinf_req_ftrkr_misng++;
-                debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                    "%s_REQ: ftracker missing\n", smb2_command_string[SMB2_COM_SET_INFO]);
-            }
-        }
-        else
-        {
-            debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-                "%s_REQ: header error\n", smb2_command_string[SMB2_COM_SET_INFO]);
-            dce2_smb_stats.v2_stinf_req_hdr_err++;
-        }
-    }
-    else if (structure_size != SMB2_SET_INFO_RESPONSE_STRUC_SIZE)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_SET_INFO]);
-        dce2_smb_stats.v2_stinf_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process read request to create read request trackers to get file offset
-//-------------------------------------------------------------------------
-static void DCE2_Smb2ReadRequest(DCE2_Smb2SsnData* ssd,
-    const Smb2ReadRequestHdr* smb_read_hdr, const uint8_t*, DCE2_Smb2SessionTracker* str,
-    DCE2_Smb2TreeTracker* ttr, uint64_t message_id)
-{
-    uint64_t offset = alignedNtohq((const uint64_t*)(&(smb_read_hdr->offset)));
-    uint64_t fileId_persistent = alignedNtohq((const
-        uint64_t*)(&(smb_read_hdr->fileId_persistent)));
-
-    if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
-    {
-        DCE2_Smb2RequestTracker* readtracker = ttr->findRtracker(message_id);
-        if (!readtracker)
-        {
-            readtracker = new DCE2_Smb2RequestTracker(fileId_persistent, offset);
-            ttr->insertRtracker(message_id, readtracker);
-        }
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_REQ: max req exceeded\n", smb2_command_string[SMB2_COM_READ]);
-        dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
-            ssd->sd);
-        return;
-    }
-
-    DCE2_Smb2FileTracker* ftracker =  ttr->findFtracker(fileId_persistent);
-    if (!ftracker) // compounded create request + read request case
-    {
-        ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow);
-        ttr->insertFtracker(fileId_persistent, ftracker);
-    }
-
-    if (ftracker->file_size and (offset > ftracker->file_size))
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_REQ: invalid file offset\n", smb2_command_string[SMB2_COM_READ]);
-        dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats,
-            ssd->sd);
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process read response to send file data for inspection. read request
-// trackers is cleaned after updating file offset in file tracker
-//-------------------------------------------------------------------------
-static void DCE2_Smb2ReadResponse(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const Smb2ReadResponseHdr* smb_read_hdr, const uint8_t* end, DCE2_Smb2TreeTracker* ttr,
-    uint64_t message_id)
-{
-    const uint8_t* file_data =  (const uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1;
-    int data_size = end - file_data;
-    uint16_t data_offset;
-    DCE2_Smb2RequestTracker* request;
-
-    request = ttr->findRtracker(message_id);
-    if (!request)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: request tracker missing\n", smb2_command_string[SMB2_COM_READ]);
-        dce2_smb_stats.v2_read_rtrkr_misng++;
-        return;
-    }
-    data_offset = alignedNtohs((const uint16_t*)(&(smb_read_hdr->data_offset)));
-    if (data_offset + (const uint8_t*)smb_hdr > end)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: bad offset\n", smb2_command_string[SMB2_COM_READ]);
-        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
-    }
-
-    DCE2_Smb2FileTracker* ftracker =  ttr->findFtracker(request->get_file_id());
-    if ( ftracker and !ftracker->ignore )
-    {
-        ftracker->file_offset = request->get_offset();
-        ttr->removeRtracker(message_id);
-
-        ssd->ftracker_tcp = ftracker;
-
-        if (!DCE2_Smb2ProcessFileData(ssd, file_data, data_size))
-            return;
-        ftracker->file_offset += data_size;
-
-        uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length));
-        if (total_data_length > (uint32_t)data_size)
-        {
-            ftracker->smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
-        }
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process read message
-//-------------------------------------------------------------------------
-void DCE2_Smb2Read(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str,
-    DCE2_Smb2TreeTracker* ttr, uint64_t mid)
-{
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    if (Smb2Error(smb_hdr) and structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE)
-    {
-        DCE2_Smb2RequestTracker* rtr = ttr->findRtracker(mid);
-        if (rtr and rtr->get_file_id())
-        {
-            DCE2_Smb2CleanFtrackerTcpRef(str, rtr->get_file_id());
-            ttr->removeFtracker(rtr->get_file_id());
-        }
-        ttr->removeRtracker(mid);
-        dce2_smb_stats.v2_read_err_resp++;
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: error\n", smb2_command_string[SMB2_COM_WRITE]);
-    }
-    // Using structure size to decide whether it is response or request
-    else if (structure_size == SMB2_READ_REQUEST_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_READ_REQUEST_STRUC_SIZE - 1,
-            dce2_smb_stats.v2_read_req_hdr_err, SMB2_COM_READ)
-        DCE2_Smb2ReadRequest(ssd, (const Smb2ReadRequestHdr*)smb_data, end, str, ttr, mid);
-    }
-    else if (structure_size == SMB2_READ_RESPONSE_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_READ_RESPONSE_STRUC_SIZE - 1,
-            dce2_smb_stats.v2_read_resp_hdr_err, SMB2_COM_READ)
-
-        DCE2_Smb2ReadResponse(ssd, smb_hdr, (const Smb2ReadResponseHdr*)smb_data, end, ttr, mid);
-    }
-    else
-    {
-        dce2_smb_stats.v2_read_inv_str_sz++;
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_WRITE]);
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process write request to create write trackers (to enforce credits limit)
-// and to send file data for inspection.
-//-------------------------------------------------------------------------
-static void DCE2_Smb2WriteRequest(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const Smb2WriteRequestHdr* smb_write_hdr, const uint8_t* end, DCE2_Smb2SessionTracker* str,
-    DCE2_Smb2TreeTracker* ttr, uint64_t mid)
-{
-    const uint8_t* file_data =  (const uint8_t*)smb_write_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1;
-    int data_size = end - file_data;
-    uint64_t fileId_persistent, offset;
-    uint16_t data_offset;
-
-    fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_write_hdr->fileId_persistent)));
-
-    if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
-    {
-        DCE2_Smb2RequestTracker* writetracker = ttr->findRtracker(mid);
-        if (!writetracker)
-        {
-            writetracker = new DCE2_Smb2RequestTracker(fileId_persistent);
-            ttr->insertRtracker(mid, writetracker);
-        }
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_REQ: max req exceeded\n", smb2_command_string[SMB2_COM_WRITE]);
-        dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
-            ssd->sd);
-        return;
-    }
-
-    data_offset = alignedNtohs((const uint16_t*)(&(smb_write_hdr->data_offset)));
-    if (data_offset + (const uint8_t*)smb_hdr > end)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_REQ: bad offset\n", smb2_command_string[SMB2_COM_WRITE]);
-        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
-    }
-
-    offset = alignedNtohq((const uint64_t*)(&(smb_write_hdr->offset)));
-    DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
-    if (!ftracker) // compounded create request + write request case
-    {
-        ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow);
-        ttr->insertFtracker(fileId_persistent, ftracker);
-    }
-    if (!ftracker->ignore) // file tracker can not be nullptr here
-    {
-        if (ftracker->file_size and (offset > ftracker->file_size))
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats,
-                ssd->sd);
-        }
-        ftracker->file_offset = offset;
-        ftracker->upload = true;
-
-        ssd->ftracker_tcp = ftracker;
-
-        if (!DCE2_Smb2ProcessFileData(ssd, file_data, data_size))
-            return;
-        ftracker->file_offset += data_size;
-        uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length));
-        if (total_data_length > (uint32_t)data_size)
-        {
-            ftracker->smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
-        }
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process write message
-//-------------------------------------------------------------------------
-void DCE2_Smb2Write(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str,
-    DCE2_Smb2TreeTracker* ttr, uint64_t mid)
-{
-    uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
-    if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
-    {
-        DCE2_Smb2RequestTracker* wtr = ttr->findRtracker(mid);
-        if (wtr and wtr->get_file_id())
-        {
-            DCE2_Smb2CleanFtrackerTcpRef(str, wtr->get_file_id());
-            ttr->removeFtracker(wtr->get_file_id());
-        }
-        ttr->removeRtracker(mid);
-        dce2_smb_stats.v2_wrt_err_resp++;
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s_RESP: error\n", smb2_command_string[SMB2_COM_WRITE]);
-    }
-    // Using structure size to decide whether it is response or request
-    else if (structure_size == SMB2_WRITE_REQUEST_STRUC_SIZE)
-    {
-        SMB2_CHECK_HDR_ERROR(
-            smb_data, end, SMB2_WRITE_REQUEST_STRUC_SIZE - 1,
-            dce2_smb_stats.v2_wrt_req_hdr_err, SMB2_COM_WRITE)
-        DCE2_Smb2WriteRequest(ssd, smb_hdr, (const Smb2WriteRequestHdr*)smb_data, end, str, ttr,
-            mid);
-    }
-    else if (structure_size == SMB2_WRITE_RESPONSE_STRUC_SIZE)
-    {
-        ttr->removeRtracker(mid);
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_WRITE]);
-        dce2_smb_stats.v2_wrt_inv_str_sz++;
-    }
-}
-
-//-------------------------------------------------------------------------
-// Process logoff to cleanup session tracker and their corresponding tree
-// trackers and their corresponding file trackers
-//-------------------------------------------------------------------------
-void DCE2_Smb2Logoff(DCE2_Smb2SsnData* ssd, const uint8_t* smb_data,
-    const uint64_t sid)
-{
-    if (alignedNtohs((const uint16_t*)smb_data) == SMB2_LOGOFF_REQUEST_STRUC_SIZE)
-    {
-        DCE2_Smb2SessionTracker* str = DCE2_Smb2FindSidInSsd(ssd, sid);
-        if (str)
-        {
-            str->removeSessionFromAllConnection();
-            DCE2_SmbSessionCacheRemove(str->session_key);
-        }
-    }
-    else
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "%s: invalid struct size\n", smb2_command_string[SMB2_COM_LOGOFF]);
-        dce2_smb_stats.v2_logoff_inv_str_sz++;
-    }
-}
-
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_commands.h b/src/service_inspectors/dce_rpc/dce_smb2_commands.h
deleted file mode 100644 (file)
index 22c93a9..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2019 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// dce_smb2_commands.h author Bhargava Jandhyala <bjandhya@cisco.com>
-// based on work by Todd Wease
-
-#ifndef DCE_SMB2_COMMANDS_H
-#define DCE_SMB2_COMMANDS_H
-
-#include "dce_smb_module.h"
-#include "dce_smb_utils.h"
-#include "dce_smb2_utils.h"
-#include "detection/detection_util.h"
-#include "file_api/file_flows.h"
-#include "file_api/file_service.h"
-
-void DCE2_Smb2Setup(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint64_t sid, const uint8_t* smb_data, const uint8_t* end);
-
-void DCE2_Smb2TreeConnect(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid);
-
-void DCE2_Smb2TreeDisconnect(DCE2_Smb2SsnData*, const uint8_t* smb_data,
-    const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid);
-
-void DCE2_Smb2Create(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint8_t* smb_data, const uint8_t* end, uint64_t mid, uint64_t sid, uint32_t tid);
-
-void DCE2_Smb2Read(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str,
-    DCE2_Smb2TreeTracker* ttr, uint64_t mid);
-
-void DCE2_Smb2Write(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str,
-    DCE2_Smb2TreeTracker* ttr, uint64_t mid);
-
-void DCE2_Smb2SetInfo(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr);
-
-bool DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData*, const uint8_t* file_data,
-    uint32_t data_size);
-
-void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData*, const Smb2Hdr*,
-    const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr,
-    DCE2_Smb2SessionTracker* str);
-
-void DCE2_Smb2Logoff(DCE2_Smb2SsnData*, const uint8_t* smb_data,
-    const uint64_t sid);
-
-DCE2_Smb2TreeTracker *find_tree_for_message(DCE2_Smb2SessionTracker*, const uint64_t);
-
-#endif
-
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.cc b/src/service_inspectors/dce_rpc/dce_smb2_file.cc
new file mode 100644 (file)
index 0000000..9e18e32
--- /dev/null
@@ -0,0 +1,176 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_file.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb2_file.h"
+
+#include "file_api/file_flows.h"
+#include "hash/hash_key_operations.h"
+
+#include "dce_smb2_session.h"
+#include "dce_smb2_tree.h"
+
+using namespace snort;
+
+#define UNKNOWN_FILE_SIZE  (~0)
+
+void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow)
+{
+    if (flow)
+    {
+        smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
+        flow->set_tcp_file_tracker(this);
+    }
+}
+
+inline void Dce2Smb2FileTracker::file_detect()
+{
+    DetectionEngine::detect(DetectionEngine::get_current_packet());
+    dce2_detected = 1;
+}
+
+void Dce2Smb2FileTracker::set_info(char* file_name_v, uint16_t name_len_v,
+    uint64_t size_v, bool create)
+{
+    if (file_name_v and name_len_v)
+    {
+        file_name = file_name_v;
+        file_name_len = name_len_v;
+        file_name_hash = str_to_hash((uint8_t*)file_name, file_name_len);
+    }
+    file_size = size_v;
+    FileContext* file = get_smb_file_context(file_name_hash, file_id, create);
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "set file info: file size %"
+        PRIu64 " fid %" PRIu64 " file_name_hash %" PRIu64 " file context "
+        "%sfound\n", file_size, file_id, file_name_hash, (file ? "" : "not "));
+    if (file)
+    {
+        ignore = false;
+        if (file->verdict == FILE_VERDICT_UNKNOWN)
+        {
+            if (file_name_v and name_len_v)
+                file->set_file_name(file_name, file_name_len);
+            file->set_file_size(file_size ? file_size : UNKNOWN_FILE_SIZE);
+        }
+    }
+}
+
+bool Dce2Smb2FileTracker::close()
+{
+    if (!ignore and !file_size and file_offset)
+    {
+        file_size = file_offset;
+        FileContext* file =
+            get_smb_file_context(file_name_hash, file_id, false);
+        if (file)
+            file->set_file_size(file_size);
+        return (!process_data(nullptr, 0));
+    }
+    return true;
+}
+
+bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data,
+    uint32_t data_size, uint64_t offset)
+{
+    file_offset = offset;
+    return process_data(file_data, data_size);
+}
+
+bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data,
+    uint32_t data_size)
+{
+    Dce2Smb2SessionData* current_flow = parent_tree->get_parent()->get_current_flow();
+    int64_t file_detection_depth = current_flow->get_smb_file_depth();
+    int64_t detection_size = 0;
+
+    if (file_detection_depth == 0)
+        detection_size = data_size;
+    else if ( file_offset < (uint64_t)file_detection_depth)
+    {
+        if ( file_detection_depth - file_offset < data_size )
+            detection_size = file_detection_depth - file_offset;
+        else
+            detection_size = data_size;
+    }
+
+    if (detection_size)
+    {
+        set_file_data(file_data, (detection_size > UINT16_MAX) ?
+            UINT16_MAX : (uint16_t)detection_size);
+        file_detect();
+    }
+
+    if (ignore)
+        return true;
+
+    Packet* p = DetectionEngine::get_current_packet();
+
+    if (file_size and file_offset > file_size)
+    {
+        debug_logf(dce_smb_trace, p, "file_process: bad offset\n");
+        dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)
+            &dce2_smb_stats, *(current_flow->get_dce2_session_data()));
+    }
+
+    debug_logf(dce_smb_trace, p, "file_process fid %" PRIu64 " data_size %"
+        PRIu32 " offset %" PRIu64 "\n", file_id, data_size, file_offset);
+
+    FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
+
+    if (!file_flows)
+        return true;
+
+    if (!file_flows->file_process(p, file_name_hash, file_data, data_size,
+        file_offset, direction, file_id))
+    {
+        debug_logf(dce_smb_trace, p, "file_process completed\n");
+        return false;
+    }
+
+    file_offset += data_size;
+    return true;
+}
+
+Dce2Smb2FileTracker::~Dce2Smb2FileTracker(void)
+{
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "file tracker %" PRIu64
+        " file name hash %" PRIu64 " terminating\n", file_id, file_name_hash);
+
+    if (file_name)
+        snort_free((void*)file_name);
+
+    Dce2Smb2SessionDataMap attached_flows = parent_tree->get_parent()->get_attached_flows();
+
+    for (auto it_flow : attached_flows)
+    {
+        FileFlows* file_flows = FileFlows::get_file_flows(it_flow.second->get_flow(), false);
+        if (file_flows)
+            file_flows->remove_processed_file_context(file_name_hash, file_id);
+        it_flow.second->reset_matching_tcp_file_tracker(this);
+    }
+
+    parent_tree->close_file(file_id, false);
+
+    memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.h b/src/service_inspectors/dce_rpc/dce_smb2_file.h
new file mode 100644 (file)
index 0000000..0384c7a
--- /dev/null
@@ -0,0 +1,80 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_file.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB2_FILE_H
+#define DCE_SMB2_FILE_H
+
+// This provides file tracker for SMBv2
+
+#include "dce_smb2.h"
+
+class Dce2Smb2TreeTracker;
+
+class Dce2Smb2FileTracker
+{
+public:
+
+    Dce2Smb2FileTracker() = delete;
+    Dce2Smb2FileTracker(const Dce2Smb2FileTracker& arg) = delete;
+    Dce2Smb2FileTracker& operator=(const Dce2Smb2FileTracker& arg) = delete;
+
+    Dce2Smb2FileTracker(uint64_t file_idv, Dce2Smb2TreeTracker* p_tree) : ignore(true),
+        file_name_len(0), file_offset(0), file_id(file_idv), file_size(0), file_name_hash(0),
+        file_name(nullptr), direction(FILE_DOWNLOAD), smb2_pdu_state(DCE2_SMB_PDU_STATE__COMMAND),
+        parent_tree(p_tree)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "file tracker %" PRIu64 " created\n", file_id);
+        memory::MemoryCap::update_allocations(sizeof(*this));
+    }
+
+    ~Dce2Smb2FileTracker();
+    bool process_data(const uint8_t*, uint32_t, uint64_t);
+    bool process_data(const uint8_t*, uint32_t);
+    bool close();
+    void set_info(char*, uint16_t, uint64_t, bool = false);
+    void accept_raw_data_from(Dce2Smb2SessionData*);
+
+    bool accepting_raw_data()
+    { return (smb2_pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); }
+
+    void set_direction(FileDirection dir) { direction = dir; }
+    Dce2Smb2TreeTracker* get_parent() { return parent_tree; }
+    uint64_t get_file_id() { return file_id; }
+
+private:
+    void file_detect();
+    bool ignore;
+    uint16_t file_name_len;
+    uint64_t file_offset;
+    uint64_t file_id;
+    uint64_t file_size;
+    uint64_t file_name_hash;
+    char* file_name;
+    FileDirection direction;
+    Dce2SmbPduState smb2_pdu_state;
+    Dce2Smb2TreeTracker* parent_tree;
+};
+
+using  Dce2Smb2FileTrackerMap =
+    std::unordered_map<uint64_t, Dce2Smb2FileTracker*, std::hash<uint64_t> >;
+
+#endif
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_request.h b/src/service_inspectors/dce_rpc/dce_smb2_request.h
new file mode 100644 (file)
index 0000000..b78230f
--- /dev/null
@@ -0,0 +1,76 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_request.h author Bhargava Jandhyala <bjandhya@cisco.com>
+
+#ifndef DCE_SMB2_REQUEST_H
+#define DCE_SMB2_REQUEST_H
+
+// This provides request trackers for SMBv2.
+// Request trackers are used to track CREATE, READ and WRITE requests
+
+#include "dce_smb2.h"
+
+class Dce2Smb2RequestTracker
+{
+public:
+
+    Dce2Smb2RequestTracker() = delete;
+    Dce2Smb2RequestTracker(const Dce2Smb2RequestTracker& arg) = delete;
+    Dce2Smb2RequestTracker& operator=(const Dce2Smb2RequestTracker& arg) = delete;
+
+    Dce2Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0)
+        : fname(nullptr), fname_len(0), file_id(file_id_v), offset(offset_v)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "request tracker created\n");
+        memory::MemoryCap::update_allocations(sizeof(*this));
+    }
+
+    Dce2Smb2RequestTracker(char* fname_v, uint16_t fname_len_v)
+        : fname(fname_v), fname_len(fname_len_v), file_id(0), offset(0)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "request tracker created\n");
+        memory::MemoryCap::update_allocations(sizeof(*this));
+    }
+
+    ~Dce2Smb2RequestTracker()
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "request tracker terminating\n");
+        if (fname)
+            snort_free(fname);
+        memory::MemoryCap::update_deallocations(sizeof(*this));
+    }
+
+    void reset_file_name() { fname = nullptr; fname_len = 0; }
+    uint64_t get_offset() { return offset; }
+    uint64_t get_file_id() { return file_id; }
+    char* get_file_name() { return fname; }
+    uint16_t get_file_name_size() { return fname_len; }
+
+private:
+    char* fname;
+    uint16_t fname_len;
+    uint64_t file_id;
+    uint64_t offset;
+};
+
+using Dce2Smb2RequestTrackerMap =
+    std::unordered_map<uint64_t, Dce2Smb2RequestTracker*, std::hash<uint64_t> >;
+
+#endif
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.cc b/src/service_inspectors/dce_rpc/dce_smb2_session.cc
new file mode 100644 (file)
index 0000000..deb12aa
--- /dev/null
@@ -0,0 +1,180 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_session.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb2_session.h"
+
+inline uint32_t Smb2Tid(const Smb2Hdr* hdr)
+{
+    return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id));
+}
+
+//init must be called when a session tracker is created.
+void Dce2Smb2SessionTracker::init(uint64_t sid,
+    const Smb2SessionKey& session_key_v)
+{
+    session_id = sid;
+    session_key = session_key_v;
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "session tracker %" PRIu64
+        " created\n", session_id);
+}
+
+Dce2Smb2SessionData* Dce2Smb2SessionTracker::get_current_flow()
+{
+    Smb2FlowKey flow_key = get_smb2_flow_key();
+    auto it_flow = attached_flows.find(flow_key);
+    return (it_flow != attached_flows.end()) ? it_flow->second : nullptr;
+}
+
+Dce2Smb2TreeTracker* Dce2Smb2SessionTracker::find_tree_for_message(
+    uint64_t message_id)
+{
+    for (auto it_tree : connected_trees)
+    {
+        Dce2Smb2RequestTracker* request = it_tree.second->find_request(message_id);
+        if (request)
+            return it_tree.second;
+    }
+    return nullptr;
+}
+
+void Dce2Smb2SessionTracker::process(uint16_t command, uint8_t command_type,
+    const Smb2Hdr* smb_header, const uint8_t* end)
+{
+    Dce2Smb2TreeTracker* tree = nullptr;
+    uint32_t tree_id = Smb2Tid(smb_header);
+
+    if (tree_id)
+    {
+        auto it_tree = connected_trees.find(tree_id);
+        if (it_tree != connected_trees.end())
+            tree = it_tree->second;
+    }
+    else
+    {
+        //async response case
+        tree = find_tree_for_message(Smb2Mid(smb_header));
+    }
+
+    switch (command)
+    {
+    case SMB2_COM_TREE_CONNECT:
+    {
+        uint8_t share_type = ((const Smb2TreeConnectResponseHdr*)
+            ((const uint8_t*)smb_header + SMB2_HEADER_LENGTH))->share_type;
+        connect_tree(tree_id, share_type);
+    }
+    break;
+
+    case SMB2_COM_TREE_DISCONNECT:
+        if (tree)
+        {
+            delete tree;
+            connected_trees.erase(tree_id);
+        }
+        else
+            dce2_smb_stats.v2_tree_discn_ignored++;
+        break;
+
+    //for all other cases, tree tracker should handle the command
+    case SMB2_COM_CREATE:
+        if (!tree and SMB2_CMD_TYPE_REQUEST == command_type)
+        {
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "%s_REQ: mid-stream session detected\n",
+                smb2_command_string[command]);
+            tree = connect_tree(tree_id);
+            if (!tree)
+                debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                    "%s_REQ: insert tree tracker failed\n",
+                    smb2_command_string[command]);
+        }
+    // fallthrough
+    default:
+        if (tree)
+            tree->process(command, command_type, smb_header, end);
+        else
+        {
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "%s: tree tracker missing\n", smb2_command_string[command]);
+            dce2_smb_stats.v2_tree_ignored++;
+        }
+        break;
+    }
+}
+
+Dce2Smb2TreeTracker* Dce2Smb2SessionTracker::connect_tree(uint32_t tree_id,
+    uint8_t share_type)
+{
+    Dce2Smb2SessionData* current_flow = get_current_flow();
+    if ((SMB2_SHARE_TYPE_DISK == share_type) and (-1 == current_flow->get_max_file_depth()) and
+        (-1 == current_flow->get_smb_file_depth()))
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "Not inserting TID (%u) "
+            "because it's not IPC and not inspecting normal file data.\n", tree_id);
+        dce2_smb_stats.v2_tree_cnct_ignored++;
+        return nullptr;
+    }
+    Dce2Smb2TreeTracker* tree = nullptr;
+    auto it_tree = connected_trees.find(tree_id);
+    if (it_tree != connected_trees.end())
+        tree = it_tree->second;
+    if (!tree)
+    {
+        tree = new Dce2Smb2TreeTracker(tree_id, this, share_type);
+        connected_trees.insert(std::make_pair(tree_id, tree));
+    }
+    return tree;
+}
+
+void Dce2Smb2SessionTracker::attach_flow(Smb2FlowKey flow_key,
+    Dce2Smb2SessionData* ssd)
+{
+    attached_flows.insert(std::make_pair(flow_key,ssd));
+}
+
+bool Dce2Smb2SessionTracker::detach_flow(Smb2FlowKey& flow_key)
+{
+    attached_flows.erase(flow_key);
+    return (0 == attached_flows.size());
+}
+
+// Session Tracker is created and destroyed only from session cache
+Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker(void)
+{
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "session tracker %" PRIu64
+        " terminating\n", session_id);
+    auto it_tree = connected_trees.begin();
+    while (it_tree != connected_trees.end())
+    {
+        Dce2Smb2TreeTracker* tree = it_tree->second;
+        it_tree = connected_trees.erase(it_tree);
+        delete tree;
+    }
+
+    for (auto it_flow : attached_flows)
+        it_flow.second->remove_session(session_id);
+
+    memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.h b/src/service_inspectors/dce_rpc/dce_smb2_session.h
new file mode 100644 (file)
index 0000000..e747206
--- /dev/null
@@ -0,0 +1,61 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_session.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB2_SESSION_H
+#define DCE_SMB2_SESSION_H
+
+// This provides session tracker for SMBv2
+
+#include "dce_smb2.h"
+#include "dce_smb2_tree.h"
+
+uint32_t Smb2Tid(const Smb2Hdr* hdr);
+
+class Dce2Smb2SessionTracker
+{
+public:
+    Dce2Smb2SessionTracker()
+    {
+        session_id = 0;
+        session_key = { };
+        memory::MemoryCap::update_allocations(sizeof(*this));
+    }
+
+    ~Dce2Smb2SessionTracker();
+    void init(uint64_t, const Smb2SessionKey&);
+    void attach_flow(Smb2FlowKey, Dce2Smb2SessionData*);
+    bool detach_flow(Smb2FlowKey&);
+    void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*);
+    void disconnect_tree(uint32_t tree_id) { connected_trees.erase(tree_id); }
+    Dce2Smb2SessionData* get_current_flow();
+    Smb2SessionKey get_key() { return session_key; }
+    Dce2Smb2SessionDataMap get_attached_flows() { return attached_flows; }
+    Dce2Smb2TreeTracker* connect_tree(uint32_t, uint8_t=SMB2_SHARE_TYPE_DISK);
+
+private:
+    Dce2Smb2TreeTracker* find_tree_for_message(uint64_t);
+    uint64_t session_id;
+    Smb2SessionKey session_key;
+    Dce2Smb2SessionDataMap attached_flows;
+    Dce2Smb2TreeTrackerMap connected_trees;
+};
+
+#endif
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h b/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h
new file mode 100644 (file)
index 0000000..f383977
--- /dev/null
@@ -0,0 +1,60 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_session_cache.h author Bhargava Jandhyala <bjandhya@cisco.com>
+
+#ifndef DCE_SMB2_SESSION_CACHE_H
+#define DCE_SMB2_SESSION_CACHE_H
+
+// This provides a wrapper over LRU cache shared for SMBv2 Session trackers
+
+#include "hash/lru_cache_shared.h"
+
+#include "dce_smb2_session.h"
+
+#define SMB_AVG_FILES_PER_SESSION 5
+
+template<typename Key, typename Value, typename Hash>
+class Dce2Smb2SharedCache : public LruCacheShared<Key, Value, Hash>
+{
+public:
+    Dce2Smb2SharedCache() = delete;
+    Dce2Smb2SharedCache(const Dce2Smb2SharedCache& arg) = delete;
+    Dce2Smb2SharedCache& operator=(const Dce2Smb2SharedCache& arg) = delete;
+    Dce2Smb2SharedCache(const size_t initial_size) :
+        LruCacheShared<Key, Value, Hash>(initial_size) { }
+    virtual ~Dce2Smb2SharedCache() { }
+
+    Value* find_session(Key key)
+    { return this->find(key).get(); }
+    Value* find_else_create_session(Key key)
+    { return this->find_else_create(key, nullptr).get(); }
+};
+
+using Dce2Smb2SessionCache =
+    Dce2Smb2SharedCache<Smb2SessionKey, Dce2Smb2SessionTracker, Smb2KeyHash>;
+
+extern THREAD_LOCAL Dce2Smb2SessionCache* smb2_session_cache;
+
+inline void DCE2_SmbSessionCacheInit(const size_t cache_size)
+{
+    smb2_session_cache = new Dce2Smb2SessionCache(cache_size);
+}
+
+#endif
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc
new file mode 100644 (file)
index 0000000..76b3c95
--- /dev/null
@@ -0,0 +1,452 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_tree.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb2_tree.h"
+
+#include "dce_smb2_session.h"
+
+using namespace snort;
+
+#define SMB2_CREATE_DURABLE_RECONNECT "DHnC"
+#define SMB2_CREATE_DURABLE_RECONNECT_V2 "DH2C"
+
+uint64_t Smb2Mid(const Smb2Hdr* hdr)
+{
+    return alignedNtohq(&(hdr->message_id));
+}
+
+Dce2Smb2FileTracker* Dce2Smb2TreeTracker::find_file(uint64_t file_id)
+{
+    auto it_file = opened_files.find(file_id);
+    if (it_file != opened_files.end())
+        return it_file->second;
+    return nullptr;
+}
+
+void Dce2Smb2TreeTracker::close_file(uint64_t file_id, bool destroy)
+{
+    auto it_file = opened_files.find(file_id);
+    if (it_file != opened_files.end())
+    {
+        Dce2Smb2FileTracker* file = it_file->second;
+        if (opened_files.erase(file_id) and destroy)
+            delete file;
+    }
+}
+
+Dce2Smb2RequestTracker* Dce2Smb2TreeTracker::find_request(uint64_t message_id)
+{
+    auto request_it = active_requests.find(message_id);
+    return (request_it == active_requests.end()) ?
+        nullptr : request_it->second;
+}
+
+bool Dce2Smb2TreeTracker::remove_request(uint64_t message_id)
+{
+    auto request_it = active_requests.find(message_id);
+    if (request_it != active_requests.end())
+    {
+        delete request_it->second;
+        return active_requests.erase(message_id);
+    }
+    return false;
+}
+
+void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const Smb2SetInfoRequestHdr* set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data;
+
+    if (set_info_hdr->file_info_class == SMB2_FILE_ENDOFFILE_INFO)
+    {
+        uint64_t file_size = alignedNtohq((const uint64_t*)((const uint8_t*)
+            set_info_hdr + SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1));
+        uint64_t file_id = alignedNtohq(&(set_info_hdr->fileId_persistent));
+        Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+        if (file_tracker)
+            file_tracker->set_info(nullptr, 0, file_size);
+        else
+        {
+            dce2_smb_stats.v2_stinf_req_ftrkr_misng++;
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: ftracker missing\n",
+                smb2_command_string[SMB2_COM_SET_INFO]);
+        }
+    }
+    else
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: header error\n",
+            smb2_command_string[SMB2_COM_SET_INFO]);
+        dce2_smb_stats.v2_stinf_req_hdr_err++;
+    }
+}
+
+void Dce2Smb2TreeTracker::process_close_request(const Smb2Hdr* smb_header)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    uint64_t file_id = alignedNtohq(&(((const Smb2CloseRequestHdr*)
+        smb_data)->fileId_persistent));
+    Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+    if (!file_tracker)
+    {
+        dce2_smb_stats.v2_cls_req_ftrkr_misng++;
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: ftracker missing %" PRIu64 "\n",
+            smb2_command_string[SMB2_COM_CLOSE], file_id);
+        return;
+    }
+    if (file_tracker->close())
+        close_file(file_id);
+}
+
+uint64_t Dce2Smb2TreeTracker::get_durable_file_id(
+    const Smb2CreateRequestHdr* smb_create_hdr, const uint8_t* end)
+{
+    const uint8_t* data = (const uint8_t*)smb_create_hdr +
+        alignedNtohl(&smb_create_hdr->create_contexts_offset) - SMB2_HEADER_LENGTH;
+    uint32_t remaining = alignedNtohl(&smb_create_hdr->create_contexts_length);
+
+    while (remaining > sizeof(Smb2CreateContextHdr) and data < end)
+    {
+        const Smb2CreateContextHdr* context = (const Smb2CreateContextHdr*)data;
+        uint32_t next = alignedNtohl(&context->next);
+        uint16_t name_offset = alignedNtohs(&context->name_offset);
+        uint16_t name_length = alignedNtohs(&context->name_length);
+        uint16_t data_offset = alignedNtohs(&context->data_offset);
+        uint32_t data_length =  alignedNtohl(&context->data_length);
+
+        /* Check for general error condition */
+        if (((next & 0x7) != 0) or (next > remaining) or (name_offset != 16) or
+            (name_length != 4) or (name_offset + name_length > remaining) or
+            ((data_offset & 0x7) != 0) or
+            (data_offset and (data_offset < name_offset + name_length)) or
+            (data_offset > remaining) or (data_offset + data_length > remaining))
+        {
+            return 0;
+        }
+
+        if ((strncmp((const char*)context+name_offset,
+            SMB2_CREATE_DURABLE_RECONNECT_V2, name_length) == 0) or
+            (strncmp((const char*)context+name_offset,
+            SMB2_CREATE_DURABLE_RECONNECT, name_length) == 0))
+        {
+            return alignedNtohq((const uint64_t*)(((const uint8_t*)context) +
+                data_offset));
+        }
+
+        if (!next)
+            break;
+
+        data += next;
+        remaining -= next;
+    }
+    return 0;
+}
+
+void Dce2Smb2TreeTracker::process_create_response(uint64_t message_id,
+    const Smb2Hdr* smb_header)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const Smb2CreateResponseHdr* create_res_hdr = (const Smb2CreateResponseHdr*)smb_data;
+    uint64_t file_size = 0;
+    uint64_t file_id = alignedNtohq((const uint64_t*)(&(create_res_hdr->fileId_persistent)));
+    if (create_res_hdr->end_of_file)
+        file_size = alignedNtohq((const uint64_t*)(&(create_res_hdr->end_of_file)));
+    if (create_res_hdr->file_attributes & SMB2_CREATE_RESPONSE_DIRECTORY)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_RESP: not processing for directory\n",
+            smb2_command_string[SMB2_COM_CREATE]);
+        close_file(file_id);
+    }
+    else
+    {
+        Dce2Smb2RequestTracker* create_request = find_request(message_id);
+        if (create_request)
+        {
+            Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+            if (!file_tracker)
+            {
+                file_tracker = new Dce2Smb2FileTracker(file_id, this);
+                opened_files.insert(std::make_pair(file_id, file_tracker));
+            }
+            file_tracker->set_info(create_request->get_file_name(),
+                create_request->get_file_name_size(), file_size, true);
+            create_request->reset_file_name();
+        }
+        else
+        {
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_RESP: req tracker missing\n",
+                smb2_command_string[SMB2_COM_CREATE]);
+            dce2_smb_stats.v2_crt_rtrkr_misng++;
+        }
+    }
+}
+
+void Dce2Smb2TreeTracker::process_create_request(uint64_t message_id,
+    const Smb2Hdr* smb_header, const uint8_t* end)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const Smb2CreateRequestHdr* create_req_hdr = (const Smb2CreateRequestHdr*)smb_data;
+    if (alignedNtohs(&(create_req_hdr->name_offset)) <= SMB2_HEADER_LENGTH)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: name_offset %" PRIu16 "\n",
+            smb2_command_string[SMB2_COM_CREATE], create_req_hdr->name_offset);
+        dce2_smb_stats.v2_crt_req_hdr_err++;
+        return;
+    }
+    const uint8_t* file_name_offset = (const uint8_t*)smb_header +
+        create_req_hdr->name_offset;
+    uint16_t file_name_size = alignedNtohs(&(create_req_hdr->name_length));
+    if (!file_name_size or (file_name_offset >= end) or
+        (file_name_offset + file_name_size > end))
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "%s_REQ: invalid file name data seen with size %" PRIu16 "\n",
+            smb2_command_string[SMB2_COM_CREATE], file_name_size);
+        dce2_smb_stats.v2_crt_inv_file_data++;
+        return;
+    }
+
+    uint16_t name_len = 0;
+    char* file_name = get_smb_file_name(file_name_offset, file_name_size, true, &name_len);
+    //keep a request tracker with the available info
+    Dce2Smb2RequestTracker* create_request = new Dce2Smb2RequestTracker(file_name, name_len);
+    store_request(message_id, create_request);
+    //check if file_id is available form a durable reconnect request.
+    //if present we can create a file tracker right now.
+    //mostly this is the case for compound request.
+    uint64_t file_id = get_durable_file_id(create_req_hdr, end);
+    if (file_id)
+    {
+        Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+        if (!file_tracker)
+        {
+            file_tracker = new Dce2Smb2FileTracker(file_id, this);
+            file_tracker->set_info(file_name, name_len, 0, true);
+            create_request->reset_file_name();
+            opened_files.insert(std::make_pair(file_id, file_tracker));
+        }
+    }
+}
+
+void Dce2Smb2TreeTracker::process_read_response(uint64_t message_id,
+    const Smb2Hdr* smb_header, const uint8_t* end)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const Smb2ReadResponseHdr* read_resp_hdr = (const Smb2ReadResponseHdr*)smb_data;
+
+    Dce2Smb2RequestTracker* read_request = find_request(message_id);
+    if (!read_request)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "SMB2_COM_READ_RESP: request tracker missing\n");
+        dce2_smb_stats.v2_read_rtrkr_misng++;
+        return;
+    }
+    uint16_t data_offset = alignedNtohs((const uint16_t*)(&(read_resp_hdr->data_offset)));
+    Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+    if (data_offset + (const uint8_t*)smb_header > end)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: bad offset\n");
+        if (current_flow)
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats,
+                *current_flow->get_dce2_session_data());
+    }
+    Dce2Smb2FileTracker* file_tracker = find_file(read_request->get_file_id());
+    if (file_tracker)
+    {
+        const uint8_t* file_data =  (const uint8_t*)read_resp_hdr +
+            SMB2_READ_RESPONSE_STRUC_SIZE - 1;
+        int data_size = end - file_data;
+        if (file_tracker->process_data(file_data, data_size, read_request->get_offset()))
+        {
+            if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(read_resp_hdr->length)))
+            {
+                file_tracker->accept_raw_data_from(current_flow);
+            }
+        }
+        else
+            close_file(file_tracker->get_file_id());
+    }
+    else
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "SMB2_COM_READ_RESP: file tracker missing\n");
+    }
+}
+
+void Dce2Smb2TreeTracker::process_read_request(uint64_t message_id,
+    const Smb2Hdr* smb_header)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const Smb2ReadRequestHdr* read_req_hdr = (const Smb2ReadRequestHdr*)smb_data;
+    uint64_t file_id = alignedNtohq((const uint64_t*)(&(read_req_hdr->fileId_persistent)));
+    uint64_t offset = alignedNtohq((const uint64_t*)(&(read_req_hdr->offset)));
+    Dce2Smb2RequestTracker* read_request = new Dce2Smb2RequestTracker(file_id, offset);
+    store_request(message_id, read_request);
+}
+
+void Dce2Smb2TreeTracker::process_write_request(uint64_t message_id,
+    const Smb2Hdr* smb_header, const uint8_t* end)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const Smb2WriteRequestHdr* write_req_hdr = (const Smb2WriteRequestHdr*)smb_data;
+    uint64_t file_id = alignedNtohq((const uint64_t*)(&(write_req_hdr->fileId_persistent)));
+    Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+    if ((alignedNtohs((const uint16_t*)(&(write_req_hdr->data_offset))) +
+        (const uint8_t*)smb_header > end) and current_flow)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats,
+            *current_flow->get_dce2_session_data());
+    }
+    //track this request to clean up opened file in case of error response
+    Dce2Smb2RequestTracker* write_request = new Dce2Smb2RequestTracker(file_id);
+    store_request(message_id, write_request);
+    const uint8_t* file_data = (const uint8_t*)write_req_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1;
+    Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+    if (file_tracker)
+    {
+        file_tracker->set_direction(FILE_UPLOAD);
+        int data_size = end - file_data;
+        uint64_t offset = alignedNtohq((const uint64_t*)(&(write_req_hdr->offset)));
+        if (file_tracker->process_data(file_data, data_size, offset))
+        {
+            if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(write_req_hdr->length)))
+            {
+                file_tracker->accept_raw_data_from(current_flow);
+            }
+        }
+        else
+            close_file(file_tracker->get_file_id());
+    }
+    else
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "SMB2_COM_WRITE_REQ: file tracker missing\n");
+    }
+}
+
+void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
+    const Smb2Hdr* smb_header, const uint8_t* end)
+{
+    Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+    if (SMB2_CMD_TYPE_REQUEST == command_type and current_flow and
+        active_requests.size() >= current_flow->get_max_outstanding_requests())
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "%s_REQ: max req exceeded\n", smb2_command_string[command]);
+        dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
+            *current_flow->get_dce2_session_data());
+        
+        return;
+    }
+    uint64_t message_id = Smb2Mid(smb_header);
+
+    switch (command)
+    {
+    case SMB2_COM_CREATE:
+        if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+        {
+            dce2_smb_stats.v2_crt_err_resp++;
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "%s_RESP: error\n", smb2_command_string[command]);
+        }
+        else if (SMB2_CMD_TYPE_REQUEST == command_type)
+        {
+            if (SMB2_SHARE_TYPE_DISK != share_type)
+            {
+                debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ:"
+                    " ignored for ipc share\n", smb2_command_string[command]);
+                dce2_smb_stats.v2_crt_req_ipc++;
+                return;
+            }
+            process_create_request(message_id, smb_header, end);
+        }
+        else if (SMB2_CMD_TYPE_RESPONSE == command_type)
+            process_create_response(message_id, smb_header);
+        break;
+    case SMB2_COM_CLOSE:
+        process_close_request(smb_header);
+        break;
+    case SMB2_COM_SET_INFO:
+        process_set_info_request(smb_header);
+        break;
+    case SMB2_COM_READ:
+        if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+        {
+            dce2_smb_stats.v2_read_err_resp++;
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "%s_RESP: error\n", smb2_command_string[command]);
+            Dce2Smb2RequestTracker* request = find_request(message_id);
+            if (request)
+                close_file(request->get_file_id());
+        }
+        else if (SMB2_CMD_TYPE_REQUEST == command_type)
+            process_read_request(message_id, smb_header);
+        else if (SMB2_CMD_TYPE_RESPONSE == command_type)
+            process_read_response(message_id, smb_header, end);
+        break;
+    case SMB2_COM_WRITE:
+        if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+        {
+            dce2_smb_stats.v2_wrt_err_resp++;
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "%s_RESP: error\n", smb2_command_string[command]);
+            Dce2Smb2RequestTracker* request = find_request(message_id);
+            if (request)
+                close_file(request->get_file_id());
+        }
+        else if (SMB2_CMD_TYPE_REQUEST == command_type)
+            process_write_request(message_id, smb_header, end);
+        break;
+    }
+    if (SMB2_CMD_TYPE_RESPONSE == command_type or SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+        remove_request(message_id);
+}
+
+Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void)
+{
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+        "tree tracker %" PRIu32 " terminating\n", tree_id);
+    if (active_requests.size())
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "cleanup pending requests for below MIDs:\n");
+        for (auto it_request : active_requests)
+        {
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "mid %" PRIu64 "\n", it_request.first);
+            delete it_request.second;
+        }
+    }
+
+    auto it_file = opened_files.begin();
+    while (it_file != opened_files.end())
+    {
+        Dce2Smb2FileTracker* file = it_file->second;
+        it_file = opened_files.erase(it_file);
+        delete file;
+    }
+    parent_session->disconnect_tree(tree_id);
+    memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.h b/src/service_inspectors/dce_rpc/dce_smb2_tree.h
new file mode 100644 (file)
index 0000000..84dfba4
--- /dev/null
@@ -0,0 +1,83 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb2_tree.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB2_TREE_H
+#define DCE_SMB2_TREE_H
+
+// This provides tree trackers for SMBv2.
+// Tree trackers are used to identify and track an opened share
+
+#include "dce_smb2.h"
+#include "dce_smb2_file.h"
+#include "dce_smb2_request.h"
+
+uint64_t Smb2Mid(const Smb2Hdr* hdr);
+
+class Dce2Smb2SessionTracker;
+
+class Dce2Smb2TreeTracker
+{
+public:
+    Dce2Smb2TreeTracker() = delete;
+    Dce2Smb2TreeTracker(const Dce2Smb2TreeTracker&) = delete;
+    Dce2Smb2TreeTracker& operator=(const Dce2Smb2TreeTracker&) = delete;
+
+    Dce2Smb2TreeTracker(uint32_t tree_id_v, Dce2Smb2SessionTracker* p_session, uint8_t sharetype)
+        : tree_id(tree_id_v), share_type(sharetype), parent_session(p_session)
+    {
+        debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+            "tree tracker %" PRIu32 " created\n", tree_id);
+        memory::MemoryCap::update_allocations(sizeof(*this));
+    }
+
+    ~Dce2Smb2TreeTracker();
+
+    void open_file(uint64_t);
+    void close_file(uint64_t, bool=true);
+    Dce2Smb2FileTracker* find_file(uint64_t);
+    Dce2Smb2RequestTracker* find_request(uint64_t);
+    void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*);
+    Dce2Smb2SessionTracker* get_parent() { return parent_session; }
+
+private:
+    void process_set_info_request(const Smb2Hdr*);
+    void process_close_request(const Smb2Hdr*);
+    void process_create_response(uint64_t, const Smb2Hdr*);
+    void process_create_request(uint64_t, const Smb2Hdr*, const uint8_t*);
+    void process_read_response(uint64_t, const Smb2Hdr*, const uint8_t*);
+    void process_read_request(uint64_t, const Smb2Hdr*);
+    void process_write_request(uint64_t, const Smb2Hdr*, const uint8_t*);
+    uint64_t get_durable_file_id(const Smb2CreateRequestHdr*, const uint8_t*);
+    bool remove_request(uint64_t);
+    void store_request(uint64_t message_id, Dce2Smb2RequestTracker* request)
+    { active_requests.insert(std::make_pair(message_id, request)); }
+
+    uint32_t tree_id;
+    uint8_t share_type;
+    Dce2Smb2FileTrackerMap opened_files;
+    Dce2Smb2RequestTrackerMap active_requests;
+    Dce2Smb2SessionTracker* parent_session;
+};
+
+using Dce2Smb2TreeTrackerMap =
+    std::unordered_map<uint32_t, Dce2Smb2TreeTracker*, std::hash<uint32_t> >;
+
+#endif
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_utils.cc b/src/service_inspectors/dce_rpc/dce_smb2_utils.cc
deleted file mode 100644 (file)
index 6f35b45..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2015-2019 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// SMB2 utils processing
-// dce_smb2_utils.cc author Bhargava Jandhyala <bjandhya@cisco.com>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "dce_smb_module.h"
-#include "dce_smb_utils.h"
-#include "dce_smb2_utils.h"
-#include "detection/detection_util.h"
-#include "flow/flow_key.h"
-#include "main/snort_debug.h"
-
-using namespace snort;
-
-size_t session_cache_size;
-THREAD_LOCAL SmbSessionCache* smb2_session_cache;
-
-Smb2SidHashKey get_key(uint64_t sid)
-{
-    Smb2SidHashKey key;
-    Flow* flow = DetectionEngine::get_current_packet()->flow;
-    memcpy(key.cip, flow->client_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
-    memcpy(key.sip, flow->server_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
-    key.sid = sid;
-    key.cgroup = flow->client_group;
-    key.sgroup = flow->server_group;
-    key.asid = flow->key->addressSpaceId;
-    key.padding = 0;
-    return key;
-}
-
-DCE2_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData* ssd, const
-    uint64_t sid)
-{
-    // Local MAP search
-    DCE2_Smb2SessionTracker* stracker = DCE2_Smb2FindSidInSsd(ssd, sid);
-
-    if (!stracker)
-    {
-        // Global Hash Search
-        bool entry_created = false;
-        stracker = DCE2_SmbSessionCacheFindElseCreate(sid, &entry_created);
-        assert(stracker);
-        if (entry_created)
-        {
-            stracker->set_session_id(sid);
-            stracker->session_key = get_key(sid);
-        }
-
-        DCE2_Smb2InsertSidInSsd(ssd, sid, stracker);
-    }
-
-    return stracker;
-}
-
-DCE2_Smb2TreeTracker* DCE2_Smb2InsertTid(DCE2_Smb2SsnData* ssd, const uint32_t tid, uint8_t
-    share_type,
-    DCE2_Smb2SessionTracker* str)
-{
-    if (share_type == SMB2_SHARE_TYPE_DISK and
-        ssd->max_file_depth == -1 and DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config) == -1)
-    {
-        debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
-            "Not inserting TID (%u) because it's "
-            "not IPC and not inspecting normal file data.\n", tid);
-        return nullptr;
-    }
-
-    DCE2_Smb2TreeTracker* ttracker = str->findTtracker(tid);
-    if (!ttracker)
-    {
-        ttracker = new DCE2_Smb2TreeTracker(tid, share_type);
-        str->insertTtracker(tid, ttracker);
-    }
-
-    return ttracker;
-}
-
-void DCE2_Smb2RemoveAllSession(DCE2_Smb2SsnData* ssd)
-{
-    ssd->ftracker_tcp = nullptr;
-
-    // iterate over smb sessions for this tcp connection and cleanup its instance from them
-    auto all_session_trackers = ssd->session_trackers.get_all_entry();
-    for ( auto& h : all_session_trackers )
-    {
-        ssd->session_trackers.Remove(h.second->session_id);  // remove session tracker from this
-                                                             // tcp conn
-        h.second->removeConnTracker(ssd->flow_key); // remove tcp connection from session tracker
-        if (!h.second->getConnTrackerSize()) // if no tcp connection present in session tracker,
-                                             // delete session tracker
-        {
-            DCE2_SmbSessionCacheRemove(h.second->session_key);
-        }
-    }
-}
diff --git a/src/service_inspectors/dce_rpc/dce_smb2_utils.h b/src/service_inspectors/dce_rpc/dce_smb2_utils.h
deleted file mode 100644 (file)
index ec83b1e..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2019 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// dce_smb2_utils.h author Bhargava Jandhyala <bjandhya@cisco.com>
-// based on work by Todd Wease
-
-#ifndef DCE_SMB2_UTILS_H
-#define DCE_SMB2_UTILS_H
-
-#include "dce_smb.h"
-#include "dce_smb2.h"
-#include "file_api/file_flows.h"
-
-Smb2SidHashKey get_key(uint64_t sid);
-
-template<typename Key, typename Value, typename Hash>
-class SmbSessionCache_map : public LruCacheShared<Key, Value, Hash>
-{
-public:
-    SmbSessionCache_map() = delete;
-    SmbSessionCache_map(const SmbSessionCache_map& arg) = delete;
-    SmbSessionCache_map& operator=(const SmbSessionCache_map& arg) = delete;
-    SmbSessionCache_map(const size_t initial_size) : LruCacheShared<Key, Value, Hash>(initial_size)
-    {
-    }
-    ~SmbSessionCache_map() override = default;
-};
-
-typedef SmbSessionCache_map<Smb2SidHashKey, DCE2_Smb2SessionTracker, SmbKeyHash> SmbSessionCache;
-
-extern THREAD_LOCAL SmbSessionCache* smb2_session_cache;
-extern size_t session_cache_size;
-
-// SMB2 Session cache manipulation functions
-inline void DCE2_SmbSessionCacheInit(const size_t cache_size)
-{
-    smb2_session_cache = new SmbSessionCache(cache_size);
-}
-
-inline DCE2_Smb2SessionTracker* DCE2_SmbSessionCacheFind(uint64_t sid)
-{
-    return (smb2_session_cache->find(get_key(sid))).get();
-}
-
-inline DCE2_Smb2SessionTracker* DCE2_SmbSessionCacheFindElseCreate(uint64_t sid,
-    bool* entry_created)
-{
-    return (smb2_session_cache->find_else_create(get_key(sid), entry_created)).get();
-}
-
-inline bool DCE2_SmbSessionCacheRemove(Smb2SidHashKey key)
-{
-    return smb2_session_cache->remove(key);
-}
-
-// SMB2 functions for fetching sid, tid, request type and so on.
-inline uint64_t Smb2Sid(const Smb2Hdr* hdr)
-{
-    return snort::alignedNtohq(&(((const Smb2SyncHdr*)hdr)->session_id));
-}
-
-inline uint32_t Smb2Tid(const Smb2Hdr* hdr)
-{
-    return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id));
-}
-
-inline uint64_t Smb2Mid(const Smb2Hdr* hdr)
-{
-    return snort::alignedNtohq(&(((const Smb2SyncHdr*)hdr)->message_id));
-}
-
-inline bool Smb2Error(const Smb2Hdr* hdr)
-{
-    return (SMB_NT_STATUS_SEVERITY__ERROR == (uint8_t)(hdr->status >> 30));
-}
-
-inline DCE2_Smb2SessionTracker* DCE2_Smb2FindSidInSsd(DCE2_Smb2SsnData* ssd, const
-    uint64_t sid)
-{
-    return (DCE2_Smb2SessionTracker*)(ssd->session_trackers.Find(sid));
-}
-
-inline void DCE2_Smb2InsertSidInSsd(DCE2_Smb2SsnData* ssd, const uint64_t sid,
-    DCE2_Smb2SessionTracker* stracker)
-{
-    // add ssd in session tracker's tcp trackers database
-    stracker->insertConnTracker(ssd->flow_key, ssd);
-
-    ssd->session_trackers.Insert(sid, stracker);
-}
-
-inline void DCE2_Smb2RemoveSidInSsd(DCE2_Smb2SsnData* ssd, const uint64_t sid)
-{
-    ssd->session_trackers.Remove(sid);
-}
-
-DCE2_Smb2TreeTracker* DCE2_Smb2InsertTid(DCE2_Smb2SsnData*, const uint32_t tid, uint8_t share_type,
-    DCE2_Smb2SessionTracker*);
-
-DCE2_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData*, const uint64_t sid);
-
-DCE2_Ret DCE2_Smb2InitData(DCE2_Smb2SsnData*);
-
-void DCE2_Smb2RemoveAllSession(DCE2_Smb2SsnData* ssd);
-
-#endif
-
index bfd6a75faebe57771088daa21b93053e34d4650c..94537a48f2bb163f94fe6d363a1c0c7ed17ae112 100644 (file)
@@ -567,7 +567,7 @@ DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
         dce2_move(nb_ptr, nb_len, 1);
 
         ssd->cur_rtracker->file_name =
-            DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr),
+            get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
             &ssd->cur_rtracker->file_name_size);
     }
 
@@ -625,7 +625,7 @@ DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
         dce2_move(nb_ptr, nb_len, 1);
 
         ssd->cur_rtracker->file_name =
-            DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr),
+            get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
             &ssd->cur_rtracker->file_name_size);
     }
 
@@ -856,7 +856,7 @@ DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
         dce2_move(nb_ptr, nb_len, 1);
 
         ssd->cur_rtracker->file_name =
-            DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr),
+            get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
             &ssd->cur_rtracker->file_name_size);
     }
 
@@ -1069,7 +1069,7 @@ DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
         if (ssd->cur_rtracker->file_name == nullptr)
         {
             ssd->cur_rtracker->file_name =
-                DCE2_SmbGetFileName(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size);
+                get_smb_file_name(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size);
         }
     }
 
@@ -1930,7 +1930,7 @@ DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
         if (ssd->cur_rtracker->file_name == nullptr)
         {
             ssd->cur_rtracker->file_name =
-                DCE2_SmbGetFileName(nb_ptr, file_name_length, unicode,
+                get_smb_file_name(nb_ptr, file_name_length, unicode,
                 &ssd->cur_rtracker->file_name_size);
         }
 
diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.cc b/src/service_inspectors/dce_rpc/dce_smb_common.cc
new file mode 100644 (file)
index 0000000..034fbdb
--- /dev/null
@@ -0,0 +1,198 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb_common.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb_common.h"
+
+#include "file_api/file_flows.h"
+#include "file_api/file_service.h"
+#include "memory/memory_cap.h"
+
+#include "dce_smb1.h"
+#include "dce_smb2.h"
+
+using namespace snort;
+
+THREAD_LOCAL dce2SmbStats dce2_smb_stats;
+THREAD_LOCAL ProfileStats dce2_smb_pstat_main;
+
+//Dce2SmbFlowData members
+
+unsigned Dce2SmbFlowData::inspector_id = 0;
+
+Dce2SmbFlowData::Dce2SmbFlowData(Dce2SmbSessionData* ssd_v) : FlowData(inspector_id)
+{
+    dce2_smb_stats.concurrent_sessions++;
+    if (dce2_smb_stats.max_concurrent_sessions < dce2_smb_stats.concurrent_sessions)
+        dce2_smb_stats.max_concurrent_sessions = dce2_smb_stats.concurrent_sessions;
+    ssd = ssd_v;
+    memory::MemoryCap::update_allocations(sizeof(*this));
+}
+
+Dce2SmbSessionData* Dce2SmbFlowData::upgrade(const Packet* p)
+{
+    dce2SmbProtoConf* config =
+        (dce2SmbProtoConf*)ssd->get_dce2_session_data()->config;
+    delete ssd;
+    ssd = new Dce2Smb2SessionData(p, config);
+    return ssd;
+}
+
+void Dce2SmbFlowData::handle_retransmit(Packet* p)
+{
+    FilePosition position = get_file_position(p);
+    if (!(SNORT_FILE_FULL == position or SNORT_FILE_END == position))
+        return;
+    FileContext* context = get_smb_file_context(p);
+    FileVerdict verdict = context ? context->verdict : FILE_VERDICT_UNKNOWN;
+    ssd->handle_retransmit(position, verdict);
+}
+
+Dce2SmbFlowData::~Dce2SmbFlowData()
+{
+    delete ssd;
+    assert(dce2_smb_stats.concurrent_sessions > 0);
+    dce2_smb_stats.concurrent_sessions--;
+    memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
+//Dce2SmbSessionData members
+
+Dce2SmbSessionData::Dce2SmbSessionData(const Packet* p,
+    const dce2SmbProtoConf* config)
+{
+    sd = { };
+    policy = { };
+    tcp_flow = p->flow;
+    DCE2_ResetRopts(&sd, p);
+    sd.trans = DCE2_TRANS_TYPE__SMB;
+    sd.server_policy = config->common.policy;
+    sd.client_policy = DCE2_POLICY__WINXP;
+    sd.config = (void*)config;
+    dialect_index = DCE2_SENTINEL;
+    max_file_depth = FileService::get_max_file_depth();
+    dce2_smb_stats.smb_sessions++;
+}
+
+//Helper functions
+
+static inline DCE2_SmbVersion get_smb_version(const Packet* p)
+{
+    // Only check reassembled SMB2 packet
+    if ( p->has_paf_payload() and
+        (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE))
+    {
+        const SmbNtHdr* smb_hdr = (const SmbNtHdr*)(p->data + sizeof(NbssHdr));
+        uint32_t smb_version_id = SmbId(smb_hdr);
+
+        if (smb_version_id == DCE2_SMB_ID)
+            return DCE2_SMB_VERSION_1;
+        else if (smb_version_id == DCE2_SMB2_ID)
+            return DCE2_SMB_VERSION_2;
+    }
+
+    return DCE2_SMB_VERSION_NULL;
+}
+
+Dce2SmbSessionData* create_new_smb_session(const Packet* p,
+    dce2SmbProtoConf* config)
+{
+    DCE2_SmbVersion smb_version = get_smb_version(p);
+
+    if (DCE2_SMB_VERSION_NULL == smb_version)
+        return nullptr;
+
+    Dce2SmbSessionData* ssd = (DCE2_SMB_VERSION_1 == smb_version) ?
+        (Dce2SmbSessionData*)new Dce2Smb1SessionData(p, config) :
+        (Dce2SmbSessionData*)new Dce2Smb2SessionData(p, config);
+
+    Dce2SmbFlowData* flow_data = new Dce2SmbFlowData(ssd);
+    p->flow->set_flow_data(flow_data);
+
+    return ssd;
+}
+
+DCE2_SsnData* get_dce2_session_data(snort::Flow* flow)
+{
+    Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id);
+    return fd ? fd->get_smb_session_data()->get_dce2_session_data() : nullptr;
+}
+
+inline FileContext* get_smb_file_context(const Packet* p)
+{
+    FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
+    return file_flows ? file_flows->get_current_file_context() : nullptr;
+}
+
+FileContext* get_smb_file_context(uint64_t file_id,
+    uint64_t multi_file_processing_id, bool to_create)
+{
+    FileFlows* file_flows = FileFlows::get_file_flows(DetectionEngine::get_current_packet()->flow);
+
+    if ( !file_flows )
+    {
+        dce2_smb_stats.v2_inv_file_ctx_err++;
+        return nullptr;
+    }
+
+    return file_flows->get_file_context(file_id, to_create, multi_file_processing_id);
+}
+
+char* get_smb_file_name(const uint8_t* data, uint32_t data_len, bool unicode,
+    uint16_t* file_name_len)
+{
+    const uint8_t inc = unicode ? 2 : 1;
+    if (data_len < inc)
+        return nullptr;
+
+    const uint32_t max_len =  unicode ? data_len - 1 : data_len;
+    // Move forward.  Don't know if the end of data is actually
+    // the end of the string.
+    uint32_t i;
+    for (i = 0; i < max_len; i += inc)
+    {
+        uint16_t uchar = unicode ? extract_16bits(data + i) : data[i];
+        if (uchar == 0)
+            break;
+    }
+
+    char* fname = nullptr;
+    const uint32_t real_len = i;
+
+    if (unicode)
+    {
+        fname = (char*)snort_calloc(real_len + UTF_16_LE_BOM_LEN + 2);
+        memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM
+        memcpy(fname + UTF_16_LE_BOM_LEN, data, real_len);
+        *file_name_len = real_len + UTF_16_LE_BOM_LEN;
+    }
+    else
+    {
+        fname = (char*)snort_alloc(real_len + 1);
+        memcpy(fname, data, real_len);
+        fname[real_len] = 0;
+        *file_name_len = real_len;
+    }
+    return fname;
+}
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.h b/src/service_inspectors/dce_rpc/dce_smb_common.h
new file mode 100644 (file)
index 0000000..19c3338
--- /dev/null
@@ -0,0 +1,290 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb_common.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB_COMMON_H
+#define DCE_SMB_COMMON_H
+
+// This provides SMB flow data and base class for SMB session data
+// Also provides common functions used by both versions
+
+#include "file_api/file_api.h"
+#include "main/snort_debug.h"
+#include "protocols/packet.h"
+#include "profiler/profiler_defs.h"
+
+#include "dce_common.h"
+#include "dce_smb_module.h"
+#include "smb_common.h"
+
+#define DCE2_SMB_NAME "dce_smb"
+#define DCE2_SMB_HELP "dce over smb inspection"
+
+#define DCE2_SMB_ID   0xff534d42  /* \xffSMB */
+#define DCE2_SMB2_ID  0xfe534d42  /* \xfeSMB */
+#define DCE2_SMB_ID_SIZE 4
+
+#define SMB_DEFAULT_MAX_CREDIT        8192
+#define SMB_DEFAULT_MEMCAP            8388608
+#define SMB_DEFAULT_MAX_COMPOUND_REQ  3
+
+#define DCE2_SMB_RPKT_TYPE_MAX 4
+#define DCE2_SMB_RPKT_TYPE_START 1
+
+#define DCE2_SMB_BAD_NBSS_TYPE 2
+#define DCE2_SMB_BAD_TYPE 3
+#define DCE2_SMB_BAD_ID 4
+#define DCE2_SMB_BAD_WCT 5
+#define DCE2_SMB_BAD_BCC 6
+#define DCE2_SMB_BAD_FORM 7
+#define DCE2_SMB_BAD_OFF 8
+#define DCE2_SMB_TDCNT_ZE 9
+#define DCE2_SMB_NB_LT_SMBHDR 10
+#define DCE2_SMB_NB_LT_COM 11
+#define DCE2_SMB_NB_LT_BCC 12
+#define DCE2_SMB_NB_LT_DSIZE 13
+#define DCE2_SMB_TDCNT_LT_DSIZE 14
+#define DCE2_SMB_DSENT_GT_TDCNT 15
+#define DCE2_SMB_BCC_LT_DSIZE 16
+#define DCE2_SMB_INVALID_DSIZE 17
+#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS 18
+#define DCE2_SMB_EXCESSIVE_READS 19
+#define DCE2_SMB_EXCESSIVE_CHAINING 20
+#define DCE2_SMB_MULT_CHAIN_SS 21
+#define DCE2_SMB_MULT_CHAIN_TC 22
+#define DCE2_SMB_CHAIN_SS_LOGOFF 23
+#define DCE2_SMB_CHAIN_TC_TDIS 24
+#define DCE2_SMB_CHAIN_OPEN_CLOSE 25
+#define DCE2_SMB_INVALID_SHARE 26
+
+#define DCE2_SMB_V1 44
+#define DCE2_SMB_V2 45
+#define DCE2_SMB_INVALID_BINDING 46
+#define DCE2_SMB2_EXCESSIVE_COMPOUNDING 47
+#define DCE2_SMB_DCNT_ZERO 48
+#define DCE2_SMB_DCNT_MISMATCH 49
+#define DCE2_SMB_MAX_REQS_EXCEEDED 50
+#define DCE2_SMB_REQS_SAME_MID 51
+#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED 52
+#define DCE2_SMB_DEPR_COMMAND_USED 53
+#define DCE2_SMB_UNUSUAL_COMMAND_USED 54
+#define DCE2_SMB_INVALID_SETUP_COUNT 55
+#define DCE2_SMB_MULTIPLE_NEGOTIATIONS 56
+#define DCE2_SMB_EVASIVE_FILE_ATTRS 57
+#define DCE2_SMB_INVALID_FILE_OFFSET 58
+#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET 59
+
+struct dce2SmbStats
+{
+    PegCount events;
+
+    PegCount co_pdus;
+    PegCount co_bind;
+    PegCount co_bind_ack;
+    PegCount co_alter_ctx;
+    PegCount co_alter_ctx_resp;
+    PegCount co_bind_nack;
+    PegCount co_request;
+    PegCount co_response;
+    PegCount co_cancel;
+    PegCount co_orphaned;
+    PegCount co_fault;
+    PegCount co_auth3;
+    PegCount co_shutdown;
+    PegCount co_reject;
+    PegCount co_ms_pdu;
+    PegCount co_other_req;
+    PegCount co_other_resp;
+    PegCount co_req_fragments;
+    PegCount co_resp_fragments;
+    PegCount co_cli_max_frag_size;
+    PegCount co_cli_min_frag_size;
+    PegCount co_cli_seg_reassembled;
+    PegCount co_cli_frag_reassembled;
+    PegCount co_srv_max_frag_size;
+    PegCount co_srv_min_frag_size;
+    PegCount co_srv_seg_reassembled;
+    PegCount co_srv_frag_reassembled;
+
+    PegCount smb_sessions;
+    PegCount smb_pkts;
+    PegCount smb_ignored_bytes;
+    PegCount smb_cli_seg_reassembled;
+    PegCount smb_srv_seg_reassembled;
+    PegCount smb_max_outstanding_requests;
+    //  FIXIT-M more peg count foo
+    /*uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS];
+    uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS];
+    // The +1 is for codes beyond the range of the highest valid subcommand code
+    // Indicates a bogus subcommand
+    uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1];
+    uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1];
+    uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1];
+    */
+    PegCount smb_files_processed;
+    /* SMB2 stats */
+    PegCount v2_setup;
+    PegCount v2_setup_err_resp;
+    PegCount v2_setup_inv_str_sz;
+    PegCount v2_setup_resp_hdr_err;
+    PegCount v2_tree_cnct;
+    PegCount v2_tree_cnct_err_resp;
+    PegCount v2_tree_cnct_ignored;
+    PegCount v2_tree_cnct_inv_str_sz;
+    PegCount v2_tree_cnct_resp_hdr_err;
+    PegCount v2_crt;
+    PegCount v2_crt_err_resp;
+    PegCount v2_crt_inv_file_data;
+    PegCount v2_crt_inv_str_sz;
+    PegCount v2_crt_resp_hdr_err;
+    PegCount v2_crt_req_hdr_err;
+    PegCount v2_crt_rtrkr_misng;
+    PegCount v2_crt_req_ipc;
+    PegCount v2_crt_tree_trkr_misng;
+    PegCount v2_wrt;
+    PegCount v2_wrt_err_resp;
+    PegCount v2_wrt_inv_str_sz;
+    PegCount v2_wrt_req_hdr_err;
+    PegCount v2_wrt_resp_hdr_err;
+    PegCount v2_read;
+    PegCount v2_read_err_resp;
+    PegCount v2_read_inv_str_sz;
+    PegCount v2_read_rtrkr_misng;
+    PegCount v2_read_resp_hdr_err;
+    PegCount v2_read_req_hdr_err;
+    PegCount v2_setinfo;
+    PegCount v2_stinf_err_resp;
+    PegCount v2_stinf_inv_str_sz;
+    PegCount v2_stinf_req_ftrkr_misng;
+    PegCount v2_stinf_req_hdr_err;
+    PegCount v2_cls;
+    PegCount v2_cls_err_resp;
+    PegCount v2_cls_inv_str_sz;
+    PegCount v2_cls_req_ftrkr_misng;
+    PegCount v2_cls_req_hdr_err;
+    PegCount v2_tree_discn;
+    PegCount v2_tree_discn_ignored;
+    PegCount v2_tree_discn_inv_str_sz;
+    PegCount v2_tree_discn_req_hdr_err;
+    PegCount v2_logoff;
+    PegCount v2_logoff_inv_str_sz;
+    PegCount v2_hdr_err;
+    PegCount v2_bad_next_cmd_offset;
+    PegCount v2_inv_file_ctx_err;
+    PegCount v2_msgs_uninspected;
+    PegCount v2_cmpnd_req_lt_crossed;
+    PegCount v2_tree_ignored;
+    PegCount v2_session_ignored;
+    PegCount concurrent_sessions;
+    PegCount max_concurrent_sessions;
+};
+
+enum DCE2_SmbVersion
+{
+    DCE2_SMB_VERSION_NULL,
+    DCE2_SMB_VERSION_1,
+    DCE2_SMB_VERSION_2
+};
+
+enum Dce2SmbPduState
+{
+    DCE2_SMB_PDU_STATE__COMMAND,
+    DCE2_SMB_PDU_STATE__RAW_DATA
+};
+
+extern THREAD_LOCAL dce2SmbStats dce2_smb_stats;
+extern THREAD_LOCAL snort::ProfileStats dce2_smb_pstat_main;
+
+class Dce2SmbSessionData
+{
+public:
+    Dce2SmbSessionData() = delete;
+    Dce2SmbSessionData(const snort::Packet*, const dce2SmbProtoConf*);
+    virtual ~Dce2SmbSessionData() { }
+
+    virtual void process() = 0;
+    virtual void handle_retransmit(FilePosition, FileVerdict) = 0;
+
+    DCE2_SsnData* get_dce2_session_data()
+    { return &sd; }
+
+    snort::Flow* get_flow()
+    { return tcp_flow; }
+
+    int64_t get_max_file_depth()
+    { return max_file_depth; }
+
+    uint16_t get_max_outstanding_requests()
+    {
+        return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_credit :
+               SMB_DEFAULT_MAX_CREDIT;
+    }
+
+    int64_t get_smb_file_depth()
+    {
+        return ((dce2SmbProtoConf*)sd.config)->smb_file_depth;
+    }
+
+    uint16_t get_smb_max_compound()
+    {
+        return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_compound :
+            SMB_DEFAULT_MAX_COMPOUND_REQ;
+    }
+
+protected:
+    DCE2_SsnData sd;
+    DCE2_Policy policy;
+    int64_t max_file_depth;
+    int dialect_index;
+    snort::Flow* tcp_flow;
+};
+
+class Dce2SmbFlowData : public snort::FlowData
+{
+public:
+    Dce2SmbFlowData(Dce2SmbSessionData*);
+    ~Dce2SmbFlowData() override;
+
+    static void init()
+    { inspector_id = snort::FlowData::create_flow_data_id(); }
+
+    size_t size_of() override
+    { return sizeof(*this); }
+
+    Dce2SmbSessionData* get_smb_session_data()
+    { return ssd; }
+
+    Dce2SmbSessionData* upgrade(const snort::Packet*);
+    void handle_retransmit(snort::Packet*) override;
+
+public:
+    static unsigned inspector_id;
+
+private:
+    Dce2SmbSessionData* ssd;
+};
+
+Dce2SmbSessionData* create_new_smb_session(const snort::Packet*, dce2SmbProtoConf*);
+DCE2_SsnData* get_dce2_session_data(snort::Flow*);
+snort::FileContext* get_smb_file_context(const snort::Packet*);
+snort::FileContext* get_smb_file_context(uint64_t, uint64_t, bool);
+char* get_smb_file_name(const uint8_t*, uint32_t, bool, uint16_t*);
+
+#endif
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb_inspector.cc b/src/service_inspectors/dce_rpc/dce_smb_inspector.cc
new file mode 100644 (file)
index 0000000..fdcabbf
--- /dev/null
@@ -0,0 +1,181 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb_inspector.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb_inspector.h"
+
+#include "dce_smb_common.h"
+#include "dce_smb_module.h"
+#include "dce_smb_utils.h"
+#include "dce_smb2_session_cache.h"
+
+using namespace snort;
+
+Dce2Smb::Dce2Smb(const dce2SmbProtoConf& pc)
+{
+    config = pc;
+}
+
+Dce2Smb::~Dce2Smb()
+{
+    if (config.smb_invalid_shares)
+    {
+        DCE2_ListDestroy(config.smb_invalid_shares);
+    }
+}
+
+void Dce2Smb::show(const SnortConfig*) const
+{
+    print_dce2_smb_conf(config);
+}
+
+void Dce2Smb::eval(Packet* p)
+{
+    Profile profile(dce2_smb_pstat_main);
+
+    assert(p->has_tcp_data());
+    assert(p->flow);
+
+    Dce2SmbFlowData* smb_flowdata =
+        (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id);
+
+    Dce2SmbSessionData* smb_session_data;
+    if (smb_flowdata)
+        smb_session_data = smb_flowdata->get_smb_session_data();
+    else
+        smb_session_data = create_new_smb_session(p, &config);
+
+    if (smb_session_data)
+    {
+        dce2_detected = 0;
+        p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
+        p->endianness = new DceEndianness();
+
+        smb_session_data->process();
+
+        //smb_session_data may not be valid anymore in case of upgrade
+        //but flow will always have updated session
+        if (!dce2_detected)
+            DCE2_Detect(get_dce2_session_data(p->flow));
+
+        delete(p->endianness);
+        p->endianness = nullptr;
+    }
+    else
+        debug_logf(dce_smb_trace, p, "non-smb packet detected\n");
+}
+
+void Dce2Smb::clear(Packet* p)
+{
+    DCE2_SsnData* sd = get_dce2_session_data(p->flow);
+    if (sd)
+        DCE2_ResetRopts(sd, p);
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+size_t session_cache_size;
+
+static Module* mod_ctor()
+{
+    return new Dce2SmbModule;
+}
+
+static void mod_dtor(Module* m)
+{
+    delete m;
+}
+
+static void dce2_smb_init()
+{
+    Dce2SmbFlowData::init();
+    DCE2_SmbInitGlobals();
+    DCE2_SmbInitDeletePdu();
+    DceContextData::init(DCE2_TRANS_TYPE__SMB);
+}
+
+static void dce2_smb_thread_int()
+{
+    DCE2_SmbSessionCacheInit(session_cache_size);
+}
+
+static void dce_smb_thread_term()
+{
+    delete smb2_session_cache;
+}
+
+static size_t get_max_smb_session(dce2SmbProtoConf* config)
+{
+    size_t smb_sess_storage_req = (sizeof(Dce2Smb2SessionTracker) +
+        sizeof(Dce2Smb2TreeTracker) + sizeof(Dce2Smb2RequestTracker) +
+        (sizeof(Dce2Smb2FileTracker) * SMB_AVG_FILES_PER_SESSION));
+
+    size_t max_smb_mem = DCE2_ScSmbMemcap(config);
+
+    return (max_smb_mem/smb_sess_storage_req);
+}
+
+static Inspector* dce2_smb_ctor(Module* m)
+{
+    Dce2SmbModule* mod = (Dce2SmbModule*)m;
+    dce2SmbProtoConf config;
+    mod->get_data(config);
+    session_cache_size = get_max_smb_session(&config);
+    return new Dce2Smb(config);
+}
+
+static void dce2_smb_dtor(Inspector* p)
+{
+    delete p;
+}
+
+const InspectApi dce2_smb_api =
+{
+    {
+        PT_INSPECTOR,
+        sizeof(InspectApi),
+        INSAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        DCE2_SMB_NAME,
+        DCE2_SMB_HELP,
+        mod_ctor,
+        mod_dtor
+    },
+    IT_SERVICE,
+    PROTO_BIT__PDU,
+    nullptr,  // buffers
+    "netbios-ssn",
+    dce2_smb_init,
+    nullptr, // pterm
+    dce2_smb_thread_int, // tinit
+    dce_smb_thread_term, // tterm
+    dce2_smb_ctor,
+    dce2_smb_dtor,
+    nullptr, // ssn
+    nullptr  // reset
+};
+
diff --git a/src/service_inspectors/dce_rpc/dce_smb_inspector.h b/src/service_inspectors/dce_rpc/dce_smb_inspector.h
new file mode 100644 (file)
index 0000000..fb1c8dd
--- /dev/null
@@ -0,0 +1,50 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// dce_smb_inspector.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB_INSPECTOR_H
+#define DCE_SMB_INSPECTOR_H
+
+#include "managers/inspector_manager.h"
+
+#include "dce_smb_module.h"
+#include "dce_smb_paf.h"
+
+class Dce2Smb : public snort::Inspector
+{
+public:
+    Dce2Smb(const dce2SmbProtoConf&);
+    ~Dce2Smb() override;
+
+    void show(const snort::SnortConfig*) const override;
+    void eval(snort::Packet*) override;
+    void clear(snort::Packet*) override;
+
+    snort::StreamSplitter* get_splitter(bool c2s) override
+    { return new Dce2SmbSplitter(c2s); }
+
+    bool can_carve_files() const override
+    { return true; }
+
+private:
+    dce2SmbProtoConf config;
+};
+
+#endif
+
index 59785958ccfc444704d31318cb03df7022049cdc..842f49de9cb92ce9696f5baec8863fc7a42ab9a8 100644 (file)
@@ -29,7 +29,7 @@
 #include "trace/trace.h"
 #include "utils/util.h"
 
-#include "dce_smb.h"
+#include "dce_smb_common.h"
 
 using namespace snort;
 using namespace std;
@@ -84,7 +84,8 @@ static const PegInfo dce2_smb_pegs[] =
     { CountType::SUM, "max_outstanding_requests", "total smb maximum outstanding requests" },
     { CountType::SUM, "files_processed", "total smb files processed" },
     { CountType::SUM, "v2_setup", "total number of SMBv2 setup packets seen" },
-    { CountType::SUM, "v2_setup_err_resp", "total number of SMBv2 setup error response packets seen" },
+    { CountType::SUM, "v2_setup_err_resp",
+        "total number of SMBv2 setup error response packets seen" },
     { CountType::SUM, "v2_setup_inv_str_sz",
         "total number of SMBv2 setup packets seen with invalid structure size" },
     { CountType::SUM, "v2_setup_resp_hdr_err",
@@ -99,15 +100,16 @@ static const PegInfo dce2_smb_pegs[] =
     { CountType::SUM, "v2_tree_cnct_resp_hdr_err",
         "total number of SMBv2 tree connect response packets ignored due to corrupted header" },
     { CountType::SUM, "v2_crt", "total number of SMBv2 create packets seen" },
-    { CountType::SUM, "v2_crt_err_resp", "total number of SMBv2 create error response packets seen" },
+    { CountType::SUM, "v2_crt_err_resp",
+        "total number of SMBv2 create error response packets seen" },
     { CountType::SUM, "v2_crt_inv_file_data",
         "total number of SMBv2 create request packets ignored due to error in getting file name" },
     { CountType::SUM, "v2_crt_inv_str_sz",
         "total number of SMBv2 create packets seen with invalid structure size" },
     { CountType::SUM, "v2_crt_resp_hdr_err",
-        "total number of SMBv2 create response packets ignored due to corrupted header" },
+         "total number of SMBv2 create response packets ignored due to corrupted header" },
     { CountType::SUM, "v2_crt_req_hdr_err",
-        "total number of SMBv2 create request packets ignored due to corrupted header" },
+         "total number of SMBv2 create request packets ignored due to corrupted header" },
     { CountType::SUM, "v2_crt_rtrkr_misng",
         "total number of SMBv2 create response packets ignored due to missing create request tracker" },
     { CountType::SUM, "v2_crt_req_ipc",
@@ -115,17 +117,17 @@ static const PegInfo dce2_smb_pegs[] =
     { CountType::SUM, "v2_crt_tree_trkr_misng",
         "total number of SMBv2 create response packets ignored due to missing tree tracker" },
     { CountType::SUM, "v2_wrt", "total number of SMBv2 write packets seen" },
-    { CountType::SUM, "v2_wrt_err_resp", "total number of SMBv2 write error response packets seen" },
-    { CountType::SUM, "v2_wrt_ignored",
-        "total number of SMBv2 write packets ignored due to missing trackers or invalid share type" },
+    { CountType::SUM, "v2_wrt_err_resp",
+        "total number of SMBv2 write error response packets seen" },
     { CountType::SUM, "v2_wrt_inv_str_sz",
         "total number of SMBv2 write packets seen with invalid structure size" },
     { CountType::SUM, "v2_wrt_req_hdr_err",
         "total number of SMBv2 write request packets ignored due to corrupted header" },
+    { CountType::SUM, "v2_wrt_resp_hdr_err",
+        "total number of SMBv2 write response packets ignored due to corrupted header" },
     { CountType::SUM, "v2_read", "total number of SMBv2 read packets seen" },
-    { CountType::SUM, "v2_read_err_resp", "total number of SMBv2 read error response packets seen" },
-    { CountType::SUM, "v2_read_ignored",
-        "total number of SMBv2 write packets ignored due to missing trackers or invalid share type" },
+    { CountType::SUM, "v2_read_err_resp",
+        "total number of SMBv2 read error response packets seen" },
     { CountType::SUM, "v2_read_inv_str_sz",
         "total number of SMBv2 read packets seen with invalid structure size" },
     { CountType::SUM, "v2_read_rtrkr_misng",
@@ -134,10 +136,9 @@ static const PegInfo dce2_smb_pegs[] =
         "total number of SMBv2 read response packets ignored due to corrupted header" },
     { CountType::SUM, "v2_read_req_hdr_err",
         "total number of SMBv2 read request packets ignored due to corrupted header" },
-    { CountType::SUM, "v2_stinf", "total number of SMBv2 set info packets seen" },
-    { CountType::SUM, "v2_stinf_err_resp", "total number of SMBv2 set info error response packets seen" },
-    { CountType::SUM, "v2_stinf_ignored",
-        "total number of SMBv2 set info packets ignored due to missing trackers or invalid share type" },
+    { CountType::SUM, "v2_setinfo", "total number of SMBv2 set info packets seen" },
+    { CountType::SUM, "v2_stinf_err_resp",
+        "total number of SMBv2 set info error response packets seen" },
     { CountType::SUM, "v2_stinf_inv_str_sz",
         "total number of SMBv2 set info packets seen with invalid structure size" },
     { CountType::SUM, "v2_stinf_req_ftrkr_misng",
@@ -145,9 +146,8 @@ static const PegInfo dce2_smb_pegs[] =
     { CountType::SUM, "v2_stinf_req_hdr_err",
         "total number of SMBv2 set info request packets ignored due to corrupted header" },
     { CountType::SUM, "v2_cls", "total number of SMBv2 close packets seen" },
-    { CountType::SUM, "v2_cls_err_resp", "total number of SMBv2 close error response packets seen" },
-    { CountType::SUM, "v2_cls_ignored",
-        "total number of SMBv2 close packets ignored due to missing trackers or invalid share type" },
+    { CountType::SUM, "v2_cls_err_resp",
+        "total number of SMBv2 close error response packets seen" },
     { CountType::SUM, "v2_cls_inv_str_sz",
         "total number of SMBv2 close packets seen with invalid structure size" },
     { CountType::SUM, "v2_cls_req_ftrkr_misng",
@@ -168,14 +168,16 @@ static const PegInfo dce2_smb_pegs[] =
     { CountType::SUM, "v2_hdr_err", "total number of SMBv2 packets seen with corrupted hdr" },
     { CountType::SUM, "v2_bad_next_cmd_offset",
         "total number of SMBv2 packets seen with invalid next command offset" },
-    { CountType::SUM, "v2_extra_file_data_err",
-        "total number of SMBv2 packets seen with where file data beyond file size is observed" },
     { CountType::SUM, "v2_inv_file_ctx_err",
         "total number of times null file context are seen resulting in not being able to set file size" },
     { CountType::SUM, "v2_msgs_uninspected",
         "total number of SMBv2 packets seen where command is not being inspected" },
     { CountType::SUM, "v2_cmpnd_req_lt_crossed",
         "total number of SMBv2 packets seen where compound requests exceed the smb_max_compound limit" },
+    { CountType::SUM, "v2_tree_ignored",
+        "total number of packets ignored due to missing tree tracker" },
+    { CountType::SUM, "v2_session_ignored",
+        "total number of packets ignored due to missing session tracker" },
     { CountType::NOW, "concurrent_sessions", "total concurrent sessions" },
     { CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" },
     { CountType::END, nullptr, nullptr }
@@ -536,6 +538,5 @@ void print_dce2_smb_conf(const dce2SmbProtoConf& config)
         get_shares(config.smb_invalid_shares).c_str());
     ConfigLogger::log_flag("smb_legacy_mode", config.legacy_mode);
     ConfigLogger::log_limit("smb_max_credit", config.smb_max_credit, 0, 1);
-
 }
 
index 3d7b0be19e0da622e1a6ae9cd469d6b5968b3d1a..60c72b65261a413e708a53a494eaeeb4cb2079c1 100644 (file)
@@ -21,8 +21,9 @@
 #ifndef DCE_SMB_MODULE_H
 #define DCE_SMB_MODULE_H
 
-#include "dce_common.h"
 #include "framework/module.h"
+
+#include "dce_common.h"
 #include "dce_list.h"
 
 namespace snort
@@ -36,6 +37,59 @@ extern THREAD_LOCAL const snort::Trace* dce_smb_trace;
 #define DCE2_VALID_SMB_VERSION_FLAG_V1 1
 #define DCE2_VALID_SMB_VERSION_FLAG_V2 2
 
+#define DCE2_SMB_BAD_NBSS_TYPE_STR "SMB - bad NetBIOS session service session type"
+#define DCE2_SMB_BAD_TYPE_STR  "SMB - bad SMB message type"
+#define DCE2_SMB_BAD_ID_STR "SMB - bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)"
+#define DCE2_SMB_BAD_WCT_STR "SMB - bad word count or structure size"
+#define DCE2_SMB_BAD_BCC_STR  "SMB - bad byte count"
+#define DCE2_SMB_BAD_FORM_STR  "SMB - bad format type"
+#define DCE2_SMB_BAD_OFF_STR  "SMB - bad offset"
+#define DCE2_SMB_TDCNT_ZE_STR  "SMB - zero total data count"
+#define DCE2_SMB_NB_LT_SMBHDR_STR "SMB - NetBIOS data length less than SMB header length"
+#define DCE2_SMB_NB_LT_COM_STR   "SMB - remaining NetBIOS data length less than command length"
+#define DCE2_SMB_NB_LT_BCC_STR  "SMB - remaining NetBIOS data length less than command byte count"
+#define DCE2_SMB_NB_LT_DSIZE_STR \
+    "SMB - remaining NetBIOS data length less than command data size"
+#define DCE2_SMB_TDCNT_LT_DSIZE_STR \
+    "SMB - remaining total data count less than this command data size"
+#define DCE2_SMB_DSENT_GT_TDCNT_STR \
+    "SMB - total data sent (STDu64) greater than command total data expected"
+#define DCE2_SMB_BCC_LT_DSIZE_STR   "SMB - byte count less than command data size (STDu64)"
+#define DCE2_SMB_INVALID_DSIZE_STR  "SMB - invalid command data size for byte count"
+#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS_STR \
+    "SMB - excessive tree connect requests with pending tree connect responses"
+#define DCE2_SMB_EXCESSIVE_READS_STR  "SMB - excessive read requests with pending read responses"
+#define DCE2_SMB_EXCESSIVE_CHAINING_STR  "SMB - excessive command chaining"
+#define DCE2_SMB_MULT_CHAIN_SS_STR   "SMB - multiple chained tree connect requests"
+#define DCE2_SMB_MULT_CHAIN_TC_STR   "SMB - multiple chained tree connect requests"
+#define DCE2_SMB_CHAIN_SS_LOGOFF_STR   "SMB - chained/compounded login followed by logoff"
+#define DCE2_SMB_CHAIN_TC_TDIS_STR \
+    "SMB - chained/compounded tree connect followed by tree disconnect"
+#define DCE2_SMB_CHAIN_OPEN_CLOSE_STR \
+    "SMB - chained/compounded open pipe followed by close pipe"
+#define DCE2_SMB_INVALID_SHARE_STR   "SMB - invalid share access"
+
+#define DCE2_SMB_V1_STR  "SMB - invalid SMB version 1 seen"
+#define DCE2_SMB_V2_STR  "SMB - invalid SMB version 2 seen"
+#define DCE2_SMB_INVALID_BINDING_STR "SMB - invalid user, tree connect, file binding"
+#define DCE2_SMB2_EXCESSIVE_COMPOUNDING_STR  "SMB - excessive command compounding"
+#define DCE2_SMB_DCNT_ZERO_STR   "SMB - zero data count"
+#define DCE2_SMB_DCNT_MISMATCH_STR "SMB - data count mismatch in command and format"
+#define DCE2_SMB_MAX_REQS_EXCEEDED_STR  "SMB - maximum number of outstanding requests exceeded"
+#define DCE2_SMB_REQS_SAME_MID_STR "SMB - outstanding requests with same MID"
+#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED_STR  "SMB - deprecated dialect negotiated"
+#define DCE2_SMB_DEPR_COMMAND_USED_STR   "SMB - deprecated command used"
+#define DCE2_SMB_UNUSUAL_COMMAND_USED_STR "SMB - unusual command used"
+#define DCE2_SMB_INVALID_SETUP_COUNT_STR  "SMB - invalid setup count for command"
+#define DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR \
+    "SMB - client attempted multiple dialect negotiations on session"
+#define DCE2_SMB_EVASIVE_FILE_ATTRS_STR \
+    "SMB - client attempted to create or set a file's attributes to readonly/hidden/system"
+#define DCE2_SMB_INVALID_FILE_OFFSET_STR \
+    "SMB - file offset provided is greater than file size specified"
+#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \
+    "SMB - next command specified in SMB2 header is beyond payload boundary"
+
 enum dce2SmbFingerprintPolicy
 {
     DCE2_SMB_FINGERPRINT_POLICY_NONE = 0,
index 12d2250abb4cd1f1fe73320f9747d9e3208ec079..26758cc2c6c91b8a43f4658e6fabbd6e35e66da6 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "dce_smb_paf.h"
 
-#include "dce_smb.h"
+#include "dce_smb_common.h"
 
 namespace
 {
@@ -45,8 +45,8 @@ using namespace snort;
  *          junk states, header type must be Session Message.
  *
  *********************************************************************/
-static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, const SmbNtHdr* nt_hdr,
-    uint32_t* nb_len)
+static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk,
+    const SmbNtHdr* nt_hdr, uint32_t* nb_len)
 {
     uint8_t type = (uint8_t)(nb_hdr >> 24);
     uint8_t bit = (uint8_t)((nb_hdr & 0x00ff0000) >> 16);
@@ -78,7 +78,7 @@ static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, cons
     //See [MS-SMB] 2.1 Transport. There is no such limit for SMB2 or SMB3
     if (smb_id == DCE2_SMB_ID)
     {
-        if ((bit != 0x00) && (bit != 0x01))
+        if ((bit != 0x00) and (bit != 0x01))
             return false;
     }
     nbs_hdr = htonl(nb_hdr);
@@ -106,8 +106,8 @@ static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, cons
  *          state 7 until this is the case.
  *
  *********************************************************************/
-static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8_t* data,
-    uint32_t len, uint32_t, uint32_t* fp)
+static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow,
+    const uint8_t* data, uint32_t len, uint32_t, uint32_t* fp)
 {
     uint32_t n = 0;
     StreamSplitter::Status ps = StreamSplitter::SEARCH;
index 8652394ae3b3b08ecbe21978acc6084936befd71..427da039e8161fbbb5aa246c4b6c3a1123d28fe0 100644 (file)
@@ -290,7 +290,7 @@ static DCE2_Ret DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData* ssd,
     dce2_move(param_ptr, param_len, pad);
 
     ssd->cur_rtracker->file_name =
-      DCE2_SmbGetFileName(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size);
+      get_smb_file_name(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size);
 
     return DCE2_RET__SUCCESS;
 }
@@ -958,7 +958,7 @@ static DCE2_Ret DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData* ssd,
     dce2_move(param_ptr, param_len, sizeof(SmbTrans2Open2ReqParams));
 
     ssd->cur_rtracker->file_name =
-      DCE2_SmbGetFileName(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_size);
+      get_smb_file_name(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_size);
 
     return DCE2_RET__SUCCESS;
 }
index db534f8062b7969025241fd4b3c8bc86f4880518..fe528acad841e20d19f06f0381246d6bb2480d37 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef DCE_SMB_TRANSACTION_UTILS_H
 #define DCE_SMB_TRANSACTION_UTILS_H
 
-#include "dce_smb.h"
+#include "dce_smb1.h"
 
 DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t* nb_ptr,
     uint32_t nb_len, uint16_t bcc, bool unicode);
index d253ee4b56ea9378d718b3360d11647385de1260..a5fab9775779309b0f94a6b26c2a362400fed369 100644 (file)
@@ -94,47 +94,6 @@ bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData* ssd, const uint16_t tid)
     return false;
 }
 
-// Extract file name from data. Supports ASCII and UTF-16LE.
-// Returns byte stream (ASCII or UTF-16LE with BOM)
-char* DCE2_SmbGetFileName(const uint8_t* data, uint32_t data_len, bool unicode,
-    uint16_t* file_name_len)
-{
-    const uint8_t inc = unicode ? 2 : 1;
-    if (data_len < inc)
-        return nullptr;
-
-    const uint32_t max_len =  unicode ? data_len - 1 : data_len;
-    // Move forward.  Don't know if the end of data is actually
-    // the end of the string.
-    uint32_t i;
-    for (i = 0; i < max_len; i += inc)
-    {
-        uint16_t uchar = unicode ? extract_16bits(data + i) : data[i];
-        if (uchar == 0)
-            break;
-    }
-
-    char* fname = nullptr;
-    const uint32_t real_len = i;
-
-    if (unicode)
-    {
-        fname = (char*)snort_calloc(real_len + UTF_16_LE_BOM_LEN + 2);
-        memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM
-        memcpy(fname + UTF_16_LE_BOM_LEN, data, real_len);
-        *file_name_len = real_len + UTF_16_LE_BOM_LEN;
-    }
-    else
-    {
-        fname = (char*)snort_alloc(real_len + 1);
-        memcpy(fname, data, real_len);
-        fname[real_len] = 0;
-        *file_name_len = real_len;
-    }
-
-    return fname;
-}
-
 int DCE2_SmbUidTidFidCompare(const void* a, const void* b)
 {
     int x = (int)(uintptr_t)a;
@@ -1797,9 +1756,10 @@ void DCE2_SmbProcessFileData(DCE2_SmbSsnData* ssd,
             }
             else if (ftracker->ff_file_offset < ftracker->ff_bytes_processed)
             {
-                debug_logf(dce_smb_trace, nullptr, "File offset %" PRIu64 " is "
-                    "less than bytes processed %" PRIu64 " - aborting.\n",
-                    ftracker->ff_file_offset, ftracker->ff_bytes_processed);
+                debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
+                    "File offset %" PRIu64 " is less than bytes processed %"
+                    PRIu64 " - aborting.\n", ftracker->ff_file_offset,
+                    ftracker->ff_bytes_processed);
 
                 DCE2_SmbAbortFileAPI(ssd);
                 DCE2_SmbSetNewFileAPIFileTracker(ssd);
index d9834a69aae32fb2568bff387c69e5e31f4732ae..4f947bf31a5f01d2703f883a7fa1766532f98e56 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef DCE_SMB_UTILS_H
 #define DCE_SMB_UTILS_H
 
-#include "dce_smb.h"
+#include "dce_smb1.h"
 #include "file_api/file_flows.h"
 
 /********************************************************************
@@ -125,7 +125,6 @@ inline bool DCE2_ComInfoCanProcessCommand(const DCE2_SmbComInfo* com_info)
  * Function prototypes
  ********************************************************************/
 bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData*, const uint16_t);
-char* DCE2_SmbGetFileName(const uint8_t *data, uint32_t data_len, bool unicode, uint16_t *file_name_len);
 int DCE2_SmbUidTidFidCompare(const void*, const void*);
 DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData*, const uint16_t);
 void DCE2_SmbInsertUid(DCE2_SmbSsnData*, const uint16_t);
@@ -178,6 +177,7 @@ void DCE2_SmbProcessFileData(DCE2_SmbSsnData* ssd,
     uint32_t data_len, bool upload);
 void DCE2_FileDetect();
 FileVerdict DCE2_get_file_verdict();
+void DCE2_SmbInitGlobals();
 void DCE2_SmbInitDeletePdu();
 void DCE2_Update_Ftracker_from_ReqTracker(DCE2_SmbFileTracker*, DCE2_SmbRequestTracker*);
 
index 7a1524640c3484bf097e48091789860dd9cc6dde..6942429e4b4d8db3a38413810050af119fef4c83 100644 (file)
@@ -27,5 +27,16 @@ to the DCE TCP inspector.
 
 The SMB inspector supports version 1 and version 2 of the protocol. 
 It processes relevant messages and inspects file transferred over this transport. 
-For SMBv2, it supports TCP as transport and it also supports 
-Multiple File transfer on single SMB2 connection.
+For SMBv2, it supports TCP as transport and it also supports multiple File transfer
+on single SMB2 connection.
+The SMB inspector implements base class for smb flow data,
+which all versions now inherits and implements. SMBv1 and SMBv2 code is completely
+segregated, maintaining common code in separate file to reduce redundancy.
+The common functionality used by both versions are in dce_smb_common files.
+SMBv2 specific trackers are in there own file now.
+
+The inspector eval function checks for the presence of SMB flow data in the flow,
+if not present, it creates an SMB flow data according to detected version, otherwise
+calls the respective process function.
+The process functions processes the commands according to respective versions and when
+file transfer is detected, it calls file_flow process().
\ No newline at end of file
index d8da1ca69e91c96270a2815633e1f564b3a10b44..31246362edf30b852845316c779ae6dcffd2dccd 100644 (file)
@@ -28,7 +28,6 @@
 #include "dce_smb_module.h"
 #include "dce_smb_paf.h"
 #include "dce_smb_transaction.h"
-#include "dce_smb2_utils.h"
 #include "detection/detect.h"
 #include "file_api/file_service.h"
 #include "main/snort_debug.h"
@@ -1032,6 +1031,8 @@ static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData* ssd, const SmbNt
 {
     int smb_com = SmbCom(smb_hdr);
 
+    if (smb_com < 0 or smb_com > 255) return nullptr;
+    
     debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
         "SMB command: %s (0x%02X)\n", get_smb_com_string(smb_com), smb_com);
 
@@ -1293,74 +1294,6 @@ void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd)
     }
 }
 
-Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(inspector_id)
-{
-    dce2_smb_stats.concurrent_sessions++;
-    if (dce2_smb_stats.max_concurrent_sessions < dce2_smb_stats.concurrent_sessions)
-        dce2_smb_stats.max_concurrent_sessions = dce2_smb_stats.concurrent_sessions;
-    smb_version = DCE2_SMB_VERSION_NULL;
-    dce2_smb_session_data = nullptr;
-    memory::MemoryCap::update_allocations(sizeof(*this));
-}
-
-Dce2SmbFlowData::~Dce2SmbFlowData()
-{
-    if (DCE2_SMB_VERSION_1 == smb_version)
-    {
-        DCE2_SmbDataFree((DCE2_SmbSsnData*)dce2_smb_session_data);
-        delete (DCE2_SmbSsnData*)dce2_smb_session_data;
-    }
-    else
-    {
-        DCE2_Smb2RemoveAllSession((DCE2_Smb2SsnData*)dce2_smb_session_data);
-        delete (DCE2_Smb2SsnData*)dce2_smb_session_data;
-        memory::MemoryCap::update_deallocations(sizeof(*(DCE2_Smb2SsnData*)dce2_smb_session_data));
-    }
-    assert(dce2_smb_stats.concurrent_sessions > 0);
-    dce2_smb_stats.concurrent_sessions--;
-    memory::MemoryCap::update_deallocations(sizeof(*this));
-}
-
-unsigned Dce2SmbFlowData::inspector_id = 0;
-
-static inline DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
-{
-    Dce2SmbFlowData* fd = new Dce2SmbFlowData;
-    fd->smb_version = DCE2_SMB_VERSION_1;
-    fd->dce2_smb_session_data = new DCE2_SmbSsnData();
-    p->flow->set_flow_data(fd);
-    return (DCE2_SmbSsnData*)(fd->dce2_smb_session_data);
-}
-
-DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config)
-{
-    DCE2_SmbSsnData* dce2_smb_sess = set_new_dce2_smb_session(p);
-    if ( dce2_smb_sess )
-    {
-        dce2_smb_sess->dialect_index = DCE2_SENTINEL;
-        dce2_smb_sess->max_outstanding_requests = 10;  // Until Negotiate/SessionSetupAndX
-        dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-        dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-        dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
-        dce2_smb_sess->uid = DCE2_SENTINEL;
-        dce2_smb_sess->tid = DCE2_SENTINEL;
-        dce2_smb_sess->ftracker.fid_v1 = DCE2_SENTINEL;
-        dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
-        dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
-
-        DCE2_ResetRopts(&dce2_smb_sess->sd, p);
-
-        dce2_smb_stats.smb_sessions++;
-
-        dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
-        dce2_smb_sess->sd.server_policy = config->common.policy;
-        dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
-        dce2_smb_sess->sd.config = (void*)config;
-    }
-
-    return dce2_smb_sess;
-}
-
 /********************************************************************
  * Function: DCE2_NbssHdrChecks()
  *
@@ -1622,14 +1555,13 @@ void DCE2_Smb1Process(DCE2_SmbSsnData* ssd)
                 {
                     // Upgrade connection to SMBv2
                     debug_log(dce_smb_trace, p, "upgrading to smb2 session\n");
-                    dce2SmbProtoConf* config = (dce2SmbProtoConf*)ssd->sd.config;
                     Dce2SmbFlowData* fd = (Dce2SmbFlowData*)p->flow->get_flow_data(
                         Dce2SmbFlowData::inspector_id);
-                    p->flow->free_flow_data(fd);
-                    DCE2_Smb2SsnData* dce2_smb2_sess = dce2_create_new_smb2_session(p, config);
-                    DCE2_Smb2Process(dce2_smb2_sess);
-                    if (!dce2_detected)
-                        DCE2_Detect(&dce2_smb2_sess->sd);
+                    if (fd)
+                    {
+                        Dce2SmbSessionData* dce2_smb2_sess = fd->upgrade(p);
+                        dce2_smb2_sess->process();
+                    }
                 }
                 else
                     ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
@@ -2554,49 +2486,3 @@ void DCE2_SmbInitGlobals()
     }
 }
 
-/* smb2 Functions */
-
-static inline DCE2_Smb2SsnData* set_new_dce2_smb2_session(Packet* p)
-{
-    Dce2SmbFlowData* fd = new Dce2SmbFlowData;
-    fd->smb_version = DCE2_SMB_VERSION_2;
-    fd->dce2_smb_session_data = new DCE2_Smb2SsnData();
-    memory::MemoryCap::update_allocations(sizeof(*(DCE2_Smb2SsnData*)(fd->dce2_smb_session_data)));
-    DCE2_Smb2InitData((DCE2_Smb2SsnData*)fd->dce2_smb_session_data);
-    p->flow->set_flow_data(fd);
-    return((DCE2_Smb2SsnData*)fd->dce2_smb_session_data);
-}
-
-DCE2_Smb2SsnData* dce2_create_new_smb2_session(Packet* p, dce2SmbProtoConf* config)
-{
-    DCE2_Smb2SsnData* dce2_smb2_sess = set_new_dce2_smb2_session(p);
-    if ( dce2_smb2_sess )
-    {
-        dce2_smb2_sess->sd.flags |= DCE2_SSN_FLAG__SMB2;
-        dce2_smb2_sess->dialect_index = DCE2_SENTINEL;
-
-        DCE2_ResetRopts(&dce2_smb2_sess->sd, p);
-
-        dce2_smb_stats.smb_sessions++;
-
-        dce2_smb2_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
-        dce2_smb2_sess->sd.server_policy = config->common.policy;
-        dce2_smb2_sess->sd.client_policy = DCE2_POLICY__WINXP;
-        dce2_smb2_sess->sd.config = (void*)config;
-        dce2_smb2_sess->max_outstanding_requests = DCE2_ScSmbMaxCredit(config);
-    }
-
-    return dce2_smb2_sess;
-}
-
-DCE2_SsnData* get_dce2_session_data(snort::Flow* flow)
-{
-    Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id);
-    if (fd and fd->dce2_smb_session_data)
-        return (fd->smb_version == DCE2_SMB_VERSION_1) ?
-               (DCE2_SsnData*)(&((DCE2_SmbSsnData*)fd->dce2_smb_session_data)->sd) :
-               (DCE2_SsnData*)(&((DCE2_Smb2SsnData*)fd->dce2_smb_session_data)->sd);
-    else
-        return nullptr;
-}
-
index 019e63f7da99e068034836210675bfa96f173cc8..0956b715805e9a29568b0fb7e74558f90960b7b0 100644 (file)
@@ -2190,10 +2190,7 @@ inline uint16_t SmbWriteAndCloseRespCount(const SmbWriteAndCloseResp* resp)
 
 #pragma pack()
 
-void DCE2_SmbInitGlobals();
 void DCE2_Smb1Process(struct DCE2_SmbSsnData*);
-struct DCE2_SmbSsnData* dce2_create_new_smb_session(snort::Packet*, struct dce2SmbProtoConf*);
-struct DCE2_Smb2SsnData* dce2_create_new_smb2_session(snort::Packet*, struct dce2SmbProtoConf*);
 void DCE2_SmbDataFree(DCE2_SmbSsnData*);
 
 #endif