Exemple #1
0
ib_status_t ib_parsed_tx_each_header(
    ib_parsed_name_value_pair_list_wrapper_t *headers,
    ib_parsed_tx_each_header_callback callback,
    void* user_data)
{
    IB_FTRACE_INIT();

    assert(headers!=NULL);

    ib_status_t rc = IB_OK;

    /* Loop over headers elements until the end of the list is reached or
     * IB_OK is not returned by the callback. */
    for(const ib_parsed_name_value_pair_list_t *le = headers->head;
        le != NULL && rc == IB_OK;
        le = le->next)
    {
        rc = callback((const char *)ib_bytestr_const_ptr(le->name),
                      ib_bytestr_size(le->name),
                      (const char *)ib_bytestr_const_ptr(le->value),
                      ib_bytestr_size(le->value),
                      user_data);
    }

    IB_FTRACE_RET_STATUS(rc);
}
Exemple #2
0
TEST_F(TestIBUtilField, AliasBytestr)
{
    const char s1[] = "hello";
    const char s2[] = "bye";
    ib_field_t *f;
    const ib_bytestr_t *obs;
    ib_status_t rc;
    ib_bytestr_t *bs;
    uint8_t *copy;

    copy = (uint8_t *)ib_mm_strdup(MM(), "x");
    rc = ib_field_create_bytestr_alias(&f, MM(),
                                       IB_S2SL("foo"), copy, 0);
    ASSERT_EQ(IB_OK, rc);

    rc = ib_bytestr_dup_nulstr(&bs, MM(), s1);
    ASSERT_EQ(IB_OK, rc);
    rc = ib_field_setv(f, bs);
    ASSERT_EQ(IB_OK, rc);
    rc = ib_field_value(f, ib_ftype_bytestr_out(&obs));
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(strlen(s1), ib_bytestr_length(obs));
    ASSERT_EQ(0, memcmp(s1,
                        ib_bytestr_const_ptr(obs), ib_bytestr_length(obs)) );

    rc = ib_bytestr_dup_nulstr(&bs, MM(), s2);
    ASSERT_EQ(IB_OK, rc);
    rc = ib_field_setv(f, bs);
    ASSERT_EQ(IB_OK, rc);
    rc = ib_field_value(f, ib_ftype_bytestr_out(&obs));
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(strlen(s2), ib_bytestr_length(obs));
    ASSERT_EQ(0, memcmp(s2,
                        ib_bytestr_const_ptr(obs), ib_bytestr_length(obs)) );
}
Exemple #3
0
ib_status_t ib_bytestr_alias(
    ib_bytestr_t       **pdst,
    ib_mpool_t          *pool,
    const ib_bytestr_t  *src
)
{
    IB_FTRACE_INIT();

    assert(pdst != NULL);
    assert(pool != NULL);

    ib_status_t rc;

    if ((src == NULL) || (src->data == NULL)) {
        IB_FTRACE_RET_STATUS(IB_EINVAL);
    }

    rc = ib_bytestr_alias_mem(
        pdst,
        pool,
        ib_bytestr_const_ptr(src),
        src->length
    );

    IB_FTRACE_RET_STATUS(rc);
}
Exemple #4
0
TEST_F(PcreModuleTest, test_match_capture)
{
    ib_field_t *ib_field;

    const ib_bytestr_t *ib_bytestr;
    ib_status_t rc;

    /* Check :0 */
    ib_field = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :1 */
    ib_field = getTarget1(IB_TX_CAPTURE":1");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :2 */
    ib_field = getTarget1(IB_TX_CAPTURE":2");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr));
    ASSERT_EQ(IB_OK, rc);

    /* Check that a value is over written correctly. */
    ASSERT_EQ("4", std::string(
        reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)),
        ib_bytestr_length(ib_bytestr)
    ));

    ib_field = getTarget1(IB_TX_CAPTURE":3");
    ASSERT_FALSE(ib_field);
}
Exemple #5
0
static
ib_status_t sqli_op_execute(
    ib_tx_t *tx,
    void *instance_data,
    const ib_field_t *field,
    ib_field_t *capture,
    ib_num_t *result,
    void *cbdata
)
{
    assert(tx            != NULL);
    assert(field         != NULL);
    assert(result        != NULL);

    sfilter sf;
    ib_bytestr_t *bs;
    ib_status_t rc;
    const sqli_pattern_set_t *ps = (const sqli_pattern_set_t *)instance_data;

    *result = 0;

    /* Currently only bytestring types are supported.
     * Other types will just get passed through. */
    if (field->type != IB_FTYPE_BYTESTR) {
        return IB_OK;
    }

    rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs));
    if (rc != IB_OK) {
        return rc;
    }

    /* Run through libinjection. */
    libinjection_sqli_init(
        &sf,
        (const char *)ib_bytestr_const_ptr(bs),
        ib_bytestr_length(bs),
        FLAG_NONE
    );
    if (ps != NULL ) {
        libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)ps);
    }
    if ( libinjection_is_sqli(&sf) ) {
        ib_log_debug_tx(tx, "Matched SQLi fingerprint: %s", sf.fingerprint);
        *result = 1;
    }

    return IB_OK;
}
Exemple #6
0
ib_status_t ib_bytestr_dup(
    ib_bytestr_t       **pdst,
    ib_mm_t              mm,
    const ib_bytestr_t  *src
) {
    assert(pdst != NULL);

    ib_status_t rc;
    rc = ib_bytestr_dup_mem(
        pdst,
        mm,
        ib_bytestr_const_ptr(src),
        ib_bytestr_length(src)
    );

    return rc;
}
Exemple #7
0
ib_status_t ib_bytestr_append_mem(
    ib_bytestr_t  *dst,
    const uint8_t *data,
    size_t         data_length
)
{
    IB_FTRACE_INIT();

    size_t dst_length = ib_bytestr_length(dst);
    size_t new_length;
    uint8_t *new_data = NULL;

    if (dst == NULL || IB_BYTESTR_CHECK_FREADONLY(dst->flags)) {
        IB_FTRACE_RET_STATUS(IB_EINVAL);
    }
    if (data == NULL && data_length != 0) {
        IB_FTRACE_RET_STATUS(IB_EINVAL);
    }

    new_length = dst_length + data_length;

    if (new_length > dst->size) {
        new_data = (uint8_t *)ib_mpool_alloc(dst->mp, new_length);
        if (new_data == NULL) {
            IB_FTRACE_RET_STATUS(IB_EALLOC);
        }
        if (dst_length > 0) {
            memcpy(
                new_data,
                ib_bytestr_const_ptr(dst),
                ib_bytestr_length(dst)
            );
        }
        dst->data = new_data;
        dst->size = new_length;
    }
    assert(new_length <= dst->size);

    if (data_length > 0) {
        memcpy(dst->data + dst_length, data, data_length);
        dst->length = new_length;
    }

    IB_FTRACE_RET_STATUS(IB_OK);
}
Exemple #8
0
ib_status_t ib_bytestr_append(
    ib_bytestr_t *dst,
    const ib_bytestr_t *src
)
{
    ib_status_t rc;

    if ( src == NULL ) {
        return IB_EINVAL;
    }

    rc = ib_bytestr_append_mem(
        dst,
        ib_bytestr_const_ptr(src),
        ib_bytestr_length(src)
    );

    return rc;
}
Exemple #9
0
TEST_F(PcreModuleTest, test_match_capture_named)
{
    ib_field_t *ib_field;
    const char *capname;

    const ib_bytestr_t *ib_bytestr;
    ib_status_t rc;

    /* Check :0 */
    capname = ib_capture_fullname(ib_tx, "captest", 0);
    ASSERT_STREQ(capname, "captest:0");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :1 */
    capname = ib_capture_fullname(ib_tx, "captest", 1);
    ASSERT_STREQ(capname, "captest:1");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :2 */
    capname = ib_capture_fullname(ib_tx, "captest", 2);
    ASSERT_STREQ(capname, "captest:2");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr));
    ASSERT_EQ(IB_OK, rc);

    /* Check that a value is over written correctly. */
    ASSERT_EQ("4", std::string(
        reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)),
        ib_bytestr_length(ib_bytestr)
    ));

    capname = ib_capture_fullname(ib_tx, "captest", 3);
    ASSERT_STREQ(capname, "captest:3");
    ib_field = getTarget1(capname);
    ASSERT_FALSE(ib_field);
}
Exemple #10
0
ib_status_t ib_bytestr_append_mem(
    ib_bytestr_t  *dst,
    const uint8_t *data,
    size_t         data_length
)
{
    size_t dst_length = ib_bytestr_length(dst);
    size_t new_length;
    uint8_t *new_data = NULL;

    if (dst == NULL || IB_BYTESTR_CHECK_FREADONLY(dst->flags)) {
        return IB_EINVAL;
    }
    if (data == NULL && data_length != 0) {
        return IB_EINVAL;
    }

    new_length = dst_length + data_length;

    if (new_length > dst->size) {
        new_data = (uint8_t *)ib_mm_alloc(dst->mm, new_length);
        if (new_data == NULL) {
            return IB_EALLOC;
        }
        if (dst_length > 0) {
            memcpy(
                new_data,
                ib_bytestr_const_ptr(dst),
                ib_bytestr_length(dst)
            );
        }
        dst->data = new_data;
        dst->size = new_length;
    }
    assert(new_length <= dst->size);

    if (data_length > 0) {
        memcpy(dst->data + dst_length, data, data_length);
        dst->length = new_length;
    }

    return IB_OK;
}
Exemple #11
0
ib_status_t ib_bytestr_dup(
    ib_bytestr_t       **pdst,
    ib_mpool_t          *pool,
    const ib_bytestr_t  *src
) {
    IB_FTRACE_INIT();

    assert(pdst != NULL);
    assert(pool != NULL);

    ib_status_t rc;
    rc = ib_bytestr_dup_mem(
        pdst,
        pool,
        ib_bytestr_const_ptr(src),
        ib_bytestr_length(src)
    );

    IB_FTRACE_RET_STATUS(rc);
}
Exemple #12
0
ib_status_t ib_bytestr_append(
    ib_bytestr_t *dst,
    const ib_bytestr_t *src
)
{
    IB_FTRACE_INIT();

    ib_status_t rc;

    if ( src == NULL ) {
        IB_FTRACE_RET_STATUS(IB_EINVAL);
    }

    rc = ib_bytestr_append_mem(
        dst,
        ib_bytestr_const_ptr(src),
        ib_bytestr_length(src)
    );

    IB_FTRACE_RET_STATUS(rc);
}
Exemple #13
0
int ib_bytestr_index_of_c(
    const ib_bytestr_t *haystack,
    const char   *needle
)
{
    const uint8_t* haystack_data = ib_bytestr_const_ptr(haystack);
    const char *found;

    /* Let ib_strstr() do the heavy lifting */
    found = ib_strstr( (const char *)haystack_data,
                       ib_bytestr_length(haystack),
                       IB_S2SL(needle) );

    /* Return the offset (or -1) */
    if (found != NULL) {
        return found - (const char *)haystack_data;
    }
    else {
        return -1;
    }
}
Exemple #14
0
static
ib_status_t xss_op_execute(
    ib_tx_t *tx,
    const ib_field_t *field,
    ib_field_t *capture,
    ib_num_t *result,
    void *instance_data,
    void *cbdata
)
{
    assert(tx     != NULL);
    assert(field  != NULL);
    assert(result != NULL);

    ib_bytestr_t *bs;
    ib_status_t rc;

    *result = 0;

    /* Currently only bytestring types are supported.
     * Other types will just get passed through. */
    if (field->type != IB_FTYPE_BYTESTR) {
        return IB_OK;
    }

    rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs));
    if (rc != IB_OK) {
        return rc;
    }

    /* Run through libinjection. */
    // TODO: flags parameter is currently undocumented - using 0
    if (libinjection_is_xss((const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), 0)) {
        ib_log_debug_tx(tx, "Matched XSS.");
        *result = 1;
    }

   return IB_OK;
}
Exemple #15
0
ib_status_t ib_bytestr_alias(
    ib_bytestr_t       **pdst,
    ib_mm_t              mm,
    const ib_bytestr_t  *src
)
{
    assert(pdst != NULL);

    ib_status_t rc;

    if ((src == NULL) || (src->data == NULL)) {
        return IB_EINVAL;
    }

    rc = ib_bytestr_alias_mem(
        pdst,
        mm,
        ib_bytestr_const_ptr(src),
        src->length
    );

    return rc;
}
Exemple #16
0
int ib_bytestr_index_of_c(
    const ib_bytestr_t *haystack,
    const char   *needle
)
{
    IB_FTRACE_INIT();

    const uint8_t* haystack_data = ib_bytestr_const_ptr(haystack);
    const char *found;

    /* Let ib_strstr_ex() do the heavy lifting */
    found = ib_strstr_ex( (const char *)haystack_data,
                          ib_bytestr_length(haystack),
                          needle,
                          strlen(needle));

    /* Return the offset (or -1) */
    if (found != NULL) {
        IB_FTRACE_RET_INT(found - (const char *)haystack_data);
    }
    else {
        IB_FTRACE_RET_INT(-1);
    }
}
Exemple #17
0
/**
 * 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;
}
Exemple #18
0
/**
 * Parse the user agent header, splitting into component fields.
 *
 * Attempt to tokenize the user agent string passed in, storing the
 * result in the DPI associated with the transaction.
 *
 * @param[in] ib IronBee object
 * @param[in,out] tx Transaction object
 * @param[in] bs Byte string containing the agent string
 *
 * @returns Status code
 */
