/** * Handle request_header events for user agent extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "User-Agent" field. If found, the value is parsed and used to update the * connection object fields. * * @param[in] ib IronBee object * @param[in,out] tx Transaction. * @param[in] event Event type * @param[in] data Callback data (not used) * * @returns Status code */ static ib_status_t modua_user_agent(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *data) { assert(ib != NULL); assert(tx != NULL); assert(tx->data != NULL); assert(event == request_header_finished_event); ib_field_t *req_agent = NULL; ib_status_t rc = IB_OK; const ib_list_t *bs_list; const ib_bytestr_t *bs; /* Extract the User-Agent header field from the provider instance */ rc = ib_data_get(tx->data, "request_headers:User-Agent", &req_agent); if ( (req_agent == NULL) || (rc != IB_OK) ) { ib_log_debug_tx(tx, "request_header_finished_event: No user agent"); return IB_OK; } if (req_agent->type != IB_FTYPE_LIST) { ib_log_error_tx(tx, "Expected request_headers:User-Agent to " "return list of values."); return IB_EINVAL; } rc = ib_field_value_type(req_agent, ib_ftype_list_out(&bs_list), IB_FTYPE_LIST); if (rc != IB_OK) { ib_log_error_tx(tx, "Cannot retrieve request_headers:User-Agent: %d", rc); return rc; } if (IB_LIST_ELEMENTS(bs_list) == 0) { ib_log_debug_tx(tx, "request_header_finished_event: No user agent"); return IB_OK; } req_agent = (ib_field_t *)IB_LIST_NODE_DATA(IB_LIST_LAST(bs_list)); /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(req_agent, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_error_tx(tx, "Request user agent is not a BYTESTR: %s", ib_status_to_string(rc)); return rc; } /* Finally, split it up & store the components */ rc = modua_agent_fields(ib, tx, bs); return rc; }
/** * Handle request_header events for remote IP extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "X-Forwarded-For" field. If found, the first value in the (comma * separated) list replaces the local ip address string in the connection * object. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] event Event type * @param[in] cbdata Callback data (not used) * * @returns Status code */ static ib_status_t modua_remoteip(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *cbdata) { assert(ib != NULL); assert(tx != NULL); assert(tx->data != NULL); assert(event == request_header_finished_event); ib_field_t *field = NULL; ib_status_t rc = IB_OK; const ib_bytestr_t *bs; const uint8_t *data; size_t len; char *buf; uint8_t *comma; const ib_list_t *list; const ib_list_node_t *node; const ib_field_t *forwarded; uint8_t *stripped; size_t num; ib_flags_t flags; ib_log_debug3_tx(tx, "Checking for alternate remote address"); /* Extract the X-Forwarded-For from the provider instance */ rc = ib_data_get(tx->data, "request_headers:X-Forwarded-For", &field); if ( (field == NULL) || (rc != IB_OK) ) { ib_log_debug_tx(tx, "No X-Forwarded-For field"); return IB_OK; } /* Because we asked for a filtered item, what we get back is a list */ rc = ib_field_value(field, ib_ftype_list_out(&list)); if (rc != IB_OK) { ib_log_debug_tx(tx, "No request header collection"); return rc; } num = ib_list_elements(list); if (num == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For header found"); return rc; } else if (num != 1) { ib_log_debug_tx(tx, "%zd X-Forwarded-For headers found: ignoring", num); return rc; } node = ib_list_last_const(list); if ( (node == NULL) || (node->data == NULL) ) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header found"); return rc; } forwarded = (const ib_field_t *)node->data; /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(forwarded, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header value"); return rc; } if (bs == NULL) { ib_log_notice_tx(tx, "X-Forwarded-For header not a bytestr"); return IB_EINVAL; } len = ib_bytestr_length(bs); data = ib_bytestr_const_ptr(bs); /* Search for a comma in the buffer */ comma = memchr(data, ',', len); if (comma != NULL) { len = comma - data; } /* Trim whitespace */ stripped = (uint8_t *)data; rc = ib_strtrim_lr_ex(IB_STROP_INPLACE, tx->mp, stripped, len, &stripped, &len, &flags); if (rc != IB_OK) { return rc; } /* Verify that it looks like a valid IP v4/6 address */ rc = ib_ip_validate_ex((const char *)stripped, len); if (rc != IB_OK) { ib_log_error_tx(tx, "X-Forwarded-For \"%.*s\" is not a valid IP address", (int)len, stripped ); return IB_OK; } /* Allocate memory for copy of stripped string */ buf = (char *)ib_mpool_alloc(tx->mp, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for remote address", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, stripped, len); buf[len] = '\0'; ib_log_debug_tx(tx, "Remote address changed to \"%s\"", buf); /* This will lose the pointer to the original address * buffer, but it should be cleaned up with the rest * of the memory pool. */ tx->er_ipstr = buf; /* Update the remote address field in the tx collection */ rc = ib_data_add_bytestr(tx->data, "remote_addr", (uint8_t*)buf, len, NULL); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to create remote address TX field: %s", ib_status_to_string(rc)); return rc; } return IB_OK; }
/** * Length transformation * * @param[in] mp Memory pool to use for allocations. * @param[in] fin Input field. * @param[out] fout Output field. This is NULL on error. * @param[in] fndata Callback data * * @returns IB_OK if successful. */ static ib_status_t tfn_length(ib_mpool_t *mp, const ib_field_t *fin, const ib_field_t **fout, void *fndata) { assert(mp != NULL); assert(fin != NULL); assert(fout != NULL); ib_status_t rc = IB_OK; ib_field_t *fnew; /* Initialize the output field pointer */ *fout = NULL; /** * This works on C-style (NUL terminated) and byte strings. Note * that data is assumed to be a NUL terminated string (because our * configuration parser can't produce anything else). **/ if (fin->type == IB_FTYPE_NULSTR) { const char *fval; rc = ib_field_value(fin, ib_ftype_nulstr_out(&fval)); if (rc != IB_OK) { return rc; } const ib_num_t len = strlen(fval); rc = ib_field_create( &fnew, mp, IB_FIELD_NAME("Length"), IB_FTYPE_NUM, ib_ftype_num_in(&len) ); } else if (fin->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *value; rc = ib_field_value(fin, ib_ftype_bytestr_out(&value)); if (rc != IB_OK) { return rc; } const ib_num_t len = ib_bytestr_length(value); rc = ib_field_create( &fnew, mp, IB_FIELD_NAME("Length"), IB_FTYPE_NUM, ib_ftype_num_in(&len) ); } else if (fin->type == IB_FTYPE_LIST) { const ib_list_node_t *node = NULL; const ib_list_t *ilist; /** Incoming list */ /* Get the incoming list */ // @todo Remove mutable once list is const correct. rc = ib_field_value(fin, ib_ftype_list_out(&ilist)); if (rc != IB_OK) { return rc; } if (ilist == NULL) { return IB_EUNKNOWN; } /* Create the outgoing list field */ rc = ib_field_create( &fnew, mp, IB_FIELD_NAME("Length"), IB_FTYPE_LIST, NULL ); if (rc != IB_OK) { return rc; } /* Walk through the incoming fields */ IB_LIST_LOOP_CONST(ilist, node) { const ib_field_t *ifield = (ib_field_t *)node->data; const ib_field_t *ofield = NULL; rc = tfn_length(mp, ifield, &ofield, NULL); if (rc != IB_OK) { return rc; } rc = ib_field_list_add_const(fnew, ofield); if (rc != IB_OK) { return rc; } } } else {
const char *ib_field_format( const ib_field_t *field, bool quote, bool escape, const char **type_name, char *buf, size_t bufsize ) { ib_status_t rc; const char *tname = NULL; assert(buf != NULL); assert(bufsize > 0); *buf = '\0'; if (field == NULL) { tname = "NULL"; if (quote) { strncpy(buf, "\"\"", bufsize-1); *(buf+bufsize) = '\0'; } else { *buf = '\0'; } } else { switch (field->type) { case IB_FTYPE_NULSTR : { const char *s; tname = "NULSTR"; rc = ib_field_value(field, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { break; } if (escape) { ib_string_escape_json_buf(s, quote, buf, bufsize, NULL, NULL); } else if (quote) { snprintf(buf, bufsize, "\"%s\"", (s?s:"")); } else { strncpy(buf, s, bufsize-1); *(buf+bufsize-1) = '\0'; } break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; tname = "BYTESTR"; rc = ib_field_value(field, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { break; } if (escape) { ib_string_escape_json_buf_ex(ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), true, quote, buf, bufsize, NULL, NULL); } else if (quote) { snprintf(buf, bufsize, "\"%.*s\"", (int)ib_bytestr_length(bs), (const char *)ib_bytestr_const_ptr(bs)); } else { size_t len = ib_bytestr_length(bs); if (len > (bufsize - 1) ) { len = bufsize - 1; } strncpy(buf, (const char *)ib_bytestr_const_ptr(bs), len); *(buf+len) = '\0'; } break; } case IB_FTYPE_NUM : /**< Numeric value */ { ib_num_t n; tname = "NUM"; rc = ib_field_value(field, ib_ftype_num_out(&n)); if (rc != IB_OK) { break; } snprintf(buf, bufsize, "%"PRId64, n); break; } case IB_FTYPE_FLOAT : /**< Float numeric value */ { ib_float_t f; tname = "FLOAT"; rc = ib_field_value(field, ib_ftype_float_out(&f)); if (rc != IB_OK) { break; } snprintf(buf, bufsize, "%Lf", f); break; } case IB_FTYPE_LIST : /**< List */ { const ib_list_t *lst; size_t len; tname = "LIST"; rc = ib_field_value(field, ib_ftype_list_out(&lst)); if (rc != IB_OK) { break; } len = IB_LIST_ELEMENTS(lst); if (len == 0) { snprintf(buf, bufsize, "list[%zd]", len); } else { const ib_list_node_t *node; node = ib_list_last_const(lst); if (node == NULL) { snprintf(buf, bufsize, "list[%zd]", len); } else { ib_field_format((const ib_field_t *)node->data, quote, escape, &tname, buf, bufsize); } } break; } default: tname = buf; snprintf(buf, bufsize, "type = %d", field->type); break; } } /* Store the type name */ if (type_name != NULL) { *type_name = tname; } /* Return the buffer */ return buf; }
ib_status_t ib_tfn_execute( ib_mpool_t *mp, const ib_tfn_t *tfn, const ib_field_t *fin, const ib_field_t **fout ) { assert(mp != NULL); assert(tfn != NULL); assert(fin != NULL); assert(fout != NULL); ib_status_t rc; const ib_field_t *out = NULL; if (fin->type == IB_FTYPE_LIST && ! ib_tfn_handle_list(tfn)) { /* Unroll list */ const ib_list_t *value_list; const ib_list_node_t *node; ib_list_t *out_list; ib_field_t *fnew; rc = ib_field_value(fin, ib_ftype_list_out(&value_list)); if (rc != IB_OK) { return rc; } rc = ib_list_create(&out_list, mp); if (rc != IB_OK) { return rc; } IB_LIST_LOOP_CONST(value_list, node) { const ib_field_t *in; const ib_field_t *tfn_out; in = (const ib_field_t *)ib_list_node_data_const(node); assert(in != NULL); rc = ib_tfn_execute(mp, tfn, in, &tfn_out); if (rc != IB_OK) { return rc; } if (tfn_out == NULL) { return IB_EINVAL; } rc = ib_list_push(out_list, (void *)tfn_out); if (rc != IB_OK) { return rc; } } /* Finally, create the output field (list) and return it */ rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_LIST, ib_ftype_list_in(out_list)); if (rc != IB_OK) { return rc; } out = fnew; } else {
void ib_field_util_log_debug( const char *prefix, const ib_field_t *f ) { assert(prefix != NULL); assert(f != NULL); ib_status_t rc; if (ib_util_get_log_level() < IB_LOG_DEBUG) { return; } if (ib_field_is_dynamic(f)) { ib_util_log_debug( "%s is dynamic: fn_get=%p cbdata_get=%p fn_set=%p cbdata_set=%p", prefix, f->val->fn_get, f->val->cbdata_get, f->val->fn_set, f->val->cbdata_set ); } ib_util_log_debug("%s name=%.*s type=%d", prefix, (int)f->nlen, f->name, f->type ); if (ib_field_is_dynamic(f)) { return; } assert(f->val->pval); if (*(void **)(f->val->pval) == NULL) { ib_util_log_debug( "%s has no value.", prefix ); } else { switch (f->type) { case IB_FTYPE_GENERIC: { void *v; rc = ib_field_value(f, ib_ftype_generic_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s value=%p", prefix, v); } break; } case IB_FTYPE_NUM: { ib_num_t v; rc = ib_field_value(f, ib_ftype_num_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s value=%"PRId64, prefix, v); } break; } case IB_FTYPE_FLOAT: { ib_float_t v; rc = ib_field_value(f, ib_ftype_float_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s value=%Lf", prefix, v); } break; } case IB_FTYPE_NULSTR: { const char *v; rc = ib_field_value(f, ib_ftype_nulstr_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s value=%s", prefix, v); } break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *v; rc = ib_field_value(f, ib_ftype_bytestr_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s value=%" IB_BYTESTR_FMT, prefix, IB_BYTESTR_FMT_PARAM(v)); } break; } case IB_FTYPE_LIST: { const ib_list_t* v; rc = ib_field_value(f, ib_ftype_list_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s &value=%p", prefix, v); } break; } case IB_FTYPE_SBUFFER: { const ib_stream_t* v; rc = ib_field_value(f, ib_ftype_sbuffer_out(&v)); if (rc == IB_OK) { ib_util_log_debug("%s &value=%p", prefix, v); } break; } default: ib_util_log_debug("%s Unknown field type: %u", prefix, f->type ); } } }
/** * Join a field with strings before and after it * * @param[in] mp Memory pool * @param[in] f Field to join * @param[in] iptr Pointer to initial string * @param[in] ilen Length of @a iptr * @param[in] fptr Pointer to final string * @param[in] flen Length of @a fptr * @param[in] nul true if NUL byte should be tacked on, false if not * @param[out] out Pointer to output block * @param[out] olen Length of the output block * * @returns status code */ static ib_status_t join_parts(ib_mpool_t *mp, const ib_field_t *f, const char *iptr, size_t ilen, const char *fptr, size_t flen, bool nul, char **out, size_t *olen) { IB_FTRACE_INIT(); ib_status_t rc; char numbuf[NUM_BUF_LEN+1]; /* Buffer used to convert number to str */ assert(NUM_BUF_LEN <= 256); switch(f->type) { case IB_FTYPE_NULSTR: { /* Field is a NUL-terminated string */ const char *s; rc = ib_field_value(f, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } size_t slen = strlen(s); rc = join3(mp, iptr, ilen, s, slen, fptr, flen, nul, out, olen); break; } case IB_FTYPE_BYTESTR: { /* Field is a byte string */ const ib_bytestr_t *bs; rc = ib_field_value(f, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = join3(mp, iptr, ilen, (const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), fptr, flen, nul, out, olen); break; } case IB_FTYPE_NUM: { /* Field is a number; convert it to a string */ ib_num_t n; rc = ib_field_value(f, ib_ftype_num_out(&n)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } snprintf(numbuf, NUM_BUF_LEN, "%"PRId64, n); rc = join3(mp, iptr, ilen, numbuf, strlen(numbuf), fptr, flen, nul, out, olen); break; } case IB_FTYPE_UNUM: { /* Field is an unsigned number; convert it to a string */ ib_unum_t n; rc = ib_field_value(f, ib_ftype_unum_out(&n)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } snprintf(numbuf, NUM_BUF_LEN, "%"PRIu64, n); rc = join3(mp, iptr, ilen, numbuf, strlen(numbuf), fptr, flen, nul, out, olen); break; } case IB_FTYPE_LIST: { /* Field is a list: use the first element in the list */ const ib_list_t *list; const ib_list_node_t *node; const ib_field_t *element; rc = ib_field_value(f, ib_ftype_list_out(&list)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } node = ib_list_first_const(list); if (node == NULL) { rc = join2(mp, iptr, ilen, fptr, flen, nul, out, olen); break; } element = (const ib_field_t *)ib_list_node_data_const(node); rc = join_parts(mp, element, iptr, ilen, fptr, flen, nul, out, olen); break; } default: /* Something else: replace with "" */ rc = join2(mp, iptr, ilen, fptr, flen, nul, out, olen); break; } IB_FTRACE_RET_STATUS(rc); }
/** * Length transformation * * @param[in] ib IronBee engine * @param[in] mp Memory pool to use for allocations. * @param[in] fndata Function specific data. * @param[in] fin Input field. * @param[out] fout Output field. * @param[out] pflags Transformation flags. * * @returns IB_OK if successful. */ static ib_status_t tfn_length(ib_engine_t *ib, ib_mpool_t *mp, void *fndata, const ib_field_t *fin, ib_field_t **fout, ib_flags_t *pflags) { IB_FTRACE_INIT(); ib_status_t rc = IB_OK; assert(mp != NULL); assert(fin != NULL); assert(fout != NULL); assert(pflags != NULL); /** * This works on C-style (NUL terminated) and byte strings. Note * that data is assumed to be a NUL terminated string (because our * configuration parser can't produce anything else). **/ if (fin->type == IB_FTYPE_NULSTR) { const char *fval; rc = ib_field_value(fin, ib_ftype_nulstr_out(&fval)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } const ib_unum_t len = strlen(fval); rc = ib_field_create( fout, mp, IB_FIELD_NAME("Length"), IB_FTYPE_UNUM, ib_ftype_unum_in(&len) ); } else if (fin->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *value; rc = ib_field_value(fin, ib_ftype_bytestr_out(&value)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } const ib_unum_t len = ib_bytestr_length(value); rc = ib_field_create( fout, mp, IB_FIELD_NAME("Length"), IB_FTYPE_UNUM, ib_ftype_unum_in(&len) ); } else if (fin->type == IB_FTYPE_LIST) { const ib_list_node_t *node = NULL; const ib_list_t *ilist; /** Incoming list */ /* Get the incoming list */ // @todo Remove mutable once list is const correct. rc = ib_field_value(fin, ib_ftype_list_out(&ilist)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } if (ilist == NULL) { IB_FTRACE_RET_STATUS(IB_EUNKNOWN); } /* Create the outgoing list field */ rc = ib_field_create( fout, mp, IB_FIELD_NAME("Length"), IB_FTYPE_LIST, NULL ); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } /* Walk through the incoming fields */ IB_LIST_LOOP_CONST(ilist, node) { const ib_field_t *ifield = (ib_field_t *)node->data; ib_field_t *ofield = NULL; ib_flags_t flags = 0; rc = tfn_length(ib, mp, NULL, ifield, &ofield, &flags); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = ib_field_list_add(*fout, ofield); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } } } else {
/** * JSON YAJL encode: Encode a list * * @param[in,out] handle YAJL generator handle * @param[in] name Name of @a list (or NULL) * @param[in] nlen Length of @a name * @param[in] list IronBee list to encode * * @returns IronBee status code */ static ib_status_t encode_list( yajl_gen handle, const char *name, size_t nlen, const ib_list_t *list) { ib_status_t rc = IB_OK; const ib_list_node_t *node; yajl_gen_status status; int errors = 0; /* Encode the name */ if ( (name != NULL) && (nlen != 0) ) { status = yajl_gen_string(handle, (const unsigned char *)name, nlen); if (status != yajl_gen_status_ok) { return IB_EUNKNOWN; } } /* Encode the map start */ status = yajl_gen_map_open(handle); if (status != yajl_gen_status_ok) { return IB_EUNKNOWN; } IB_LIST_LOOP_CONST(list, node) { const ib_field_t *field = (const ib_field_t *)node->data; ib_status_t tmprc; status = yajl_gen_string(handle, (const unsigned char *)field->name, field->nlen); if (status != yajl_gen_status_ok) { rc = IB_EUNKNOWN; ++errors; continue; } switch(field->type) { case IB_FTYPE_LIST: { const ib_list_t *list2; tmprc = ib_field_value(field, ib_ftype_list_out(&list2)); if ( (tmprc != IB_OK) && (rc == IB_OK) ) { rc = tmprc; ++errors; } else { tmprc = encode_list(handle, NULL, 0, list2); if ( (tmprc != IB_OK) && (rc == IB_OK) ) { rc = tmprc; ++errors; } } break; } case IB_FTYPE_NUM: { ib_num_t num; tmprc = ib_field_value(field, ib_ftype_num_out(&num)); if ( (tmprc != IB_OK) && (rc == IB_OK) ) { rc = tmprc; ++errors; } else { status = yajl_gen_integer(handle, num); if (status != yajl_gen_status_ok) { if (rc != IB_OK) { rc = IB_EUNKNOWN; } ++errors; } } break; } case IB_FTYPE_FLOAT: { ib_float_t fnum; tmprc = ib_field_value(field, ib_ftype_float_out(&fnum)); if ( (tmprc != IB_OK) && (rc == IB_OK) ) { rc = tmprc; ++errors; } else { char buf[float_buf_size+1]; snprintf(buf, float_buf_size, "%#.8Lg", fnum); status = yajl_gen_number(handle, buf, strlen(buf)); if (status != yajl_gen_status_ok) { if (rc != IB_OK) { rc = IB_EUNKNOWN; } ++errors; } } break; } case IB_FTYPE_NULSTR: { const char *str; tmprc = ib_field_value(field, ib_ftype_nulstr_out(&str)); if ( (tmprc != IB_OK) && (rc == IB_OK) ) { rc = tmprc; ++errors; } else { status = yajl_gen_string(handle, (unsigned char *)str, strlen(str)); if (status != yajl_gen_status_ok) { if (rc != IB_OK) { rc = IB_EUNKNOWN; } ++errors; } } break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; tmprc = ib_field_value(field, ib_ftype_bytestr_out(&bs)); if ( (tmprc != IB_OK) && (rc == IB_OK) ) { rc = tmprc; ++errors; } else { status = yajl_gen_string(handle, ib_bytestr_const_ptr(bs), ib_bytestr_length(bs)); if (status != yajl_gen_status_ok) { if (rc != IB_OK) { rc = IB_EUNKNOWN; } ++errors; } } break; } default: /* Just ignore it */ break; } /* switch(f->type) */ } /* Encode the map end */ status = yajl_gen_map_close(handle); if (status != yajl_gen_status_ok) { return IB_EUNKNOWN; } return IB_OK; }
/** * Feed a collection of byte strings from an @ref ib_data_t to automata. * * @param[in] ib IronBee engine; used for logging. * @param[in] eudoxus Eudoxus engine; used for ia_eudoxus_error(). * @param[in] state Current Eudoxus execution state; updated. * @param[in] data Data source. * @param[in] collection Collection to feed. * @return * - IB_OK on success. * - IB_EINVAL on IronAutomata failure; will emit log message. * - IB_EOTHER on IronBee failure; will emit log message. */ static ib_status_t fast_feed_data_collection( const ib_engine_t *ib, const ia_eudoxus_t *eudoxus, ia_eudoxus_state_t *state, const ib_data_t *data, const fast_collection_spec_t *collection ) { assert(ib != NULL); assert(eudoxus != NULL); assert(state != NULL); assert(data != NULL); assert(collection != NULL); ib_field_t *field; const ib_list_t *subfields; const ib_list_node_t *node; const ib_field_t *subfield; const ib_bytestr_t *bs; ib_status_t rc; rc = ib_data_get(data, collection->name, &field); if (rc == IB_ENOENT) { ib_log_error( ib, "fast: No such data %s", collection->name ); return IB_EOTHER; } else if (rc != IB_OK) { ib_log_error( ib, "fast: Error fetching data %s: %s", collection->name, ib_status_to_string(rc) ); return IB_EOTHER; } rc = ib_field_value_type( field, ib_ftype_list_out(&subfields), IB_FTYPE_LIST ); if (rc != IB_OK) { ib_log_error( ib, "fast: Error loading data field %s: %s", collection->name, ib_status_to_string(rc) ); return IB_EOTHER; } IB_LIST_LOOP_CONST(subfields, node) { subfield = (const ib_field_t *)ib_list_node_data_const(node); assert(subfield != NULL); rc = ib_field_value_type( subfield, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR ); if (rc != IB_OK) { ib_log_error( ib, "fast: Error loading data subfield %s of %s: %s", subfield->name, collection->name, ib_status_to_string(rc) ); return IB_EOTHER; } rc = fast_feed( ib, eudoxus, state, (const uint8_t *)subfield->name, subfield->nlen ); if (rc != IB_OK) { return rc; } rc = fast_feed( ib, eudoxus, state, (const uint8_t *)collection->separator, strlen(collection->separator) ); if (rc != IB_OK) { return rc; } if (ib_bytestr_const_ptr(bs) != NULL && ib_bytestr_size(bs) > 0) { rc = fast_feed( ib, eudoxus, state, ib_bytestr_const_ptr(bs), ib_bytestr_size(bs) ); if (rc != IB_OK) { return rc; } } rc = fast_feed( ib, eudoxus, state, (const uint8_t *)c_data_separator, strlen(c_data_separator) ); if (rc != IB_OK) { return rc; } }