/// @test Test util field library - ib_field_from_string() TEST_F(TestIBUtilField, test_field_from_string) { ib_field_t *f; ib_status_t rc; ib_num_t fnum; ib_float_t ffloat; const char *fnulstr; rc = ib_field_from_string(MM(), IB_S2SL("test_num"), "11", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NUM, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_num_out(&fnum))); ASSERT_EQ(11, fnum); rc = ib_field_from_string(MM(), IB_S2SL("test_num"), "-11", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NUM, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_num_out(&fnum))); ASSERT_EQ(-11, fnum); rc = ib_field_from_string(MM(), IB_S2SL("test_float"), "1.0", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_FLOAT, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_float_out(&ffloat))); ASSERT_EQ(1.0, ffloat); rc = ib_field_from_string(MM(), IB_S2SL("test_num"), "-1.0", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_FLOAT, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_float_out(&ffloat))); ASSERT_EQ(-1.0, ffloat); rc = ib_field_from_string(MM(), IB_S2SL("test_str"), "x", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NULSTR, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_nulstr_out(&fnulstr))); ASSERT_STREQ("x", fnulstr); rc = ib_field_from_string(MM(), IB_S2SL("test_str"), "-1.1x", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NULSTR, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_nulstr_out(&fnulstr))); ASSERT_STREQ("-1.1x", fnulstr); }
ib_status_t test_execute_fn(const ib_rule_exec_t *rule_exec, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { char *searchstr = (char *)data; const char* s; ib_status_t rc; if (field->type != IB_FTYPE_NULSTR) { return IB_EINVAL; } rc = ib_field_value(field, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { return rc; } if (strstr(s, searchstr) == NULL) { *result = 0; } else { *result = 1; } return IB_OK; }
ib_status_t test_execute_fn( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { char *searchstr = (char *)instance_data; const char* s; ib_status_t rc; if (field->type != IB_FTYPE_NULSTR) { return IB_EINVAL; } rc = ib_field_value(field, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { return rc; } if (strstr(s, searchstr) == NULL) { *result = 0; } else { *result = 1; } return IB_OK; }
/// @test Test util field library - ib_field_create() ib_field_create() TEST_F(TestIBUtilField, test_field_create) { ib_field_t *f; ib_status_t rc; const char *nulstrval = "TestValue"; ib_num_t numval = 5; ib_bytestr_t *bytestrval; const char *nulout; const char *nulcopy; nulcopy = ib_mm_strdup(MM(), nulstrval); ASSERT_STRNE(NULL, nulcopy); rc = ib_field_create(&f, MM(), IB_S2SL("test_nulstr"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(nulcopy)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(11UL, f->nlen); ASSERT_EQ(0, memcmp("test_nulstr", f->name, 11)); rc = ib_field_value(f, ib_ftype_nulstr_out(&nulout)); ASSERT_EQ(IB_OK, rc); ASSERT_STREQ(nulstrval, nulout); rc = ib_field_create(&f, MM(), IB_S2SL("test_num"), IB_FTYPE_NUM, ib_ftype_num_in(&numval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(8UL, f->nlen); ASSERT_EQ(0, memcmp("test_num", f->name, 8)); rc = ib_bytestr_dup_mem(&bytestrval, MM(), (uint8_t *)nulstrval, strlen(nulstrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); rc = ib_field_create(&f, MM(), IB_S2SL("test_bytestr"), IB_FTYPE_BYTESTR, ib_ftype_bytestr_in(bytestrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(12UL, f->nlen); ASSERT_EQ(0, memcmp("test_bytestr", f->name, 12)); rc = ib_field_create(&f, MM(), IB_S2SL("test_nulstr_ex"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(nulstrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); rc = ib_field_create(&f, MM(), IB_S2SL("test_num_ex"), IB_FTYPE_NUM, ib_ftype_num_in(&numval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); rc = ib_field_create(&f, MM(), IB_S2SL("test_bytestr_ex"), IB_FTYPE_BYTESTR, ib_ftype_bytestr_in(bytestrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); }
const char* ConstField::value_as_null_string() const { Internal::check_type(NULL_STRING, type()); const char* v; throw_if_error(ib_field_value( ib(), ib_ftype_nulstr_out(&v) )); return v; }
const char* ConstField::value_as_null_string( const char* arg, size_t arg_length ) const { Internal::check_type(NULL_STRING, type()); const char* v; throw_if_error(ib_field_value_ex( ib(), ib_ftype_nulstr_out(&v), arg, arg_length )); return v; }
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 ); } } }
/** * Attempt to convert a single field. * * If the desired type matches the in_field type, out_field is set to NULL * and IB_OK is returned. * * @param[in,out] mp Memory pool to use. * @param[in] desired_type The type to try to convert this to. * @param[in] in_field The input field. * @param[out] out_field The output field to write to. * * @returns * - IB_OK On success. * - IB_EINVAL If a string cannot be converted to a number type * or some other invalid type conversion is requested. * - IB_EALLOC Memory allocation error. */ ib_status_t ib_field_convert( ib_mpool_t *mp, const ib_ftype_t desired_type, const ib_field_t *in_field, ib_field_t **out_field) { assert(mp); assert(in_field); ib_status_t rc; /* Holder values for in_field values before being set in out_field. */ size_t sz; const char *str; const ib_bytestr_t *bstr; ib_num_t num; ib_float_t flt; void *new_field_value; if (in_field->type == desired_type) { *out_field = NULL; return IB_OK; } switch (in_field->type) { case IB_FTYPE_NULSTR: /* Extract string. */ rc = ib_field_value(in_field, ib_ftype_nulstr_out(&str)); if (rc!=IB_OK){ return rc; } switch(desired_type) { case IB_FTYPE_BYTESTR: rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc!=IB_OK){ return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_NUM: rc = ib_string_to_num(str, 0, &num); new_field_value = ib_ftype_num_in(&num); break; case IB_FTYPE_FLOAT: rc = ib_string_to_float(str, &flt); new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_BYTESTR: /* Extract bytestr. */ rc = ib_field_value(in_field, ib_ftype_bytestr_out(&bstr)); if (rc!=IB_OK){ return rc; } sz = ib_bytestr_length(bstr); /* Convert byte str. */ switch(desired_type) { case IB_FTYPE_NULSTR: str = ib_mpool_memdup_to_str(mp, bstr, sz); if (!str) { return rc; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_NUM: rc = ib_string_to_num_ex((char *)bstr, sz, 0, &num); new_field_value = ib_ftype_num_in(&num); break; case IB_FTYPE_FLOAT: rc = ib_string_to_float_ex((char *)bstr, sz, &flt); new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_NUM: /* Extract unum. */ rc = ib_field_value(in_field, ib_ftype_num_out(&num)); if (rc!=IB_OK){ return rc; } switch(desired_type) { case IB_FTYPE_NULSTR: str = ib_num_to_string(mp, num); if (!str) { return IB_EINVAL; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_BYTESTR: str = ib_num_to_string(mp, num); if (!str) { return IB_EINVAL; } rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc!=IB_OK){ return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_FLOAT: flt = (ib_float_t)num; new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_FLOAT: /* Extract unum. */ rc = ib_field_value(in_field, ib_ftype_float_out(&flt)); if (rc!=IB_OK){ return rc; } switch(desired_type) { case IB_FTYPE_NULSTR: str = ib_float_to_string(mp, flt); if (!str) { return IB_EINVAL; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_BYTESTR: str = ib_float_to_string(mp, flt); if (!str) { return IB_EINVAL; } rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc!=IB_OK){ return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_NUM: num = (ib_float_t)flt; new_field_value = ib_ftype_num_in(&num); break; default: return IB_EINVAL; } break; default: return IB_EINVAL; } rc = ib_field_create( out_field, mp, in_field->name, in_field->nlen, desired_type, new_field_value); return rc; }
///@test Test util field library - ib_field_dyn_register_get() TEST_F(TestIBUtilField, test_dyn_field) { ib_field_t *dynf; ib_field_t *cdynf; ib_status_t rc; const char *fval; /* Create a field with no initial value. */ rc = ib_field_create_dynamic( &dynf, MM(), IB_S2SL("test_dynf"), IB_FTYPE_NULSTR, dyn_get, (void *)"dynf_get", dyn_set, (void *)"dynf_set" ); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(dynf); ASSERT_EQ(9UL, dynf->nlen); ASSERT_EQ(0, memcmp("test_dynf", dynf->name, 9)); /* Get the value from the dynamic field. */ rc = ib_field_value_ex(dynf, ib_ftype_nulstr_out(&fval), (void *)"fetch1", 6 ); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(fval); ASSERT_EQ( std::string("testval_dynf_get_fetch1_call01"), fval ); /* Get the value from the dynamic field again. */ rc = ib_field_value_ex(dynf, ib_ftype_nulstr_out(&fval), (void *)"fetch2", 6 ); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(fval); ASSERT_EQ( std::string("testval_dynf_get_fetch2_call02"), fval ); /* Set */ rc = ib_field_setv_ex(dynf, (void *)"val1", (void *)"set1", 4); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(std::string("testval_dynf_set_set1_val1_call03"), g_dyn_call_val); /* Reset call counter. */ g_dyn_call_count = 0; /* Create another field with no initial value. */ rc = ib_field_create_dynamic( &cdynf, MM(), IB_S2SL("test_cdynf"), IB_FTYPE_NULSTR, dyn_get_cached, (void *)("cdynf_get"), dyn_set, NULL ); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(cdynf); ASSERT_EQ(10UL, cdynf->nlen); ASSERT_EQ(0, memcmp("test_cdynf", cdynf->name, 10)); /* Get the value from the dynamic field. */ rc = ib_field_value_ex(cdynf, ib_ftype_nulstr_out(&fval), (void *)"fetch1", 6 ); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(fval); ASSERT_EQ( std::string("testval_cdynf_get_fetch1_call01"), fval ); /* Get the value from the dynamic field again. */ rc = ib_field_value_ex(cdynf, ib_ftype_nulstr_out(&fval), NULL, 0 ); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(fval); ASSERT_EQ( std::string("testval_cdynf_get_fetch1_call01"), fval ); }
ib_status_t ib_field_convert( ib_mpool_t *mp, const ib_ftype_t desired_type, const ib_field_t *in_field, ib_field_t **out_field ) { assert(mp); assert(in_field); ib_status_t rc; /* Holder values for in_field values before being set in out_field. */ size_t sz; const char *str; const ib_bytestr_t *bstr; ib_num_t num; ib_time_t tme; ib_float_t flt; void *new_field_value; if (in_field->type == desired_type) { *out_field = NULL; return IB_OK; } switch (in_field->type) { case IB_FTYPE_NULSTR: /* Extract string. Note that a zero-length nulstr field can * have a NULL value in the union. */ if ( (in_field->val->u.nulstr == NULL) && (in_field->val->pval == NULL) ) { str = ""; } else { rc = ib_field_value(in_field, ib_ftype_nulstr_out(&str)); if (rc != IB_OK){ return rc; } } switch (desired_type) { case IB_FTYPE_BYTESTR: rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_TIME: rc = ib_string_to_time(str, &tme); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_time_in(&tme); break; case IB_FTYPE_NUM: rc = ib_string_to_num(str, 0, &num); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_num_in(&num); break; case IB_FTYPE_FLOAT: rc = ib_string_to_float(str, &flt); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_BYTESTR: /* Extract bytestr. */ rc = ib_field_value(in_field, ib_ftype_bytestr_out(&bstr)); if (rc != IB_OK){ return rc; } str = (const char *)ib_bytestr_const_ptr(bstr); sz = ib_bytestr_length(bstr); /* Convert byte str. */ switch(desired_type) { case IB_FTYPE_NULSTR: str = ib_mpool_memdup_to_str(mp, str, sz); if (!str) { return rc; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_TIME: rc = ib_string_to_time_ex(str, sz, &tme); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_time_in(&tme); break; case IB_FTYPE_NUM: rc = ib_string_to_num_ex(str, sz, 0, &num); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_num_in(&num); break; case IB_FTYPE_FLOAT: rc = ib_string_to_float_ex(str, sz, &flt); if (rc != IB_OK) { return rc; } new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_TIME: /* Extract time. */ rc = ib_field_value(in_field, ib_ftype_time_out(&tme)); if (rc != IB_OK){ return rc; } switch (desired_type) { case IB_FTYPE_NULSTR: str = ib_time_to_string(mp, tme); if (! str) { return IB_EINVAL; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_BYTESTR: str = ib_time_to_string(mp, tme); if (! str) { return IB_EINVAL; } rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc != IB_OK){ return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_FLOAT: flt = (ib_float_t)tme; /* Check that our assignment is within error=1, or fail. */ if (llabs(tme - flt) > 1) { return IB_EINVAL; } new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_NUM: /* Extract unum. */ rc = ib_field_value(in_field, ib_ftype_num_out(&num)); if (rc != IB_OK){ return rc; } switch (desired_type) { case IB_FTYPE_NULSTR: str = ib_num_to_string(mp, num); if (! str) { return IB_EINVAL; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_BYTESTR: str = ib_num_to_string(mp, num); if (! str) { return IB_EINVAL; } rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc != IB_OK){ return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_TIME: if (num < 0) { return IB_EINVAL; } tme = (ib_time_t)num; new_field_value = ib_ftype_time_in(&tme); break; case IB_FTYPE_FLOAT: flt = (ib_float_t)num; if (llabs(flt - num) > 1) { return IB_EINVAL; } new_field_value = ib_ftype_float_in(&flt); break; default: return IB_EINVAL; } break; case IB_FTYPE_FLOAT: /* Extract unum. */ rc = ib_field_value(in_field, ib_ftype_float_out(&flt)); if (rc != IB_OK){ return rc; } switch (desired_type) { case IB_FTYPE_NULSTR: str = ib_float_to_string(mp, flt); if (!str) { return IB_EINVAL; } new_field_value = ib_ftype_nulstr_in(str); break; case IB_FTYPE_BYTESTR: str = ib_float_to_string(mp, flt); if (!str) { return IB_EINVAL; } rc = ib_bytestr_dup_nulstr((ib_bytestr_t **)&bstr, mp, str); if (rc != IB_OK){ return rc; } new_field_value = ib_ftype_bytestr_in(bstr); break; case IB_FTYPE_TIME: if (flt < 0) { return IB_EINVAL; } tme = (ib_float_t)flt; new_field_value = ib_ftype_time_in(&tme); break; case IB_FTYPE_NUM: num = (ib_float_t)flt; new_field_value = ib_ftype_num_in(&num); break; default: return IB_EINVAL; } break; default: return IB_EINVAL; } rc = ib_field_create( out_field, mp, in_field->name, in_field->nlen, desired_type, new_field_value ); return rc; }
static ib_status_t foo2bar(ib_engine_t *ib, ib_mpool_t *mp, void *fndata, const ib_field_t *fin, const ib_field_t **fout, ib_flags_t *pflags) { ib_status_t rc = IB_OK; ib_field_t *fnew; if (fin->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *ibs; rc = ib_field_value(fin, ib_ftype_bytestr_out(&ibs)); if (rc != IB_OK) { return rc; } const uint8_t *data_in; size_t dlen_in; uint8_t *data_out; assert (ibs != NULL); data_in = ib_bytestr_const_ptr(ibs); dlen_in = ib_bytestr_length(ibs); if ( (data_in != NULL) && (dlen_in == 3) && (strncmp("foo", (char *)data_in, 3) == 0) ) { data_out = (uint8_t *)ib_mpool_alloc(mp, dlen_in); if (data_out == NULL) { return IB_EINVAL; } *pflags = (IB_TFN_FMODIFIED); *(data_out+0) = 'b'; *(data_out+1) = 'a'; *(data_out+2) = 'r'; } else { data_out = (uint8_t *)data_in; } rc = ib_field_create_bytestr_alias(&fnew, mp, fin->name, fin->nlen, data_out, dlen_in); if (rc == IB_OK) { *fout = fnew; } } else if (fin->type == IB_FTYPE_NULSTR) { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { return rc; } if ( (in != NULL) && (strncmp(in, "foo", 3) == 0) ) { out = (char *)ib_mpool_alloc(mp, strlen(in) + 1); if (out == NULL) { return IB_EINVAL; } *pflags = (IB_TFN_FMODIFIED); *(out+0) = 'b'; *(out+1) = 'a'; *(out+2) = 'r'; *(out+3) = '\0'; } else { out = (char *)in; } rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc == IB_OK) { *fout = fnew; } } else { return IB_EINVAL; } return 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 {
/** * @brief Execute the rule. * * @param[in] ib Ironbee engine * @param[in] tx The transaction. * @param[in,out] User data. A @c pcre_rule_data_t. * @param[in] flags Operator instance flags * @param[in] field The field content. * @param[out] result The result. * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t dfa_operator_execute(ib_engine_t *ib, ib_tx_t *tx, const ib_rule_t *rule, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { IB_FTRACE_INIT(); assert(tx); assert(data); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; dfa_rule_data_t *rule_data; int *ovector; const char* subject; size_t subject_len; const ib_bytestr_t* bytestr; dfa_workspace_t *dfa_workspace; int options; /* dfa exec options. */ ovector = (int *)malloc(ovecsize*sizeof(*ovector)); if (ovector==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Pull out the rule data. */ rule_data = (dfa_rule_data_t *)data; if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } subject_len = strlen(subject); } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } else { free(ovector); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Debug block. Escapes a string and prints it to the log. * Memory is freed. */ if (ib_log_get_level(ib) >= 9) { /* Worst case, we can have a string that is 4x larger. * Consider if a string of 0xF7 is passed. That single character * will expand to a string of 4 printed characters +1 for the \0 * character. */ char *debug_str = ib_util_hex_escape(subject, subject_len); if ( debug_str != NULL ) { ib_log_debug3_tx(tx, "Matching against: %s", debug_str); free( debug_str ); } } /* Get the per-tx workspace data for this rule data id. */ ib_rc = get_dfa_tx_data(tx, rule_data->id, &dfa_workspace); if (ib_rc == IB_ENOENT) { options = PCRE_PARTIAL_SOFT; ib_rc = alloc_dfa_tx_data(tx, rule_data->id, &dfa_workspace); if (ib_rc != IB_OK) { free(ovector); ib_log_error_tx(tx, "Unexpected error creating tx storage " "for dfa operator %s", rule_data->id); IB_FTRACE_RET_STATUS(ib_rc); } ib_log_debug_tx(tx, "Created DFA workspace at %p for id %s.", dfa_workspace, rule_data->id); } else if (ib_rc == IB_OK) { options = PCRE_PARTIAL_SOFT | PCRE_DFA_RESTART; ib_log_debug_tx(tx, "Reusing existing DFA workspace %p for id %s.", dfa_workspace, rule_data->id); } else { free(ovector); ib_log_error_tx(tx, "Unexpected error fetching dfa data " "for dfa operator %s", rule_data->id); IB_FTRACE_RET_STATUS(ib_rc); } /* Actually do the DFA match. */ matches = pcre_dfa_exec(rule_data->cpatt, rule_data->edata, subject, subject_len, 0, /* Starting offset. */ options, ovector, ovecsize, dfa_workspace->workspace, dfa_workspace->wscount); if (matches >= 0) { ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_PARTIAL) { ib_log_debug2_tx(tx, "Partial match found, but not a full match."); ib_rc = IB_OK; *result = 0; } else if (matches == PCRE_ERROR_NOMATCH) { if (ib_log_get_level(ib) >= 7) { char* tmp_c = malloc(subject_len+1); memcpy(tmp_c, subject, subject_len); tmp_c[subject_len] = '\0'; /* No match. Return false to the caller (*result = 0). */ ib_log_debug2_tx(tx, "No match for [%s] using pattern [%s].", tmp_c, rule_data->patt); free(tmp_c); } ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and report the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); IB_FTRACE_RET_STATUS(ib_rc); }
/** * 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 {
/** * Helper function for stream and non-stream execution. * * * * @param[in] tx Transaction * @param[in] operator_data Operator data. * @param[in] data Per-transaction data for this operator instance. * @param[in] field Input field. * @param[in] full_match If true, the full input text must be matched. * @param[out] result Result of execution. */ static ib_status_t ee_operator_execute_common( ib_tx_t *tx, ee_operator_data_t *operator_data, ee_tx_data_t *data, const ib_field_t *field, bool full_match, ib_num_t *result ) { ib_status_t rc; ia_eudoxus_result_t ia_rc; ia_eudoxus_state_t* state = NULL; const char *input; size_t input_len; assert(tx != NULL); assert(operator_data != NULL); assert(data != NULL); *result = 0; if (field->type == IB_FTYPE_NULSTR) { rc = ib_field_value(field, ib_ftype_nulstr_out(&input)); if (rc != IB_OK) { return rc; } input_len = strlen(input); } else if (field->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *bs; rc = ib_field_value(field, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { return rc; } input = (const char *)ib_bytestr_const_ptr(bs); input_len = ib_bytestr_length(bs); } else if (field->type == IB_FTYPE_LIST) { return IB_ENOTIMPL; } else { return IB_EINVAL; } if (data->end_of_automata) { /* Nothing to do. */ return IB_OK; } /* Run eudoxus */ state = data->eudoxus_state; rc = IB_OK; ia_rc = ia_eudoxus_execute(state, (const uint8_t *)input, input_len); if (ia_rc == IA_EUDOXUS_STOP) { if (full_match) { if (data->ee_cbdata->match_len == input_len) { *result = 1; } } else { *result = 1; } rc = IB_OK; } else if (ia_rc == IA_EUDOXUS_END) { data->end_of_automata = true; rc = IB_OK; } else if (ia_rc != IA_EUDOXUS_OK) { rc = IB_EUNKNOWN; } return rc; }
/** * 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); }
/** * String modification transformation core * * @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_strmod(ib_engine_t *ib, ib_mpool_t *mp, ib_strmod_fn_t str_fn, ib_strmod_ex_fn_t ex_fn, const ib_field_t *fin, ib_field_t **fout, ib_flags_t *pflags) { IB_FTRACE_INIT(); ib_status_t rc; ib_flags_t result; assert(ib != NULL); assert(mp != NULL); assert(str_fn != NULL); assert(ex_fn != NULL); assert(fin != NULL); assert(fout != NULL); assert(pflags != NULL); /* Initialize the output field pointer */ *fout = NULL; switch(fin->type) { case IB_FTYPE_NULSTR : { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } if (in == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } rc = str_fn(IB_STROP_COW, mp, (char *)in, &out, &result); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = ib_field_create(fout, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; const uint8_t *din; uint8_t *dout; size_t dlen; rc = ib_field_value(fin, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } if (bs == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } din = ib_bytestr_const_ptr(bs); if (din == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } dlen = ib_bytestr_length(bs); rc = ex_fn(IB_STROP_COW, mp, (uint8_t *)din, dlen, &dout, &dlen, &result); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = ib_field_create_bytestr_alias(fout, mp, fin->name, fin->nlen, dout, dlen); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } break; } default: IB_FTRACE_RET_STATUS(IB_EINVAL); } /* switch(fin->type) */ /* Check the flags */ if (ib_flags_all(result, IB_STRFLAG_MODIFIED) == true) { *pflags = IB_TFN_FMODIFIED; } else { *pflags = IB_TFN_NONE; } IB_FTRACE_RET_STATUS(IB_OK); }
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; }
/** * Execute the @c ee_match_any operator. * * At first match the operator will stop searching and return true. * * The capture option is supported; the matched pattern will be placed in the * capture variable if a match occurs. * * @param[in] tx Current transaction. * @param[in] instance_data Instance data needed for execution. * @param[in] field The field to operate on. * @param[in] capture If non-NULL, the collection to capture to. * @param[out] result The result of the operator 1=true 0=false. * @param[in] cbdata Callback data. */ static ib_status_t ee_match_any_operator_execute( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { ib_status_t rc; ia_eudoxus_result_t ia_rc; ee_operator_data_t *operator_data = instance_data; ia_eudoxus_t* eudoxus = operator_data->eudoxus; ia_eudoxus_state_t* state = NULL; const char *input; size_t input_len; ee_callback_data_t *ee_cbdata; const ib_module_t *m = (const ib_module_t *)cbdata; assert(m != NULL); assert(tx != NULL); assert(instance_data != NULL); *result = 0; if (field->type == IB_FTYPE_NULSTR) { rc = ib_field_value(field, ib_ftype_nulstr_out(&input)); if (rc != IB_OK) { return rc; } input_len = strlen(input); } else if (field->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *bs; rc = ib_field_value(field, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { return rc; } input = (const char *)ib_bytestr_const_ptr(bs); input_len = ib_bytestr_length(bs); } else if (field->type == IB_FTYPE_LIST) { return IB_ENOTIMPL; } else { return IB_EINVAL; } rc = get_ee_tx_data(m, tx, operator_data, &state); if (rc == IB_ENOENT) { /* State not found create it */ ee_cbdata = ib_mpool_alloc(tx->mp, sizeof(*ee_cbdata)); if (ee_cbdata == NULL) { return IB_EALLOC; } ee_cbdata->tx = tx; ee_cbdata->capture = capture; ia_rc = ia_eudoxus_create_state(&state, eudoxus, ee_first_match_callback, (void *)ee_cbdata); if (ia_rc != IA_EUDOXUS_OK) { if (state != NULL) { ia_eudoxus_destroy_state(state); state = NULL; } return IB_EINVAL; } set_ee_tx_data(m, tx, operator_data, state); } else if (rc != IB_OK) { /* Error getting the state -- abort */ return rc; } rc = IB_OK; ia_rc = ia_eudoxus_execute(state, (const uint8_t *)input, input_len); if (ia_rc == IA_EUDOXUS_STOP) { *result = 1; rc = IB_OK; } else if (ia_rc == IA_EUDOXUS_ERROR) { rc = IB_EUNKNOWN; } return rc; }
/** * @brief Execute the dfa operator * * @param[in] tx Current transaction. * @param[in] instance_data Instance data needed for execution. * @param[in] field The field to operate on. * @param[in] capture If non-NULL, the collection to capture to. * @param[out] result The result of the operator 1=true 0=false. * @param[in] cbdata Callback data. * * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t dfa_operator_execute( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { assert(instance_data != NULL); assert(tx != NULL); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; modpcre_operator_data_t *operator_data = (modpcre_operator_data_t *)instance_data; int *ovector; const char *subject; size_t subject_len; const ib_bytestr_t *bytestr; dfa_workspace_t *dfa_workspace; const char *id = operator_data->id; int options; /* dfa exec options. */ int start_offset; int match_count; const ib_module_t *m = (const ib_module_t *)cbdata; assert(m != NULL); assert(operator_data->cpdata->is_dfa == true); ovector = (int *)malloc(ovecsize*sizeof(*ovector)); if (ovector==NULL) { return IB_EALLOC; } if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } subject_len = strlen(subject); } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } else { free(ovector); return IB_EINVAL; } /* Get the per-tx workspace data for this rule data id. */ ib_rc = get_dfa_tx_data(m, tx, id, &dfa_workspace); if (ib_rc == IB_ENOENT) { /* First time we are called, clear the captures. */ if (capture) { ib_rc = ib_capture_clear(capture); if (ib_rc != IB_OK) { ib_log_error_tx(tx, "Error clearing captures: %s", ib_status_to_string(ib_rc)); } } options = PCRE_PARTIAL_SOFT; ib_rc = alloc_dfa_tx_data(m, tx, operator_data->cpdata, id, &dfa_workspace); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } } else if (ib_rc == IB_OK) { options = PCRE_PARTIAL_SOFT | PCRE_DFA_RESTART; } else { free(ovector); return ib_rc; } /* Perform the match. * If capturing is specified, then find all matches. */ start_offset = 0; match_count = 0; do { matches = pcre_dfa_exec(operator_data->cpdata->cpatt, operator_data->cpdata->edata, subject, subject_len, start_offset, /* Starting offset. */ options, ovector, ovecsize, dfa_workspace->workspace, dfa_workspace->wscount); if (matches > 0) { ++match_count; /* Use the longest match - the first in ovector - * to set the offset in the subject for the next * match. */ start_offset = ovector[1] + 1; if (capture) { pcre_dfa_set_match(tx, capture, ovector, 1, subject); } } } while (capture && (matches > 0)); if (match_count > 0) { ib_rc = IB_OK; *result = 1; } else if ((matches == 0) || (matches == PCRE_ERROR_NOMATCH)) { ib_rc = IB_OK; *result = 0; } else if (matches == PCRE_ERROR_PARTIAL) { ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and * return the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); return ib_rc; }
/** * 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; }
/** * String modification transformation core * * @param[in] mp Memory pool to use for allocations. * @param[in] str_fn NUL-terminated string transformation function * @param[in] ex_fn EX (string/length) transformation function * @param[in] fin Input field. * @param[out] fout Output field. This is NULL on error. * * @returns IB_OK if successful. */ static ib_status_t tfn_strmod(ib_mpool_t *mp, ib_strmod_fn_t str_fn, ib_strmod_ex_fn_t ex_fn, const ib_field_t *fin, const ib_field_t **fout) { ib_status_t rc; ib_flags_t result; ib_field_t *fnew; assert(mp != NULL); assert(str_fn != NULL); assert(ex_fn != NULL); assert(fin != NULL); assert(fout != NULL); /* Initialize the output field pointer */ *fout = NULL; switch(fin->type) { case IB_FTYPE_NULSTR : { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { return rc; } if (in == NULL) { return IB_EINVAL; } rc = str_fn(IB_STROP_COW, mp, (char *)in, &out, &result); if (rc != IB_OK) { return rc; } rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc != IB_OK) { return rc; } *fout = fnew; break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; const uint8_t *din; uint8_t *dout; size_t dlen; rc = ib_field_value(fin, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { return rc; } if (bs == NULL) { return IB_EINVAL; } din = ib_bytestr_const_ptr(bs); if (din == NULL) { return IB_EINVAL; } dlen = ib_bytestr_length(bs); rc = ex_fn(IB_STROP_COW, mp, (uint8_t *)din, dlen, &dout, &dlen, &result); if (rc != IB_OK) { return rc; } rc = ib_field_create_bytestr_alias(&fnew, mp, fin->name, fin->nlen, dout, dlen); if (rc != IB_OK) { return rc; } *fout = fnew; break; } default: return IB_EINVAL; } /* switch(fin->type) */ return IB_OK; }
/** * @brief Execute the PCRE operator * * @param[in] tx Current transaction. * @param[in] instance_data Instance data needed for execution. * @param[in] field The field to operate on. * @param[in] capture If non-NULL, the collection to capture to. * @param[out] result The result of the operator 1=true 0=false. * @param[in] cbdata Callback data. * * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t pcre_operator_execute( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { assert(instance_data != NULL); assert(tx != NULL); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; int *ovector = (int *)malloc(ovecsize*sizeof(*ovector)); const char *subject = NULL; size_t subject_len = 0; const ib_bytestr_t *bytestr; modpcre_operator_data_t *operator_data = (modpcre_operator_data_t *)instance_data; pcre_extra *edata = NULL; #ifdef PCRE_JIT_STACK pcre_jit_stack *jit_stack = NULL; #endif assert(operator_data->cpdata->is_dfa == false); if (ovector==NULL) { return IB_EALLOC; } if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } if (subject != NULL) { subject_len = strlen(subject); } } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } if (bytestr != NULL) { subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } } else { free(ovector); return IB_EINVAL; } if (subject == NULL) { subject = ""; } if (operator_data->cpdata->is_jit) { #ifdef PCRE_JIT_STACK jit_stack = pcre_jit_stack_alloc(operator_data->cpdata->jit_stack_start, operator_data->cpdata->jit_stack_max); if (jit_stack == NULL) { ib_log_warn(ib, "Failed to allocate a jit stack for a jit-compiled rule. " "Not using jit for this call." ); } /* If the study data is NULL or size zero, don't use it. */ else if (operator_data->cpdata->study_data_sz > 0) { edata = operator_data->cpdata->edata; } if (edata != NULL) { pcre_assign_jit_stack(edata, NULL, jit_stack); } #else edata = NULL; #endif } else if (operator_data->cpdata->study_data_sz > 0) { edata = operator_data->cpdata->edata; } else { edata = NULL; } matches = pcre_exec(operator_data->cpdata->cpatt, edata, subject, subject_len, 0, /* Starting offset. */ 0, /* Options. */ ovector, ovecsize); #ifdef PCRE_JIT_STACK if (jit_stack != NULL) { pcre_jit_stack_free(jit_stack); } #endif if (matches > 0) { if (capture != NULL) { pcre_set_matches(tx, capture, ovector, matches, subject); } ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_NOMATCH) { ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false return the * error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); return ib_rc; }
/** * @brief Execute the rule. * * @param[in] ib Ironbee engine * @param[in] tx The transaction. * @param[in,out] User data. A @c pcre_rule_data_t. * @param[in] flags Operator instance flags * @param[in] field The field content. * @param[out] result The result. * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t pcre_operator_execute(ib_engine_t *ib, ib_tx_t *tx, const ib_rule_t *rule, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { IB_FTRACE_INIT(); assert(ib!=NULL); assert(tx!=NULL); assert(tx->dpi!=NULL); assert(data!=NULL); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; int *ovector = (int *)malloc(ovecsize*sizeof(*ovector)); const char* subject = NULL; size_t subject_len = 0; const ib_bytestr_t* bytestr; pcre_rule_data_t *rule_data = (pcre_rule_data_t *)data; pcre_extra *edata = NULL; #ifdef PCRE_JIT_STACK pcre_jit_stack *jit_stack = pcre_jit_stack_alloc(PCRE_JIT_MIN_STACK_SZ, PCRE_JIT_MAX_STACK_SZ); #endif if (ovector==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } if (subject != NULL) { subject_len = strlen(subject); } } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } if (bytestr != NULL) { subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } } else { free(ovector); IB_FTRACE_RET_STATUS(IB_EINVAL); } if (subject == NULL) { subject = ""; } /* Debug block. Escapes a string and prints it to the log. * Memory is freed. */ if (ib_log_get_level(ib) >= 9) { /* Worst case, we can have a string that is 4x larger. * Consider if a string of 0xF7 is passed. That single character * will expand to a string of 4 printed characters +1 for the \0 * character. */ char *debug_str = ib_util_hex_escape(subject, subject_len); if ( debug_str != NULL ) { ib_log_debug3_tx(tx, "Matching against: %s", debug_str); free( debug_str ); } } #ifdef PCRE_JIT_STACK /* Log if we expected jit, but did not get it. */ if (rule_data->is_jit && jit_stack == NULL) { ib_log_debug(ib, "Failed to allocate a jit stack for a jit-compiled rule. " "Not using jit for this call."); edata = NULL; } /* If the study data is NULL or size zero, don't use it. */ else if (rule_data->edata == NULL || rule_data->study_data_sz <= 0) { edata = NULL; } /* Only if we get here do we use the study data (edata) in the rule_data. */ else { edata = rule_data->edata; pcre_assign_jit_stack(rule_data->edata, NULL, jit_stack); } #endif matches = pcre_exec(rule_data->cpatt, edata, subject, subject_len, 0, /* Starting offset. */ 0, /* Options. */ ovector, ovecsize); #ifdef PCRE_JIT_STACK if (jit_stack != NULL) { pcre_jit_stack_free(jit_stack); } #endif if (matches > 0) { if (ib_flags_all(rule->flags, IB_RULE_FLAG_CAPTURE) == true) { pcre_set_matches(ib, tx, ovector, matches, subject); } ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_NOMATCH) { if (ib_log_get_level(ib) >= 7) { char* tmp_c = malloc(subject_len+1); memcpy(tmp_c, subject, subject_len); tmp_c[subject_len] = '\0'; /* No match. Return false to the caller (*result = 0). */ ib_log_debug2_tx(tx, "No match for [%s] using pattern [%s].", tmp_c, rule_data->patt); free(tmp_c); } ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and report the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); IB_FTRACE_RET_STATUS(ib_rc); }
/** * @brief Execute the rule. * * @param[in] ib Ironbee engine * @param[in] tx The transaction. * @param[in,out] User data. A @c pcre_rule_data_t. * @param[in] flags Operator instance flags * @param[in] field The field content. * @param[in] result The result. * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t pcre_operator_execute(ib_engine_t *ib, ib_tx_t *tx, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { IB_FTRACE_INIT(); assert(ib!=NULL); assert(tx!=NULL); assert(tx->dpi!=NULL); assert(data!=NULL); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; int *ovector = (int *)malloc(ovecsize*sizeof(*ovector)); const char* subject; size_t subject_len; const ib_bytestr_t* bytestr; pcre_rule_data_t *rule_data = (pcre_rule_data_t *)data; pcre *regex; pcre_extra *regex_extra = NULL; #ifdef PCRE_JIT_STACK pcre_jit_stack *jit_stack = pcre_jit_stack_alloc(PCRE_JIT_MIN_STACK_SZ, PCRE_JIT_MAX_STACK_SZ); #endif if (ovector==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { IB_FTRACE_RET_STATUS(ib_rc); } subject_len = strlen(subject); } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { IB_FTRACE_RET_STATUS(ib_rc); } subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } else { free(ovector); IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Debug block. Escapes a string and prints it to the log. * Memory is freed. */ if (ib_log_get_level(ib) >= 9) { /* Worst case, we can have a string that is 4x larger. * Consider if a string of 0xF7 is passed. That single character * will expand to a string of 4 printed characters +1 for the \0 * character. */ char *debug_str = ib_util_hex_escape(subject, subject_len); if ( debug_str != NULL ) { ib_log_debug3_tx(tx, "Matching against: %s", debug_str); free( debug_str ); } } /* Alloc space to copy regex. */ regex = (pcre *)malloc(rule_data->cpatt_sz); if (regex == NULL ) { free(ovector); IB_FTRACE_RET_STATUS(IB_EALLOC); } memcpy(regex, rule_data->cpatt, rule_data->cpatt_sz); if (rule_data->study_data_sz == 0 ) { regex_extra = NULL; } else { regex_extra = (pcre_extra *) malloc(sizeof(*regex_extra)); if (regex_extra == NULL ) { free(ovector); free(regex); IB_FTRACE_RET_STATUS(IB_EALLOC); } *regex_extra = *rule_data->edata; if ( rule_data->study_data_sz == 0 ) { regex_extra->study_data = NULL; } else { regex_extra->study_data = malloc(rule_data->study_data_sz); if (regex_extra->study_data == NULL ) { free(ovector); if (regex_extra != NULL) { free(regex_extra); } free(regex); IB_FTRACE_RET_STATUS(IB_EALLOC); } memcpy(regex_extra->study_data, rule_data->edata->study_data, rule_data->study_data_sz); } /* Put some modest limits on our regex. */ regex_extra->match_limit = 1000; regex_extra->match_limit_recursion = 1000; regex_extra->flags = regex_extra->flags | PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION; } #ifdef PCRE_JIT_STACK if (jit_stack == NULL) { if ( regex_extra != NULL ) { if ( regex_extra->study_data != NULL ) { free(regex_extra->study_data); } free(regex_extra); } free(ovector); free(regex); IB_FTRACE_RET_STATUS(IB_EALLOC); } pcre_assign_jit_stack(regex_extra, NULL, jit_stack); #endif matches = pcre_exec(regex, regex_extra, subject, subject_len, 0, /* Starting offset. */ 0, /* Options. */ ovector, ovecsize); #ifdef PCRE_JIT_STACK pcre_jit_stack_free(jit_stack); #endif if (matches > 0) { pcre_set_matches(ib, tx, "TX", ovector, matches, subject); ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_NOMATCH) { if (ib_log_get_level(ib) >= 7) { char* tmp_c = malloc(subject_len+1); memcpy(tmp_c, subject, subject_len); tmp_c[subject_len] = '\0'; /* No match. Return false to the caller (*result = 0). */ ib_log_debug2_tx(tx, "No match for [%s] using pattern [%s].", tmp_c, rule_data->patt); free(tmp_c); } ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and report the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } if ( regex_extra != NULL ) { if ( regex_extra->study_data != NULL ) { free(regex_extra->study_data); } free(regex_extra); } free(ovector); free(regex); IB_FTRACE_RET_STATUS(ib_rc); }