static ib_status_t modua_agent_fields(ib_engine_t *ib,
                                      ib_tx_t *tx,
                                      const ib_bytestr_t *bs)
{
    const modua_match_rule_t *rule = NULL;
    ib_field_t               *agent_list = NULL;
    char                     *product = NULL;
    char                     *platform = NULL;
    char                     *extra = NULL;
    char                     *agent;
    char                     *buf;
    size_t                    len;
    ib_status_t               rc;

    /* Get the length of the byte string */
    len = ib_bytestr_length(bs);

    /* Allocate memory for a copy of the string to split up below. */
    buf = (char *)ib_mpool_calloc(tx->mp, 1, len+1);
    if (buf == NULL) {
        ib_log_error_tx(tx,
                        "Failed to allocate %zd bytes for agent string",
                        len+1);
        return IB_EALLOC;
    }

    /* Copy the string out */
    memcpy(buf, ib_bytestr_const_ptr(bs), len);
    buf[len] = '\0';
    ib_log_debug_tx(tx, "Found user agent: '%s'", buf);

    /* Copy the agent string */
    agent = (char *)ib_mpool_strdup(tx->mp, buf);
    if (agent == NULL) {
        ib_log_error_tx(tx, "Failed to allocate copy of agent string");
        return IB_EALLOC;
    }

    /* Parse the user agent string */
    rc = modua_parse_uastring(buf, &product, &platform, &extra);
    if (rc != IB_OK) {
        ib_log_debug_tx(tx, "Failed to parse User Agent string '%s'", agent);
        return IB_OK;
    }

    /* Categorize the parsed string */
    rule = modua_match_cat_rules(product, platform, extra);
    if (rule == NULL) {
        ib_log_debug_tx(tx, "No rule matched" );
    }
    else {
        ib_log_debug_tx(tx, "Matched to rule #%d / category '%s'",
                        rule->rule_num, rule->category );
    }

    /* Build a new list. */
    rc = ib_data_add_list(tx->data, "UA", &agent_list);
    if (rc != IB_OK)
    {
        ib_log_alert_tx(tx, "Unable to add UserAgent list to DPI.");
        return rc;
    }

    /* Store Agent */
    rc = modua_store_field(ib, tx->mp, agent_list, "agent", agent);
    if (rc != IB_OK) {
        return rc;
    }

    /* Store product */
    rc = modua_store_field(ib, tx->mp, agent_list, "PRODUCT", product);
    if (rc != IB_OK) {
        return rc;
    }

    /* Store Platform */
    rc = modua_store_field(ib, tx->mp, agent_list, "OS", platform);
    if (rc != IB_OK) {
        return rc;
    }

    /* Store Extra */
    rc = modua_store_field(ib, tx->mp, agent_list, "extra", extra);
    if (rc != IB_OK) {
        return rc;
    }

    /* Store Extra */
    if (rule != NULL) {
        rc = modua_store_field(ib, tx->mp, agent_list,
                               "category", rule->category);
    }
    else {
        rc = modua_store_field(ib, tx->mp, agent_list, "category", NULL );
    }
    if (rc != IB_OK) {
        return rc;
    }

    /* Done */
    return IB_OK;
}
Exemple #19
0
/**
 * 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;
}
Exemple #20
0
/**
 * 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);
}
Exemple #21
0
/**
 * 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);
}
Exemple #22
0
/**
 * 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;
}
Exemple #23
0
static
ib_status_t sqli_normalize_tfn(ib_mpool_t *mp,
                               const ib_field_t *field_in,
                               const ib_field_t **field_out,
                               void *tfn_data)
{
    assert(mp != NULL);
    assert(field_in != NULL);
    assert(field_out != NULL);

    const sqli_pattern_set_t *ps = (const sqli_pattern_set_t *)tfn_data;
    sfilter sf;
    ib_bytestr_t *bs_in;
    ib_bytestr_t *bs_out;
    const char *buf_in;
    char *buf_in_start;
    size_t buf_in_len;
    char *buf_out;
    char *buf_out_end;
    size_t buf_out_len;
    size_t lead_len = 0;
    char prev_token_type;
    ib_field_t *field_new;
    ib_status_t rc;
    size_t fingerprint_len;

    /* Currently only bytestring types are supported.
     * Other types will just get passed through. */
    if (field_in->type != IB_FTYPE_BYTESTR) {
        *field_out = field_in;
        return IB_OK;
    }

    /* Extract the underlying incoming value. */
    rc = ib_field_value(field_in, ib_ftype_bytestr_mutable_out(&bs_in));
    if (rc != IB_OK) {
        return rc;
    }

    /* Create a buffer big enough (double) to allow for normalization. */
    buf_in = (const char *)ib_bytestr_const_ptr(bs_in);
    buf_out = buf_out_end = (char *)ib_mpool_calloc(mp, 2, ib_bytestr_length(bs_in));
    if (buf_out == NULL) {
        return IB_EALLOC;
    }

