]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #308 in SNORT/snort3 from dce to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 4 Mar 2016 15:55:39 +0000 (10:55 -0500)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 4 Mar 2016 15:55:39 +0000 (10:55 -0500)
Squashed commit of the following:

commit 6b30e2a5302afcca4f220f84a8ee022f1d7e4b6c
Author: rrp <rrp@cisco.com>
Date:   Thu Mar 3 09:09:13 2016 -0500

    Changes based on code-review comments

commit 8814f03f78443986d3179fd6962b350ef57d1086
Author: rrp <rrp@cisco.com>
Date:   Mon Feb 22 11:06:51 2016 -0500

    DCE over TCP support for single(non-fragmented) PDU packet processing.
    Tested with pcap with 4 DCE packets - Bind, Bind Ack, Request and Response. Verified that all packets get decoded and processed properly. Verified  debugs, counters(stats) and profile stats

17 files changed:
src/events/event_queue.h
src/service_inspectors/dce_rpc/dce_co.cc
src/service_inspectors/dce_rpc/dce_co.h
src/service_inspectors/dce_rpc/dce_common.cc
src/service_inspectors/dce_rpc/dce_common.h
src/service_inspectors/dce_rpc/dce_list.cc
src/service_inspectors/dce_rpc/dce_list.h
src/service_inspectors/dce_rpc/dce_smb.cc
src/service_inspectors/dce_rpc/dce_smb.h
src/service_inspectors/dce_rpc/dce_smb_module.cc
src/service_inspectors/dce_rpc/dce_smb_paf.cc
src/service_inspectors/dce_rpc/dce_tcp.cc
src/service_inspectors/dce_rpc/dce_tcp.h
src/service_inspectors/dce_rpc/dce_tcp_module.cc
src/service_inspectors/dce_rpc/dce_tcp_paf.cc
src/service_inspectors/dce_rpc/dce_utils.cc
src/service_inspectors/dce_rpc/dce_utils.h

index d35cb62f48851e8f2c242936e06175383e3d2bcb..0b4681f62bc3170b48c9a3f82d97f62dff44693b 100644 (file)
@@ -58,8 +58,8 @@ SO_PUBLIC int SnortEventqAdd(const struct OptTreeNode*);
 SO_PUBLIC int SnortEventqAdd(uint32_t gid, uint32_t sid, RuleType = RULE_TYPE__NONE);
 SO_PUBLIC bool event_is_enabled(uint32_t gid, uint32_t sid);
 
-void SnortEventqPush(void);
-void SnortEventqPop(void);
+SO_PUBLIC void SnortEventqPush(void);
+SO_PUBLIC void SnortEventqPop(void);
 
 #endif
 
index 46bd5fdc8e67db076d24d22a3da88360dfcfd6ee..f53043374772378f097f4fd19fe60ef747f116e5 100644 (file)
 // based on work by Todd Wease
 
 #include "dce_co.h"
+#include "dce_tcp.h"
+#include "dce_smb.h"
+#include "dce_list.h"
+#include "dce_utils.h"
+#include "profiler/profiler.h"
+#include "main/snort_debug.h"
+#include "log/messages.h"
+
+THREAD_LOCAL int co_reassembled = 0;
 
 /********************************************************************
  * Function: DCE2_CoInitTracker()
@@ -29,9 +38,9 @@
  * these fields have been set.
  *
  ********************************************************************/
-void DCE2_CoInitTracker(DCE2_CoTracker *cot)
+void DCE2_CoInitTracker(DCE2_CoTrackercot)
 {
-    if (cot == NULL)
+    if (cot == nullptr)
         return;
 
     cot->max_xmit_frag = DCE2_SENTINEL;
@@ -39,7 +48,7 @@ void DCE2_CoInitTracker(DCE2_CoTracker *cot)
     cot->ctx_id = DCE2_SENTINEL;
     cot->opnum = DCE2_SENTINEL;
     cot->call_id = DCE2_SENTINEL;
-    cot->stub_data = NULL;
+    cot->stub_data = nullptr;
     cot->got_bind = 0;
 
     cot->frag_tracker.opnum = DCE2_SENTINEL;
@@ -49,3 +58,1312 @@ void DCE2_CoInitTracker(DCE2_CoTracker *cot)
     cot->frag_tracker.expected_ctx_id = DCE2_SENTINEL;
 }
 
