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); }
static void core_gen_tx_bytestr_alias2( ib_tx_t *tx, const char *name, const char *val, size_t val_length ) { assert(tx != NULL); assert(name != NULL); assert(val != NULL); ib_status_t rc; ib_bytestr_t *bytestr; rc = ib_bytestr_alias_mem( &bytestr, tx->mp, (const uint8_t *)val, val_length ); if (rc != IB_OK) { ib_log_warning_tx(tx, "Failed to create alias for \"%s\" var: %s", name, ib_status_to_string(rc)); return; } core_gen_tx_bytestr_alias(tx, name, bytestr); }
ib_status_t ib_bytestr_alias_nulstr( ib_bytestr_t **pdst, ib_mm_t mm, const char *data ) { assert(pdst != NULL); ib_status_t rc; rc = ib_bytestr_alias_mem(pdst, mm, (uint8_t *)data, strlen(data)); return rc; }
ib_status_t ib_bytestr_alias_nulstr(ib_bytestr_t **pdst, ib_mpool_t *pool, const char *data) { IB_FTRACE_INIT(); assert(pdst != NULL); assert(pool != NULL); ib_status_t rc; rc = ib_bytestr_alias_mem(pdst, pool, (uint8_t *)data, strlen(data)); IB_FTRACE_RET_STATUS(rc); }
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; }
ib_status_t ib_field_create_bytestr_alias( ib_field_t **pf, ib_mpool_t *mp, const char *name, size_t nlen, uint8_t *val, size_t vlen ) { ib_status_t rc; ib_bytestr_t *bs; rc = ib_bytestr_alias_mem(&bs, mp, val, vlen); if (rc != IB_OK) { goto failed; } rc = ib_field_create_no_copy( pf, mp, name, nlen, IB_FTYPE_BYTESTR, ib_ftype_bytestr_mutable_in(bs) ); if (rc != IB_OK) { goto failed; } ib_field_util_log_debug("FIELD_CREATE_BYTESTR_ALIAS", (*pf)); return IB_OK; failed: /* Make sure everything is cleaned up on failure. */ *pf = NULL; return rc; }
ib_status_t ib_tfn_transform_field(ib_tfn_t *tfn, ib_field_t *f, ib_flags_t *pflags) { IB_FTRACE_INIT(ib_tfn_transform); ib_bytestr_t *bs; char *str; uint8_t *data_out; size_t dlen_out; ib_status_t rc; switch(f->type) { case IB_FTYPE_BYTESTR: bs = ib_field_value_bytestr(f); rc = tfn->transform(tfn->fndata, f->mp, ib_bytestr_ptr(bs), ib_bytestr_length(bs), &data_out, &dlen_out, pflags); /* If it is modified and not done inplace, then the * field value needs to be updated. */ if ( IB_TFN_CHECK_FMODIFIED(*pflags) && !IB_TFN_CHECK_FINPLACE(*pflags)) { ib_bytestr_t *bs_new; rc = ib_bytestr_alias_mem(&bs_new, f->mp, data_out, dlen_out); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = ib_field_setv(f, bs_new); } IB_FTRACE_RET_STATUS(rc); case IB_FTYPE_NULSTR: str = ib_field_value_nulstr(f), rc = tfn->transform(tfn->fndata, f->mp, (uint8_t *)str, strlen(str), &data_out, &dlen_out, pflags); /* If it is modified and not done inplace, then the * field value needs to be updated. * * NOTE: Anytime a transformation modifies data it * MUST NUL terminate the data and it is a bug * if this is not done. */ if ( IB_TFN_CHECK_FMODIFIED(*pflags) && !IB_TFN_CHECK_FINPLACE(*pflags)) { rc = ib_field_setv(f, data_out); } IB_FTRACE_RET_STATUS(rc); } IB_FTRACE_RET_STATUS(IB_EINVAL); }
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; }
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; }
/** * Create an alias list collection. * * @param ib Engine. * @param tx Transaction. * @param name Collection name * @param header Header list to alias * * @returns Status code */ static ib_status_t create_header_alias_list( ib_engine_t *ib, ib_tx_t *tx, const char *name, ib_parsed_header_wrapper_t *header) { ib_field_t *f; ib_list_t *header_list; ib_status_t rc; ib_parsed_name_value_pair_list_t *nvpair; assert(ib != NULL); assert(tx != NULL); assert(name != NULL); assert(header != NULL); /* Create the list */ rc = ib_data_get(tx->data, name, &f); if (rc == IB_ENOENT) { rc = ib_data_add_list(tx->data, name, &f); if (rc != IB_OK) { return rc; } } else if (rc != IB_OK) { return rc; } rc = ib_field_mutable_value(f, ib_ftype_list_mutable_out(&header_list)); if (rc != IB_OK) { return rc; } /* Loop through the list & alias everything */ for(nvpair = header->head; nvpair != NULL; nvpair = nvpair->next) { assert(nvpair); assert(nvpair->value); ib_bytestr_t *bs = NULL; if (ib_bytestr_ptr(nvpair->value) != NULL) { rc = ib_bytestr_alias_mem( &bs, tx->mp, ib_bytestr_ptr(nvpair->value), ib_bytestr_length(nvpair->value) ); } else { rc = ib_bytestr_dup_mem(&bs, tx->mp, (const uint8_t *)"", 0); } if (rc != IB_OK) { ib_log_error_tx( tx, "Error creating bytestring of '%.*s' for %s: %s", (int)ib_bytestr_length(nvpair->name), (const char *)ib_bytestr_ptr(nvpair->name), name, ib_status_to_string(rc) ); return rc; } /* Create a byte string field */ rc = ib_field_create( &f, tx->mp, (const char *)ib_bytestr_const_ptr(nvpair->name), ib_bytestr_length(nvpair->name), IB_FTYPE_BYTESTR, ib_ftype_bytestr_in(bs) ); if (rc != IB_OK) { ib_log_error_tx(tx, "Error creating field of '%.*s' for %s: %s", (int)ib_bytestr_length(nvpair->name), (const char *)ib_bytestr_ptr(nvpair->name), name, ib_status_to_string(rc)); return rc; } /* Add the field to the list */ rc = ib_list_push(header_list, f); if (rc != IB_OK) { ib_log_error_tx(tx, "Error adding alias of '%.*s' to %s list: %s", (int)ib_bytestr_length(nvpair->name), (const char *)ib_bytestr_ptr(nvpair->name), name, ib_status_to_string(rc)); return rc; } } return IB_OK; }
static ib_status_t sqli_normalize_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); 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 pat_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; } /* 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; } /* 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_is_sqli(&sf, buf_in_start, buf_in_len, NULL, NULL); buf_out_len = 0; prev_token_type = 0; pat_len = strlen(sf.pat); for (size_t i = 0; i < pat_len; ++i) { stoken_t current = sf.tokenvec[i]; size_t token_len = strlen(current.val); ib_log_debug2(ib, "SQLi TOKEN: %c \"%s\"", current.type, 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; } /* 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; }