/* TODO: With the latest libinjection, we will need to do something like the
 * following, but more robust, instead of just calling is_sqli. This seems
 * to be because folding is now called, which removes some tokens.
 */
#if 0
    /* As SQL can be injected into a string, the normalization
     * needs to start after the first quote character if one
     * exists.
     *
     * First try single quote, then double, then none.
     *
     * TODO: Handle returning multiple transformations:
     *       1) Straight normalization
     *       2) Normalization as if with single quotes (starting point
     *          should be based on straight normalization)
     *       3) Normalization as if with double quotes (starting point
     *          should be based on straight normalization)
     */
    buf_in_start = memchr(buf_in, CHAR_SINGLE, ib_bytestr_length(bs_in));
    if (buf_in_start == NULL) {
        buf_in_start = memchr(buf_in, CHAR_DOUBLE, ib_bytestr_length(bs_in));
    }
    if (buf_in_start == NULL) {
        buf_in_start = (char *)buf_in;
        buf_in_len = ib_bytestr_length(bs_in);
    }
    else {
        ++buf_in_start; /* After the quote. */
        buf_in_len = ib_bytestr_length(bs_in) - (buf_in_start - buf_in);
    }

    /* Copy the leading string if one exists. */
    if (buf_in_start != buf_in) {
        lead_len = buf_in_start - buf_in;
        memcpy(buf_out, buf_in, lead_len);
        buf_out_end += lead_len;
    }