+/********************************************************************
+ * Function: DCE2_CoResetFragTracker()
+ *
+ * Resets frag tracker fields after having reassembled.
+ *
+ ********************************************************************/
+static inline void DCE2_CoResetFragTracker(DCE2_CoFragTracker* ft)
+{
+    if (ft == nullptr)
+        return;
+
+    ft->opnum = DCE2_SENTINEL;
+    ft->ctx_id = DCE2_SENTINEL;
+    ft->expected_call_id = DCE2_SENTINEL;
+    ft->expected_ctx_id = DCE2_SENTINEL;
+    ft->expected_opnum = DCE2_SENTINEL;
+}
+
+/********************************************************************
+ * Function: DCE2_CoResetTracker()
+ *
+ * Resets fields that are transient for requests after the bind or
+ * alter context.  The context id and opnum are dependent on the
+ * request and in the case of fragmented requests are set until all
+ * fragments are received.  If we got a full request or all of the
+ * fragments, these should be reset.
+ *
+ ********************************************************************/
+static inline void DCE2_CoResetTracker(DCE2_CoTracker* cot)
+{
+    if (cot == nullptr)
+        return;
+
+    cot->ctx_id = DCE2_SENTINEL;
+    cot->opnum = DCE2_SENTINEL;
+    cot->call_id = DCE2_SENTINEL;
+    cot->stub_data = nullptr;
+
+    DCE2_CoResetFragTracker(&cot->frag_tracker);
+}
+
+static inline bool DCE2_CoIsSegBuf(DCE2_SsnData* sd, DCE2_CoTracker* cot, const uint8_t* ptr)
+{
+    DCE2_Buffer* seg_buf;
+
+    if (DCE2_SsnFromServer(sd->wire_pkt))
+        seg_buf = cot->srv_seg.buf;
+    else
+        seg_buf = cot->cli_seg.buf;
+
+    if (DCE2_BufferIsEmpty(seg_buf))
+        return 0;
+
+    /* See if we're looking at a segmentation buffer */
+    if ((ptr < DCE2_BufferData(seg_buf)) ||
+        (ptr > (DCE2_BufferData(seg_buf) + DCE2_BufferLength(seg_buf))))
+    {
+        return 0;
+    }
+
+    return 1;
+}
+
+static inline DCE2_CoSeg* DCE2_CoGetSegPtr(DCE2_SsnData* sd, DCE2_CoTracker* cot)
+{
+    if (DCE2_SsnFromServer(sd->wire_pkt))
+        return &cot->srv_seg;
+
+    return &cot->cli_seg;
+}
+
+/********************************************************************
+ * Function: DCE2_CoSetIface()
+ *
+ * Sets the interface UUID for the rules options.  Looks in the
+ * context id list.  If nothing found there, it looks in the pending
+ * list (in case we never saw the server response because of
+ * missed packets) to see if something is there.
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_CoSetIface(DCE2_SsnData* sd, DCE2_CoTracker* cot, uint16_t ctx_id)
+{
+    DCE2_CoCtxIdNode* ctx_id_node;
+
+    /* This should be set if we've gotten a Bind */
+    if (cot->ctx_ids == nullptr)
+        return DCE2_RET__ERROR;
+    if (sd->trans == DCE2_TRANS_TYPE__TCP)
+    {
+        Profile profile(dce2_tcp_pstat_co_ctx);
+    }
+    else
+    {
+        Profile profile(dce2_smb_pstat_co_ctx);
+    }
+
+    ctx_id_node = (DCE2_CoCtxIdNode*)DCE2_ListFind(cot->ctx_ids, (void*)(uintptr_t)ctx_id);
+    if (ctx_id_node == nullptr)  /* context id not found in list */
+    {
+        /* See if it's in the queue.  An easy evasion would be to stagger the writes
+         * and reads such that we see a request before seeing the server bind ack */
+        if (cot->pending_ctx_ids != nullptr)
+        {
+            for (ctx_id_node = (DCE2_CoCtxIdNode*)DCE2_QueueFirst(cot->pending_ctx_ids);
+                ctx_id_node != nullptr;
+                ctx_id_node = (DCE2_CoCtxIdNode*)DCE2_QueueNext(cot->pending_ctx_ids))
+            {
+                if (ctx_id_node->ctx_id == ctx_id)
+                    break;
+            }
+        }
+
+        if (ctx_id_node == nullptr)
+        {
+            return DCE2_RET__ERROR;
+        }
+    }
+
+    if (ctx_id_node->state == DCE2_CO_CTX_STATE__REJECTED)
+    {
+        return DCE2_RET__ERROR;
+    }
+
+    DCE2_CopyUuid(&sd->ropts.iface, &ctx_id_node->iface, DCERPC_BO_FLAG__NONE);
+    sd->ropts.iface_vers_maj = ctx_id_node->iface_vers_maj;
+    sd->ropts.iface_vers_min = ctx_id_node->iface_vers_min;
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_CoSetRopts()
+ *
+ * Sets values necessary for the rule options.
+ *
+ ********************************************************************/
+static inline void DCE2_CoSetRopts(DCE2_SsnData* sd, DCE2_CoTracker* cot, const
+    DceRpcCoHdr* co_hdr)
+{
+    DCE2_CoFragTracker* ft = &cot->frag_tracker;
+    int opnum = (ft->opnum != DCE2_SENTINEL) ? ft->opnum : cot->opnum;
+    int ctx_id = (ft->ctx_id != DCE2_SENTINEL) ? ft->ctx_id : cot->ctx_id;
+
+    int data_byte_order =
+        (cot->data_byte_order != DCE2_SENTINEL) ?
+        cot->data_byte_order : (int)DceRpcCoByteOrder(co_hdr);
+
+    if (DCE2_CoSetIface(sd, cot, (uint16_t)ctx_id) != DCE2_RET__SUCCESS)
+        sd->ropts.first_frag = DCE2_SENTINEL;
+    else
+        sd->ropts.first_frag = DceRpcCoFirstFrag(co_hdr);
+
+    sd->ropts.hdr_byte_order = DceRpcCoByteOrder(co_hdr);
+    sd->ropts.data_byte_order = data_byte_order;
+    sd->ropts.opnum = opnum;
+    sd->ropts.stub_data = cot->stub_data;
+}
+
+static inline dce2CommonStats* dce_get_proto_stats_ptr(DCE2_SsnData* sd)
+{
+    if (sd->trans == DCE2_TRANS_TYPE__TCP)
+    {
+        return((dce2CommonStats*)&dce2_tcp_stats);
+    }
+    else
+    {
+        return((dce2CommonStats*)&dce2_smb_stats);
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_CoHdrChecks()
+ *
+ * Checks some relevant fields in the header to make sure they're
+ * sane.
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_CoHdrChecks(DCE2_SsnData* sd, DCE2_CoTracker* cot, const DceRpcCoHdr* co_hdr)
+{
+    uint16_t frag_len = DceRpcCoFragLen(co_hdr);
+    DceRpcPduType pdu_type = DceRpcCoPduType(co_hdr);
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (frag_len < sizeof(DceRpcCoHdr))
+    {
+        /* Assume we autodetected incorrectly or that DCE/RPC is not running
+         * over the SMB named pipe */
+        if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+        {
+            //FIXIT-M add segment check
+            dce_alert(GID_DCE2, DCE2_CO_FRAG_LEN_LT_HDR,dce_common_stats);
+        }
+
+        return DCE2_RET__ERROR;
+    }
+
+    if (DceRpcCoVersMaj(co_hdr) != DCERPC_PROTO_MAJOR_VERS__5)
+    {
+        if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+        {
+            //FIXIT-M add segment check
+            dce_alert(GID_DCE2, DCE2_CO_BAD_MAJOR_VERSION,dce_common_stats);
+        }
+
+        return DCE2_RET__ERROR;
+    }
+
+    if (DceRpcCoVersMin(co_hdr) != DCERPC_PROTO_MINOR_VERS__0)
+    {
+        if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+        {
+            //FIXIT-M add segment check
+            dce_alert(GID_DCE2, DCE2_CO_BAD_MINOR_VERSION,dce_common_stats);
+        }
+
+        return DCE2_RET__ERROR;
+    }
+    if (pdu_type >= DCERPC_PDU_TYPE__MAX)
+    {
+        if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+        {
+            //FIXIT-M add segment check
+
+            dce_alert(GID_DCE2, DCE2_CO_BAD_PDU_TYPE,dce_common_stats);
+        }
+
+        return DCE2_RET__ERROR;
+    }
+
+    if (DCE2_SsnFromClient(sd->wire_pkt) && (cot->max_xmit_frag != DCE2_SENTINEL))
+    {
+        if (frag_len > cot->max_xmit_frag)
+        {
+            //FIXIT-M add segment check
+            dce_alert(GID_DCE2, DCE2_CO_FRAG_GT_MAX_XMIT_FRAG,dce_common_stats);
+        }
+        else if (!DceRpcCoLastFrag(co_hdr) && (pdu_type == DCERPC_PDU_TYPE__REQUEST)
+            && ((((int)cot->max_xmit_frag - DCE2_MAX_XMIT_SIZE_FUZZ) < 0)
+            || ((int)frag_len < ((int)cot->max_xmit_frag - DCE2_MAX_XMIT_SIZE_FUZZ))))
+        {
+            /* If client needs to fragment the DCE/RPC request, it shouldn't be less than the
+             * maximum xmit size negotiated. Only if it's not a last fragment. Make this alert
+             * only if it is considerably less - have seen legitimate fragments that are just
+             * slightly less the negotiated fragment size. */
+
+            //FIXIT-M add segment check
+            dce_alert(GID_DCE2, DCE2_CO_FRAG_LT_MAX_XMIT_FRAG,dce_common_stats);
+        }
+
+        /* Continue processing */
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_CoCtxCompare()
+ *
+ * Callback to context id list for finding the right interface
+ * UUID node.  Values passed in are context ids which are used as
+ * the keys for the list.
+ *
+ ********************************************************************/
+static int DCE2_CoCtxCompare(const void* a, const void* b)
+{
+    int x = (int)(uintptr_t)a;
+    int y = (int)(uintptr_t)b;
+
+    if (x == y)
+        return 0;
+
+    /* Only care about equality for finding */
+    return -1;
+}
+
+/********************************************************************
+ * Function: DCE2_CoCtxFree()
+ *
+ * Callback to context id list for freeing context id nodes in
+ * the list.
+ *
+ ********************************************************************/
+static void DCE2_CoCtxFree(void* data)
+{
+    if (data == nullptr)
+        return;
+
+    free(data);
+}
+
+/********************************************************************
+ * Function: DCE2_CoInitCtxStorage()
+ *
+ * Allocates, if necessary, and initializes the context id list
+ * and the context id pending queue.
+ *
+ *
+ ********************************************************************/
+static inline DCE2_Ret DCE2_CoInitCtxStorage(DCE2_CoTracker* cot)
+{
+    if (cot == nullptr)
+        return DCE2_RET__ERROR;
+
+    if (cot->ctx_ids == nullptr)
+    {
+        cot->ctx_ids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_CoCtxCompare, DCE2_CoCtxFree,
+            nullptr, DCE2_LIST_FLAG__NO_DUPS);
+        if (cot->ctx_ids == nullptr)
+            return DCE2_RET__ERROR;
+    }
+
+    if (cot->pending_ctx_ids == nullptr)
+    {
+        cot->pending_ctx_ids = DCE2_QueueNew(DCE2_CoCtxFree);
+        if (cot->pending_ctx_ids == nullptr)
+        {
+            DCE2_ListDestroy(cot->ctx_ids);
+            cot->ctx_ids = nullptr;
+            return DCE2_RET__ERROR;
+        }
+    }
+    else if (!DCE2_QueueIsEmpty(cot->pending_ctx_ids))
+    {
+        DCE2_QueueEmpty(cot->pending_ctx_ids);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_CoEraseCtxIds()
+ *
+ * Empties out the context id list and the pending context id
+ * queue.  Does not free the list and queue - might need to still
+ * use them.
+ *
+ ********************************************************************/
+static inline void DCE2_CoEraseCtxIds(DCE2_CoTracker* cot)
+{
+    if (cot == nullptr)
+        return;
+
+    DCE2_QueueEmpty(cot->pending_ctx_ids);
+    DCE2_ListEmpty(cot->ctx_ids);
+}
+
+DCE2_CoCtxIdNode* dce_process_ctx_id(DCE2_SsnData* sd,DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr,DCE2_Policy policy,
+    const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DCE2_CoCtxIdNode* ctx_node;
+    DCE2_Ret status;
+    uint16_t ctx_id;
+    uint8_t num_tsyns;
+    const Uuid* iface;
+    uint16_t if_vers_maj;
+    uint16_t if_vers_min;
+    DceRpcCoContElem* ctx_elem = (DceRpcCoContElem*)frag_ptr;
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    int j;
+
+    if (frag_len < sizeof(DceRpcCoContElem))
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE, dce_common_stats);
+        return nullptr;
+    }
+
+    ctx_id = DceRpcCoContElemCtxId(co_hdr, ctx_elem);
+    num_tsyns = DceRpcCoContElemNumTransSyntaxes(ctx_elem);
+    iface = DceRpcCoContElemIface(ctx_elem);
+    if_vers_maj = DceRpcCoContElemIfaceVersMaj(co_hdr, ctx_elem);
+    if_vers_min = DceRpcCoContElemIfaceVersMin(co_hdr, ctx_elem);
+
+    /* No transfer syntaxes */
+    if (num_tsyns == 0)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_NO_TFER_SYNTAX_SPECFD,dce_common_stats);
+        return nullptr;
+    }
+
+    DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoContElem));
+
+    /* Don't really care about the transfer syntaxes */
+    for (j = 0; j < num_tsyns; j++)
+    {
+        if (frag_len < sizeof(DceRpcCoSynId))
+        {
+            dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE, dce_common_stats);
+            return nullptr;
+        }
+
+        DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoSynId));
+    }
+    if (sd->trans == DCE2_TRANS_TYPE__TCP)
+    {
+        Profile profile(dce2_tcp_pstat_co_ctx);
+    }
+    else
+    {
+        Profile profile(dce2_smb_pstat_co_ctx);
+    }
+
+    /* If there is already an accepted node with in the list
+     * with this ctx, just return */
+    if (policy == DCE2_POLICY__SAMBA_3_0_20)
+    {
+        ctx_node = (DCE2_CoCtxIdNode*)DCE2_ListFind(cot->ctx_ids, (void*)(uintptr_t)ctx_id);
+        if ((ctx_node != nullptr) && (ctx_node->state != DCE2_CO_CTX_STATE__REJECTED))
+        {
+            return nullptr;
+        }
+    }
+
+    ctx_node = (DCE2_CoCtxIdNode*)calloc(sizeof(DCE2_CoCtxIdNode),1);
+    if (ctx_node == nullptr)
+    {
+        return nullptr;
+    }
+
+    /* Add context id to pending queue */
+    status = DCE2_QueueEnqueue(cot->pending_ctx_ids, ctx_node);
+    if (status != DCE2_RET__SUCCESS)
+    {
+        free(ctx_node);
+        return nullptr;
+    }
+
+    /* This node will get moved to the context id list upon server response */
+    ctx_node->ctx_id = ctx_id;
+    DCE2_CopyUuid(&ctx_node->iface, iface, DceRpcCoByteOrder(co_hdr));
+    ctx_node->iface_vers_maj = if_vers_maj;
+    ctx_node->iface_vers_min = if_vers_min;
+    ctx_node->state = DCE2_CO_CTX_STATE__PENDING;
+    return ctx_node;
+}
+
+/********************************************************************
+ * Function: DCE2_CoCtxReq()
+ *
+ * Handles parsing the context id list out of the packet.
+ * Context ids and associated uuids are stored in a queue and
+ * dequeued upon server response.  Server response doesn't
+ * indicate by context id which bindings were accepted or
+ * rejected, but the index or order they were in in the client
+ * bind or alter context, hence the queue.
+ *
+ ********************************************************************/
+static void DCE2_CoCtxReq(DCE2_SsnData* sd, DCE2_CoTracker* cot, const DceRpcCoHdr* co_hdr,
+    const uint8_t num_ctx_items, const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+    unsigned int i;
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (num_ctx_items == 0)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_NO_CTX_ITEMS_SPECFD, dce_common_stats);
+        return;
+    }
+
+    for (i = 0; i < num_ctx_items; i++)
+    {
+        DCE2_CoCtxIdNode* ctx_node;
+
+        ctx_node = dce_process_ctx_id(sd,cot,co_hdr,policy,frag_ptr,frag_len);
+        if ((ctx_node == nullptr))
+        {
+            return;
+        }
+
+        DebugFormat(DEBUG_DCE_COMMON, "Added Context item to queue.\n"
+            " Context id: %u\n"
+            " Interface: %s\n"
+            " Interface major version: %u\n"
+            " Interface minor version: %u\n",
+            ctx_node->ctx_id,
+            DCE2_UuidToStr(&ctx_node->iface, DCERPC_BO_FLAG__NONE),
+            ctx_node->iface_vers_maj, ctx_node->iface_vers_min);
+
+        switch (policy)
+        {
+        case DCE2_POLICY__SAMBA:
+        case DCE2_POLICY__SAMBA_3_0_37:
+        case DCE2_POLICY__SAMBA_3_0_22:
+        case DCE2_POLICY__SAMBA_3_0_20:
+            /* Samba only ever looks at one context item.  Not sure
+             * if this is an alertable offense */
+            return;
+
+        default:
+            break;
+        }
+    }
+}
+
+void dce_process_ctx_result(DCE2_SsnData* sd,DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr,DCE2_Policy policy,
+    uint16_t result)
+{
+    DCE2_CoCtxIdNode* ctx_node, * existing_ctx_node;
+    DCE2_Ret status;
+
+    if (sd->trans == DCE2_TRANS_TYPE__TCP)
+    {
+        Profile profile(dce2_tcp_pstat_co_ctx);
+    }
+    else
+    {
+        Profile profile(dce2_smb_pstat_co_ctx);
+    }
+
+    /* Dequeue context item in pending queue - this will get put in the permanent
+     * context id list or free'd */
+    ctx_node = (DCE2_CoCtxIdNode*)DCE2_QueueDequeue(cot->pending_ctx_ids);
+    if (ctx_node == nullptr)
+    {
+        LogMessage("%s(%d) Failed to dequeue a context id node.\n",
+            __FILE__, __LINE__);
+        return;
+    }
+
+    DebugFormat(DEBUG_DCE_COMMON, "Adding Context item to context item list.\n"
+        " Context id: %u\n"
+        " Interface: %s\n"
+        " Interface major version: %u\n"
+        " Interface minor version: %u\n",
+        ctx_node->ctx_id,
+        DCE2_UuidToStr(&ctx_node->iface, DCERPC_BO_FLAG__NONE),
+        ctx_node->iface_vers_maj, ctx_node->iface_vers_min);
+
+    if (result == DCERPC_CO_CONT_DEF_RESULT__ACCEPTANCE)
+    {
+        DebugMessage(DEBUG_DCE_COMMON, "Server accepted context item.\n");
+        ctx_node->state = DCE2_CO_CTX_STATE__ACCEPTED;
+        if (DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)
+            cot->got_bind = 1;
+    }
+    else
+    {
+        DebugMessage(DEBUG_DCE_COMMON, "Server rejected context item.\n");
+        ctx_node->state = DCE2_CO_CTX_STATE__REJECTED;
+        cot->got_bind = 0;
+    }
+
+    existing_ctx_node =
+        (DCE2_CoCtxIdNode*)DCE2_ListFind(cot->ctx_ids, (void*)(uintptr_t)ctx_node->ctx_id);
+
+    if (existing_ctx_node != nullptr)
+    {
+        switch (policy)
+        {
+        case DCE2_POLICY__WIN2000:
+        case DCE2_POLICY__WIN2003:
+        case DCE2_POLICY__WINXP:
+        case DCE2_POLICY__WINVISTA:
+        case DCE2_POLICY__WIN2008:
+        case DCE2_POLICY__WIN7:
+            if (ctx_node->state == DCE2_CO_CTX_STATE__REJECTED)
+                break;
+
+            if (existing_ctx_node->state == DCE2_CO_CTX_STATE__REJECTED)
+            {
+                existing_ctx_node->ctx_id = ctx_node->ctx_id;
+                DCE2_CopyUuid(&existing_ctx_node->iface, &ctx_node->iface, DCERPC_BO_FLAG__NONE);
+                existing_ctx_node->iface_vers_maj = ctx_node->iface_vers_maj;
+                existing_ctx_node->iface_vers_min = ctx_node->iface_vers_min;
+                existing_ctx_node->state = ctx_node->state;
+            }
+
+            break;
+
+        case DCE2_POLICY__SAMBA:
+        case DCE2_POLICY__SAMBA_3_0_37:
+        case DCE2_POLICY__SAMBA_3_0_22:
+        case DCE2_POLICY__SAMBA_3_0_20:
+            /* Samba actually alters the context.  Windows keeps the old */
+            if (ctx_node->state != DCE2_CO_CTX_STATE__REJECTED)
+            {
+                existing_ctx_node->ctx_id = ctx_node->ctx_id;
+                DCE2_CopyUuid(&existing_ctx_node->iface, &ctx_node->iface, DCERPC_BO_FLAG__NONE);
+                existing_ctx_node->iface_vers_maj = ctx_node->iface_vers_maj;
+                existing_ctx_node->iface_vers_min = ctx_node->iface_vers_min;
+                existing_ctx_node->state = ctx_node->state;
+            }
+
+            break;
+
+        default:
+            break;
+        }
+
+        free((void*)ctx_node);
+    }
+    else
+    {
+        status = DCE2_ListInsert(cot->ctx_ids, (void*)(uintptr_t)ctx_node->ctx_id,
+            (void*)ctx_node);
+        if (status != DCE2_RET__SUCCESS)
+        {
+            free((void*)ctx_node);
+            DebugMessage(DEBUG_DCE_COMMON,
+                "Failed to add context id node to list.\n");
+            return;
+        }
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_CoBindAck()
+ *
+ * Handles the processing of a server bind ack or a server alter
+ * context response since they share the same header.
+ * Moves context id items from the pending queue into a list
+ * ultimately used by the rule options and sets each context item
+ * as accepted or rejected based on the server response.
+ *
+ ********************************************************************/
+static void DCE2_CoBindAck(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr, const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+    DceRpcCoBindAck* bind_ack = (DceRpcCoBindAck*)frag_ptr;
+    uint16_t sec_addr_len;
+    const uint8_t* ctx_data;
+    uint16_t ctx_len;
+    uint16_t pad = 0;
+    DceRpcCoContResultList* ctx_list;
+    uint8_t num_ctx_results;
+    unsigned int i;
+    uint16_t max_recv_frag;
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (frag_len < sizeof(DceRpcCoBindAck))
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoBindAck));
+
+    /* Set what should be the maximum amount of data a client can send in a fragment */
+    max_recv_frag = DceRpcCoBindAckMaxRecvFrag(co_hdr, bind_ack);
+    if ((cot->max_xmit_frag == DCE2_SENTINEL) || (max_recv_frag < cot->max_xmit_frag))
+        cot->max_xmit_frag = (int)max_recv_frag;
+
+    sec_addr_len = DceRpcCoSecAddrLen(co_hdr, bind_ack);
+
+    ctx_data = frag_ptr;
+    ctx_len = frag_len;
+
+    /* First move past secondary address */
+    if (ctx_len < sec_addr_len)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    DCE2_MOVE(ctx_data, ctx_len, sec_addr_len);
+
+    /* padded to 4 octet */
+    if ((sizeof(DceRpcCoBindAck) + sec_addr_len) & 3)
+        pad = (4 - ((sizeof(DceRpcCoBindAck) + sec_addr_len) & 3));
+
+    if (ctx_len < pad)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    DCE2_MOVE(ctx_data, ctx_len, pad);
+
+    /* Now we're at the start of the context item results */
+    if (ctx_len < sizeof(DceRpcCoContResultList))
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    ctx_list = (DceRpcCoContResultList*)ctx_data;
+    num_ctx_results = DceRpcCoContNumResults(ctx_list);
+
+    DCE2_MOVE(ctx_data, ctx_len, sizeof(DceRpcCoContResultList));
+
+    for (i = 0; i < num_ctx_results; i++)
+    {
+        DceRpcCoContResult* ctx_result;
+        uint16_t result;
+
+        if (ctx_len < sizeof(DceRpcCoContResult))
+        {
+            dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+            return;
+        }
+        ctx_result = (DceRpcCoContResult*)ctx_data;
+        result = DceRpcCoContRes(co_hdr, ctx_result);
+
+        DCE2_MOVE(ctx_data, ctx_len, sizeof(DceRpcCoContResult));
+
+        if (DCE2_QueueIsEmpty(cot->pending_ctx_ids))
+            return;
+
+        dce_process_ctx_result(sd,cot,co_hdr,policy,result);
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_CoBind()
+ *
+ * Handles the processing of a client bind request.  There are
+ * differences between Windows and Samba and even early Samba in
+ * how multiple binds on the session are handled.  Processing of
+ * the context id bindings is handed off.
+ *
+ ********************************************************************/
+static void DCE2_CoBind(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr, const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+    DceRpcCoBind* bind = (DceRpcCoBind*)frag_ptr;
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (frag_len < sizeof(DceRpcCoBind))
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoBind));
+
+    switch (policy)
+    {
+    case DCE2_POLICY__WIN2000:
+    case DCE2_POLICY__WIN2003:
+    case DCE2_POLICY__WINXP:
+    case DCE2_POLICY__WINVISTA:
+    case DCE2_POLICY__WIN2008:
+    case DCE2_POLICY__WIN7:
+        /* Windows will not accept more than one bind */
+        if (!DCE2_ListIsEmpty(cot->ctx_ids))
+        {
+            /* Delete context id list if anything there */
+            DCE2_CoEraseCtxIds(cot);
+            return;
+        }
+
+        /* Byte order of stub data will be that of the bind */
+        cot->data_byte_order = DceRpcCoByteOrder(co_hdr);
+
+        break;
+
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+        if (cot->got_bind)
+            return;
+
+        break;
+
+    case DCE2_POLICY__SAMBA_3_0_20:
+        /* Accepts multiple binds */
+        break;
+
+    default:
+        LogMessage("%s(%d) Invalid policy: %d\n",
+            __FILE__, __LINE__, policy);
+        return;
+    }
+
+    cot->max_xmit_frag = (int)DceRpcCoBindMaxXmitFrag(co_hdr, bind);
+    DCE2_CoCtxReq(sd, cot, co_hdr, DceRpcCoNumCtxItems(bind), frag_ptr, frag_len);
+}
+
+/********************************************************************
+ * Function: DCE2_CoAlterCtx()
+ *
+ * Handles the processing of a client alter context request.
+ * Again, differences in how this is handled - whether we've seen
+ * a bind yet or not, altering the data byte order.  Processing
+ * of the context id bindings is handed off.
+ *
+ ********************************************************************/
+static void DCE2_CoAlterCtx(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr, const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+    DceRpcCoAltCtx* alt_ctx = (DceRpcCoAltCtx*)frag_ptr;
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (frag_len < sizeof(DceRpcCoAltCtx))
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoAltCtx));
+
+    switch (policy)
+    {
+    case DCE2_POLICY__WIN2000:
+    case DCE2_POLICY__WIN2003:
+    case DCE2_POLICY__WINXP:
+    case DCE2_POLICY__WINVISTA:
+    case DCE2_POLICY__WIN2008:
+    case DCE2_POLICY__WIN7:
+        /* Windows will not accept an alter context before
+         * bind and will bind_nak it */
+        if (DCE2_ListIsEmpty(cot->ctx_ids))
+            return;
+
+        if (cot->data_byte_order != (int)DceRpcCoByteOrder(co_hdr))
+        {
+            /* This is anomalous behavior.  Alert, but continue processing */
+            if (cot->data_byte_order != DCE2_SENTINEL)
+                dce_alert(GID_DCE2, DCE2_CO_ALTER_CHANGE_BYTE_ORDER,dce_common_stats);
+        }
+
+        break;
+
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+    case DCE2_POLICY__SAMBA_3_0_20:
+        /* Nothing for Samba */
+        break;
+
+    default:
+        LogMessage("%s(%d) Invalid policy: %d\n",
+            __FILE__, __LINE__, policy);
+        break;
+    }
+
+    /* Alter context is typedef'ed as a bind */
+    DCE2_CoCtxReq(sd, cot, co_hdr, DceRpcCoNumCtxItems((DceRpcCoBind*)alt_ctx), frag_ptr,
+        frag_len);
+}
+
+static int DCE2_CoGetAuthLen(DCE2_SsnData* sd, const DceRpcCoHdr* co_hdr,
+    const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DceRpcCoAuthVerifier* auth_hdr;
+    uint16_t auth_len = DceRpcCoAuthLen(co_hdr);
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (auth_len == 0)
+        return 0;
+
+    auth_len += sizeof(DceRpcCoAuthVerifier);
+
+    /* This means the auth len was bogus */
+    if (auth_len > frag_len)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return -1;
+    }
+
+    auth_hdr = (DceRpcCoAuthVerifier*)(frag_ptr + (frag_len - auth_len));
+    if (DceRpcCoAuthLevel(auth_hdr) == DCERPC_CO_AUTH_LEVEL__PKT_PRIVACY)
+    {
+        /* Data is encrypted - don't inspect */
+        return -1;
+    }
+
+    auth_len += DceRpcCoAuthPad(auth_hdr);
+
+    /* This means the auth pad len was bogus */
+    if (auth_len > frag_len)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return -1;
+    }
+
+    return (int)auth_len;
+}
+
+/********************************************************************
+ * Function: DCE2_CoRequest()
+ *
+ * Handles a DCE/RPC request from the client.  This is were the
+ * client actually asks the server to do stuff on it's behalf.
+ * If it's a first/last fragment, set relevant rule option
+ * data and return. If it's a true fragment, do some target
+ * based futzing to set the right opnum and context id for
+ * the to be reassembled packet.
+ *
+ *
+ ********************************************************************/
+static void DCE2_CoRequest(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr, const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DceRpcCoRequest* rhdr = (DceRpcCoRequest*)frag_ptr;
+    uint16_t req_size = sizeof(DceRpcCoRequest);
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    /* Account for possible object uuid */
+    if (DceRpcCoObjectFlag(co_hdr))
+        req_size += sizeof(Uuid);
+
+    if (frag_len < req_size)
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+        return;
+    }
+
+    switch (policy)
+    {
+    /* After 3.0.37 up to 3.5.2 byte order of stub data is always
+     * interpreted as little endian */
+    case DCE2_POLICY__SAMBA:
+        cot->data_byte_order = DCERPC_BO_FLAG__LITTLE_ENDIAN;
+        break;
+
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+    case DCE2_POLICY__SAMBA_3_0_20:
+        cot->data_byte_order = DceRpcCoByteOrder(co_hdr);
+        break;
+
+    default:
+        break;
+    }
+
+    /* Move past header */
+    DCE2_MOVE(frag_ptr, frag_len, req_size);
+
+    //FIXIT-M frag stuff
+
+    cot->stub_data = frag_ptr;
+    cot->opnum = DceRpcCoOpnum(co_hdr, rhdr);
+    cot->ctx_id = DceRpcCoCtxId(co_hdr, rhdr);
+    cot->call_id = DceRpcCoCallId(co_hdr);
+
+    if (DceRpcCoFirstFrag(co_hdr) && DceRpcCoLastFrag(co_hdr))
+    {
+        int auth_len = DCE2_CoGetAuthLen(sd, co_hdr, frag_ptr, frag_len);
+        DebugMessage(DEBUG_DCE_COMMON, "First and last fragment.\n");
+        if (auth_len == -1)
+            return;
+        DCE2_CoSetRopts(sd, cot, co_hdr);
+    }
+    else
+    {
+        //FIXIT-M frag stuff
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_CoResponse()
+ *
+ * Handles a DCE/RPC response from the server.
+ * Samba responds to SMB bind write, request write before read with
+ * a response to the request and doesn't send a bind ack.  Get the
+ * context id from the pending context id list and put in stable
+ * list.
+ *
+
+ ********************************************************************/
+static void DCE2_CoResponse(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const DceRpcCoHdr* co_hdr, const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    DceRpcCoResponse* rhdr = (DceRpcCoResponse*)frag_ptr;
+    uint16_t ctx_id;
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    if (frag_len < sizeof(DceRpcCoResponse))
+    {
+        dce_alert(GID_DCE2, DCE2_CO_REM_FRAG_LEN_LT_SIZE,dce_common_stats);
+
+        return;
+    }
+
+    switch (policy)
+    {
+    case DCE2_POLICY__SAMBA:
+        cot->data_byte_order = DCERPC_BO_FLAG__LITTLE_ENDIAN;
+        break;
+
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+    case DCE2_POLICY__SAMBA_3_0_20:
+        cot->data_byte_order = DceRpcCoByteOrder(co_hdr);
+        break;
+
+    default:
+        break;
+    }
+
+    ctx_id = DceRpcCoCtxIdResp(co_hdr, rhdr);
+
+    /* If pending queue is not empty, add this context id as accepted and all
+     * others as pending */
+    while (!DCE2_QueueIsEmpty(cot->pending_ctx_ids))
+    {
+        DCE2_Ret status;
+        DCE2_CoCtxIdNode* ctx_node = (DCE2_CoCtxIdNode*)DCE2_QueueDequeue(cot->pending_ctx_ids);
+
+        if (ctx_node == nullptr)
+        {
+            LogMessage("%s(%d) Failed to dequeue a context id node.\n",
+                __FILE__, __LINE__);
+            return;
+        }
+
+        if (ctx_node->ctx_id == ctx_id)
+            ctx_node->state = DCE2_CO_CTX_STATE__ACCEPTED;
+
+        status = DCE2_ListInsert(cot->ctx_ids, (void*)(uintptr_t)ctx_node->ctx_id,
+            (void*)ctx_node);
+        if (status != DCE2_RET__SUCCESS)
+        {
+            /* Might be a duplicate in there already.  If there is we would have used it
+             * anyway before looking at the pending queue.  Just get rid of it */
+            free((void*)ctx_node);
+            return;
+        }
+    }
+
+    /* Move past header */
+    DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoResponse));
+
+    //FIXIT-M frag stuff
+
+    cot->stub_data = frag_ptr;
+    /* Opnum not in response header - have to use previous client's */
+    cot->ctx_id = ctx_id;
+    cot->call_id = DceRpcCoCallId(co_hdr);
+
+    if (DceRpcCoFirstFrag(co_hdr) && DceRpcCoLastFrag(co_hdr))
+    {
+        int auth_len = DCE2_CoGetAuthLen(sd, co_hdr, frag_ptr, frag_len);
+        DebugMessage(DEBUG_DCE_COMMON, "First and last fragment.\n");
+        if (auth_len == -1)
+            return;
+        DCE2_CoSetRopts(sd, cot, co_hdr);
+    }
+    else
+    {
+        /* FIXIT-M frag stuff */
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_CoDecode()
+ *
+ * Main processing for the DCE/RPC pdu types.  Most are not
+ * implemented as, currently, they are not necessary and only
+ * stats are kept for them.  Important are the bind, alter context
+ * and request.
+ *
+ ********************************************************************/
+static void DCE2_CoDecode(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const uint8_t* frag_ptr, uint16_t frag_len)
+{
+    /* Already checked that we have enough data for header */
+    const DceRpcCoHdr* co_hdr = (DceRpcCoHdr*)frag_ptr;
+    int pdu_type = DceRpcCoPduType(co_hdr);
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    /* We've got the main header.  Move past it to the
+     * start of the pdu */
+    DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoHdr));
+
+    DebugMessage(DEBUG_DCE_COMMON, "PDU type: ");
+
+    /* Client specific pdu types - some overlap with server */
+    if (DCE2_SsnFromClient(sd->wire_pkt))
+    {
+        switch (pdu_type)
+        {
+        case DCERPC_PDU_TYPE__BIND:
+            DebugMessage(DEBUG_DCE_COMMON, "Bind\n");
+            dce_common_stats->co_bind++;
+
+            /* Make sure context id list and queue are initialized */
+            if (DCE2_CoInitCtxStorage(cot) != DCE2_RET__SUCCESS)
+                return;
+
+            DCE2_CoBind(sd, cot, co_hdr, frag_ptr, frag_len);
+
+            break;
+
+        case DCERPC_PDU_TYPE__ALTER_CONTEXT:
+            DebugMessage(DEBUG_DCE_COMMON, "Alter Context\n");
+            dce_common_stats->co_alter_ctx++;
+
+            if (DCE2_CoInitCtxStorage(cot) != DCE2_RET__SUCCESS)
+                return;
+
+            DCE2_CoAlterCtx(sd, cot, co_hdr, frag_ptr, frag_len);
+
+            break;
+
+        case DCERPC_PDU_TYPE__REQUEST:
+            DebugMessage(DEBUG_DCE_COMMON, "Request\n");
+            dce_common_stats->co_request++;
+
+            if (DCE2_ListIsEmpty(cot->ctx_ids) &&
+                DCE2_QueueIsEmpty(cot->pending_ctx_ids))
+            {
+                return;
+            }
+
+            DCE2_CoRequest(sd, cot, co_hdr, frag_ptr, frag_len);
+
+            break;
+
+        case DCERPC_PDU_TYPE__AUTH3:
+            DebugMessage(DEBUG_DCE_COMMON, "Auth3\n");
+            dce_common_stats->co_auth3++;
+            break;
+
+        case DCERPC_PDU_TYPE__CO_CANCEL:
+            DebugMessage(DEBUG_DCE_COMMON, "Cancel\n");
+            dce_common_stats->co_cancel++;
+            break;
+
+        case DCERPC_PDU_TYPE__ORPHANED:
+            DebugMessage(DEBUG_DCE_COMMON, "Orphaned\n");
+            dce_common_stats->co_orphaned++;
+            break;
+
+        case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP:
+            DebugMessage(DEBUG_DCE_COMMON, "Microsoft Request To Send RPC over HTTP\n");
+            dce_common_stats->co_ms_pdu++;
+            break;
+
+        default:
+            DebugFormat(DEBUG_DCE_COMMON, "Unknown (0x%02x)\n", pdu_type);
+            dce_common_stats->co_other_req++;
+            break;
+        }
+    }
+    else
+    {
+        switch (pdu_type)
+        {
+        case DCERPC_PDU_TYPE__BIND_ACK:
+        case DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP:
+            if (pdu_type == DCERPC_PDU_TYPE__BIND_ACK)
+            {
+                DebugMessage(DEBUG_DCE_COMMON, "Bind Ack\n");
+                dce_common_stats->co_bind_ack++;
+            }
+            else
+            {
+                DebugMessage(DEBUG_DCE_COMMON, "Alter Context Response\n");
+                dce_common_stats->co_alter_ctx_resp++;
+            }
+
+            if (DCE2_QueueIsEmpty(cot->pending_ctx_ids))
+                return;
+
+            /* Bind ack and alter context response have the same
+             * header structure, just different pdu type */
+            DCE2_CoBindAck(sd, cot, co_hdr, frag_ptr, frag_len);
+
+            /* Got the bind/alter response - clear out the pending queue */
+            DCE2_QueueEmpty(cot->pending_ctx_ids);
+
+            break;
+
+        case DCERPC_PDU_TYPE__BIND_NACK:
+            DebugMessage(DEBUG_DCE_COMMON, "Bind Nack\n");
+            dce_common_stats->co_bind_nack++;
+
+            /* Bind nack in Windows seems to blow any previous context away */
+            switch (DCE2_SsnGetServerPolicy(sd))
+            {
+            case DCE2_POLICY__WIN2000:
+            case DCE2_POLICY__WIN2003:
+            case DCE2_POLICY__WINXP:
+            case DCE2_POLICY__WINVISTA:
+            case DCE2_POLICY__WIN2008:
+            case DCE2_POLICY__WIN7:
+                DCE2_CoEraseCtxIds(cot);
+                break;
+
+            default:
+                break;
+            }
+
+            cot->got_bind = 0;
+
+            break;
+
+        case DCERPC_PDU_TYPE__RESPONSE:
+            DebugMessage(DEBUG_DCE_COMMON, "Response\n");
+            dce_common_stats->co_response++;
+            DCE2_CoResponse(sd, cot, co_hdr, frag_ptr, frag_len);
+            break;
+
+        case DCERPC_PDU_TYPE__FAULT:
+            DebugMessage(DEBUG_DCE_COMMON, "Fault\n");
+            dce_common_stats->co_fault++;
+
+            /* Clear out the client side */
+            DCE2_QueueEmpty(cot->pending_ctx_ids);
+            DCE2_BufferEmpty(cot->cli_seg.buf);
+            DCE2_BufferEmpty(cot->frag_tracker.cli_stub_buf);
+
+            DCE2_CoResetTracker(cot);
+
+            break;
+
+        case DCERPC_PDU_TYPE__SHUTDOWN:
+            DebugMessage(DEBUG_DCE_COMMON, "Shutdown\n");
+            dce_common_stats->co_shutdown++;
+            break;
+
+        case DCERPC_PDU_TYPE__REJECT:
+            DebugMessage(DEBUG_DCE_COMMON, "Reject\n");
+            dce_common_stats->co_reject++;
+
+            DCE2_QueueEmpty(cot->pending_ctx_ids);
+
+            break;
+
+        case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP:
+            DebugMessage(DEBUG_DCE_COMMON, "Microsoft Request To Send RPC over HTTP\n");
+            dce_common_stats->co_ms_pdu++;
+            break;
+
+        default:
+            DebugFormat(DEBUG_DCE_COMMON, "Unknown (0x%02x)\n", pdu_type);
+            dce_common_stats->co_other_resp++;
+            break;
+        }
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_CoProcess()
+ *
+ * Main entry point for connection-oriented DCE/RPC processing.
+ * Since there can be more than one DCE/RPC pdu in the packet, it
+ * loops through the packet data until none is left.  It handles
+ * transport layer segmentation and buffers data until it gets the
+ * full pdu, then hands off to pdu processing.
+ *
+ *
+ ********************************************************************/
+void DCE2_CoProcess(DCE2_SsnData* sd, DCE2_CoTracker* cot,
+    const uint8_t* data_ptr, uint16_t data_len)
+{
+    DCE2_CoSeg* seg = DCE2_CoGetSegPtr(sd, cot);
+    uint32_t num_frags = 0;
+    dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+
+    dce_common_stats->co_pdus++;
+
+    co_reassembled = 0;
+
+    while (data_len > 0)
+    {
+        num_frags++;
+
+        DebugFormat(DEBUG_DCE_COMMON, "DCE/RPC message number: %u\n", num_frags);
+
+        /* Fast track full fragments */
+        if (DCE2_BufferIsEmpty(seg->buf))
+        {
+            const uint8_t* frag_ptr = data_ptr;
+            uint16_t frag_len;
+
+            /* Not enough data left for a header.  Buffer it and return */
+            if (data_len < sizeof(DceRpcCoHdr))
+            {
+                // FIXIT-M add logic for this case
+                break;
+            }
+
+            if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS)
+                return;
+
+            frag_len = DceRpcCoFragLen((DceRpcCoHdr*)data_ptr);
+
+            /* Not enough data left for the pdu. */
+            if (data_len < frag_len)
+            {
+                // FIXIT-M add logic for this case
+                break;
+            }
+
+            DCE2_MOVE(data_ptr, data_len, frag_len);
+
+            /* Got a full DCE/RPC pdu */
+            DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
+
+            /* If we're configured to do defragmentation only detect on first frag
+             * since we'll detect on reassembled */
+            if (!DCE2_GcDceDefrag((dce2CommonProtoConf*)sd->config) ||
+                ((num_frags == 1) && !co_reassembled))
+                DCE2_Detect(sd);
+
+            /* Reset if this is a last frag */
+            if (DceRpcCoLastFrag((DceRpcCoHdr*)frag_ptr))
+                num_frags = 0;
+        }
+        else  /* We've already buffered data */
+        {
+            // FIXIT-M add logic for this case
+        }
+    }
+
+    // FIXIT-M add reassemble logic
+}
+
index d97ce9d62ee0800a8a1f90fca9d1a0f91e176059..ea1e7775bcf7bbc8c911942af27772a3a807fd79 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "dce_common.h"
 #include "dce_list.h"
