/******************************************************************** * 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: * ********************************************************************/ void DCE2_BufferDestroy(DCE2_Buffer *buf) { if (buf == NULL) return; if (buf->data != NULL) DCE2_Free((void *)buf->data, buf->size, buf->mtype); DCE2_Free((void *)buf, sizeof(DCE2_Buffer), buf->mtype); }
/******************************************************************** * Function: DCE2_ClFragDataFree() * * Callback to fragment list for freeing data kept in list. Need * to free the frag node and the data attached to it. * * Arguments: * void * * Pointer to fragment data (a frag node). * * Returns: None * ********************************************************************/ static void DCE2_ClFragDataFree(void *data) { DCE2_ClFragNode *fn = (DCE2_ClFragNode *)data; if (fn == NULL) return; if (fn->frag_data != NULL) DCE2_Free((void *)fn->frag_data, fn->frag_len, DCE2_MEM_TYPE__CL_FRAG); DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); }
/******************************************************************** * 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_ClActKeyFree() * * Callback to activity tracker list for freeing the key (this is * the activity UUID). Since key is dynamically allocated, we need * to free it. * * Arguments: * void * * The activity UUID to free. * * Returns: None * ********************************************************************/ static void DCE2_ClActKeyFree(void *key) { if (key == NULL) return; DCE2_Free(key, sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); }
/******************************************************************** * 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: DCE2_HttpSsnFree() * * Frees the session data structure and any dynamically allocated * data within it. * * Arguments: * void * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ void DCE2_HttpSsnFree(void *ssn) { DCE2_HttpSsnData *hsd = (DCE2_HttpSsnData *)ssn; if (hsd == NULL) return; DCE2_HttpDataFree(hsd); DCE2_Free((void *)hsd, sizeof(DCE2_HttpSsnData), DCE2_MEM_TYPE__HTTP_SSN); }
/******************************************************************** * Function: DCE2_UdpSsnFree() * * Purpose: Callback to session for freeing sessiond data. * * Arguments: * void * - pointer to the memory to be freed. * * Returns: None * ********************************************************************/ void DCE2_UdpSsnFree(void *data) { DCE2_UdpSsnData *usd = (DCE2_UdpSsnData *)data; if (usd == NULL) return; DCE2_UdpDataFree(usd); DCE2_Free((void *)usd, sizeof(DCE2_UdpSsnData), DCE2_MEM_TYPE__UDP_SSN); }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_StatsFree(void) { if (dce2_trans_strs != NULL) { unsigned int i; for (i = DCE2_TRANS_TYPE__NONE; i < DCE2_TRANS_TYPE__MAX; i++) { if (dce2_trans_strs[i] != NULL) { DCE2_Free((void *)dce2_trans_strs[i], strlen(dce2_trans_strs[i]) + 1, DCE2_MEM_TYPE__INIT); } } DCE2_Free((void *)dce2_trans_strs, (DCE2_TRANS_TYPE__MAX * sizeof(char *)), DCE2_MEM_TYPE__INIT); dce2_trans_strs = NULL; } }
/******************************************************************** * Function: DCE2_ClActDataFree() * * Callback to activity tracker list for freeing activity trackers. * * Arguments: * void * * Activity tracker to free. * * Returns: None * ********************************************************************/ static void DCE2_ClActDataFree(void *data) { DCE2_ClActTracker *at = (DCE2_ClActTracker *)data; if (at == NULL) return; DCE2_ListDestroy(at->frag_tracker.frags); at->frag_tracker.frags = NULL; DCE2_Free((void *)at, sizeof(DCE2_ClActTracker), DCE2_MEM_TYPE__CL_ACT); }
/****************************************************************** * Function: DCE2_EventsFree() * * Frees any global data that was dynamically allocated. * * Arguments: None * * Returns: None * ******************************************************************/ void DCE2_EventsFree(void) { unsigned int i; for (i = 0; i < DCE2_EVENT__MAX; i++) { if (dce2_events[i].format != NULL) { DCE2_Free((void *)dce2_events[i].format, strlen(dce2_events[i].format) + 1, DCE2_MEM_TYPE__INIT); dce2_events[i].format = NULL; } } for (i = 0; i < (sizeof(dce2_pdu_types) / sizeof(char *)); i++) { if (dce2_pdu_types[i] != NULL) { DCE2_Free((void *)dce2_pdu_types[i], strlen(dce2_pdu_types[i]) + 1, DCE2_MEM_TYPE__INIT); dce2_pdu_types[i] = NULL; } } }
/******************************************************************** * 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; }