#endif
    buf_in_start = (char *)buf_in;
    buf_in_len = ib_bytestr_length(bs_in);

    /* Copy the normalized tokens as a space separated list. Since
     * the tokenizer does not backtrack, and the normalized values
     * are always equal to or less than the original length, the
     * tokens are written back to the beginning of the original
     * buffer.
     */
    libinjection_sqli_init(&sf,buf_in_start, buf_in_len, FLAG_NONE);
    libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)ps);

    /* NOTE: We do not care if it is sqli, but just want the tokens. */
    libinjection_is_sqli(&sf);

    if (strlen(sf.fingerprint) == 0) {
        *field_out = field_in;
        return IB_OK;
    }

    buf_out_len = 0;
    prev_token_type = 0;
    fingerprint_len = strlen(sf.fingerprint);
    for (size_t i = 0; i < fingerprint_len; ++i) {
        stoken_t current = sf.tokenvec[i];
        size_t token_len = strlen(current.val);

        /* Add in the space if required. */
        if ((buf_out_end != buf_out) &&
            (current.type != 'o') &&
            (prev_token_type != 'o') &&
            (current.type != ',') &&
            (*(buf_out_end - 1) != ','))
        {
            *buf_out_end = ' ';
            buf_out_end += 1;
            ++buf_out_len;
        }

        /* Copy the token value. */
        memcpy(buf_out_end, current.val, token_len);
        buf_out_end += token_len;
        buf_out_len += token_len;

        prev_token_type = current.type;
    }


    /* Create the output field wrapping bs_out. */
    buf_out_len += lead_len;
    rc = ib_bytestr_alias_mem(&bs_out, mp, (uint8_t *)buf_out, buf_out_len);
    if (rc != IB_OK) {
        return rc;
    }
    rc = ib_field_create(&field_new, mp,
                         field_in->name, field_in->nlen,
                         IB_FTYPE_BYTESTR,
                         ib_ftype_bytestr_mutable_in(bs_out));
    if (rc == IB_OK) {
        *field_out = field_new;
    }
    return rc;
}
Exemple #24
0
static
ib_status_t sqltfn_normalize_pg_tfn(ib_engine_t *ib,
                                    ib_mpool_t *mp,
                                    void *tfn_data,
                                    const ib_field_t *field_in,
                                    const ib_field_t **field_out,
                                    ib_flags_t *pflags)
{
    assert(ib != NULL);
    assert(mp != NULL);
    assert(field_in != NULL);
    assert(field_out != NULL);
    assert(pflags != NULL);

    ib_bytestr_t *bs_in;
    ib_bytestr_t *bs_out;
    const char *buf_in;
    const char *buf_in_start;
    size_t buf_in_len;
    char *buf_out;
    char *buf_out_end;
    size_t buf_out_len;
    size_t lead_len = 0;
    ib_status_t rc;
    int ret;
    ib_field_t *field_new;

    /* Currently only bytestring types are supported.
     * Other types will just get passed through. */
    if (field_in->type != IB_FTYPE_BYTESTR) {
        *field_out = field_in;
        return IB_OK;
    }

    /* Extract the underlying incoming value. */
    rc = ib_field_value(field_in, ib_ftype_bytestr_mutable_out(&bs_in));
    if (rc != IB_OK) {
        return rc;
    }

    /* Create a buffer for normalization. */
    buf_out = buf_out_end = (char *)ib_mpool_alloc(mp, ib_bytestr_length(bs_in));
    if (buf_out == NULL) {
        return IB_EALLOC;
    }

    /* As SQL can be injected into a string, the normalization
     * needs to start after the first quote character if one
     * exists.
     *
     * First try single quote, then double, then none.
     *
     * TODO: Handle returning multiple transformations:
     *       1) Straight normalization
     *       2) Normalization as if with single quotes (starting point
     *          should be based on straight normalization)
     *       3) Normalization as if with double quotes (starting point
     *          should be based on straight normalization)
     */
    buf_in = (const char *)ib_bytestr_const_ptr(bs_in);
    buf_in_start = memchr(buf_in, '\'', ib_bytestr_length(bs_in));
    if (buf_in_start == NULL) {
        buf_in_start = memchr(buf_in, '"', ib_bytestr_length(bs_in));
    }
    if (buf_in_start == NULL) {
        buf_in_start = buf_in;
        buf_in_len = ib_bytestr_length(bs_in);
    }
    else {
        ++buf_in_start; /* After the quote. */
        buf_in_len = ib_bytestr_length(bs_in) - (buf_in_start - buf_in);
    }

    /* Copy the leading string if one exists. */
    if (buf_in_start != buf_in) {
        lead_len = buf_in_start - buf_in;
        memcpy(buf_out, buf_in, lead_len);
        buf_out_end += lead_len;
    }

    /* Normalize. */
    ret = sqltfn_normalize_pg_ex(buf_in_start, buf_in_len,
                                 &buf_out_end, &buf_out_len);
    if (ret < 0) {
        return IB_EALLOC;
    }
    else if (ret > 0) {
        /* Mark as modified. */
        *pflags = IB_TFN_FMODIFIED;
    }


    /* Create the output field wrapping bs_out. */
    buf_out_len += lead_len;
    rc = ib_bytestr_alias_mem(&bs_out, mp, (uint8_t *)buf_out, buf_out_len);
    if (rc != IB_OK) {
        return rc;
    }
    rc =ib_field_create(&field_new, mp,
                        field_in->name, field_in->nlen,
                        IB_FTYPE_BYTESTR,
                        ib_ftype_bytestr_mutable_in(bs_out));
    if (rc == IB_OK) {
        *field_out = field_new;
    }
    return rc;
}
Exemple #25
0
/**
 * @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;
}
Exemple #26
0
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;
}
Exemple #27
0
/**
 * @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;
}
Exemple #28
0
/**
 * @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);
}
Exemple #29
0
/**
 * @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);
}
Exemple #30
0
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;
}