+#include "dce_utils.h"
 
 #define DCE2_CO_BAD_MAJOR_VERSION           27
 #define DCE2_CO_BAD_MINOR_VERSION           28
@@ -68,6 +69,8 @@ from opnum established for fragmented request."
     "Connection-oriented DCE/RPC - Context id of non first/last fragment different \
 from context id established for fragmented request."
 
+#define DCE2_MAX_XMIT_SIZE_FUZZ    500
+
 #pragma pack(1)
 
 struct DceRpcCoVersion
@@ -88,6 +91,80 @@ struct DceRpcCoHdr
     uint32_t call_id;
 };
 
+/* Bind */
+struct DceRpcCoBind
+{
+    uint16_t max_xmit_frag;
+    uint16_t max_recv_frag;
+    uint32_t assoc_group_id;
+    uint8_t n_context_elem;   /* number of context elements */
+    uint8_t reserved;
+    uint16_t reserved2;
+};
+
+struct DceRpcCoSynId
+{
+    Uuid if_uuid;
+    uint32_t if_version;
+};
+
+struct DceRpcCoContElem
+{
+    uint16_t p_cont_id;
+    uint8_t n_transfer_syn;  /* number of transfer syntaxes */
+    uint8_t reserved;
+    DceRpcCoSynId abstract_syntax;
+};
+
+struct DceRpcCoBindAck
+{
+    uint16_t max_xmit_frag;
+    uint16_t max_recv_frag;
+    uint32_t assoc_group_id;
+    uint16_t sec_addr_len;
+};
+
+struct DceRpcCoContResult
+{
+    uint16_t result;
+    uint16_t reason;
+    DceRpcCoSynId transfer_syntax;
+};
+
+struct DceRpcCoAuthVerifier
+{
+    uint8_t auth_type;
+    uint8_t auth_level;
+    uint8_t auth_pad_length;
+    uint8_t auth_reserved;
+    uint32_t auth_context_id;
+};
+
+struct DceRpcCoRequest
+{
+    uint32_t alloc_hint;
+    uint16_t context_id;
+    uint16_t opnum;
+};
+
+struct DceRpcCoResponse
+{
+    uint32_t alloc_hint;
+    uint16_t context_id;
+    uint8_t cancel_count;
+    uint8_t reserved;
+};
+
+struct DceRpcCoContResultList
+{
+    uint8_t n_results;
+    uint8_t reserved;
+    uint16_t reserved2;
+};
+
+typedef DceRpcCoBind DceRpcCoAltCtx;
+typedef DceRpcCoBindAck DceRpcCoAltCtxResp;
+
 #pragma pack()
 
 struct DCE2_CoFragTracker
