/******************************************************************** * Function: DCE2_ClInsertActTracker() * * Creates and inserts a new activity tracker into a list. * * Arguments: * DCE2_ClTracker * * Pointer to connectionless tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * * Returns: * DCE2_ClActTracker * * A valid pointer to an activity tracker on success. * NULL on error. * ********************************************************************/ static DCE2_ClActTracker * DCE2_ClInsertActTracker(DCE2_ClTracker *clt, DceRpcClHdr *cl_hdr) { Uuid *uuid = (Uuid *)DCE2_Alloc(sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); DCE2_ClActTracker *at; DCE2_Ret status; if (uuid == NULL) return NULL; at = (DCE2_ClActTracker *)DCE2_Alloc(sizeof(DCE2_ClActTracker), DCE2_MEM_TYPE__CL_ACT); if (at == NULL) { DCE2_Free((void *)uuid, sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); return NULL; } DCE2_CopyUuid(uuid, &cl_hdr->act_id, DceRpcClByteOrder(cl_hdr)); DCE2_CopyUuid(&at->act, &cl_hdr->act_id, DceRpcClByteOrder(cl_hdr)); status = DCE2_ListInsert(clt->act_trackers, (void *)uuid, (void *)at); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)uuid, sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); DCE2_Free((void *)at, sizeof(DCE2_ClActTracker), DCE2_MEM_TYPE__CL_ACT); return NULL; } return at; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_Buffer * DCE2_BufferNew(uint32_t initial_size, uint32_t min_add_size, DCE2_MemType mem_type) { DCE2_Buffer *buf = (DCE2_Buffer *)DCE2_Alloc(sizeof(DCE2_Buffer), mem_type); if (buf == NULL) return NULL; if (initial_size != 0) { buf->data = (uint8_t *)DCE2_Alloc(initial_size, mem_type); if (buf->data == NULL) { DCE2_Free((void *)buf, sizeof(DCE2_Buffer), mem_type); return NULL; } } buf->size = initial_size; buf->len = 0; buf->mtype = mem_type; buf->min_add_size = min_add_size; buf->offset = 0; return buf; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_BufferAddData( DCE2_Buffer *buf, const uint8_t *data, uint32_t data_len, uint32_t offset, DCE2_BufferMinAddFlag mflag) { DCE2_Ret status; if ((buf == NULL) || (data == NULL)) return DCE2_RET__ERROR; /* Return success for this since ultimately nothing _was_ added */ if (data_len == 0) return DCE2_RET__SUCCESS; if ( !offset ) offset = DCE2_BufferLength(buf); if (buf->data == NULL) { uint32_t size = offset + data_len; if ((size < buf->min_add_size) && (mflag == DCE2_BUFFER_MIN_ADD_FLAG__USE)) size = buf->min_add_size; buf->data = (uint8_t *)DCE2_Alloc(size, buf->mtype); if (buf->data == NULL) return DCE2_RET__ERROR; buf->size = size; } else if ((offset + data_len) > buf->size) { uint8_t *tmp; uint32_t new_size = offset + data_len; if (((new_size - buf->size) < buf->min_add_size) && (mflag == DCE2_BUFFER_MIN_ADD_FLAG__USE)) new_size += buf->min_add_size; tmp = (uint8_t *)DCE2_ReAlloc(buf->data, buf->size, new_size, buf->mtype); if (tmp == NULL) return DCE2_RET__ERROR; buf->data = tmp; buf->size = new_size; } status = DCE2_Memcpy(buf->data + offset, data, data_len, buf->data, buf->data + buf->size); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } buf->len = offset + data_len; return DCE2_RET__SUCCESS; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_UdpSsnData * DCE2_UdpSsnInit(void) { DCE2_UdpSsnData *usd = DCE2_Alloc(sizeof(DCE2_UdpSsnData), DCE2_MEM_TYPE__UDP_SSN); if (usd == NULL) return NULL; DCE2_ResetRopts(&usd->sd.ropts); dce2_stats.udp_sessions++; return usd; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_CreateTransStr(char **trans_buf, DCE2_TransType ttype, char *trans_str) { if ((trans_buf == NULL) || (trans_str == NULL)) return; trans_buf[ttype] = (char *)DCE2_Alloc(strlen(trans_str) + 1, DCE2_MEM_TYPE__INIT); if (trans_buf[ttype] == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for transport string", __FILE__, __LINE__); } snprintf(trans_buf[ttype], strlen(trans_str) + 1, "%s", trans_str); }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void * DCE2_ReAlloc(void *old_mem, uint32_t old_size, uint32_t new_size, DCE2_MemType mtype) { void *new_mem; DCE2_Ret status; if (dce2_mem_state == DCE2_MEM_STATE__MEMCAP) return NULL; if (old_mem == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Old memory passed in was NULL.", __FILE__, __LINE__); return NULL; } else if (new_size < old_size) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) New size is less than old size.", __FILE__, __LINE__); return NULL; } else if (new_size == old_size) { return old_mem; } if (DCE2_CheckMemcap(new_size - old_size, mtype) == DCE2_MEMCAP_EXCEEDED) return NULL; new_mem = DCE2_Alloc(new_size, mtype); if (new_mem == NULL) return NULL; status = DCE2_Memcpy(new_mem, old_mem, old_size, new_mem, (void *)((uint8_t *)new_mem + new_size)); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy old memory into new memory.", __FILE__, __LINE__); DCE2_Free(new_mem, new_size, mtype); return NULL; } DCE2_Free(old_mem, old_size, mtype); return new_mem; }
/******************************************************************** * Function: DCE2_HttpSsnInit() * * Creates and initializes an rpc over http session data structure. * * Arguments: None * * Returns: * DCE2_HttpSsnData * * Valid pointer to an rpc over http session data structure. * NULL if unable to allocate memory. * ********************************************************************/ static DCE2_HttpSsnData * DCE2_HttpSsnInit(void) { DCE2_HttpSsnData *hsd = DCE2_Alloc(sizeof(DCE2_HttpSsnData), DCE2_MEM_TYPE__HTTP_SSN); if (hsd == NULL) return NULL; hsd->state = DCE2_HTTP_STATE__NONE; DCE2_CoInitTracker(&hsd->co_tracker); DCE2_ResetRopts(&hsd->sd.ropts); return hsd; }
/********************************************************************* * Function: DCE2_ReloadGlobal() * * Purpose: Creates a new global DCE/RPC preprocessor config. * * Arguments: snort.conf argument line for the DCE/RPC preprocessor. * * Returns: None * *********************************************************************/ static void DCE2_ReloadGlobal(char *args) { tSfPolicyId policy_id = _dpd.getParserPolicy(); DCE2_Config *pDefaultPolicyConfig = NULL; DCE2_Config *pCurrentPolicyConfig = NULL; if ((_dpd.streamAPI == NULL) || (_dpd.streamAPI->version != STREAM_API_VERSION5)) { DCE2_Die("%s(%d) \"%s\" configuration: " "Stream5 must be enabled with TCP and UDP tracking.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } if (dce2_swap_config == NULL) { //create a context dce2_swap_config = sfPolicyConfigCreate(); if (dce2_swap_config == NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Could not allocate memory " "configuration.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } _dpd.addPreprocReloadVerify(DCE2_ReloadVerify); } sfPolicyUserPolicySet(dce2_swap_config, policy_id); pDefaultPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetDefault(dce2_swap_config); pCurrentPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetCurrent(dce2_swap_config); if ((policy_id != 0) && (pDefaultPolicyConfig == NULL)) { DCE2_Die("%s(%d) \"%s\" configuration: Must configure default policy " "if other policies are to be configured.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } /* Can only do one global configuration */ if (pCurrentPolicyConfig != NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Only one global configuration can be specified.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } DCE2_RegRuleOptions(); pCurrentPolicyConfig = (DCE2_Config *)DCE2_Alloc(sizeof(DCE2_Config), DCE2_MEM_TYPE__CONFIG); sfPolicyUserDataSetCurrent(dce2_swap_config, pCurrentPolicyConfig); /* Parse configuration args */ DCE2_GlobalConfigure(pCurrentPolicyConfig, args); if ( pCurrentPolicyConfig->gconfig->disabled ) return; _dpd.addPreproc(DCE2_Main, PRIORITY_APPLICATION, PP_DCE2, PROTO_BIT__TCP | PROTO_BIT__UDP); #ifdef TARGET_BASED _dpd.streamAPI->set_service_filter_status (dce2_proto_ids.dcerpc, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_service_filter_status (dce2_proto_ids.nbss, PORT_MONITOR_SESSION, policy_id, 1); #endif if (policy_id != 0) pCurrentPolicyConfig->gconfig->memcap = pDefaultPolicyConfig->gconfig->memcap; }
/********************************************************************* * Function: DCE2_InitGlobal() * * Purpose: Initializes the global DCE/RPC preprocessor config. * * Arguments: snort.conf argument line for the DCE/RPC preprocessor. * * Returns: None * *********************************************************************/ static void DCE2_InitGlobal(char *args) { tSfPolicyId policy_id = _dpd.getParserPolicy(); DCE2_Config *pDefaultPolicyConfig = NULL; DCE2_Config *pCurrentPolicyConfig = NULL; if ((_dpd.streamAPI == NULL) || (_dpd.streamAPI->version != STREAM_API_VERSION5)) { DCE2_Die("%s(%d) \"%s\" configuration: " "Stream5 must be enabled with TCP and UDP tracking.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } if (dce2_config == NULL) { dce2_config = sfPolicyConfigCreate(); if (dce2_config == NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Could not allocate memory " "configuration.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } DCE2_MemInit(); DCE2_StatsInit(); DCE2_EventsInit(); /* Initialize reassembly packet */ DCE2_InitRpkts(); DCE2_SmbInitGlobals(); _dpd.addPreprocConfCheck(DCE2_CheckConfig); _dpd.registerPreprocStats(DCE2_GNAME, DCE2_PrintStats); _dpd.addPreprocReset(DCE2_Reset, NULL, PRIORITY_LAST, PP_DCE2); _dpd.addPreprocResetStats(DCE2_ResetStats, NULL, PRIORITY_LAST, PP_DCE2); _dpd.addPreprocExit(DCE2_CleanExit, NULL, PRIORITY_LAST, PP_DCE2); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc(DCE2_PSTAT__MAIN, &dce2_pstat_main, 0, _dpd.totalPerfStats); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SESSION, &dce2_pstat_session, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__NEW_SESSION, &dce2_pstat_new_session, 2, &dce2_pstat_session); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SSN_STATE, &dce2_pstat_session_state, 2, &dce2_pstat_session); _dpd.addPreprocProfileFunc(DCE2_PSTAT__LOG, &dce2_pstat_log, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__DETECT, &dce2_pstat_detect, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_SEG, &dce2_pstat_smb_seg, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_REQ, &dce2_pstat_smb_req, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_UID, &dce2_pstat_smb_uid, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_TID, &dce2_pstat_smb_tid, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FID, &dce2_pstat_smb_fid, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FP, &dce2_pstat_smb_fingerprint, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_NEG, &dce2_pstat_smb_negotiate, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_SEG, &dce2_pstat_co_seg, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_FRAG, &dce2_pstat_co_frag, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_REASS, &dce2_pstat_co_reass, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_CTX, &dce2_pstat_co_ctx, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CL_ACTS, &dce2_pstat_cl_acts, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CL_FRAG, &dce2_pstat_cl_frag, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CL_REASS, &dce2_pstat_cl_reass, 1, &dce2_pstat_main); #endif #ifdef TARGET_BASED dce2_proto_ids.dcerpc = _dpd.findProtocolReference(DCE2_PROTO_REF_STR__DCERPC); if (dce2_proto_ids.dcerpc == SFTARGET_UNKNOWN_PROTOCOL) dce2_proto_ids.dcerpc = _dpd.addProtocolReference(DCE2_PROTO_REF_STR__DCERPC); /* smb and netbios-ssn refer to the same thing */ dce2_proto_ids.nbss = _dpd.findProtocolReference(DCE2_PROTO_REF_STR__NBSS); if (dce2_proto_ids.nbss == SFTARGET_UNKNOWN_PROTOCOL) dce2_proto_ids.nbss = _dpd.addProtocolReference(DCE2_PROTO_REF_STR__NBSS); #endif } sfPolicyUserPolicySet(dce2_config, policy_id); pDefaultPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetDefault(dce2_config); pCurrentPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetCurrent(dce2_config); if ((policy_id != 0) && (pDefaultPolicyConfig == NULL)) { DCE2_Die("%s(%d) \"%s\" configuration: Must configure default policy " "if other policies are to be configured.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } /* Can only do one global configuration */ if (pCurrentPolicyConfig != NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Only one global configuration can be specified.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } DCE2_RegRuleOptions(); pCurrentPolicyConfig = (DCE2_Config *)DCE2_Alloc(sizeof(DCE2_Config), DCE2_MEM_TYPE__CONFIG); sfPolicyUserDataSetCurrent(dce2_config, pCurrentPolicyConfig); /* Parse configuration args */ DCE2_GlobalConfigure(pCurrentPolicyConfig, args); if (policy_id != 0) pCurrentPolicyConfig->gconfig->memcap = pDefaultPolicyConfig->gconfig->memcap; if ( pCurrentPolicyConfig->gconfig->disabled ) return; /* Register callbacks */ _dpd.addPreproc(DCE2_Main, PRIORITY_APPLICATION, PP_DCE2, PROTO_BIT__TCP | PROTO_BIT__UDP); #ifdef TARGET_BASED _dpd.streamAPI->set_service_filter_status (dce2_proto_ids.dcerpc, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_service_filter_status (dce2_proto_ids.nbss, PORT_MONITOR_SESSION, policy_id, 1); #endif }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_StatsInit(void) { memset(&dce2_stats, 0, sizeof(dce2_stats)); if (dce2_trans_strs == NULL) { DCE2_TransType ttype; dce2_trans_strs = (char **)DCE2_Alloc((DCE2_TRANS_TYPE__MAX * sizeof(char *)), DCE2_MEM_TYPE__INIT); if (dce2_trans_strs == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for transport string " "array", __FILE__, __LINE__); } for (ttype = DCE2_TRANS_TYPE__NONE; ttype < DCE2_TRANS_TYPE__MAX; ttype++) { switch (ttype) { case DCE2_TRANS_TYPE__NONE: break; case DCE2_TRANS_TYPE__SMB: { char *str = "SMB"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__TCP: { char *str = "TCP"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__UDP: { char *str = "UDP"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__HTTP_PROXY: { char *str = "HTTP Proxy"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__HTTP_SERVER: { char *str = "HTTP Server"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; default: DCE2_Die("%s(%d) Invalid transport type for allocing " "transport strings: %d", __FILE__, __LINE__, ttype); break; } } } }
/******************************************************************** * Function: DCE2_ClHandleFrag() * * Handles connectionless fragments. Creates a new fragment list * if necessary and inserts fragment into list. Sets rule option * values based on the fragment. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_ClActTracker * * Pointer to the connectionless activity tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * const uint8_t * * Pointer to current position in the packet payload. * uint16_t * Length of packet payload left from current pointer * position. * * Returns: None * ********************************************************************/ static void DCE2_ClHandleFrag(DCE2_SsnData *sd, DCE2_ClActTracker *at, DceRpcClHdr *cl_hdr, const uint8_t *data_ptr, uint16_t data_len) { DCE2_ClFragTracker *ft = &at->frag_tracker; DCE2_ClFragNode *fn; uint16_t frag_len; int status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_cl_frag); /* If the frag length is less than data length there might be authentication * data that we don't want to include, otherwise just set to data len */ if (DceRpcClLen(cl_hdr) < data_len) frag_len = DceRpcClLen(cl_hdr); else frag_len = data_len; if (frag_len == 0) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); return; } if (frag_len > dce2_stats.cl_max_frag_size) dce2_stats.cl_max_frag_size = frag_len; if (DCE2_GcMaxFrag() && (frag_len > DCE2_GcMaxFragLen())) frag_len = DCE2_GcMaxFragLen(); if (ft->frags == NULL) { /* Create new list if we don't have one already */ ft->frags = DCE2_ListNew(DCE2_LIST_TYPE__SORTED, DCE2_ClFragCompare, DCE2_ClFragDataFree, NULL, DCE2_LIST_FLAG__NO_DUPS | DCE2_LIST_FLAG__INS_TAIL, DCE2_MEM_TYPE__CL_FRAG); if (ft->frags == NULL) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); return; } } else { /* If we already have a fragment in the list with the same fragment number, * that fragment will take precedence over this fragment and this fragment * will not be used by the server */ fn = (DCE2_ClFragNode *)DCE2_ListFind(ft->frags, (void *)(uintptr_t)DceRpcClFragNum(cl_hdr)); if (fn != NULL) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); return; } } /* Create a new frag node to insert into the list */ fn = (DCE2_ClFragNode *)DCE2_Alloc(sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); if (fn == NULL) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } fn->frag_number = DceRpcClFragNum(cl_hdr); fn->frag_len = frag_len; /* Allocate space for the fragment data */ fn->frag_data = (uint8_t *)DCE2_Alloc(frag_len, DCE2_MEM_TYPE__CL_FRAG); if (fn->frag_data == NULL) { DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } /* Copy the fragment data in the packet to the space just allocated */ status = DCE2_Memcpy(fn->frag_data, data_ptr, frag_len, fn->frag_data, fn->frag_data + frag_len); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)fn->frag_data, frag_len, DCE2_MEM_TYPE__CL_FRAG); DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } if (DCE2_ListIsEmpty(ft->frags)) { /* If this is the first fragment we've received, set interface uuid */ DCE2_CopyUuid(&ft->iface, DceRpcClIface(cl_hdr), DceRpcClByteOrder(cl_hdr)); ft->iface_vers = DceRpcClIfaceVers(cl_hdr); } if (DceRpcClLastFrag(cl_hdr)) { /* Set number of expected frags on last frag */ ft->num_expected_frags = DceRpcClFragNum(cl_hdr) + 1; } else if (DceRpcClFirstFrag(cl_hdr)) { /* Set opum and byte order on first frag */ ft->opnum = DceRpcClOpnum(cl_hdr); ft->data_byte_order = DceRpcClByteOrder(cl_hdr); } /* Insert frag node into the list */ status = DCE2_ListInsert(ft->frags, (void *)(uintptr_t)fn->frag_number, (void *)fn); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)fn->frag_data, frag_len, DCE2_MEM_TYPE__CL_FRAG); DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } /* Fragment number field in header is uint16_t */ if ((ft->num_expected_frags != DCE2_SENTINEL) && (uint16_t)ft->frags->num_nodes == (uint16_t)ft->num_expected_frags) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); /* We got all of the frags - reassemble */ DCE2_ClFragReassemble(sd, at, cl_hdr); at->seq_num_invalid = 1; return; } PREPROC_PROFILE_END(dce2_pstat_cl_frag); /* Cache relevant values for rule option processing */ sd->ropts.first_frag = DceRpcClFirstFrag(cl_hdr); DCE2_CopyUuid(&sd->ropts.iface, &ft->iface, DCERPC_BO_FLAG__NONE); sd->ropts.iface_vers = ft->iface_vers; sd->ropts.hdr_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->data_byte_order != DCE2_SENTINEL) sd->ropts.data_byte_order = ft->data_byte_order; else sd->ropts.data_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->opnum != DCE2_SENTINEL) sd->ropts.opnum = ft->opnum; else sd->ropts.opnum = DceRpcClOpnum(cl_hdr); sd->ropts.stub_data = (uint8_t *)cl_hdr + sizeof(DceRpcClHdr); DCE2_Detect(sd); }
/******************************************************************** * Function: * * Must have allocated data in buffer and data_len must fit in * buffer. * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_BufferMoveData(DCE2_Buffer *buf, uint32_t data_offset, const uint8_t *move, uint32_t move_len) { DCE2_Ret status; uint8_t *offset, *end; if ((buf == NULL) || (buf->data == NULL) || (move == NULL)) return DCE2_RET__ERROR; /* Return success for this since ultimately nothing _was_ moved */ if (move_len == 0) return DCE2_RET__SUCCESS; offset = buf->data + data_offset; end = buf->data + buf->len; /* Moved data must be within current data */ if ((move < buf->data) || ((move + move_len) > end)) return DCE2_RET__ERROR; /* No move required */ if (move == offset) return DCE2_RET__SUCCESS; /* Would have to do two moves. One for the data and one to realign data * with start of moved data. Don't want to succeed on the first and fail * on the second and leave the buffer in a bad state. Don't want to use * an offset in data buffer because want to keep the size the same. */ if (move == buf->data) { uint32_t tmp_size = buf->len; uint8_t *tmp = (uint8_t *)DCE2_Alloc(tmp_size, buf->mtype); uint8_t *tmp_offset, *tmp_end; uint32_t new_len; if (tmp == NULL) return DCE2_RET__ERROR; tmp_offset = tmp + data_offset; tmp_end = tmp + tmp_size; status = DCE2_Memcpy(tmp, buf->data, buf->len, tmp, tmp_end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } status = DCE2_Memmove(tmp_offset, tmp, move_len, tmp_offset, tmp_end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } if (tmp_offset > (tmp + move_len)) tmp_offset = tmp + move_len; new_len = tmp_end - tmp_offset; status = DCE2_Memcpy(buf->data, tmp_offset, new_len, buf->data, end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } buf->len = new_len; DCE2_Free((void *)tmp, tmp_size, buf->mtype); } else { status = DCE2_Memmove(offset, move, move_len, offset, end); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer", __FILE__, __LINE__); return DCE2_RET__ERROR; } /* If we have a new end of data, adjust length */ if ((move + move_len) == end) buf->len = data_offset + move_len; } return DCE2_RET__SUCCESS; }
/****************************************************************** * Function: DCE2_EventsInit() * * Initializes global data. * * Arguments: None * * Returns: None * ******************************************************************/ void DCE2_EventsInit(void) { DCE2_Event event; char gname[100]; unsigned int i; static const DCE2_EventNode events[DCE2_EVENT__MAX] = { { DCE2_EVENT_FLAG__NONE, DCE2_EVENT__NO_EVENT, "Have to use this because can't have an event sid of zero" }, { DCE2_EVENT_FLAG__MEMCAP, DCE2_EVENT__MEMCAP, "Memory cap exceeded" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_NBSS_TYPE, "SMB - Bad NetBIOS Session Service session type" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_TYPE, "SMB - Bad SMB message type" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_ID, "SMB - Bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_WCT, "SMB - Bad word count or structure size: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_BCC, "SMB - Bad byte count: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_FORMAT, "SMB - Bad format type: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_OFF, "SMB - Bad offset: %p not between %p and %p" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_TDCNT_ZERO, "SMB - Zero total data count" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_SMBHDR, "SMB - NetBIOS data length (%u) less than SMB header length (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_COM, "SMB - Remaining NetBIOS data length (%u) less than command length (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_BCC, "SMB - Remaining NetBIOS data length (%u) less than command byte count (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_DSIZE, "SMB - Remaining NetBIOS data length (%u) less than command data size (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_TDCNT_LT_DSIZE, "SMB - Remaining total data count (%u) less than this command data size (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DSENT_GT_TDCNT, "SMB - Total data sent ("STDu64") greater than command total data expected (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BCC_LT_DSIZE, "SMB - Byte count (%u) less than command data size ("STDu64")" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_DSIZE, "SMB - Invalid command data size (%u) for byte count (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EXCESSIVE_TREE_CONNECTS, "SMB - Excessive Tree Connect requests (>%u) with pending Tree Connect responses" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EXCESSIVE_READS, "SMB - Excessive Read requests (>%u) with pending Read responses" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EXCESSIVE_CHAINING, "SMB - Excessive command chaining (>%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MULT_CHAIN_SS, "SMB - Multiple chained login requests" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MULT_CHAIN_TC, "SMB - Multiple chained tree connect requests" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_CHAIN_SS_LOGOFF, "SMB - Chained/Compounded login followed by logoff" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_CHAIN_TC_TDIS, "SMB - Chained/Compounded tree connect followed by tree disconnect" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE, "SMB - Chained/Compounded open pipe followed by close pipe" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_SHARE, "SMB - Invalid share access: %s" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_BAD_MAJ_VERSION, "Connection-oriented DCE/RPC - Invalid major version: %u" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_BAD_MIN_VERSION, "Connection-oriented DCE/RPC - Invalid minor version: %u" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_BAD_PDU_TYPE, "Connection-oriented DCE/RPC - Invalid pdu type: 0x%02x" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FLEN_LT_HDR, "Connection-oriented DCE/RPC - Fragment length (%u) less than header size (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FLEN_LT_SIZE, "Connection-oriented DCE/RPC - %s: Remaining fragment length (%u) less than size needed (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_ZERO_CTX_ITEMS, "Connection-oriented DCE/RPC - %s: No context items specified" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_ZERO_TSYNS, "Connection-oriented DCE/RPC - %s: No transfer syntaxes specified" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG, "Connection-oriented DCE/RPC - %s: Fragment length on non-last fragment (%u) less than " "maximum negotiated fragment transmit size for client (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG, "Connection-oriented DCE/RPC - %s: Fragment length (%u) greater than " "maximum negotiated fragment transmit size (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_ALTER_CHANGE_BYTE_ORDER, "Connection-oriented DCE/RPC - Alter Context byte order different from Bind" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_DIFF_CALL_ID, "Connection-oriented DCE/RPC - Call id (%u) of non first/last fragment different " "from call id established for fragmented request (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_DIFF_OPNUM, "Connection-oriented DCE/RPC - Opnum (%u) of non first/last fragment different " "from opnum established for fragmented request (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_DIFF_CTX_ID, "Connection-oriented DCE/RPC - Context id (%u) of non first/last fragment different " "from context id established for fragmented request (%u)" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_BAD_MAJ_VERSION, "Connection-less DCE/RPC - Invalid major version: %u" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_BAD_PDU_TYPE, "Connection-less DCE/RPC - Invalid pdu type: 0x%02x" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_DATA_LT_HDR, "Connection-less DCE/RPC - Data length (%u) less than header size (%u)" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_BAD_SEQ_NUM, "Connection-less DCE/RPC - %s: Bad sequence number" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_V1, "SMB - Invalid SMB version 1 seen" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_V2, "SMB - Invalid SMB version 2 seen" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_BINDING, "SMB - Invalid user, tree connect, file binding" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB2_EXCESSIVE_COMPOUNDING, "SMB - Excessive command compounding (>%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DCNT_ZERO, "SMB - Zero data count" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DCNT_MISMATCH, "SMB - Data count mismatch %u in command / %u in format" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MAX_REQS_EXCEEDED, "SMB - Maximum number of outstanding requests exceeded: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_REQS_SAME_MID, "SMB - Outstanding requests with same MID", }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED, "SMB - Deprecated dialect negotiated" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DEPR_COMMAND_USED, "SMB - Deprecated command used: %s" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, "SMB - Unusual command used: %s" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_SETUP_COUNT, "SMB - Invalid setup count for %s/%s command: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS, "SMB - Client attempted multiple dialect negotiations on session" } }; snprintf(gname, sizeof(gname) - 1, "(%s) ", DCE2_GNAME); gname[sizeof(gname) - 1] = '\0'; for (event = DCE2_EVENT__NO_EVENT; event < DCE2_EVENT__MAX; event++) { int size = strlen(gname) + strlen(events[event].format) + 1; /* This is a check to make sure all of the events in the array are * in the same order as the enum, so we index the right thing when * alerting - DO NOT REMOVE THIS CHECK */ if (events[event].event != event) { DCE2_Die("%s(%d) Events are not in the right order.", __FILE__, __LINE__); } dce2_events[event].format = (char *)DCE2_Alloc(size, DCE2_MEM_TYPE__INIT); if (dce2_events[event].format == NULL) { DCE2_Die("%s(%d) Could not allocate memory for events array.", __FILE__, __LINE__); } dce2_events[event].format[size - 1] = '\0'; snprintf(dce2_events[event].format, size, "%s%s", gname, events[event].format); if (dce2_events[event].format[size - 1] != '\0') { DCE2_Die("%s(%d) Event string truncated.", __FILE__, __LINE__); } dce2_events[event].eflag = events[event].eflag; dce2_events[event].event = events[event].event; } for (i = 0; i < (sizeof(dce2_pdu_types) / sizeof(char *)); i++) { char *type; switch (i) { case DCERPC_PDU_TYPE__REQUEST: type = "Request"; break; case DCERPC_PDU_TYPE__PING: type = "Ping"; break; case DCERPC_PDU_TYPE__RESPONSE: type = "Response"; break; case DCERPC_PDU_TYPE__FAULT: type = "Fault"; break; case DCERPC_PDU_TYPE__WORKING: type = "Working"; break; case DCERPC_PDU_TYPE__NOCALL: type = "NoCall"; break; case DCERPC_PDU_TYPE__REJECT: type = "Reject"; break; case DCERPC_PDU_TYPE__ACK: type = "Ack"; break; case DCERPC_PDU_TYPE__CL_CANCEL: type = "Cancel"; break; case DCERPC_PDU_TYPE__FACK: type = "Fack"; break; case DCERPC_PDU_TYPE__CANCEL_ACK: type = "Cancel Ack"; break; case DCERPC_PDU_TYPE__BIND: type = "Bind"; break; case DCERPC_PDU_TYPE__BIND_ACK: type = "Bind Ack"; break; case DCERPC_PDU_TYPE__BIND_NACK: type = "Bind Nack"; break; case DCERPC_PDU_TYPE__ALTER_CONTEXT: type = "Alter Context"; break; case DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP: type = "Alter Context Response"; break; case DCERPC_PDU_TYPE__AUTH3: type = "Auth3"; break; case DCERPC_PDU_TYPE__SHUTDOWN: type = "Shutdown"; break; case DCERPC_PDU_TYPE__CO_CANCEL: type = "Cancel"; break; case DCERPC_PDU_TYPE__ORPHANED: type = "Orphaned"; break; case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP: type = "Microsoft Exchange/Outlook 2003"; break; default: type = "Unknown DCE/RPC type"; break; } dce2_pdu_types[i] = (char *)DCE2_Alloc(strlen(type) + 1, DCE2_MEM_TYPE__INIT); strncpy(dce2_pdu_types[i], type, strlen(type)); dce2_pdu_types[i][strlen(type)] = '\0'; #ifdef DCE2_EVENT_PRINT_DEBUG printf("%s\n", dce2_pdu_types[i]); #endif } }