static void globalCleanup(KSI_CTX *ctx) { int res; size_t pos; void (*fn)(void); for (pos = 0; pos < KSI_List_length(ctx->cleanupFnList); pos++) { res = KSI_List_elementAt(ctx->cleanupFnList, pos, (void **)&fn); if (res != KSI_OK) { KSI_LOG_error(ctx, "Unable to retrieve cleanup function - possible MEMORY CURRUPTION."); break; } if (fn == NULL) { KSI_LOG_error(ctx, "Got NULL as global cleanup method - possible MEMORY CURRUPTION."); break; } fn(); } }
static int construct(KSI_CTX *ctx, KSI_TLV *tlv, const void *payload, const KSI_TlvTemplate *tmpl, struct tlv_track_s *tr, size_t tr_len, const size_t tr_size) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; void *payloadp = NULL; int isNonCritical = 0; int isForward = 0; size_t template_len = 0; bool templateHit[MAX_TEMPLATE_SIZE]; bool groupHit[2] = {false, false}; bool oneOf[2] = {false, false}; size_t i; char buf[1000]; KSI_ERR_clearErrors(ctx); if (ctx == NULL || tlv == NULL || payload == NULL || tmpl == NULL || tr == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Calculate the template length. */ template_len = getTemplateLength(tmpl); if (template_len == 0) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "A template may not be empty."); goto cleanup; } if (template_len > MAX_TEMPLATE_SIZE) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Template too big."); goto cleanup; } memset(templateHit, 0, sizeof(templateHit)); for (i = 0; i < template_len; i++) { if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_NO_SERIALIZE) != 0) continue; payloadp = NULL; res = tmpl[i].getValue(payload, &payloadp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (payloadp != NULL) { /* Register for tracking. */ if (tr_len < tr_size) { tr[tr_len].tag = tmpl[i].tag; tr[tr_len].desc = tmpl[i].descr; } templateHit[i] = true; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G0) != 0) groupHit[0] = true; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G1) != 0) groupHit[1] = true; if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G0)) { if (oneOf[0]) { char errm[1000]; KSI_snprintf(errm, sizeof(errm), "Mutually exclusive elements present within group 0 (%s).", track_str(tr, tr_len, tr_size, buf, sizeof(buf))); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); } oneOf[0] = true; } if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G1)) { if (oneOf[1]) { char errm[1000]; KSI_snprintf(errm, sizeof(errm), "Mutually exclusive elements present within group 1 (%s).", track_str(tr, tr_len, tr_size, buf, sizeof(buf))); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); } oneOf[1] = true; } isNonCritical = (tmpl[i].flags & KSI_TLV_TMPL_FLG_NONCRITICAL) != 0; isForward = (tmpl[i].flags & KSI_TLV_TMPL_FLG_FORWARD) != 0; switch (tmpl[i].type) { case KSI_TLV_TEMPLATE_OBJECT: if (tmpl[i].toTlv == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Invalid template: toTlv not set."); goto cleanup; } if (tmpl[i].listLength != NULL) { int j; for (j = 0; j < tmpl[i].listLength(payloadp); j++) { void *listElement = NULL; res = tmpl[i].listElementAt(payloadp, j, &listElement); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = tmpl[i].toTlv(ctx, listElement, tmpl[i].tag, isNonCritical, isForward != 0, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } } else { res = tmpl[i].toTlv(ctx, payloadp, tmpl[i].tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } break; case KSI_TLV_TEMPLATE_COMPOSITE: if (tmpl[i].listLength != NULL) { int j; for (j = 0; j < tmpl[i].listLength(payloadp); j++) { void *listElement = NULL; res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_TLV, tmpl[i].tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = tmpl[i].listElementAt(payloadp, j, &listElement); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = construct(ctx, tmp, listElement, tmpl[i].subTemplate, tr, tr_len + 1, tr_size); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } } else { res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_TLV, tmpl[i].tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = construct(ctx, tmp, payloadp, tmpl[i].subTemplate, tr, tr_len + 1, tr_size); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } break; default: KSI_LOG_error(ctx, "Unimplemented template type: %d", tmpl[i].type); KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Unimplemented template type."); goto cleanup; } } } /* Check that every mandatory component was present. */ for (i = 0; i < template_len; i++) { char errm[1000]; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_MANDATORY) != 0 && !templateHit[i]) { KSI_snprintf(errm, sizeof(errm), "Mandatory element missing: %s->[0x%02x]%s", track_str(tr, tr_len, tr_size, buf, sizeof(buf)), tmpl[i].tag, tmpl[i].descr == NULL ? "" : tmpl[i].descr); KSI_LOG_debug(ctx, "%s", errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } if (((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G0) != 0 && !groupHit[0]) || ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G1) != 0 && !groupHit[1])) { KSI_snprintf(errm, sizeof(errm), "Mandatory group missing: %s->[0x%02x]%s", track_str(tr, tr_len, tr_size, buf, sizeof(buf)), tmpl[i].tag, tmpl[i].descr == NULL ? "" : tmpl[i].descr); KSI_LOG_debug(ctx, "%s", errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } } res = KSI_OK; cleanup: KSI_nofree(payloadp); KSI_TLV_free(tmp); return res; }
static int extractGenerator(KSI_CTX *ctx, void *payload, void *generatorCtx, const KSI_TlvTemplate *tmpl, int (*generator)(void *, KSI_TLV **), struct tlv_track_s *tr, size_t tr_len, size_t tr_size) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tlv = NULL; char buf[1024]; void *voidVal = NULL; void *compositeVal = NULL; void *valuep = NULL; KSI_TLV *tlvVal = NULL; size_t template_len = 0; bool templateHit[MAX_TEMPLATE_SIZE]; bool groupHit[2] = {false, false}; bool oneOf[2] = {false, false}; size_t i; size_t tmplStart = 0; KSI_ERR_clearErrors(ctx); if (ctx == NULL || payload == NULL || generatorCtx == NULL || tmpl == NULL || generator == NULL || tr == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Analyze the template. */ template_len = getTemplateLength(tmpl); if (template_len == 0) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Empty template suggests invalid state."); goto cleanup; } /* Make sure there will be no buffer overflow. */ if (template_len > MAX_TEMPLATE_SIZE) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Template too big"); goto cleanup; } memset(templateHit, 0, sizeof(templateHit)); while (1) { int matchCount = 0; res = generator(generatorCtx, &tlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (tlv == NULL) break; KSI_LOG_trace(ctx, "Starting to parse TLV[0x%02x]", KSI_TLV_getTag(tlv)); if (tr_len < tr_size) { tr[tr_len].tag = KSI_TLV_getTag(tlv); tr[tr_len].desc = NULL; } for (i = tmplStart; i < template_len; i++) { if (tmpl[i].tag != KSI_TLV_getTag(tlv)) continue; if (i == tmplStart && !tmpl[i].multiple) tmplStart++; tr[tr_len].desc = tmpl[i].descr; matchCount++; templateHit[i] = true; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G0) != 0) groupHit[0] = true; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G1) != 0) groupHit[1] = true; if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G0)) { if (oneOf[0]) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Mutually exclusive elements present within group 0."); goto cleanup; } oneOf[0] = true; } if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G1)) { if (oneOf[1]) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Mutually exclusive elements present within group 0."); goto cleanup; } oneOf[1] = true; } valuep = NULL; if (tmpl[i].getValue != NULL) { /* Validate the value has not been set */ res = tmpl[i].getValue(payload, (void **)&valuep); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } } if (valuep != NULL && !tmpl[i].multiple) { compositeVal = NULL; KSI_LOG_error(ctx, "Multiple occurrences of a unique tag 0x%02x", tmpl[i].tag); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "To avoid memory leaks, a value may not be set more than once while parsing."); goto cleanup; } /* Parse the current TLV */ switch (tmpl[i].type) { case KSI_TLV_TEMPLATE_OBJECT: KSI_LOG_trace(ctx, "Detected object template for TLV value extraction."); if (tmpl[i].fromTlv == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Invalid template: fromTlv not set."); goto cleanup; } res = tmpl[i].fromTlv(tlv, &voidVal); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = storeObjectValue(ctx, &tmpl[i], payload, voidVal); if (res != KSI_OK) { tmpl[i].destruct(voidVal); // FIXME: Make sure, it is a valid pointer. goto cleanup; } break; case KSI_TLV_TEMPLATE_COMPOSITE: { KSI_LOG_trace(ctx, "Detected composite template for TLV value extraction."); res = tmpl[i].construct(ctx, &compositeVal); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = extract(ctx, compositeVal, tlv, tmpl[i].subTemplate, tr, tr_len + 1, tr_size); if (res != KSI_OK) { KSI_LOG_error(ctx, "Unable to parse composite TLV: %s", track_str(tr, tr_len, tr_size, buf, sizeof(buf))); tmpl[i].destruct(compositeVal); // FIXME: Make sure is is a valid pointer. goto cleanup; } res = storeObjectValue(ctx, &tmpl[i], payload, (void *)compositeVal); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /* Reset the buffer. */ break; } default: KSI_LOG_error(ctx, "No template found."); /* Should not happen, but just in case. */ KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Undefined template type"); goto cleanup; } if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_MORE_DEFS) == 0) break; } /* Check if a match was found, an raise an error if the TLV is marked as critical. */ if (matchCount == 0 && !KSI_TLV_isNonCritical(tlv)) { char errm[1024]; KSI_snprintf(errm, sizeof(errm), "Unknown critical tag: %s", track_str(tr, tr_len + 1, tr_size, buf, sizeof(buf))); KSI_LOG_error(ctx, errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } } /* Check that every mandatory component was present. */ for (i = 0; i < template_len; i++) { char errm[100]; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_MANDATORY) != 0 && !templateHit[i]) { KSI_snprintf(errm, sizeof(errm), "Mandatory element missing: %s->[0x%x]%s", track_str(tr, tr_len, tr_size, buf, sizeof(buf)), tmpl[i].tag, tmpl[i].descr != NULL ? tmpl[i].descr : ""); KSI_LOG_debug(ctx, "%s", errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } if (((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G0) != 0 && !groupHit[0]) || ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G1) != 0 && !groupHit[1])) { KSI_snprintf(errm, sizeof(errm), "Mandatory group missing: %s->[0x%x]%s", track_str(tr, tr_len, tr_size, buf, sizeof(buf)), tmpl[i].tag, tmpl[i].descr != NULL ? tmpl[i].descr : ""); KSI_LOG_debug(ctx, "%s", errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } } res = KSI_OK; cleanup: KSI_TLV_free(tlvVal); return res; }