@@ -140,6 +217,56 @@ struct DCE2_CoTracker
     DCE2_CoSeg srv_seg;
 };
 
+/*
+ * Connection oriented
+ */
+enum DceRpcCoPfcFlags
+{
+    DCERPC_CO_PFC_FLAGS__FIRST_FRAG = 0x01,
+    DCERPC_CO_PFC_FLAGS__LAST_FRAG = 0x02,
+    DCERPC_CO_PFC_FLAGS__PENDING_CANCEL = 0x04,
+    DCERPC_CO_PFC_FLAGS__RESERVED_1 = 0x08,
+    DCERPC_CO_PFC_FLAGS__CONC_MPX = 0x10,
+    DCERPC_CO_PFC_FLAGS__DID_NOT_EXECUTE = 0x20,
+    DCERPC_CO_PFC_FLAGS__MAYBE = 0x40,
+    DCERPC_CO_PFC_FLAGS__OBJECT_UUID = 0x80
+};
+
+enum DCE2_CoCtxState
+{
+    DCE2_CO_CTX_STATE__ACCEPTED,
+    DCE2_CO_CTX_STATE__REJECTED,
+    DCE2_CO_CTX_STATE__PENDING
+};
+
+struct DCE2_CoCtxIdNode
+{
+    uint16_t ctx_id;           /* The context id */
+    Uuid iface;                /* The presentation syntax uuid for the interface */
+    uint16_t iface_vers_maj;   /* The major version of the interface */
+    uint16_t iface_vers_min;   /* The minor version of the interface */
+
+    /* Whether or not the server accepted or rejected the client bind/alter context
+     * request.  Initially set to pending until server response */
+    DCE2_CoCtxState state;
+};
+
+enum DceRpcCoAuthLevelType
+{
+    DCERPC_CO_AUTH_LEVEL__NONE = 1,
+    DCERPC_CO_AUTH_LEVEL__CONNECT,
+    DCERPC_CO_AUTH_LEVEL__CALL,
+    DCERPC_CO_AUTH_LEVEL__PKT,
+    DCERPC_CO_AUTH_LEVEL__PKT_INTEGRITY,
+    DCERPC_CO_AUTH_LEVEL__PKT_PRIVACY
+};
+
+enum DceRpcCoContDefResult
+{
+    DCERPC_CO_CONT_DEF_RESULT__ACCEPTANCE = 0,
+    DCERPC_CO_CONT_DEF_RESULT__USER_REJECTION,
+    DCERPC_CO_CONT_DEF_RESULT__PROVIDER_REJECTION
+};
 inline uint8_t DceRpcCoVersMaj(const DceRpcCoHdr* co)
 {
     return co->pversion.major;
@@ -165,7 +292,115 @@ inline uint16_t DceRpcCoFragLen(const DceRpcCoHdr* co)
     return DceRpcNtohs(&co->frag_length, DceRpcCoByteOrder(co));
 }
 
+inline uint8_t DceRpcCoNumCtxItems(const DceRpcCoBind* cob)
+{
+    return cob->n_context_elem;
+}
+
+inline uint16_t DceRpcCoContElemCtxId(const DceRpcCoHdr* co, const DceRpcCoContElem* coce)
+{
+    return DceRpcNtohs(&coce->p_cont_id, DceRpcCoByteOrder(co));
+}
+
+inline uint8_t DceRpcCoContElemNumTransSyntaxes(const DceRpcCoContElem* coce)
+{
+    return coce->n_transfer_syn;
+}
+
+inline const Uuid* DceRpcCoContElemIface(const DceRpcCoContElem* coce)
+{
+    return &coce->abstract_syntax.if_uuid;
+}
+
+inline uint16_t DceRpcCoContElemIfaceVersMaj(const DceRpcCoHdr* co, const DceRpcCoContElem* coce)
+{
+    return (uint16_t)(DceRpcNtohl(&coce->abstract_syntax.if_version, DceRpcCoByteOrder(co)) &
+           0x0000ffff);
+}
+
+inline uint16_t DceRpcCoContElemIfaceVersMin(const DceRpcCoHdr* co, const DceRpcCoContElem* coce)
+{
+    return (uint16_t)(DceRpcNtohl(&coce->abstract_syntax.if_version, DceRpcCoByteOrder(co)) >> 16);
+}
+
+inline uint16_t DceRpcCoBindAckMaxRecvFrag(const DceRpcCoHdr* co, const DceRpcCoBindAck* coba)
+{
+    return DceRpcNtohs(&coba->max_recv_frag, DceRpcCoByteOrder(co));
+}
+
+inline uint16_t DceRpcCoSecAddrLen(const DceRpcCoHdr* co, const DceRpcCoBindAck* coba)
+{
+    return DceRpcNtohs(&coba->sec_addr_len, DceRpcCoByteOrder(co));
+}
+
+inline uint16_t DceRpcCoContRes(const DceRpcCoHdr* co, const DceRpcCoContResult* cocr)
+{
+    return DceRpcNtohs(&cocr->result, DceRpcCoByteOrder(co));
+}
+
+inline int DceRpcCoObjectFlag(const DceRpcCoHdr* co)
+{
+    return co->pfc_flags & DCERPC_CO_PFC_FLAGS__OBJECT_UUID;
+}
+
+inline int DceRpcCoFirstFrag(const DceRpcCoHdr* co)
+{
+    return co->pfc_flags & DCERPC_CO_PFC_FLAGS__FIRST_FRAG;
+}
+
+inline int DceRpcCoLastFrag(const DceRpcCoHdr* co)
+{
+    return co->pfc_flags & DCERPC_CO_PFC_FLAGS__LAST_FRAG;
+}
+
+inline uint16_t DceRpcCoAuthLen(const DceRpcCoHdr* co)
+{
+    return DceRpcNtohs(&co->auth_length, DceRpcCoByteOrder(co));
+}
+
+inline uint8_t DceRpcCoAuthLevel(const DceRpcCoAuthVerifier* coav)
+{
+    return coav->auth_level;
+}
+
+inline uint16_t DceRpcCoAuthPad(const DceRpcCoAuthVerifier* coav)
+{
+    return coav->auth_pad_length;
+}
+
+inline uint16_t DceRpcCoCtxIdResp(const DceRpcCoHdr* co, const DceRpcCoResponse* cor)
+{
+    return DceRpcNtohs(&cor->context_id, DceRpcCoByteOrder(co));
+}
+
+inline uint16_t DceRpcCoBindMaxXmitFrag(const DceRpcCoHdr* co, const DceRpcCoBind* cob)
+{
+    return DceRpcNtohs(&cob->max_xmit_frag, DceRpcCoByteOrder(co));
+}
+
+inline uint8_t DceRpcCoContNumResults(const DceRpcCoContResultList* cocrl)
+{
+    return cocrl->n_results;
+}
+
+inline uint32_t DceRpcCoCallId(const DceRpcCoHdr* co)
+{
+    return DceRpcNtohl(&co->call_id, DceRpcCoByteOrder(co));
+}
+
+inline uint16_t DceRpcCoOpnum(const DceRpcCoHdr* co, const DceRpcCoRequest* cor)
+{
+    return DceRpcNtohs(&cor->opnum, DceRpcCoByteOrder(co));
+}
+
+inline uint16_t DceRpcCoCtxId(const DceRpcCoHdr* co, const DceRpcCoRequest* cor)
+{
+    return DceRpcNtohs(&cor->context_id, DceRpcCoByteOrder(co));
+}
+
 void DCE2_CoInitTracker(DCE2_CoTracker*);
+void DCE2_CoProcess(DCE2_SsnData*, DCE2_CoTracker*,
+    const uint8_t*, uint16_t);
 
 #endif
 
index 9c96365d087f804b92cbc3439171cb07b685cd3f..7334dfa15f229a17b92dd053af4e97ac47746072 100644 (file)
 // dce_common.cc author Rashmi Pitre <rrp@cisco.com>
 
 #include "dce_common.h"
+#include "dce_tcp.h"
+#include "dce_smb.h"
 #include "framework/base_api.h"
 #include "framework/module.h"
 #include "flow/flow.h"
 #include "log/messages.h"
 #include "main/snort_debug.h"
+#include "detection/detect.h"
+
+THREAD_LOCAL int dce2_detected = 0;
 
 const char* dce2_get_policy_name(DCE2_Policy policy)
 {
@@ -107,7 +112,7 @@ bool dce2_paf_abort(Flow* flow, DCE2_SsnData* sd)
         return true;
     }
 
-    if ((sd != NULL) && DCE2_SsnNoInspect(sd))
+    if ((sd != nullptr) && DCE2_SsnNoInspect(sd))
     {
         DebugMessage(DEBUG_DCE_COMMON, "Aborting PAF because of session data check.\n");
         return true;
@@ -116,6 +121,78 @@ bool dce2_paf_abort(Flow* flow, DCE2_SsnData* sd)
     return false;
 }
 
+void DCE2_PrintRoptions(DCE2_Roptions* ropts)
+{
+    DebugFormat(DEBUG_DCE_COMMON,
+        "  First frag: %s\n", ropts->first_frag == 1 ? "yes" : (ropts->first_frag == 0 ? "no" :
+        "unset"));
+    if (ropts->first_frag == DCE2_SENTINEL)
+    {
+        DebugMessage(DEBUG_DCE_COMMON, "  Iface: unset\n");
+        DebugMessage(DEBUG_DCE_COMMON, "  Iface version: unset\n");
+    }
+    else
+    {
+        DebugFormat(DEBUG_DCE_COMMON, "  Iface: %s\n", DCE2_UuidToStr(&ropts->iface,
+            DCERPC_BO_FLAG__NONE));
+        DebugFormat(DEBUG_DCE_COMMON, "  Iface version: %u\n", ropts->iface_vers_maj);
+    }
+    if (ropts->opnum == DCE2_SENTINEL)
+        DebugMessage(DEBUG_DCE_COMMON, "  Opnum: unset\n");
+    else
+        DebugFormat(DEBUG_DCE_COMMON, "  Opnum: %u\n", ropts->opnum);
+    DebugFormat(DEBUG_DCE_COMMON, "  Header byte order: %s\n",
+        ropts->hdr_byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN ? "little endian" :
+        (ropts->hdr_byte_order == DCERPC_BO_FLAG__BIG_ENDIAN ? "big endian" : "unset"));
+    DebugFormat(DEBUG_DCE_COMMON, "  Data byte order: %s\n",
+        ropts->data_byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN ? "little endian" :
+        (ropts->data_byte_order == DCERPC_BO_FLAG__BIG_ENDIAN ? "big endian" : "unset"));
+    if (ropts->stub_data != nullptr)
+        DebugFormat(DEBUG_DCE_COMMON, "  Stub data: %p\n", ropts->stub_data);
+    else
+        DebugMessage(DEBUG_DCE_COMMON, "  Stub data: NULL\n");
+}
+
+static void dce2_protocol_detect(DCE2_SsnData* sd, Packet* pkt)
+{
+    if (sd->trans == DCE2_TRANS_TYPE__TCP)
+    {
+        Profile profile(dce2_tcp_pstat_detect);
+    }
+    else
+    {
+        Profile profile(dce2_smb_pstat_detect);
+    }
+    SnortEventqPush();
+    snort_detect(pkt);
+    SnortEventqPop();
+
+    dce2_detected = 1;
+}
+
+void DCE2_Detect(DCE2_SsnData* sd)
+{
+    Packet* top_pkt = sd->wire_pkt;
+    //FIXIT-M  Get packet from stack
+
+    DebugMessage(DEBUG_DCE_COMMON, "Detecting ------------------------------------------------\n");
+    DebugMessage(DEBUG_DCE_COMMON, " Rule options:\n");
+    DCE2_PrintRoptions(&sd->ropts);
+    DebugMessage(DEBUG_DCE_COMMON, "Payload:\n");
+    DCE2_PrintPktData(top_pkt->data, top_pkt->dsize);
+    if (sd->ropts.stub_data != nullptr)
+    {
+        DebugMessage(DEBUG_DCE_COMMON,"\nStub data:\n");
+        DCE2_PrintPktData(sd->ropts.stub_data,
+            top_pkt->dsize - (sd->ropts.stub_data - top_pkt->data));
+    }
+
+    dce2_protocol_detect(sd, top_pkt);
+    /* Always reset rule option data after detecting */
+    DCE2_ResetRopts(&sd->ropts);
+    DebugMessage(DEBUG_DCE_COMMON, "----------------------------------------------------------\n");
+}
+
 #ifdef BUILDING_SO
 
 extern const BaseApi* ips_dce_iface;
index 4250b656d3a9b638e933f1c6d8ec0a5d356a55cd..236f948b570e93fe4a0b8f39de2ff0ec82c6f8d4 100644 (file)
 #include "framework/module.h"
 #include "framework/inspector.h"
 #include "protocols/packet.h"
+#include "events/event_queue.h"
 
 extern const InspectApi dce2_smb_api;
 extern const InspectApi dce2_tcp_api;
+extern THREAD_LOCAL int dce2_detected;
 
 #define GID_DCE2 145
 
@@ -46,6 +48,40 @@ enum DCE2_Policy
     DCE2_POLICY__SAMBA_3_0_20,
 };
 
+struct dce2CommonStats
+{
+    PegCount events;
+    PegCount sessions_aborted;
+    PegCount bad_autodetects;
+
+    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;
+};
 #define DCE2_SARG__POLICY_WIN2000       "Win2000"
 #define DCE2_SARG__POLICY_WINXP         "WinXP"
 #define DCE2_SARG__POLICY_WINVISTA      "WinVista"
@@ -66,14 +102,6 @@ struct dce2CommonProtoConf
 
 #define DCE2_DEBUG__PAF_END_MSG    "=========================================================="
 
-/* DCE/RPC byte order flag */
-enum DceRpcBoFlag
-{
-    DCERPC_BO_FLAG__NONE,
-    DCERPC_BO_FLAG__BIG_ENDIAN,
-    DCERPC_BO_FLAG__LITTLE_ENDIAN
-};
-
 enum DceRpcPduType
 {
     DCERPC_PDU_TYPE__REQUEST = 0,
@@ -151,10 +179,11 @@ struct DCE2_SsnData
     DCE2_Policy server_policy;
     DCE2_Policy client_policy;
     int flags;
-    const Packet* wire_pkt;
+    Packet* wire_pkt;
     uint64_t alert_mask;
     DCE2_Roptions ropts;
     int autodetect_dir;
+    void* config;
 
     uint32_t cli_seq;
     uint32_t cli_nseq;
@@ -162,47 +191,13 @@ struct DCE2_SsnData
     uint32_t srv_nseq;
 };
 
-inline DceRpcBoFlag DceRpcByteOrder(const uint8_t value)
-{
-    if ((value & 0x10) >> 4)
-        return DCERPC_BO_FLAG__LITTLE_ENDIAN;
-
-    return DCERPC_BO_FLAG__BIG_ENDIAN;
-}
-
-inline uint16_t DceRpcNtohs(const uint16_t* ptr, const DceRpcBoFlag bo_flag)
-{
-    uint16_t value;
-
-    if (ptr == NULL)
-        return 0;
-
-#ifdef WORDS_MUSTALIGN
-    value = *((uint8_t*)ptr) << 8 | *((uint8_t*)ptr + 1);
-#else
-    value = *ptr;
-#endif  /* WORDS_MUSTALIGN */
-
-    if (bo_flag == DCERPC_BO_FLAG__NONE)
-        return value;
-
-#ifdef WORDS_BIGENDIAN
-    if (bo_flag == DCERPC_BO_FLAG__BIG_ENDIAN)
-#else
-    if (bo_flag == DCERPC_BO_FLAG__LITTLE_ENDIAN)
-#endif  /* WORDS_BIGENDIAN */
-        return value;
-
-    return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8);
-}
-
 inline void DCE2_ResetRopts(DCE2_Roptions* ropts)
 {
     ropts->first_frag = DCE2_SENTINEL;
     ropts->opnum = DCE2_SENTINEL;
     ropts->hdr_byte_order = DCE2_SENTINEL;
     ropts->data_byte_order = DCE2_SENTINEL;
-    ropts->stub_data = NULL;
+    ropts->stub_data = nullptr;
 }
 
 inline void DCE2_SsnSetAutodetected(DCE2_SsnData* sd, Packet* p)
@@ -237,9 +232,36 @@ inline int DCE2_SsnNoInspect(DCE2_SsnData* sd)
     return sd->flags & DCE2_SSN_FLAG__NO_INSPECT;
 }
 
+inline bool DCE2_GcDceDefrag(dce2CommonProtoConf* config)
+{
+    return config->disable_defrag;
+}
+
+inline int DCE2_SsnFromServer(Packet* p)
+{
+    return p->from_server();
+}
+
+inline int DCE2_SsnFromClient(Packet* p)
+{
+    return p->from_client();
+}
+
+inline DCE2_Policy DCE2_SsnGetServerPolicy(DCE2_SsnData* sd)
+{
+    return sd->server_policy;
+}
+
+inline void dce_alert(uint32_t gid, uint32_t sid, dce2CommonStats* stats)
+{
+    SnortEventqAdd(gid,sid);
+    stats->events++;
+}
+
 bool dce2_set_common_config(Value&, dce2CommonProtoConf&);
 void print_dce2_common_config(dce2CommonProtoConf&);
 bool dce2_paf_abort(Flow*, DCE2_SsnData*);
+void DCE2_Detect(DCE2_SsnData*);
 
 #endif
 
index bc484f331fc5964e23786729c7ab0468dffdc3a2..55753b17753bbc558dff32a236ffc1c864533c4a 100644 (file)
@@ -89,6 +89,7 @@ DCE2_List* DCE2_ListNew(DCE2_ListType type, DCE2_ListKeyCompare kc,
 
     return list;
 }
+
 /********************************************************************
  * Function: DCE2_ListInsert()
  *
@@ -189,7 +190,6 @@ DCE2_Ret DCE2_ListInsert(DCE2_List* list, void* key, void* data)
     return DCE2_RET__SUCCESS;
 }
 
-
 /********************************************************************
  * Function: DCE2_ListFirst()
  *
@@ -262,7 +262,6 @@ void* DCE2_ListNext(DCE2_List* list)
     return nullptr;
 }
 
-
 /********************************************************************
  * Function: DCE2_ListEmpty()
  *
@@ -445,3 +444,312 @@ static void DCE2_ListInsertBefore(DCE2_List* list, DCE2_ListNode* insert, DCE2_L
         list->num_nodes++;
     }
 }
+
+/********************************************************************
+ * Function: DCE2_ListFind()
+ *
+ * Trys to find a node in the list using key passed in.  If list
+ * is splayed, found node is moved to front of list.  The data
+ * associated with the node is returned.
+ *
+ * Arguments:
+ *  DCE2_List *
+ *      A pointer to the list object.
+ *  void *
+ *      Pointer to a key.
+ *
+ * Returns:
+ *  void *
+ *      If the key is found, the data associated with the node
+ *          is returned.
+ *      NULL is returned if the item cannot be found given the key.
+ *
+ ********************************************************************/
+void* DCE2_ListFind(DCE2_List* list, void* key)
+{
+    DCE2_ListNode* n;
+
+    if (list == nullptr)
+        return nullptr;
+
+    for (n = list->head; n != nullptr; n = n->next)
+    {
+        int comp = list->compare(key, n->key);
+        if (comp == 0)
+        {
+            /* Found it, break out */
+            break;
+        }
+        else if ((comp < 0) && (list->type == DCE2_LIST_TYPE__SORTED))
+        {
+            /* Don't look any more if the list is sorted */
+            return nullptr;
+        }
+    }
+
+    if (n != nullptr)
+    {
+        /* If list is splayed, move found node to front of list */
+        if ((list->type == DCE2_LIST_TYPE__SPLAYED) &&
+            (n != list->head))
+        {
+            n->prev->next = n->next;
+
+            if (n->next != nullptr)
+                n->next->prev = n->prev;
+            else  /* it's the tail */
+                list->tail = n->prev;
+
+            n->prev = nullptr;
+            n->next = list->head;
+            list->head->prev = n;
+            list->head = n;
+        }
+
+        return n->data;
+    }
+
+    return nullptr;
+}
+
+/********************************************************************
+ * Function: DCE2_QueueNew()
+ *
+ * Creates and initializes a new queue object.
+ *
+ * Arguments:
+ *  DCE2_QueueDataFree
+ *      An optional free function for the data inserted into
+ *      the queue.  If NULL is passed in, the user will be
+ *      responsible for freeing data left in the queue.
+ *
+ * Returns:
+ *  DCE2_Queue *
+ *      Pointer to a new queue object.
+ *      NULL if unable to allocate memory for the object.
+ *
+ ********************************************************************/
+DCE2_Queue* DCE2_QueueNew(DCE2_QueueDataFree df)
+{
+    DCE2_Queue* queue;
+
+    queue = (DCE2_Queue*)SnortAlloc(sizeof(DCE2_Queue));
+    if (queue == nullptr)
+        return nullptr;
+
+    queue->data_free = df;
+
+    return queue;
+}
+
+/********************************************************************
+ * Function: DCE2_QueueEnqueue()
+ *
+ * Inserts data into the queue.
+ *
+ * Arguments:
+ *  DCE2_Queue *
+ *      A pointer to the queue object.
+ *  void *
+ *      Pointer to the data to insert into the queue.
+ *
+ * Returns:
+ *  DCE2_Ret
+ *      DCE2_RET__ERROR if memory cannot be allocated for a new
+ *          queue node or the queue object passed in is NULL.
+ *      DCE2_RET__SUCCESS if the data is successfully added to
+ *          the queue.
+ *
+ ********************************************************************/
+DCE2_Ret DCE2_QueueEnqueue(DCE2_Queue* queue, void* data)
+{
+    DCE2_QueueNode* n;
+
+    if (queue == nullptr)
+        return DCE2_RET__ERROR;
+
+    n = (DCE2_QueueNode*)SnortAlloc(sizeof(DCE2_QueueNode));
+    if (n == nullptr)
+        return DCE2_RET__ERROR;
+
+    n->data = data;
+
+    if (queue->tail == nullptr)
+    {
+        queue->head = queue->tail = n;
+        n->next = nullptr;
+    }
+    else
+    {
+        queue->tail->next = n;
+        n->prev = queue->tail;
+        queue->tail = n;
+    }
+
+    queue->num_nodes++;
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_QueueDequeue()
+ *
+ * Removes and returns the data in the first node in the queue.
+ * Note that the user will have to free the data returned.  The
+ * data free function only applies to data that is in the queue
+ * when it is emptied or destroyed.
+ *
+ * Arguments:
+ *  DCE2_Queue *
+ *      A pointer to the queue object.
+ *
+ * Returns:
+ *  void *
+ *      The data in the first node in the queue.
+ *      NULL if there are no items in the queue or the queue object
+ *          passed in is NULL.
+ *
+ ********************************************************************/
+void* DCE2_QueueDequeue(DCE2_Queue* queue)
+{
+    DCE2_QueueNode* n;
+
+    if (queue == nullptr)
+        return nullptr;
+
+    n = queue->head;
+
+    if (n != nullptr)
+    {
+        void* data = n->data;
+
+        if (queue->head == queue->tail)
+        {
+            queue->head = queue->tail = nullptr;
+        }
+        else
+        {
+            queue->head->next->prev = nullptr;
+            queue->head = queue->head->next;
+        }
+
+        free((void*)n);
+
+        queue->num_nodes--;
+
+        return data;
+    }
+
+    return nullptr;
+}
+
+/********************************************************************
+ * Function: DCE2_QueueEmpty()
+ *
+ * Removes all of the nodes in a queue.  Does not delete the queue
+ * object itself.  Calls data free function for data if it is
+ * not NULL.
+ *
+ * Arguments:
+ *  DCE2_Queue *
+ *      A pointer to the queue object.
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_QueueEmpty(DCE2_Queue* queue)
+{
+    DCE2_QueueNode* n;
+
+    if (queue == nullptr)
+        return;
+
+    n = queue->head;
+
+    while (n != nullptr)
+    {
+        DCE2_QueueNode* tmp = n->next;
+
+        if (queue->data_free != nullptr)
+            queue->data_free(n->data);
+
+        free((void*)n);
+        n = tmp;
+    }
+
+    queue->head = queue->tail = queue->current = nullptr;
+    queue->num_nodes = 0;
+}
+
+/********************************************************************
+ * Function: DCE2_QueueFirst()
+ *
+ * Returns a pointer to the data of the first node in the queue.
+ * Sets a current pointer to the first node in the queue for
+ * iterating over the queue.
+ *
+ * Arguments:
+ *  DCE2_Queue *
+ *      A pointer to the queue object.
+ *
+ * Returns:
+ *  void *
+ *      The data in the first node in the queue.
+ *      NULL if the queue object passed in is NULL, or there are
+ *          no items in the queue.
+ *
+ ********************************************************************/
+void* DCE2_QueueFirst(DCE2_Queue* queue)
+{
+    if (queue == nullptr)
+        return nullptr;
+
+    queue->current = queue->head;
+    queue->next = nullptr;
+
+    if (queue->current != nullptr)
+        return queue->current->data;
+
+    return nullptr;
+}
+
+/********************************************************************
+ * Function: DCE2_QueueNext()
+ *
+ * Increments the current pointer in the queue to the next node in
+ * the queue and returns the data associated with it.  This in
+ * combination with DCE2_QueueFirst is useful in a for loop to
+ * iterate over the items in a queue.
+ *
+ * Arguments:
+ *  DCE2_Queue *
+ *      A pointer to the queue object.
+ *
+ * Returns:
+ *  void *
+ *      The data in the next node in the queue.
+ *      NULL if the queue object passed in is NULL, or we are at
+ *          the end of the queue and there are no next nodes.
+ *
+ ********************************************************************/
+void* DCE2_QueueNext(DCE2_Queue* queue)
+{
+    if (queue == nullptr)
+        return nullptr;
+
+    if (queue->next != nullptr)
+    {
+        queue->current = queue->next;
+        queue->next = nullptr;
+        return queue->current->data;
+    }
+    else if (queue->current != nullptr)
+    {
+        queue->current = queue->current->next;
+        if (queue->current != nullptr)
+            return queue->current->data;
+    }
+
+    return nullptr;
+}
+
index 18d6e679bc417a7be0ccd307c7d7d58b974c1252..035866b991321b47035584dd4aca83c39f86f800 100644 (file)
@@ -113,6 +113,15 @@ void* DCE2_ListNext(DCE2_List*);
 inline bool DCE2_ListIsEmpty(DCE2_List*);
 void DCE2_ListEmpty(DCE2_List*);
 void DCE2_ListDestroy(DCE2_List*);
+void* DCE2_ListFind(DCE2_List*, void*);
+
+DCE2_Queue* DCE2_QueueNew(DCE2_QueueDataFree);
+DCE2_Ret DCE2_QueueEnqueue(DCE2_Queue*, void*);
+void* DCE2_QueueDequeue(DCE2_Queue*);
+static inline bool DCE2_QueueIsEmpty(DCE2_Queue*);
+void DCE2_QueueEmpty(DCE2_Queue*);
+void* DCE2_QueueFirst(DCE2_Queue*);
+void* DCE2_QueueNext(DCE2_Queue*);
 
 /********************************************************************
  * Function: DCE2_ListIsEmpty()
@@ -140,5 +149,21 @@ inline bool DCE2_ListIsEmpty(DCE2_List* list)
     return false;
 }
 
+/********************************************************************
+ * Function: DCE2_QueueIsEmpty()
+ *
+ * Determines whether or not the queue has any items in it
+ * currently.
+ *
+ ********************************************************************/
+inline bool DCE2_QueueIsEmpty(DCE2_Queue* queue)
+{
+    if (queue == nullptr)
+        return 1;
+    if (queue->num_nodes == 0)
+        return 1;
+    return 0;
+}
+
 #endif
 
index efb93186621929c3dde1b17c45ba7107304cefac..fc71b836f21dc1ebbf0b38fdcbbf3be55e2bda26 100644 (file)
@@ -69,11 +69,14 @@ static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
     return(&fd->dce2_smb_session);
 }
 
-static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf config)
+static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config)
 {
-    DCE2_SmbSsnData* dce2_smb_sess = NULL;
+    DCE2_SmbSsnData* dce2_smb_sess = nullptr;
     Profile profile(dce2_smb_pstat_new_session);
 
+    //FIXIT-M Re-evaluate after infrastructure/binder support if autodetect here
+    //is necessary
+
     if (DCE2_SmbAutodetect(p))
     {
         DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
@@ -99,9 +102,10 @@ static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf
             DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess);
 
             dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
-            dce2_smb_sess->sd.server_policy = config.common.policy;
+            dce2_smb_sess->sd.server_policy = config->common.policy;
             dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
             dce2_smb_sess->sd.wire_pkt = p;
+            dce2_smb_sess->sd.config = (void*)config;
 
             DCE2_SsnSetAutodetected(&dce2_smb_sess->sd, p);
         }
@@ -110,7 +114,7 @@ static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf
     return dce2_smb_sess;
 }
 
-DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf& config)
+DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* config)
 {
     Profile profile(dce2_smb_pstat_session);
 
@@ -134,7 +138,7 @@ DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf& config)
                 DCE2_SsnNoInspect(sd);
                 dce2_smb_stats.sessions_aborted++;
                 dce2_smb_stats.bad_autodetects++;
-                return NULL;
+                return nullptr;
             }
             DCE2_SsnClearAutodetected(sd);
         }
@@ -200,7 +204,7 @@ void Dce2Smb::eval(Packet* p)
         return;
     }
 
-    dce2_smb_sess = dce2_handle_smb_session(p, config);
+    dce2_smb_sess = dce2_handle_smb_session(p, &config);
     if (!dce2_smb_sess)
     {
         return;
index 996c218df1b0b84392d76d0e3188c504520a172c..f93ecdc183131a6d4435bc3b9a1c98df8aae3629 100644 (file)
@@ -133,9 +133,6 @@ struct dce2SmbStats
     PegCount sessions_aborted;
     PegCount bad_autodetects;
 
-    PegCount smb_sessions;
-    PegCount smb_pkts;
-
     PegCount co_pdus;
     PegCount co_bind;
     PegCount co_bind_ack;
@@ -150,6 +147,7 @@ struct dce2SmbStats
     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;
@@ -163,6 +161,8 @@ struct dce2SmbStats
     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;
@@ -417,7 +417,7 @@ struct DCE2_SmbSsnData
 
     // For tracking requests / responses
     DCE2_SmbRequestTracker rtracker;
-    //DCE2_Queue *rtrackers;
+    DCE2_Queue* rtrackers;
     uint16_t max_outstanding_requests;
     uint16_t outstanding_requests;
 
index 4b002056dd9b0e84b9e4b5bf2fbdd4b9b1a97def..114ca72b3eb5ef87422a7f37ec5a1911bb05715d 100644 (file)
@@ -32,47 +32,48 @@ static const PegInfo dce2_smb_pegs[] =
     { "events", "total events" },
     { "aborted sessions", "total aborted sessions" },
     { "bad autodetects", "total  bad autodetects" },
-    { "smb sessions", "total smb sessions" },
-    { "smb packets", "total smb packets" },
-    { "connection-oriented PDUs", "total connection-oriented PDUs" },
-    { "connection-oriented binds", "total connection-oriented binds" },
-    { "connection-oriented bind acks", "total connection-oriented binds acks" },
-    { "connection-oriented alter contexts", "total connection-oriented alter contexts" },
-    { "connection-oriented alter context responses",
+    { "PDUs", "total connection-oriented PDUs" },
+    { "Binds", "total connection-oriented binds" },
+    { "Bind acks", "total connection-oriented binds acks" },
+    { "Alter contexts", "total connection-oriented alter contexts" },
+    { "Alter context responses",
       "total connection-oriented alter context responses" },
-    { "connection-oriented bind naks", "total connection-oriented bind naks" },
-    { "connection-oriented requests", "total connection-oriented requests" },
-    { "connection-oriented responses", "total connection-oriented responses" },
-    { "connection-oriented cancels", "total connection-oriented cancels" },
-    { "connection-oriented orphaned", "total connection-oriented orphaned" },
-    { "connection-oriented faults", "total connection-oriented faults" },
-    { "connection-oriented auth3s", "total connection-oriented auth3s" },
-    { "connection-oriented shutdowns", "total connection-oriented shutdowns" },
-    { "connection-oriented rejects", "total connection-oriented rejects" },
-    { "connection-oriented other requests", "total connection-oriented other requests" },
-    { "connection-oriented other responses", "total connection-oriented other responses" },
-    { "connection-oriented request fragments", "total connection-oriented request fragments" },
-    { "connection-oriented response fragments", "total connection-oriented response fragments" },
-    { "connection-oriented client maximum fragment size",
+    { "Bind naks", "total connection-oriented bind naks" },
+    { "Requests", "total connection-oriented requests" },
+    { "Responses", "total connection-oriented responses" },
+    { "Cancels", "total connection-oriented cancels" },
+    { "Orphaned", "total connection-oriented orphaned" },
+    { "Faults", "total connection-oriented faults" },
+    { "Auth3s", "total connection-oriented auth3s" },
+    { "Shutdowns", "total connection-oriented shutdowns" },
+    { "Rejects", "total connection-oriented rejects" },
+    { "MS RPC/HTTP PDUs", "total connection-oriented MS requests to send RPC over HTTP" },
+    { "Other requests", "total connection-oriented other requests" },
+    { "Other responses", "total connection-oriented other responses" },
+    { "Request fragments", "total connection-oriented request fragments" },
+    { "Response fragments", "total connection-oriented response fragments" },
+    { "Client max fragment size",
       "connection-oriented client maximum fragment size" },
-    { "connection-oriented client minimum fragment size",
+    { "Client min fragment size",
       "connection-oriented client minimum fragment size" },
-    { "connection-oriented client segments reassembled",
+    { "Client segs reassembled",
       "total connection-oriented client segments reassembled" },
-    { "connection-oriented client fragments reassembled",
+    { "Client frags reassembled",
       "total connection-oriented client fragments reassembled" },
-    { "connection-oriented server maximum fragment size",
+    { "Server max fragment size",
       "connection-oriented server maximum fragment size" },
-    { "connection-oriented server minimum fragment size",
+    { "Server min fragment size",
       "connection-oriented server minimum fragment size" },
-    { "connection-oriented server segments reassembled",
+    { "Server segs reassembled",
       "total connection-oriented server segments reassembled" },
-    { "connection-oriented server fragments reassembled",
+    { "Server frags reassembled",
       "total connection-oriented server fragments reassembled" },
-    { "smb client segments reassembled", "total smb client segments reassembled" },
-    { "smb server segments reassembled", "total smb server segments reassembled" },
-    { "smb maximum outstanding requests", "total smb maximum outstanding requests" },
-    { "smb files processed", "total smb files processed" },
+    { "Sessions", "total smb sessions" },
+    { "Packets", "total smb packets" },
+    { "Client segs reassembled", "total smb client segments reassembled" },
+    { "Server segs reassembled", "total smb server segments reassembled" },
+    { "Max outstanding requests", "total smb maximum outstanding requests" },
+    { "Files processed", "total smb files processed" },
     { nullptr, nullptr }
 };
 
@@ -202,99 +203,99 @@ ProfileStats* Dce2SmbModule::get_profile(
     switch ( index )
     {
     case 0:
-        name = "dce smb main";
+        name = "dce_smb_main";
         parent = nullptr;
         return &dce2_smb_pstat_main;
 
     case 1:
-        name = "dce smb session";
-        parent = "dce smb main";
+        name = "dce_smb_session";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_session;
 
     case 2:
-        name = "dce smb new_session";
-        parent = "dce smb session";
+        name = "dce_smb_new_session";
+        parent = "dce_smb_session";
 
         return &dce2_smb_pstat_new_session;
 
     case 3:
-        name = "dce smb detect";
-        parent = "dce smb main";
+        name = "dce_smb_detect";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_detect;
 
     case 4:
-        name = "dce smb log";
-        parent = "dce smb main";
+        name = "dce_smb_log";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_log;
 
     case 5:
-        name = "dce smb connection-oriented segment";
-        parent = "dce smb main";
+        name = "dce_smb_co_segment";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_co_seg;
 
     case 6:
-        name = "dce smb connection-oriented fragment";
-        parent = "dce smb main";
+        name = "dce_smb_co_fragment";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_co_frag;
 
     case 7:
-        name = "dce smb connection-oriented reassembly";
-        parent = "dce smb main";
+        name = "dce_smb_co_reassembly";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_co_reass;
 
     case 8:
-        name = "dce smb connection-oriented context";
-        parent = "dce smb main";
+        name = "dce_smb_co_context";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_co_ctx;
 
     case 9:
-        name = "dce smb segment";
-        parent = "dce smb main";
+        name = "dce_smb_segment";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_seg;
 
     case 10:
-        name = "dce smb request";
-        parent = "dce smb main";
+        name = "dce_smb_request";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_req;
 
     case 11:
-        name = "dce smb uid";
-        parent = "dce smb main";
+        name = "dce_smb_uid";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_uid;
 
     case 12:
-        name = "dce smb tid";
-        parent = "dce smb main";
+        name = "dce_smb_tid";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_tid;
 
     case 13:
-        name = "dce smb fid";
-        parent = "dce smb main";
+        name = "dce_smb_fid";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_fid;
 
     case 14:
-        name = "dce smb file";
-        parent = "dce smb main";
+        name = "dce_smb_file";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_file;
 
     case 15:
-        name = "dce smb file detect";
-        parent = "dce smb file";
+        name = "dce_smb_file_detect";
+        parent = "dce_smb_file";
         return &dce2_smb_pstat_smb_file_detect;
 
     case 16:
-        name = "dce smb file api";
-        parent = "dce smb file";
+        name = "dce_smb_file_api";
+        parent = "dce_smb_file";
         return &dce2_smb_pstat_smb_file_api;
 
     case 17:
-        name = "dce smb fingerprint";
-        parent = "dce smb main";
+        name = "dce_smb_fingerprint";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_fingerprint;
 
     case 18:
-        name = "dce smb negotiate";
-        parent = "dce smb main";
+        name = "dce_smb_negotiate";
+        parent = "dce_smb_main";
         return &dce2_smb_pstat_smb_negotiate;
     }
     return nullptr;
@@ -305,7 +306,7 @@ static int smb_invalid_share_compare(const void* a, const void* b)
     dce2SmbShare* ashare = (dce2SmbShare*)a;
     dce2SmbShare* bshare = (dce2SmbShare*)b;
 
-    if ((ashare == NULL) || (bshare == NULL))
+    if ((ashare == nullptr) || (bshare == nullptr))
         return -1;
 
     /* Just check the ascii string */
@@ -323,7 +324,7 @@ static void smb_invalid_share_free(void* data)
 {
     dce2SmbShare* smb_share = (dce2SmbShare*)data;
 
-    if (smb_share == NULL)
+    if (smb_share == nullptr)
         return;
 
     free(smb_share->unicode_str);
@@ -373,7 +374,7 @@ static bool set_smb_invalid_shares(dce2SmbProtoConf& config, Value& v)
 
         smb_share = (dce2SmbShare*)calloc(sizeof(dce2SmbShare),1);
         smb_share_key = (dce2SmbShare*)calloc(sizeof(dce2SmbShare),1);
-        if ((smb_share == NULL) || (smb_share_key == NULL))
+        if ((smb_share == nullptr) || (smb_share_key == nullptr))
         {
             FatalError("DCE2 - Could not allocate memory for config\n");
         }
@@ -384,7 +385,7 @@ static bool set_smb_invalid_shares(dce2SmbProtoConf& config, Value& v)
         smb_share->ascii_str_len = share_len + 1;
         smb_share->ascii_str = (char*)calloc(smb_share->ascii_str_len,1);
 
-        if ((smb_share->unicode_str == NULL) || (smb_share->ascii_str == NULL))
+        if ((smb_share->unicode_str == nullptr) || (smb_share->ascii_str == nullptr))
         {
             FatalError("DCE2 - Could not allocate memory for config\n");
         }
@@ -399,7 +400,7 @@ static bool set_smb_invalid_shares(dce2SmbProtoConf& config, Value& v)
         smb_share_key->ascii_str_len = smb_share->ascii_str_len;
         smb_share_key->ascii_str = (char*)calloc(smb_share_key->ascii_str_len,1);
 
-        if (smb_share_key->ascii_str == NULL)
+        if (smb_share_key->ascii_str == nullptr)
         {
             FatalError("DCE2 - Could not allocate memory for config\n");
         }
@@ -424,7 +425,7 @@ static bool set_smb_invalid_shares(dce2SmbProtoConf& config, Value& v)
     if (error)
     {
         DCE2_ListDestroy(config.smb_invalid_shares);
-        config.smb_invalid_shares = NULL;
+        config.smb_invalid_shares = nullptr;
         return error;
     }
 
@@ -517,14 +518,14 @@ void print_dce2_smb_conf(dce2SmbProtoConf& config)
     {
         LogMessage("    SMB valid versions : all\n");
     }
-    if (config.smb_invalid_shares != NULL)
+    if (config.smb_invalid_shares != nullptr)
     {
         dce2SmbShare* share;
 
         LogMessage("    Invalid SMB shares:\n");
 
         for (share = (dce2SmbShare*)DCE2_ListFirst(config.smb_invalid_shares);
-            share != NULL;
+            share != nullptr;
             share = (dce2SmbShare*)DCE2_ListNext(config.smb_invalid_shares))
         {
             LogMessage("    %s\n",share->ascii_str);
index 160f07224fd203896391830d568667e0b0957ac7..60c65a752c3afb85b2b5d0bf99066af81ef8801f 100644 (file)
@@ -110,7 +110,7 @@ StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8
 
     while (n < len)
     {
-        DebugFormat(DEBUG_DCE_SMB, " State %d : 0x%02x", ss->paf_state, data[n]);
+        Debug::print(nullptr, 0, DEBUG_DCE_SMB, " State %d : 0x%02x\n", ss->paf_state, data[n]);
 
         switch (ss->paf_state)
         {
@@ -131,7 +131,7 @@ StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8
                 DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_END_MSG);
                 return StreamSplitter::FLUSH;
             }
-            DebugMessage(DEBUG_DCE_SMB, "Invalid NetBIOS header - "
+             Debug::print(nullptr, 0, DEBUG_DCE_SMB, "%s", "Invalid NetBIOS header - "
                 "entering junk data states.\n");
             ss->paf_state = (DCE2_PafSmbStates)(((int)ss->paf_state) + 1);
             break;
@@ -140,14 +140,14 @@ StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8
 
             if (!DCE2_PafSmbIsValidNetbiosHdr((uint32_t)(ss->nb_hdr >> 32), true))
             {
-                DebugMessage(DEBUG_DCE_SMB, "Invalid NetBIOS header - "
+                 Debug::print(nullptr, 0, DEBUG_DCE_SMB, "%s", "Invalid NetBIOS header - "
                     "staying in State 7.\n");
                 break;
             }
             if (((uint32_t)ss->nb_hdr != DCE2_SMB_ID)
                 && ((uint32_t)ss->nb_hdr != DCE2_SMB2_ID))
             {
-                DebugMessage(DEBUG_DCE_SMB, "Invalid SMB ID - "
+                 Debug::print(nullptr, 0, DEBUG_DCE_SMB, "%s", "Invalid SMB ID - "
                     "staying in State 7.\n");
                 break;
             }
index e0a371eeabadcd4af4c2680b590329c01d2099f3..87033377fc1f3250eadf385bf96df84df02cf3bf 100644 (file)
@@ -22,7 +22,9 @@
 #include "dce_tcp.h"
 #include "dce_tcp_paf.h"
 #include "dce_tcp_module.h"
+#include "dce_co.h"
 #include "main/snort_debug.h"
+#include "detection/detect.h"
 
 Dce2TcpFlowData::Dce2TcpFlowData() : FlowData(flow_id)
 {
@@ -58,11 +60,13 @@ static DCE2_TcpSsnData* set_new_dce2_tcp_session(Packet* p)
     return(&fd->dce2_tcp_session);
 }
 
-static DCE2_TcpSsnData* dce2_create_new_tcp_session(Packet* p, dce2TcpProtoConf config)
+static DCE2_TcpSsnData* dce2_create_new_tcp_session(Packet* p, dce2TcpProtoConf* config)
 {
-    DCE2_TcpSsnData* dce2_tcp_sess = NULL;
+    DCE2_TcpSsnData* dce2_tcp_sess = nullptr;
     Profile profile(dce2_tcp_pstat_new_session);
 
+    //FIXIT-M Re-evaluate after infrastructure/binder support if autodetect here
+    //is necessary
     if (DCE2_TcpAutodetect(p))
     {
         DebugMessage(DEBUG_DCE_TCP, "DCE over TCP packet detected\n");
@@ -79,9 +83,10 @@ static DCE2_TcpSsnData* dce2_create_new_tcp_session(Packet* p, dce2TcpProtoConf
             DebugFormat(DEBUG_DCE_TCP,"Created (%p)\n", (void*)dce2_tcp_sess);
 
             dce2_tcp_sess->sd.trans = DCE2_TRANS_TYPE__TCP;
-            dce2_tcp_sess->sd.server_policy = config.common.policy;
+            dce2_tcp_sess->sd.server_policy = config->common.policy;
             dce2_tcp_sess->sd.client_policy = DCE2_POLICY__WINXP;
             dce2_tcp_sess->sd.wire_pkt = p;
+            dce2_tcp_sess->sd.config = (void*)config;
 
             DCE2_SsnSetAutodetected(&dce2_tcp_sess->sd, p);
         }
@@ -90,7 +95,7 @@ static DCE2_TcpSsnData* dce2_create_new_tcp_session(Packet* p, dce2TcpProtoConf
     return dce2_tcp_sess;
 }
 
-DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf& config)
+DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf* config)
 {
     Profile profile(dce2_tcp_pstat_session);
 
@@ -114,7 +119,7 @@ DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf& config)
                 DCE2_SsnNoInspect(sd);
                 dce2_tcp_stats.sessions_aborted++;
                 dce2_tcp_stats.bad_autodetects++;
-                return NULL;
+                return nullptr;
             }
 
             DCE2_SsnClearAutodetected(sd);
@@ -122,8 +127,13 @@ DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf& config)
     }
 
     DebugFormat(DEBUG_DCE_TCP, "Session pointer: %p\n", (void*)dce2_tcp_sess);
+    if (dce2_tcp_sess)
+    {
+        //FIXIT-M Stack push
 
-    // FIXIT-M add remaining session handling logic
+        p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
+        dce2_detected = 0;
+    }
 
     return dce2_tcp_sess;
 }
@@ -162,6 +172,14 @@ void Dce2Tcp::eval(Packet* p)
 {
     DCE2_TcpSsnData* dce2_tcp_sess;
     Profile profile(dce2_tcp_pstat_main);
+    if (DCE2_SsnFromServer(p))
+    {
+        DebugMessage(DEBUG_DCE_TCP, "Packet from Server.\n");
+    }
+    else
+    {
+        DebugMessage(DEBUG_DCE_TCP, "Packet from Client.\n");
+    }
 
     assert(p->has_tcp_data());
     assert(p->flow);
@@ -173,12 +191,22 @@ void Dce2Tcp::eval(Packet* p)
         return;
     }
 
-    dce2_tcp_sess = dce2_handle_tcp_session(p, config);
-    if (!dce2_tcp_sess)
+    dce2_tcp_sess = dce2_handle_tcp_session(p, &config);
+    if (dce2_tcp_sess)
     {
-        return;
+        dce2_tcp_stats.tcp_pkts++;
+        DCE2_CoProcess(&dce2_tcp_sess->sd, &dce2_tcp_sess->co_tracker, p->data,
+            p->dsize);
+
+        if (!dce2_detected)
+            DCE2_Detect(&dce2_tcp_sess->sd);
+
+        DCE2_ResetRopts(&dce2_tcp_sess->sd.ropts);
+        //FIXIT-M DCE2_PopPkt(sd);
+
+        if (!DCE2_SsnAutodetected(&dce2_tcp_sess->sd))
+            DisableInspection();
     }
-    dce2_tcp_stats.tcp_pkts++;
 }
 
 //-------------------------------------------------------------------------
index 4f63d5a792f2a3a046ec597ae8955d8a5d897c99..7c956d99b5b24bf04d55ad724a1dcd68982bdb2e 100644 (file)
@@ -38,13 +38,14 @@ struct dce2TcpStats
     PegCount autoports[65535][DCE2_TRANS_TYPE__MAX];
 #endif
 */
+    /* The common stats block has to be at the beginning followed
+       by the protocol specific stats */
+
+    /*common stats -defined in common.h*/
     PegCount events;
     PegCount sessions_aborted;
     PegCount bad_autodetects;
 
-    PegCount tcp_sessions;
-    PegCount tcp_pkts;
-
     PegCount co_pdus;
     PegCount co_bind;
     PegCount co_bind_ack;
@@ -59,6 +60,7 @@ struct dce2TcpStats
     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;
@@ -71,6 +73,10 @@ struct dce2TcpStats
     PegCount co_srv_min_frag_size;
     PegCount co_srv_seg_reassembled;
     PegCount co_srv_frag_reassembled;
+
+    /*DCE TCP specific*/
+    PegCount tcp_sessions;
+    PegCount tcp_pkts;
 };
 
 extern THREAD_LOCAL dce2TcpStats dce2_tcp_stats;
@@ -96,7 +102,7 @@ inline bool DCE2_TcpAutodetect(Packet* p)
             && (DceRpcCoVersMin(co_hdr) == DCERPC_PROTO_MINOR_VERS__0)
             && ((p->from_client()
             && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND)
-            || (p->from_server()
+            || (DCE2_SsnFromServer(p)
             && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK))
             && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr)))
         {
index ccf5ad9a4808d70e0df9507cc79c85d6107575be..3ffbe5aa2863f125f609819d469b5cab56180a5e 100644 (file)
@@ -63,43 +63,44 @@ static const PegInfo dce2_tcp_pegs[] =
     { "events", "total events" },
     { "aborted sessions", "total aborted sessions" },
     { "bad autodetects", "total bad autodetects" },
-    { "tcp sessions", "total tcp sessions" },
-    { "tcp packets", "total tcp packets" },
-    { "connection-oriented PDUs", "total connection-oriented PDUs" },
-    { "connection-oriented binds", "total connection-oriented binds" },
-    { "connection-oriented bind acks", "total connection-oriented binds acks" },
-    { "connection-oriented alter contexts", "total connection-oriented alter contexts" },
-    { "connection-oriented alter context responses",
+    { "PDUs", "total connection-oriented PDUs" },
+    { "Binds", "total connection-oriented binds" },
+    { "Bind acks", "total connection-oriented binds acks" },
+    { "Alter contexts", "total connection-oriented alter contexts" },
+    { "Alter context responses",
       "total connection-oriented alter context responses" },
-    { "connection-oriented bind naks", "total connection-oriented bind naks" },
-    { "connection-oriented requests", "total connection-oriented requests" },
-    { "connection-oriented responses", "total connection-oriented responses" },
-    { "connection-oriented cancels", "total connection-oriented cancels" },
-    { "connection-oriented orphaned", "total connection-oriented orphaned" },
-    { "connection-oriented faults", "total connection-oriented faults" },
-    { "connection-oriented auth3s", "total connection-oriented auth3s" },
-    { "connection-oriented shutdowns", "total connection-oriented shutdowns" },
-    { "connection-oriented rejects", "total connection-oriented rejects" },
-    { "connection-oriented other requests", "total connection-oriented other requests" },
-    { "connection-oriented other responses", "total connection-oriented other responses" },
-    { "connection-oriented request fragments", "total connection-oriented request fragments" },
-    { "connection-oriented response fragments", "total connection-oriented response fragments" },
-    { "connection-oriented client maximum fragment size",
+    { "Bind naks", "total connection-oriented bind naks" },
+    { "Requests", "total connection-oriented requests" },
+    { "Responses", "total connection-oriented responses" },
+    { "Cancels", "total connection-oriented cancels" },
+    { "Orphaned", "total connection-oriented orphaned" },
+    { "Faults", "total connection-oriented faults" },
+    { "Auth3s", "total connection-oriented auth3s" },
+    { "Shutdowns", "total connection-oriented shutdowns" },
+    { "Rejects", "total connection-oriented rejects" },
+    { "MS RPC/HTTP PDUs", "total connection-oriented MS requests to send RPC over HTTP" },
+    { "Other requests", "total connection-oriented other requests" },
+    { "Other responses", "total connection-oriented other responses" },
+    { "Request fragments", "total connection-oriented request fragments" },
+    { "Response fragments", "total connection-oriented response fragments" },
+    { "Client max fragment size",
       "connection-oriented client maximum fragment size" },
-    { "connection-oriented client minimum fragment size",
+    { "Client min fragment size",
       "connection-oriented client minimum fragment size" },
-    { "connection-oriented client segments reassembled",
+    { "Client segs reassembled",
       "total connection-oriented client segments reassembled" },
-    { "connection-oriented client fragments reassembled",
+    { "Client frags reassembled",
       "total connection-oriented client fragments reassembled" },
-    { "connection-oriented server maximum fragment size",
+    { "Server max fragment size",
       "connection-oriented server maximum fragment size" },
-    { "connection-oriented server minimum fragment size",
+    { "Server min fragment size",
       "connection-oriented server minimum fragment size" },
-    { "connection-oriented server segments reassembled",
+    { "Server segs reassembled",
       "total connection-oriented server segments reassembled" },
-    { "connection-oriented server fragments reassembled",
+    { "Server frags reassembled",
       "total connection-oriented server fragments reassembled" },
+    { "tcp sessions", "total tcp sessions" },
+    { "tcp packets", "total tcp packets" },
     { nullptr, nullptr }
 };
 
@@ -128,48 +129,48 @@ ProfileStats* Dce2TcpModule::get_profile(
     switch ( index )
     {
     case 0:
-        name = "dce tcp main";
+        name = "dce_tcp_main";
         parent = nullptr;
         return &dce2_tcp_pstat_main;
 
     case 1:
-        name = "dce tcp session";
-        parent = "dce tcp main";
+        name = "dce_tcp_session";
+        parent = "dce_tcp_main";
         return &dce2_tcp_pstat_session;
 
     case 2:
-        name = "dce tcp new session";
-        parent = "dce tcp session";
+        name = "dce_tcp_new_session";
+        parent = "dce_tcp_session";
         return &dce2_tcp_pstat_new_session;
 
     case 3:
-        name = "dce tcp detect";
-        parent = "dce tcp main";
+        name = "dce_tcp_detect";
+        parent = "dce_tcp_main";
         return &dce2_tcp_pstat_detect;
 
     case 4:
-        name = "dce tcp log";
+        name = "dce_tcp_log";
         parent = "dce_tcp_main";
         return &dce2_tcp_pstat_log;
 
     case 5:
-        name = "dce tcp connection-oriented segment";
-        parent = "dce tcp main";
+        name = "dce_tcp_co_segment";
+        parent = "dce_tcp_main";
         return &dce2_tcp_pstat_co_seg;
 
     case 6:
-        name = "dce tcp connection-oriented fragment";
-        parent = "dce tcp main";
+        name = "dce_tcp_co_fragment";
+        parent = "dce_tcp_main";
         return &dce2_tcp_pstat_co_frag;
 
     case 7:
-        name = "dce tcp connection-oriented reassembly";
-        parent = "dce tcp main";
+        name = "dce_tcp_co_reassembly";
+        parent = "dce_tcp_main";
         return &dce2_tcp_pstat_co_reass;
 
     case 8:
-        name = "dce tcp connection-oriented context";
-        parent = "dce tcp main";
+        name = "dce_tcp_co_context";
+        parent = "dce_tcp_main";
         return &dce2_tcp_pstat_co_ctx;
     }
     return nullptr;
index a279a529268662f33d97f03f18090a9e61823b7b..fbde18f622e3511cfc37842e379161e781f193ee 100644 (file)
@@ -62,7 +62,7 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
         return StreamSplitter::ABORT;
     }
 
-    if (sd == NULL)
+    if (sd == nullptr)
     {
         bool autodetected = false;
         DebugMessage(DEBUG_DCE_TCP, "No session data - autodetecting\n");
@@ -102,7 +102,7 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
 
     while (n < len)
     {
-        DebugFormat(DEBUG_DCE_TCP, " State %d : 0x%02x", ds->paf_state, data[n]);
+        Debug::print(nullptr, 0, DEBUG_DCE_TCP, " State %d : 0x%02x\n", ds->paf_state, data[n]);
 
         switch (ds->paf_state)
         {
@@ -111,15 +111,15 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
             ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1);
             if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN)
             {
-                DebugMessage(DEBUG_DCE_TCP, "Byte order: Little endian\n");
+                Debug::print(nullptr, 0, DEBUG_DCE_TCP, "%s","Byte order: Little endian\n");
             }
             else
             {
-                DebugMessage(DEBUG_DCE_TCP, "Byte order: Big endian\n");
+                Debug::print(nullptr, 0, DEBUG_DCE_TCP, "%s","Byte order: Big endian\n");
             }
             break;
         case DCE2_PAF_TCP_STATES__8:
-            DebugMessage(DEBUG_DCE_TCP, "First byte of fragment length\n");
+            Debug::print(nullptr, 0, DEBUG_DCE_TCP, "%s", "First byte of fragment length\n");
             if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN)
                 ds->frag_len = data[n];
             else
@@ -127,7 +127,7 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
             ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1);
             break;
         case DCE2_PAF_TCP_STATES__9:
-            DebugMessage(DEBUG_DCE_TCP, "Second byte of fragment length\n");
+            Debug::print(nullptr, 0, DEBUG_DCE_TCP, "%s", "Second byte of fragment length\n");
             if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN)
                 ds->frag_len |= data[n] << 8;
             else
@@ -136,11 +136,11 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
             /* If we get a bad frag length abort */
             if (ds->frag_len < sizeof(DceRpcCoHdr))
             {
-                DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG);
+                Debug::print(nullptr, 0, DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG);
                 return StreamSplitter::ABORT;
             }
 
-            DebugFormat(DEBUG_DCE_TCP, "Fragment length: %u\n", ds->frag_len);
+            Debug::print(nullptr, 0, DEBUG_DCE_TCP, "Fragment length: %u\n", ds->frag_len);
 
             /* Increment n here so we can continue */
             n += ds->frag_len - (uint8_t)ds->paf_state;
@@ -149,7 +149,7 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
              * flush just before it */
             if ((num_requests == 1) || (n <= len))
                 tmp_fp += ds->frag_len;
-            DebugFormat(DEBUG_DCE_TCP, "Requests: %u\n", num_requests);
+            Debug::print(nullptr, 0, DEBUG_DCE_TCP, "Requests: %u\n", num_requests);
             ds->paf_state = DCE2_PAF_TCP_STATES__0;
             continue;      // we incremented n already
         default:
index dca58f59e281911ddffbf1d4531c6a903865219b..b5a5bb942bbd424bbc8ca96057cc140b7e5a2f27 100644 (file)
@@ -18,7 +18,7 @@
 //--------------------------------------------------------------------------
 
 #include "dce_utils.h"
-
+#include "main/snort_debug.h"
 
 /********************************************************************
  * Function: DCE2_GetValue()
@@ -59,7 +59,7 @@ DCE2_Ret DCE2_GetValue(char* start, char* end, void* int_value, int negate,
     uint64_t place = 1;
     uint64_t max_value = 0;
 
-    if ((end == NULL) || (start == NULL) || (int_value == NULL))
+    if ((end == nullptr) || (start == nullptr) || (int_value == nullptr))
         return DCE2_RET__ERROR;
 
     if (start >= end)
@@ -160,3 +160,143 @@ DCE2_Ret DCE2_GetValue(char* start, char* end, void* int_value, int negate,
     return DCE2_RET__SUCCESS;
 }
 
+const char* DCE2_UuidToStr(const Uuid* uuid, DceRpcBoFlag byte_order)
+{
+#define UUID_BUF_SIZE  50
+    static char uuid_buf1[UUID_BUF_SIZE];
+    static char uuid_buf2[UUID_BUF_SIZE];
+    static int buf_num = 0;
+    char* uuid_buf;
+
+    if (buf_num == 0)
+    {
+        uuid_buf = uuid_buf1;
+        buf_num = 1;
+    }
+    else
+    {
+        uuid_buf = uuid_buf2;
+        buf_num = 0;
+    }
+
+    snprintf(uuid_buf, UUID_BUF_SIZE,
+        "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+        DceRpcHtonl(&uuid->time_low, byte_order),
+        DceRpcHtons(&uuid->time_mid, byte_order),
+        DceRpcHtons(&uuid->time_high_and_version, byte_order),
+        uuid->clock_seq_and_reserved, uuid->clock_seq_low,
+        uuid->node[0], uuid->node[1], uuid->node[2],
+        uuid->node[3], uuid->node[4], uuid->node[5]);
+
+    uuid_buf[UUID_BUF_SIZE - 1] = '\0';
+
+    return uuid_buf;
+}
+
+void DCE2_PrintPktData(const uint8_t* data, const uint16_t len)
+{
+    unsigned int i, j = 0, line_len = 0;
+    uint8_t hex_buf[16];
+    uint8_t char_buf[16];
+
+    for (i = 0; i < len; i++)
+    {
+        hex_buf[j] = data[i];
+
+        if (isascii((int)data[i]) && isprint((int)data[i]))
+            char_buf[j] = data[i];
+        else
+            char_buf[j] = '.';
+
+        if (line_len == 15)
+        {
+            unsigned int k, sub_line_len = 0;
+            for (k = 0; k <= j; k++)
+            {
+                Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%02x ", hex_buf[k]);
+                if (sub_line_len >= 7)
+                {
+                    Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s"," ");
+                    sub_line_len = 0;
+                }
+                else
+                {
+                    sub_line_len++;
+                }
+            }
+
+            Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s"," ");
+
+            sub_line_len = 0;
+            for (k = 0; k <= j; k++)
+            {
+                Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%c", char_buf[k]);
+                if (sub_line_len >= 7)
+                {
+                    Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s"," ");
+                    sub_line_len = 0;
+                }
+                else
+                {
+                    sub_line_len++;
+                }
+            }
+
+            Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s","\n");
+
+            j = line_len = 0;
+        }
+        else
+        {
+            j++;
+            line_len++;
+        }
+    }
+
+    if (line_len > 0)
+    {
+        unsigned int k, sub_line_len = 0;
+        for (k = 0; k < j; k++)
+        {
+            Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%02x ", hex_buf[k]);
+            if (sub_line_len >= 7)
+            {
+                Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s"," ");
+                sub_line_len = 0;
+            }
+            else
+            {
+                sub_line_len++;
+            }
+        }
+
+        if (k < 8)
+            Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s","   ");
+        else
+            Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s","  ");
+
+        while (k < 16)
+        {
+            Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s","   ");
+            k++;
+        }
+
+        sub_line_len = 0;
+        for (k = 0; k < j; k++)
+        {
+           Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%c", char_buf[k]);
+            if (sub_line_len >= 7)
+            {
+                Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s"," ");
+                sub_line_len = 0;
+            }
+            else
+            {
+                sub_line_len++;
+            }
+        }
+    }
+
+    Debug::print(nullptr, 0, DEBUG_DCE_COMMON,"%s","\n");
+}
+
index e923f1ed4f02ce0fc4de874fd2a5e963f4842f8a..745a69cc2e73d2f41937935035ed1857bef2374e 100644 (file)
@@ -70,6 +70,14 @@ enum DCE2_IntType
     DCE2_INT_TYPE__UINT64
 };
 
+/* DCE/RPC byte order flag */
+enum DceRpcBoFlag
+{
+    DCERPC_BO_FLAG__NONE,
+    DCERPC_BO_FLAG__BIG_ENDIAN,
+    DCERPC_BO_FLAG__LITTLE_ENDIAN
+};
+
 /********************************************************************
  * Structures
  ********************************************************************/
@@ -104,6 +112,8 @@ inline char* DCE2_PruneWhiteSpace(char*);
 inline bool DCE2_IsEmptyStr(char*);
 
 inline int DCE2_UuidCompare(const void*, const void*);
+const char* DCE2_UuidToStr(const Uuid*, DceRpcBoFlag);
+void DCE2_PrintPktData(const uint8_t*, const uint16_t);
 
 /********************************************************************
  * Public function prototypes
@@ -253,5 +263,120 @@ inline int DCE2_UuidCompare(const void* data1, const void* data2)
     return -1;
 }
 
+inline DceRpcBoFlag DceRpcByteOrder(const uint8_t value)
+{
+    if ((value & 0x10) >> 4)
+        return DCERPC_BO_FLAG__LITTLE_ENDIAN;
+
+    return DCERPC_BO_FLAG__BIG_ENDIAN;
+}
+
+inline uint16_t DceRpcNtohs(const uint16_t* ptr, const DceRpcBoFlag bo_flag)
+{
+    uint16_t value;
+
+    if (ptr == nullptr)
+        return 0;
+
+#ifdef WORDS_MUSTALIGN
+    value = *((uint8_t*)ptr) << 8 | *((uint8_t*)ptr + 1);
+#else
+    value = *ptr;
+#endif  /* WORDS_MUSTALIGN */
+
+    if (bo_flag == DCERPC_BO_FLAG__NONE)
+        return value;
+
+#ifdef WORDS_BIGENDIAN
+    if (bo_flag == DCERPC_BO_FLAG__BIG_ENDIAN)
+#else
+    if (bo_flag == DCERPC_BO_FLAG__LITTLE_ENDIAN)
+#endif  /* WORDS_BIGENDIAN */
+        return value;
+
+    return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8);
+}
+
+inline uint16_t DceRpcHtons(const uint16_t* ptr, const DceRpcBoFlag bo_flag)
+{
+    return DceRpcNtohs(ptr, bo_flag);
+}
+
+inline uint32_t DceRpcNtohl(const uint32_t* ptr, const DceRpcBoFlag bo_flag)
+{
+    uint32_t value;
+
+    if (ptr == nullptr)
+        return 0;
+
+#ifdef WORDS_MUSTALIGN
+    value = *((uint8_t*)ptr) << 24 | *((uint8_t*)ptr + 1) << 16 |
+        *((uint8_t*)ptr + 2) << 8  | *((uint8_t*)ptr + 3);
+#else
+    value = *ptr;
+#endif  /* WORDS_MUSTALIGN */
+
+    if (bo_flag == DCERPC_BO_FLAG__NONE)
+        return value;
+
+#ifdef WORDS_BIGENDIAN
+    if (bo_flag == DCERPC_BO_FLAG__BIG_ENDIAN)
+#else
+    if (bo_flag == DCERPC_BO_FLAG__LITTLE_ENDIAN)
+#endif  /* WORDS_BIGENDIAN */
+        return value;
+
+    return ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8) |
+           ((value & 0x0000ff00) << 8)  | ((value & 0x000000ff) << 24);
+}
+
+inline uint32_t DceRpcHtonl(const uint32_t* ptr, const DceRpcBoFlag bo_flag)
+{
+    return DceRpcNtohl(ptr, bo_flag);
+}
+
+inline void DCE2_CopyUuid(Uuid* dst_uuid, const Uuid* pkt_uuid, const DceRpcBoFlag byte_order)
+{
+    dst_uuid->time_low = DceRpcNtohl(&pkt_uuid->time_low, byte_order);
+    dst_uuid->time_mid = DceRpcNtohs(&pkt_uuid->time_mid, byte_order);
+    dst_uuid->time_high_and_version = DceRpcNtohs(&pkt_uuid->time_high_and_version, byte_order);
+    dst_uuid->clock_seq_and_reserved = pkt_uuid->clock_seq_and_reserved;
+    dst_uuid->clock_seq_low = pkt_uuid->clock_seq_low;
+    memcpy(dst_uuid->node, pkt_uuid->node, sizeof(dst_uuid->node));
+}
+
+inline int DCE2_BufferIsEmpty(DCE2_Buffer* buf)
+{
+    if (buf == nullptr)
+        return 1;
+    if ((buf->data == nullptr) || (buf->len == 0))
+        return 1;
+    return 0;
+}
+
+inline uint32_t DCE2_BufferLength(DCE2_Buffer* buf)
+{
+    if (buf == nullptr)
+        return 0;
+    return buf->len;
+}
+
+inline uint8_t* DCE2_BufferData(DCE2_Buffer* buf)
+{
+    if (buf == nullptr)
+        return nullptr;
+    return buf->data;
+}
+
+inline void DCE2_BufferEmpty(DCE2_Buffer* buf)
+{
+    if (buf == nullptr)
+        return;
+    buf->len = 0;
+}
+
+#define DCE2_MOVE(data_ptr, data_len, amount) \
+    { data_len -= (amount); data_ptr = (uint8_t*)data_ptr + (amount); }
+
 #endif  /* _DCE2_UTILS_H_ */