From: Arran Cudbard-Bell Date: Wed, 27 Oct 2021 16:15:47 +0000 (-0400) Subject: Add fr_value_box_from_substr X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=84889ca11e6012fa74d6735bee974f17a804b8d6;p=thirdparty%2Ffreeradius-server.git Add fr_value_box_from_substr it's not yet complete, but even the addition of the function caused significant issues. It should now be safe at least... --- diff --git a/src/bin/dhcpclient.c b/src/bin/dhcpclient.c index bec2348a1af..8596e3781cb 100644 --- a/src/bin/dhcpclient.c +++ b/src/bin/dhcpclient.c @@ -186,7 +186,10 @@ static int request_init(fr_radius_packet_t **out, fr_pair_list_t *packet_vps, ch * Xlat expansions are not supported. Convert xlat to value box (if possible). */ if (vp->type == VT_XLAT) { - if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, vp->xlat, -1, '\0', false) < 0) { + if (fr_value_box_from_str(vp, &vp->data, + vp->da->type, NULL, + vp->xlat, strlen(vp->xlat), + NULL, false) < 0) { fr_perror("dhcpclient"); fr_radius_packet_free(&packet); if (fp && (fp != stdin)) fclose(fp); diff --git a/src/bin/radclient.c b/src/bin/radclient.c index 8125b7cf879..2e4977bdd78 100644 --- a/src/bin/radclient.c +++ b/src/bin/radclient.c @@ -457,7 +457,10 @@ static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files) * Xlat expansions are not supported. Convert xlat to value box (if possible). */ if (vp->type == VT_XLAT) { - if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, vp->xlat, -1, '\0', false) < 0) { + if (fr_value_box_from_str(vp, &vp->data, + vp->da->type, NULL, + vp->xlat, strlen(vp->xlat), + NULL, false) < 0) { fr_perror("radclient"); goto error; } @@ -491,7 +494,9 @@ static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files) * Xlat expansions are not supported. Convert xlat to value box (if possible). */ if (vp->type == VT_XLAT) { - if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, vp->xlat, -1, '\0', false) < 0) { + if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, + vp->xlat, strlen(vp->xlat), + NULL, false) < 0) { fr_perror("radclient"); goto error; } diff --git a/src/bin/radmin.c b/src/bin/radmin.c index 56613204318..9f364aeddd8 100644 --- a/src/bin/radmin.c +++ b/src/bin/radmin.c @@ -521,7 +521,9 @@ static int cmd_set_profile_status(UNUSED FILE *fp, FILE *fp_err, UNUSED void *ct fr_value_box_t box; struct ProfilerState state; - if (fr_value_box_from_str(NULL, &box, FR_TYPE_BOOL, NULL, info->argv[0], strlen(info->argv[0]), '\0', false) < 0) { + if (fr_value_box_from_str(NULL, &box, FR_TYPE_BOOL, NULL, + info->argv[0], strlen(info->argv[0]), + NULL, false) <= 0) { fprintf(fp_err, "Failed setting profile status '%s' - %s\n", info->argv[0], fr_strerror()); return -1; } diff --git a/src/bin/radsniff.c b/src/bin/radsniff.c index 6380d009692..fa67aba7c14 100644 --- a/src/bin/radsniff.c +++ b/src/bin/radsniff.c @@ -2051,7 +2051,9 @@ static int rs_build_filter(fr_pair_list_t *out, char const *filter) * Xlat expansions are not supported. Convert xlat to value box (if possible). */ if (vp->type == VT_XLAT) { - if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, vp->xlat, -1, '\0', false) < 0) { + if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, + vp->xlat, strlen(vp->xlat), + NULL, false) < 0) { fr_perror("radsniff"); return -1; } diff --git a/src/bin/radsnmp.c b/src/bin/radsnmp.c index ed39b3f7e0c..92beb9fb9af 100644 --- a/src/bin/radsnmp.c +++ b/src/bin/radsnmp.c @@ -351,7 +351,7 @@ static ssize_t radsnmp_pair_from_oid(TALLOC_CTX *ctx, radsnmp_conf_t *conf, fr_d return -(slen); } - ret = fr_pair_value_from_str(vp, value, -1, '\0', true); + ret = fr_pair_value_from_str(vp, value, strlen(value), NULL, true); if (ret < 0) { slen = -(slen); goto error; diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index 2857bcc2a2f..7afc9858d5c 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -1520,7 +1520,10 @@ static size_t command_encode_dns_label(command_result_t *result, command_file_ct fr_skip_whitespace(p); - if (fr_value_box_from_str(box, box, FR_TYPE_STRING, NULL, p, -1, '"', false) < 0) { + if (fr_value_box_from_str(box, box, FR_TYPE_STRING, NULL, + p, strlen(p), + &fr_value_unescape_double, + false) < 0) { talloc_free(box); RETURN_OK_WITH_ERROR(); } @@ -2237,7 +2240,10 @@ static size_t command_value_box_normalise(command_result_t *result, UNUSED comma p = in + match_len; fr_skip_whitespace(p); - if (fr_value_box_from_str(box, box, type, NULL, p, -1, '"', false) < 0) { + if (fr_value_box_from_str(box, box, type, NULL, + p, strlen(p), + &fr_value_unescape_double, + false) < 0) { error: talloc_free(box); RETURN_OK_WITH_ERROR(); @@ -2260,7 +2266,9 @@ static size_t command_value_box_normalise(command_result_t *result, UNUSED comma * box as last time. */ box2 = talloc_zero(NULL, fr_value_box_t); - if (fr_value_box_from_str(box2, box2, type, NULL, data, slen, '"', false) < 0) { + if (fr_value_box_from_str(box2, box2, type, NULL, + data, slen, + &fr_value_unescape_double, false) < 0) { talloc_free(box2); talloc_free(box); RETURN_OK_WITH_ERROR(); diff --git a/src/lib/curl/base.c b/src/lib/curl/base.c index e71bcef91a0..417d0af5e3a 100644 --- a/src/lib/curl/base.c +++ b/src/lib/curl/base.c @@ -224,7 +224,7 @@ int fr_curl_response_certinfo(request_t *request, fr_curl_io_request_t *randle) continue; } MEM(vp = fr_pair_afrom_da(container, da)); - fr_pair_value_from_str(vp, q + 1, -1, '\0', true); + fr_pair_value_from_str(vp, q + 1, strlen(q + 1), NULL, true); fr_pair_append(&container->vp_group, vp); } diff --git a/src/lib/eap/chbind.c b/src/lib/eap/chbind.c index ad73659e7ac..7fcb3f50236 100644 --- a/src/lib/eap/chbind.c +++ b/src/lib/eap/chbind.c @@ -187,7 +187,7 @@ fr_radius_packet_code_t chbind_process(request_t *request, CHBIND_REQ *chbind) /* Set-up the fake request */ fake = request_alloc_internal(request, &(request_init_args_t){ .parent = request }); MEM(fr_pair_prepend_by_da(fake->request_ctx, &vp, &fake->request_pairs, attr_freeradius_proxied_to) >= 0); - fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1"), '\0', false); + fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1") - 1, NULL, false); /* Add the username to the fake request */ if (chbind->username) { diff --git a/src/lib/eap/crypto.c b/src/lib/eap/crypto.c index c813ec8088a..ebe9ebc7944 100644 --- a/src/lib/eap/crypto.c +++ b/src/lib/eap/crypto.c @@ -53,7 +53,7 @@ void eap_crypto_prf_label_init(eap_tls_prf_label_t *prf_label, eap_session_t *ea if (eap_tls_session->tls_session->info.version == TLS1_3_VERSION) { prf_label->keying_prf_label = "EXPORTER_EAP_TLS_Key_Material"; - prf_label->keying_prf_label_len = sizeof("EXPORTER_EAP_TLS_Key_Material") -1; + prf_label->keying_prf_label_len = sizeof("EXPORTER_EAP_TLS_Key_Material") - 1; prf_label->sessid_prf_label = "EXPORTER_EAP_TLS_Method-Id"; prf_label->sessid_prf_label_len = sizeof("EXPORTER_EAP_TLS_Method-Id") - 1; diff --git a/src/lib/ldap/map.c b/src/lib/ldap/map.c index 1ad59110156..9e43e5714c8 100644 --- a/src/lib/ldap/map.c +++ b/src/lib/ldap/map.c @@ -155,7 +155,7 @@ int fr_ldap_map_getvalue(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reques MEM(vp = fr_pair_afrom_da(ctx, tmpl_da(map->lhs))); if (fr_pair_value_from_str(vp, self->values[i]->bv_val, - self->values[i]->bv_len, '\0', true) < 0) { + self->values[i]->bv_len, NULL, true) < 0) { RPWDEBUG("Failed parsing value \"%pV\" for attribute %s", fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len), tmpl_da(map->lhs)->name); diff --git a/src/lib/server/command.c b/src/lib/server/command.c index 6d7bf0ffa6e..c42384e8e51 100644 --- a/src/lib/server/command.c +++ b/src/lib/server/command.c @@ -1835,7 +1835,9 @@ redo: * Parse the data to be sure it's well formed. */ if (fr_value_box_from_str(ctx, box, type, - NULL, name, -1, quote, true) < 0) { + NULL, + name, strlen(name), + fr_value_unescape_by_char[(uint8_t)quote], true) < 0) { fr_strerror_printf_push("Failed parsing argument '%s'", name); return -1; } @@ -1969,7 +1971,8 @@ static int syntax_str_to_argv(int start_argc, fr_cmd_argv_t *start, fr_cmd_info_ ret = fr_value_box_from_str(info->box[argc], info->box[argc], type, NULL, - word + offset, len - (offset << 1), quote, false); + word + offset, len - (offset << 1), + fr_value_unescape_by_char[(uint8_t)quote], false); if (ret < 0) return -1; /* @@ -2587,7 +2590,8 @@ static int expand_syntax(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv ret = fr_value_box_from_str(info->box[info->argc], info->box[info->argc], type, NULL, - word + offset, len - (offset << 1), quote, false); + word + offset, len - (offset << 1), + fr_value_unescape_by_char[(uint8_t)quote], false); if (ret < 0) return -1; info->argc++; *word_p = word = p; diff --git a/src/lib/server/cond_tokenize.c b/src/lib/server/cond_tokenize.c index c648b1a812c..db3e0621682 100644 --- a/src/lib/server/cond_tokenize.c +++ b/src/lib/server/cond_tokenize.c @@ -140,39 +140,18 @@ ssize_t cond_print(fr_sbuff_t *out, fr_cond_t const *in) } -static int cond_cast_tmpl(tmpl_t *vpt, fr_type_t *p_type, tmpl_t *other) +static int cond_cast_tmpl(tmpl_t *vpt, fr_type_t type, tmpl_t *other) { fr_dict_attr_t const *da; - fr_type_t type = *p_type; fr_assert(type != FR_TYPE_NULL); fr_assert(type < FR_TYPE_TLV); - if (tmpl_is_unresolved(vpt)) { - switch (type) { - case FR_TYPE_IPV4_ADDR: - if (strchr(vpt->name, '/') != NULL) { - *p_type = type = FR_TYPE_IPV4_PREFIX; - (void) tmpl_cast_set(other, type); - } - break; - - case FR_TYPE_IPV6_ADDR: - if (strchr(vpt->name, '/') != NULL) { - *p_type = type = FR_TYPE_IPV6_PREFIX; - (void) tmpl_cast_set(other, type); - } - break; - - default: - break; - } - - } else if (tmpl_is_attr(vpt)) { + if (tmpl_is_attr(vpt)) { (void) tmpl_cast_set(vpt, type); return 0; - } else if (!tmpl_is_data(vpt)) { + } else if (!tmpl_is_data(vpt) && !tmpl_is_unresolved(vpt)) { /* * Nothing to do. */ @@ -216,8 +195,7 @@ static int cond_cast_tmpl(tmpl_t *vpt, fr_type_t *p_type, tmpl_t *other) if (tmpl_cast_in_place(vpt, type, da) < 0) { fr_strerror_printf("Failed parsing value as type '%s'", - fr_table_str_by_value(fr_value_box_type_table, - type, "??")); + fr_table_str_by_value(fr_value_box_type_table, type, "??")); return -1; } @@ -502,12 +480,12 @@ set_types: /* * Cast both sides to the promoted type. */ - if (cond_cast_tmpl(c->data.map->lhs, &cast_type, c->data.map->rhs) < 0) { + if (cond_cast_tmpl(c->data.map->lhs, cast_type, c->data.map->rhs) < 0) { if (in) fr_sbuff_set(in, m_lhs); return -1; } - if (cond_cast_tmpl(c->data.map->rhs, &cast_type, c->data.map->lhs) < 0) { + if (cond_cast_tmpl(c->data.map->rhs, cast_type, c->data.map->lhs) < 0) { if (in) fr_sbuff_set(in, m_rhs); return -1; } diff --git a/src/lib/server/map.c b/src/lib/server/map.c index 84f7093110d..c1970817750 100644 --- a/src/lib/server/map.c +++ b/src/lib/server/map.c @@ -1075,7 +1075,7 @@ static int map_exec_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reque MEM(vp = fr_pair_afrom_da(ctx, tmpl_da(map->lhs))); vp->op = map->op; - if (fr_pair_value_from_str(vp, answer, -1, '"', false) < 0) { + if (fr_pair_value_from_str(vp, answer, strlen(answer), &fr_value_unescape_single, false) < 0) { RPEDEBUG("Failed parsing exec output"); talloc_free(&vp); return -2; @@ -1243,7 +1243,7 @@ int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t co RDEBUG2("--> %s", str); - rcode = fr_pair_value_from_str(n, str, -1, '\0', false); + rcode = fr_pair_value_from_str(n, str, strlen(str), NULL, false); talloc_free(str); if (rcode < 0) { talloc_free(&n); @@ -1259,7 +1259,7 @@ int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t co MEM(n = fr_pair_afrom_da(ctx, tmpl_da(map->lhs))); - if (fr_pair_value_from_str(n, map->rhs->name, -1, '\0', false) < 0) { + if (fr_pair_value_from_str(n, map->rhs->name, strlen(map->rhs->name), NULL, false) < 0) { rcode = 0; talloc_free(n); goto error; diff --git a/src/lib/server/map_async.c b/src/lib/server/map_async.c index 5a042e84107..629ffa621dd 100644 --- a/src/lib/server/map_async.c +++ b/src/lib/server/map_async.c @@ -457,7 +457,8 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, if (fr_value_box_from_str(fr_dlist_head(&n->mod), tmpl_value(fr_map_list_head(&n->mod)->rhs), type, tmpl_da(mutated->lhs), - mutated->rhs->name, mutated->rhs->len, mutated->rhs->quote, false)) { + mutated->rhs->name, mutated->rhs->len, + fr_value_unescape_by_quote[(uint8_t)mutated->rhs->quote], false)) { RPEDEBUG("Assigning value to \"%s\" failed", tmpl_da(mutated->lhs)->name); goto error; } diff --git a/src/lib/server/paircmp.c b/src/lib/server/paircmp.c index 819c4c3850f..39114849b94 100644 --- a/src/lib/server/paircmp.c +++ b/src/lib/server/paircmp.c @@ -137,7 +137,7 @@ static int generic_cmp(UNUSED void *instance, MEM(vp = fr_pair_afrom_da(request->request_ctx, check_item->da)); vp->op = check_item->op; - fr_pair_value_from_str(vp, value, -1, '"', false); + fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_single, false); /* * Paircmp returns 0 for failed comparison, 1 for succeeded -1 for error. diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index 192da0a7509..da1cf385e23 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -478,8 +478,13 @@ struct tmpl_s { #endif } data; - fr_type_t _CONST cast; - tmpl_rules_t _CONST rules; + fr_type_t _CONST cast; //!< Type we should interpret unresolved data with. + fr_dict_attr_t const * _CONST enumv; //!< Enumeration we should use when parsing unescaped + ///< i.e. barewords with an unknown format. + + tmpl_rules_t _CONST rules; //!< The rules that were used when creating the tmpl. + ///< These are useful for multiple resolution passes as + ///< they ensure the correct parsing rules are applied. }; typedef struct tmpl_cursor_ctx_s tmpl_pair_cursor_ctx_t; @@ -717,7 +722,7 @@ void tmpl_verify(char const *file, int line, tmpl_t const *vpt); #define tmpl_init_initialiser_list(_request, _list)\ { \ .name = "static", \ - .len = sizeof("static"), \ + .len = sizeof("static") - 1, \ .type = TMPL_TYPE_LIST, \ .quote = T_SINGLE_QUOTED_STRING, \ .data = { \ @@ -907,9 +912,10 @@ ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules); -ssize_t tmpl_cast_from_substr(fr_type_t *out, fr_sbuff_t *in); /* Parses cast string */ +ssize_t tmpl_cast_from_substr(fr_type_t *out, fr_sbuff_t *in); /* Parses cast string */ + +int tmpl_cast_set(tmpl_t *vpt, fr_type_t type) CC_HINT(nonnull); /* Sets cast type */ -int tmpl_cast_set(tmpl_t *vpt, fr_type_t type); /* Sets cast type */ #ifdef HAVE_REGEX ssize_t tmpl_regex_flags_substr(tmpl_t *vpt, fr_sbuff_t *in, diff --git a/src/lib/server/tmpl_eval.c b/src/lib/server/tmpl_eval.c index d8ca18f0218..7130ccddde7 100644 --- a/src/lib/server/tmpl_eval.c +++ b/src/lib/server/tmpl_eval.c @@ -28,11 +28,12 @@ RCSID("$Id$") #define _TMPL_PRIVATE 1 -#include #include #include -#include +#include #include +#include +#include /** Resolve attribute #pair_list_t value to an attribute list. * @@ -620,7 +621,8 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, * @fixme We need a way of signalling xlat not to escape things. */ ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL, - result, (size_t)slen, '"', false); + result, (size_t)slen, + &fr_value_unescape_double, false); if (ret < 0) goto error; fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted); @@ -649,7 +651,8 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, * @fixme We need a way of signalling xlat not to escape things. */ ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL, - result, (size_t)slen, '"', false); + result, (size_t)slen, + &fr_value_unescape_double, false); if (ret < 0) goto error; fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted); diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index 26222f30ae3..03231c9ac87 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -2172,8 +2172,9 @@ static ssize_t tmpl_afrom_ipv4_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t } MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_DATA, T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in))); - if (fr_value_box_from_str(vpt, &vpt->data.literal, type, NULL, - fr_sbuff_start(&our_in), fr_sbuff_used(&our_in), '\0', false) < 0) { + if (fr_value_box_from_substr(vpt, &vpt->data.literal, type, NULL, + &FR_SBUFF_REPARSE(&our_in), + NULL, false) < 0) { talloc_free(vpt); goto error; } @@ -2288,8 +2289,9 @@ static ssize_t tmpl_afrom_ipv6_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t } MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_DATA, T_BARE_WORD, fr_sbuff_start(&our_in), fr_sbuff_used(&our_in))); - if (fr_value_box_from_str(vpt, &vpt->data.literal, type, NULL, - fr_sbuff_start(&our_in), fr_sbuff_used(&our_in), '\0', false) < 0) { + if (fr_value_box_from_substr(vpt, &vpt->data.literal, type, NULL, + &FR_SBUFF_REPARSE(&our_in), + NULL, false) < 0) { talloc_free(vpt); goto error; } @@ -2929,6 +2931,36 @@ ssize_t tmpl_regex_flags_substr(tmpl_t *vpt, fr_sbuff_t *in, fr_sbuff_term_t con * @{ */ +/** Determine the correct quoting after a cast + * + * @param[in] existing_quote Exiting quotation type. + * @param[in] type Cast type. + * @param[in] enumv Enumeration values. + */ +static CC_HINT(always_inline) fr_token_t tmpl_cast_quote(fr_token_t existing_quote, + fr_type_t type, fr_dict_attr_t const *enumv, + char const *unescaped, size_t unescaped_len) +{ + if (!fr_type_is_string(type)) return T_BARE_WORD; + + if (enumv && fr_dict_enum_by_name(enumv, unescaped, unescaped_len)) return T_BARE_WORD; + + /* + * Leave the original quoting if it's + * single or double, else default to + * single quoting. + */ + switch (existing_quote) { + case T_SINGLE_QUOTED_STRING: + case T_DOUBLE_QUOTED_STRING: + return existing_quote; + + default: + return T_SINGLE_QUOTED_STRING; + } +} + + /** Convert #tmpl_t of type #TMPL_TYPE_UNRESOLVED or #TMPL_TYPE_DATA to #TMPL_TYPE_DATA of type specified * * @note Conversion is done in place. @@ -2955,27 +2987,59 @@ int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv) char *unescaped = vpt->data.unescaped; /* - * Why do we pass a pointer to a temporary type - * variable? Goddamn WiMAX. + * We're trying to convert an unresolved (bareword) + * tmpl to octets. + * + * tmpl_afrom_substr uses the 0x prefix as type + * inference, so if it was a hex string the tmpl + * type would not have fallen through to + * unresolved. + * + * That means if we're trying to resolve it here + * it's really a printable string, not a sequence + * of hexits, so we just want the binary + * representation of that string, and not the hex + * to bin conversion. */ - if (fr_value_box_from_str(vpt, &vpt->data.literal, type, - enumv, unescaped, talloc_array_length(unescaped) - 1, - '\0', false) < 0) return -1; - talloc_free(unescaped); + if (fr_type_is_octets(type)) { + if (fr_value_box_memdup(vpt, &vpt->data.literal, enumv, + (uint8_t const *)unescaped, talloc_array_length(unescaped) - 1, + false) < 0) return -1; + } else { + if (fr_value_box_from_str(vpt, &vpt->data.literal, type, + enumv, + unescaped, talloc_array_length(unescaped) - 1, + NULL, false) < 0) return -1; + } vpt->type = TMPL_TYPE_DATA; + vpt->quote = tmpl_cast_quote(vpt->quote, type, enumv, + unescaped, talloc_array_length(unescaped) - 1); + talloc_free(unescaped); } break; case TMPL_TYPE_DATA: { - fr_value_box_t new; - if (type == tmpl_value_type(vpt)) return 0; /* noop */ - if (fr_value_box_cast(vpt, &new, type, enumv, &vpt->data.literal) < 0) return -1; + /* + * Enumerations aren't used when casting between + * data types. They're only used when processing + * unresolved tmpls. + * + * i.e. TMPL_TYPE_UNRESOLVED != TMPL_TYPE_DATA(FR_TYPE_STRING) + */ + if (fr_value_box_cast_in_place(vpt, &vpt->data.literal, type, NULL) < 0) return -1; - fr_value_box_clear(&vpt->data.literal); - fr_value_box_copy(vpt, &vpt->data.literal, &new); + /* + * Strings get quoted, everything else is a bare + * word... + */ + if (fr_type_is_string(type)) { + vpt->quote = T_SINGLE_QUOTED_STRING; + } else { + vpt->quote = T_BARE_WORD; + } } break; @@ -2987,28 +3051,6 @@ int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv) default: fr_assert(0); } - - /* - * Fixup quoting - */ - switch (type) { - case FR_TYPE_STRING: - switch (vpt->quote) { - case T_SINGLE_QUOTED_STRING: - case T_DOUBLE_QUOTED_STRING: - break; - - default: - vpt->quote = T_SINGLE_QUOTED_STRING; - break; - } - break; - - default: - vpt->quote = T_BARE_WORD; - break; - } - TMPL_VERIFY(vpt); return 0; @@ -3216,24 +3258,15 @@ int tmpl_resolve(tmpl_t *vpt) * Convert unresolved tmpls into literal string values. */ } else if (tmpl_is_unresolved(vpt)) { - char *unescaped = vpt->data.unescaped; /* Copy the pointer before zeroing the union */ + fr_type_t dst_type = vpt->cast; - fr_value_box_init_null(&vpt->data.literal); + if (fr_type_is_null(dst_type)) dst_type = FR_TYPE_STRING; /* Default to strings */ - fr_value_box_bstrdup_buffer_shallow(NULL, &vpt->data.literal, NULL, unescaped, false); + if (tmpl_cast_in_place(vpt, dst_type, NULL) < 0) return -1; - /* - * Attempt to process the cast - */ - if (vpt->cast != FR_TYPE_NULL) { - ret = fr_value_box_cast_in_place(vpt, &vpt->data.literal, vpt->cast, NULL); - if (ret < 0) goto done; - } - vpt->type = TMPL_TYPE_DATA; TMPL_VERIFY(vpt); } -done: return ret; } diff --git a/src/lib/soh/soh.c b/src/lib/soh/soh.c index 4320c1cc488..9666b16e712 100644 --- a/src/lib/soh/soh.c +++ b/src/lib/soh/soh.c @@ -205,7 +205,7 @@ static int eap_peap_soh_mstlv(request_t *request, uint8_t const *p, unsigned int data_len -= 18; MEM(pair_update_request(&vp, attr_soh_ms_machine_os_vendor) >= 0); - fr_pair_value_from_str(vp, "Microsoft", -1, '\0', false); + fr_pair_value_from_str(vp, "Microsoft", sizeof("Microsoft") - 1, NULL, false); MEM(pair_update_request(&vp, attr_soh_ms_machine_os_version) >= 0); vp->vp_uint32 = soh_pull_be_32(p); diff --git a/src/lib/tls/pairs.c b/src/lib/tls/pairs.c index 098f31bc7be..50709a1430f 100644 --- a/src/lib/tls/pairs.c +++ b/src/lib/tls/pairs.c @@ -314,7 +314,7 @@ skip_alt: MEM(vp = fr_pair_afrom_da(ctx, da)); if (fr_pair_value_from_str(vp, (char *)fr_dbuff_current(out), fr_dbuff_remaining(out), - '\0', true) < 0) { + NULL, true) < 0) { RPWDEBUG3("Skipping: %s += \"%pV\"", da->name, fr_box_strvalue_len((char *)fr_dbuff_current(out), fr_dbuff_remaining(out))); diff --git a/src/lib/tls/session.c b/src/lib/tls/session.c index 8abaa46ebfa..57eb6b21dfd 100644 --- a/src/lib/tls/session.c +++ b/src/lib/tls/session.c @@ -366,7 +366,7 @@ unsigned int fr_tls_session_psk_server_cb(SSL *ssl, const char *identity, } MEM(pair_update_request(&vp, attr_tls_psk_identity) >= 0); - if (fr_pair_value_from_str(vp, identity, -1, '\0', true) < 0) { + if (fr_pair_value_from_str(vp, identity, strlen(identity), NULL, true) < 0) { RPWDEBUG2("Failed parsing TLS PSK Identity"); talloc_free(vp); return 0; diff --git a/src/lib/unlang/tmpl.c b/src/lib/unlang/tmpl.c index ec91e669a55..12c30e8ff56 100644 --- a/src/lib/unlang/tmpl.c +++ b/src/lib/unlang/tmpl.c @@ -134,8 +134,9 @@ static unlang_action_t unlang_tmpl_exec_wait_final(rlm_rcode_t *p_result, reques fr_value_box_list_init(&state->box); MEM(box = fr_value_box_alloc(state->ctx, FR_TYPE_STRING, NULL, true)); if (fr_value_box_from_str(state->ctx, box, type, NULL, - fr_sbuff_buff(&state->exec.stdout_buff), - fr_sbuff_used(&state->exec.stdout_buff), 0, true) < 0) { + fr_sbuff_start(&state->exec.stdout_buff), + fr_sbuff_used(&state->exec.stdout_buff), + NULL, true) < 0) { talloc_free(box); *p_result = RLM_MODULE_FAIL; return UNLANG_ACTION_CALCULATE_RESULT; diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index e9a54896eef..80cea64ea73 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -1090,14 +1090,21 @@ static xlat_action_t xlat_func_integer(TALLOC_CTX *ctx, fr_dcursor_t *out, break; case FR_TYPE_OCTETS: - if (in_vb->vb_length > sizeof(uint64_t)) goto error; + if (in_vb->vb_length > sizeof(uint64_t)) { + fr_strerror_printf("Expected octets length <= %zu, got %zu", sizeof(uint64_t), in_vb->vb_length); + goto error; + } if (in_vb->vb_length > sizeof(uint32_t)) { fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL); - break; + } else if (in_vb->vb_length > sizeof(uint16_t)) { + fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT32, NULL); + } else if (in_vb->vb_length > sizeof(uint8_t)) { + fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT16, NULL); + } else { + fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT8, NULL); } - fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT32, NULL); break; case FR_TYPE_IPV4_ADDR: diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index 5d63d98d6e7..be04f023fc8 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -1623,8 +1623,9 @@ static char *xlat_sync_eval(TALLOC_CTX *ctx, request_t *request, xlat_exp_t cons fr_value_box_t data; type = FR_TYPE_STRING; - if (fr_value_box_from_str(ctx, &data, type, NULL, child, - talloc_array_length(child) - 1, '"', false) < 0) { + if (fr_value_box_from_str(ctx, &data, type, NULL, + child, talloc_array_length(child) - 1, + &fr_value_unescape_double, false) < 0) { talloc_free(child); return NULL; } @@ -2076,7 +2077,7 @@ int xlat_eval_pair(request_t *request, fr_pair_t *vp) return 0; } - if (fr_pair_value_from_str(vp, expanded, -1, '"', true) < 0){ + if (fr_pair_value_from_str(vp, expanded, strlen(expanded), &fr_value_unescape_double, true) < 0){ talloc_free(expanded); return -2; } diff --git a/src/lib/util/dict_fixup.c b/src/lib/util/dict_fixup.c index eef6db26ac3..9ef2c58c359 100644 --- a/src/lib/util/dict_fixup.c +++ b/src/lib/util/dict_fixup.c @@ -174,8 +174,10 @@ static inline CC_HINT(always_inline) int dict_fixup_enumv_apply(UNUSED dict_fixu type = da->type; if (fr_value_box_from_str(fixup, &value, type, NULL, - fixup->value, talloc_array_length(fixup->value) - 1, '\0', false) < 0) { - fr_strerror_printf_push("Invalid VALUE for Attribute '%s' at %s[%d]", + fixup->value, talloc_array_length(fixup->value) - 1, + NULL, false) < 0) { + fr_strerror_printf_push("Invalid VALUE '%pV' for attribute '%s' at %s[%d]", + fr_box_strvalue_buffer(fixup->value), da->name, fr_cwd_strip(fixup->common.filename), fixup->common.line); return -1; diff --git a/src/lib/util/dict_tokenize.c b/src/lib/util/dict_tokenize.c index e0180cf4c3b..fe142d8201a 100644 --- a/src/lib/util/dict_tokenize.c +++ b/src/lib/util/dict_tokenize.c @@ -1312,8 +1312,13 @@ static int dict_read_process_value(dict_tokenize_ctx_t *ctx, char **argv, int ar break; } - if (fr_value_box_from_str(NULL, &value, da->type, NULL, argv[2], -1, '\0', false) < 0) { - fr_strerror_printf_push("Invalid VALUE for Attribute '%s'", da->name); + if (fr_value_box_from_str(NULL, &value, da->type, NULL, + argv[2], strlen(argv[2]), + NULL, false) < 0) { + fr_strerror_printf_push("Invalid VALUE '%s' for attribute '%s' of data type '%s'", + argv[2], + da->name, + fr_table_str_by_value(fr_value_box_type_table, da->type, "")); return -1; } @@ -1416,7 +1421,7 @@ static int dict_read_process_struct(dict_tokenize_ctx_t *ctx, char **argv, int a /* * Parse the value. */ - if (fr_value_box_from_str(NULL, &value, parent->type, NULL, argv[2], -1, '\0', false) < 0) { + if (fr_value_box_from_str(NULL, &value, parent->type, NULL, argv[2], strlen(argv[2]), NULL, false) < 0) { fr_strerror_printf_push("Invalid value for STRUCT \"%s\"", argv[2]); return -1; } diff --git a/src/lib/util/dict_util.c b/src/lib/util/dict_util.c index 3550502785d..ed6ee86d087 100644 --- a/src/lib/util/dict_util.c +++ b/src/lib/util/dict_util.c @@ -1802,6 +1802,7 @@ ssize_t fr_dict_oid_component(fr_dict_attr_err_t *err, * Lookup by name */ case FR_SBUFF_PARSE_ERROR_NOT_FOUND: + case FR_SBUFF_PARSE_ERROR_TRAILING: { fr_dict_attr_err_t our_err; ssize_t slen; @@ -1820,7 +1821,8 @@ ssize_t fr_dict_oid_component(fr_dict_attr_err_t *err, break; default: - fr_strerror_printf("Invalid OID component \"%.*s\"", + fr_strerror_printf("Invalid OID component (%s) \"%.*s\"", + fr_table_str_by_value(sbuff_parse_error_table, sberr, ""), (int)fr_sbuff_remaining(in), fr_sbuff_current(in)); if (err) *err = FR_DICT_ATTR_PARSE_ERROR; return -fr_sbuff_marker_release_behind(&start); diff --git a/src/lib/util/dpair_legacy.c b/src/lib/util/dpair_legacy.c index 4f59f5d0fac..712de64c126 100644 --- a/src/lib/util/dpair_legacy.c +++ b/src/lib/util/dpair_legacy.c @@ -137,7 +137,7 @@ static fr_pair_t *fr_pair_make_unknown(TALLOC_CTX *ctx, fr_dict_t const *dict, return NULL; } - if (fr_pair_value_from_str(vp, value, -1, '"', false) < 0) { + if (fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_double, false) < 0) { talloc_free(vp); return NULL; } @@ -247,7 +247,7 @@ fr_pair_t *fr_pair_make(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t * * We probably want to fix fr_pair_value_from_str to accept * octets as values for any attribute. */ - if (value && (fr_pair_value_from_str(vp, value, -1, '\"', true) < 0)) { + if (value && (fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_double, true) < 0)) { talloc_free(vp); return NULL; } @@ -493,7 +493,8 @@ static ssize_t fr_pair_list_afrom_substr(TALLOC_CTX *ctx, fr_dict_attr_t const * * don't know. So just mark it * as such to be safe. */ - } else if (fr_pair_value_from_str(vp, raw.r_opand, -1, '"', true) < 0) { + } else if (fr_pair_value_from_str(vp, raw.r_opand, strlen(raw.r_opand), + fr_value_unescape_by_quote[raw.quote], true) < 0) { talloc_free(vp); goto error; } diff --git a/src/lib/util/fuzzer.c b/src/lib/util/fuzzer.c index fdd78b4b9f8..5e6b8bf707c 100644 --- a/src/lib/util/fuzzer.c +++ b/src/lib/util/fuzzer.c @@ -35,7 +35,8 @@ static int decode_test_ctx(void **out, UNUSED TALLOC_CTX *ctx) * * This isn't perfect, but it allows simple fuzzing of the parsers for all of the data types. */ -static ssize_t util_decode_proto(TALLOC_CTX *ctx, UNUSED fr_pair_list_t *out, uint8_t const *data, size_t data_len, UNUSED void *proto_ctx) +static ssize_t util_decode_proto(TALLOC_CTX *ctx, UNUSED fr_pair_list_t *out, uint8_t const *data, size_t data_len, + UNUSED void *proto_ctx) { ssize_t rcode; fr_type_t type; @@ -68,11 +69,13 @@ static ssize_t util_decode_proto(TALLOC_CTX *ctx, UNUSED fr_pair_list_t *out, ui /* - * Some things in value_box_from_str() don't yet respect + * Some things in fr_value_box_from_substr() don't yet respect * data_len. This means that if there's no zero * termination, we _know_ there will be buffer over-runs. */ - rcode = fr_value_box_from_str(box, box, type, NULL, (char const *) copy, data_len - 1, 0, true); + rcode = fr_value_box_from_str(box, box, type, NULL, + (char const *)copy, data_len - 1, + NULL, true); talloc_free(box); return rcode; } diff --git a/src/lib/util/pair.c b/src/lib/util/pair.c index 375ceba7353..d6f88e26274 100644 --- a/src/lib/util/pair.c +++ b/src/lib/util/pair.c @@ -1805,16 +1805,15 @@ int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src) * @param[in] vp to assign value to. * @param[in] value string to convert. Binary safe for variable * length values if len is provided. - * @param[in] inlen may be < 0 in which case strlen(len) is used - * to determine length, else inlen should be the - * length of the string or sub string to parse. - * @param[in] quote character used set unescape mode. @see fr_value_str_unescape. + * @param[in] inlen The length of the input string. + * @param[in] uerules used to perform unescaping. * @param[in] tainted Whether the value came from a trusted source. * @return * - 0 on success. * - -1 on failure. */ -int fr_pair_value_from_str(fr_pair_t *vp, char const *value, ssize_t inlen, char quote, bool tainted) +int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, + fr_sbuff_unescape_rules_t const *uerules, bool tainted) { /* * This is not yet supported because the rest of the APIs @@ -1837,7 +1836,10 @@ int fr_pair_value_from_str(fr_pair_t *vp, char const *value, ssize_t inlen, char * We presume that the input data is from a double quoted * string, and needs unescaping */ - if (fr_value_box_from_str(vp, &vp->data, vp->da->type, vp->da, value, inlen, quote, tainted) < 0) return -1; + if (fr_value_box_from_str(vp, &vp->data, vp->da->type, vp->da, + value, inlen, + uerules, + tainted) < 0) return -1; vp->type = VT_DATA; PAIR_VERIFY(vp); diff --git a/src/lib/util/pair.h b/src/lib/util/pair.h index 187bb942ed6..4d652aa7612 100644 --- a/src/lib/util/pair.h +++ b/src/lib/util/pair.h @@ -447,7 +447,8 @@ int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src) CC_HINT(nonnull); * @{ */ int fr_pair_value_from_str(fr_pair_t *vp, - char const *value, ssize_t len, char quote, bool tainted) CC_HINT(nonnull); + char const *value, size_t len, fr_sbuff_unescape_rules_t const *erules, + bool tainted) CC_HINT(nonnull(1,2)); int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted) CC_HINT(nonnull); diff --git a/src/lib/util/pair_legacy.c b/src/lib/util/pair_legacy.c index e997a90b396..a91ae20dde4 100644 --- a/src/lib/util/pair_legacy.c +++ b/src/lib/util/pair_legacy.c @@ -137,7 +137,7 @@ static fr_pair_t *fr_pair_make_unknown(TALLOC_CTX *ctx, fr_dict_t const *dict, goto error; } - if (fr_pair_value_from_str(vp, value, -1, '"', false) < 0) goto error; + if (fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_double, false) < 0) goto error; vp->op = (op == 0) ? T_OP_EQ : op; return vp; @@ -244,7 +244,7 @@ fr_pair_t *fr_pair_make(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t * * We probably want to fix fr_pair_value_from_str to accept * octets as values for any attribute. */ - if (value && (fr_pair_value_from_str(vp, value, -1, '\"', false) < 0)) { + if (value && (fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_double, false) < 0)) { talloc_free(vp); return NULL; } @@ -515,14 +515,8 @@ static ssize_t fr_pair_list_afrom_substr(TALLOC_CTX *ctx, fr_dict_attr_t const * talloc_free(vp); goto error; } - - /* - * Parse it ourselves. The RHS - * might NOT be tainted, but we - * don't know. So just mark it - * as such to be safe. - */ - } else if (fr_pair_value_from_str(vp, raw.r_opand, -1, '"', false) < 0) { + } else if (fr_pair_value_from_str(vp, raw.r_opand, strlen(raw.r_opand), + fr_value_unescape_by_quote[quote], false) < 0) { talloc_free(vp); goto error; } diff --git a/src/lib/util/pair_tests.c b/src/lib/util/pair_tests.c index 92eff8b49a8..072773ca0e0 100644 --- a/src/lib/util/pair_tests.c +++ b/src/lib/util/pair_tests.c @@ -91,7 +91,7 @@ static void test_fr_pair_afrom_da(void) TEST_CHECK(vp != NULL); if (!vp) return; - TEST_CHECK(fr_pair_value_from_str(vp, test_string, strlen(test_string), '"', false) == 0); + TEST_CHECK(fr_pair_value_from_str(vp, test_string, strlen(test_string), &fr_value_unescape_double, false) == 0); TEST_CASE("Validating PAIR_VERIFY()"); PAIR_VERIFY(vp); @@ -566,7 +566,7 @@ static void test_fr_pair_value_from_str(void) PAIR_VERIFY(vp); TEST_CASE("Convert 'test_string' value to attribute value using fr_pair_value_from_str()"); - TEST_CHECK(fr_pair_value_from_str(vp, test_string, strlen(test_string), '"', false) == 0); + TEST_CHECK(fr_pair_value_from_str(vp, test_string, strlen(test_string), &fr_value_unescape_double, false) == 0); TEST_CASE("Validating PAIR_VERIFY()"); PAIR_VERIFY(vp); diff --git a/src/lib/util/pair_tokenize.c b/src/lib/util/pair_tokenize.c index 58310f61f06..ae63e2a7760 100644 --- a/src/lib/util/pair_tokenize.c +++ b/src/lib/util/pair_tokenize.c @@ -134,7 +134,7 @@ static ssize_t op_to_token(fr_token_t *token, char const *op, size_t oplen) * @param op the operator * @param value the value to parse * @param value_len length of the value string - * @param quote the quotation character for the value string. + * @param uerules used for unescaping. * @return * - fr_pair_t* on success * - NULL on error @@ -146,7 +146,7 @@ static ssize_t op_to_token(fr_token_t *token, char const *op, size_t oplen) static fr_pair_t *fr_pair_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr_t const *da, fr_token_t op, char const *value, size_t value_len, - char quote) + fr_sbuff_unescape_rules_t const *uerules) { fr_pair_t *vp; @@ -157,7 +157,7 @@ static fr_pair_t *fr_pair_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr_t const *da vp->op = op; - if (fr_pair_value_from_str(vp, value, value_len, quote, false) < 0) { + if (fr_pair_value_from_str(vp, value, value_len, uerules, false) < 0) { talloc_free(vp); return NULL; } @@ -258,7 +258,7 @@ static ssize_t fr_pair_afrom_str(fr_pair_ctx_t *pair_ctx, char const *start, cha return -(p - start); } - vp = fr_pair_afrom_fields(pair_ctx->ctx, da, op, value, value_len, quote); + vp = fr_pair_afrom_fields(pair_ctx->ctx, da, op, value, value_len, fr_value_unescape_by_char[(uint8_t)quote]); if (!vp) return -(in - start); fr_pair_append(pair_ctx->list, vp); diff --git a/src/lib/util/sbuff.c b/src/lib/util/sbuff.c index b35cb19b030..d5bd4ab5891 100644 --- a/src/lib/util/sbuff.c +++ b/src/lib/util/sbuff.c @@ -422,7 +422,7 @@ int fr_sbuff_reset_talloc(fr_sbuff_t *sbuff) */ #define FILL_OR_GOTO_DONE(_out, _in, _len) if (fr_sbuff_move(_out, _in, _len) < (size_t)(_len)) goto done -/** Constrain end pointer to prevent advancing more than the amount the called specified +/** Constrain end pointer to prevent advancing more than the amount the caller specified * * @param[in] _sbuff to constrain. * @param[in] _max maximum amount to advance. @@ -784,6 +784,8 @@ size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, p = fr_sbuff_current(&our_in); end = CONSTRAINED_END(&our_in, len, fr_sbuff_used_total(&our_in)); + if (p == end) break; + if (escape_chr == '\0') { while ((p < end) && !fr_sbuff_terminal_search(in, p, idx, tt, needle_len)) p++; } else { @@ -1064,8 +1066,9 @@ fr_slen_t fr_sbuff_out_bool(bool *out, fr_sbuff_t *in) * @param[in] _max_char Maximum digits that can be used to represent an integer. * Can't use stringify because of width modifiers like 'u' * used in . + * @param[in] _base to use. */ -#define SBUFF_PARSE_INT_DEF(_name, _type, _min, _max, _max_char) \ +#define SBUFF_PARSE_INT_DEF(_name, _type, _min, _max, _max_char, _base) \ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \ { \ char buff[_max_char + 1]; \ @@ -1078,26 +1081,27 @@ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return -1; \ } \ - num = strtoll(buff, &end, 10); \ + errno = 0; \ + num = strtoll(buff, &end, _base); \ if (end == buff) { \ if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return -1; \ } \ - if ((num > (_max)) || ((errno == EINVAL) && (num == LLONG_MAX))) { \ + if ((num > (_max)) || ((errno == EINVAL) && (num == 0)) || ((errno == ERANGE) && (num == LLONG_MAX))) { \ if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \ *out = (_type)(_max); \ return -1; \ + } else if ((num < (_min)) || ((errno == ERANGE) && (num == LLONG_MIN))) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \ + *out = (_type)(_min); \ + return -1; \ } else if (no_trailing && (((a_end = in->p + (end - buff)) + 1) < in->end)) { \ - if (isdigit(*a_end)) { \ + if (isdigit(*a_end) || (((_base > 10) || (_base == 0)) && ((tolower(*a_end) >= 'a') && (tolower(*a_end) <= 'f')))) { \ if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \ *out = (_type)(_max); \ return fr_sbuff_error(&our_in); \ } \ *out = (_type)(num); \ - } else if (num < (_min) || ((errno == EINVAL) && (num == LLONG_MIN))) { \ - if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \ - *out = (_type)(_min); \ - return -1; \ } else { \ if (err) *err = FR_SBUFF_PARSE_OK; \ *out = (_type)(num); \ @@ -1105,11 +1109,11 @@ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff return fr_sbuff_advance(in, end - buff); /* Advance by the length strtoll gives us */ \ } -SBUFF_PARSE_INT_DEF(int8, int8_t, INT8_MIN, INT8_MAX, 4) -SBUFF_PARSE_INT_DEF(int16, int16_t, INT16_MIN, INT16_MAX, 6) -SBUFF_PARSE_INT_DEF(int32, int32_t, INT32_MIN, INT32_MAX, 11) -SBUFF_PARSE_INT_DEF(int64, int64_t, INT64_MIN, INT64_MAX, 20) -SBUFF_PARSE_INT_DEF(ssize, ssize_t, SSIZE_MIN, SSIZE_MAX, 20) +SBUFF_PARSE_INT_DEF(int8, int8_t, INT8_MIN, INT8_MAX, 4, 0) +SBUFF_PARSE_INT_DEF(int16, int16_t, INT16_MIN, INT16_MAX, 6, 0) +SBUFF_PARSE_INT_DEF(int32, int32_t, INT32_MIN, INT32_MAX, 11, 0) +SBUFF_PARSE_INT_DEF(int64, int64_t, INT64_MIN, INT64_MAX, 20, 0) +SBUFF_PARSE_INT_DEF(ssize, ssize_t, SSIZE_MIN, SSIZE_MAX, 20, 0) /** Used to define a number parsing functions for singed integers * @@ -1119,7 +1123,7 @@ SBUFF_PARSE_INT_DEF(ssize, ssize_t, SSIZE_MIN, SSIZE_MAX, 20) * @param[in] _max_char Maximum digits that can be used to represent an integer. * Can't use stringify because of width modifiers like 'u' * used in . - * @param[in] _base of the number being parsed, 8, 10, 18 etc... + * @param[in] _base of the number being parsed, 8, 10, 16 etc... */ #define SBUFF_PARSE_UINT_DEF(_name, _type, _max, _max_char, _base) \ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \ @@ -1134,17 +1138,22 @@ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return -1; \ } \ + if (buff[0] == '-') { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \ + return -1; \ + } \ + errno = 0; \ num = strtoull(buff, &end, _base); \ if (end == buff) { \ if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return -1; \ } \ - if ((num > (_max)) || ((errno == EINVAL) && (num == ULLONG_MAX))) { \ + if ((num > (_max)) || ((errno == EINVAL) && (num == 0)) || ((errno == ERANGE) && (num == ULLONG_MAX))) { \ if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \ *out = (_type)(_max); \ return -1; \ } else if (no_trailing && (((a_end = in->p + (end - buff)) + 1) < in->end)) { \ - if (isdigit(*a_end) || ((_base > 10) && ((tolower(*a_end) >= 'a') && (tolower(*a_end) <= 'f')))) { \ + if (isdigit(*a_end) || (((_base > 10) || (_base == 0)) && ((tolower(*a_end) >= 'a') && (tolower(*a_end) <= 'f')))) { \ if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \ *out = (_type)(_max); \ return fr_sbuff_error(&our_in); \ @@ -1158,11 +1167,19 @@ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff return fr_sbuff_advance(in, end - buff); /* Advance by the length strtoull gives us */ \ } -SBUFF_PARSE_UINT_DEF(uint8, uint8_t, UINT8_MAX, 3, 10) -SBUFF_PARSE_UINT_DEF(uint16, uint16_t, UINT16_MAX, 4, 10) -SBUFF_PARSE_UINT_DEF(uint32, uint32_t, UINT32_MAX, 10, 10) -SBUFF_PARSE_UINT_DEF(uint64, uint64_t, UINT64_MAX, 19, 10) -SBUFF_PARSE_UINT_DEF(size, size_t, SIZE_MAX, 19, 10) +/* max chars here is the octal string value with prefix */ +SBUFF_PARSE_UINT_DEF(uint8, uint8_t, UINT8_MAX, 4, 0) +SBUFF_PARSE_UINT_DEF(uint16, uint16_t, UINT16_MAX, 7, 0) +SBUFF_PARSE_UINT_DEF(uint32, uint32_t, UINT32_MAX, 12, 0) +SBUFF_PARSE_UINT_DEF(uint64, uint64_t, UINT64_MAX, 23, 0) +SBUFF_PARSE_UINT_DEF(size, size_t, SIZE_MAX, 23, 0) + +SBUFF_PARSE_UINT_DEF(uint8_dec, uint8_t, UINT8_MAX, 3, 0) +SBUFF_PARSE_UINT_DEF(uint16_dec, uint16_t, UINT16_MAX, 4, 0) +SBUFF_PARSE_UINT_DEF(uint32_dec, uint32_t, UINT32_MAX, 10, 0) +SBUFF_PARSE_UINT_DEF(uint64_dec, uint64_t, UINT64_MAX, 19, 0) +SBUFF_PARSE_UINT_DEF(size_dec, size_t, SIZE_MAX, 19, 0) + SBUFF_PARSE_UINT_DEF(uint8_oct, uint8_t, UINT8_MAX, 3, 8) SBUFF_PARSE_UINT_DEF(uint16_oct, uint16_t, UINT16_MAX, 6, 8) @@ -1201,6 +1218,7 @@ fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return -1; \ } \ + errno = 0; \ res = _func(buff, &end); \ if (errno == ERANGE) { \ if (res > 0) { \ diff --git a/src/lib/util/sbuff.h b/src/lib/util/sbuff.h index e87780db9e6..f0f068aaa71 100644 --- a/src/lib/util/sbuff.h +++ b/src/lib/util/sbuff.h @@ -390,7 +390,7 @@ do { \ * * @private */ -#define _FR_SBUFF(_sbuff_or_marker, _start, _current, _end, _adv_parent) \ +#define _FR_SBUFF(_sbuff_or_marker, _start, _current, _end, _extend, _adv_parent) \ ((fr_sbuff_t){ \ .buff = fr_sbuff_buff(_sbuff_or_marker), \ .start = (_start), \ @@ -399,7 +399,7 @@ do { \ .is_const = fr_sbuff_ptr(_sbuff_or_marker)->is_const, \ .adv_parent = (_adv_parent), \ .shifted = fr_sbuff_ptr(_sbuff_or_marker)->shifted, \ - .extend = fr_sbuff_ptr(_sbuff_or_marker)->extend, \ + .extend = (_extend), \ .uctx = fr_sbuff_ptr(_sbuff_or_marker)->uctx, \ .parent = fr_sbuff_ptr(_sbuff_or_marker) \ }) @@ -416,6 +416,7 @@ do { \ fr_sbuff_current(_sbuff_or_marker), \ fr_sbuff_current(_sbuff_or_marker), \ fr_sbuff_end(_sbuff_or_marker), \ + fr_sbuff_ptr(_sbuff_or_marker)->extend, \ 0x00) /** Create a new sbuff pointing to the same underlying buffer @@ -429,6 +430,7 @@ do { \ fr_sbuff_start(_sbuff_or_marker), \ fr_sbuff_current(_sbuff_or_marker), \ fr_sbuff_end(_sbuff_or_marker), \ + fr_sbuff_ptr(_sbuff_or_marker)->extend, \ 0x00) /** Create a new sbuff pointing to the same underlying buffer @@ -439,6 +441,7 @@ do { \ * - Parent will _NOT_ be advanced by operations on its child. * - Child will have its `start` pointer set to the `start` pointer of the parent. * - Child will have its `end` pointer set to the `p` pointer of the parent. + * - Child will not extend parent. * * @param[in] _sbuff_or_marker to make an ephemeral copy of. */ @@ -446,6 +449,7 @@ do { \ fr_sbuff_start(_sbuff_or_marker), \ fr_sbuff_start(_sbuff_or_marker), \ fr_sbuff_current(_sbuff_or_marker), \ + NULL, \ 0x00) /** Create a new sbuff pointing to the same underlying buffer @@ -459,6 +463,7 @@ do { \ fr_sbuff_current(_sbuff_or_marker), \ fr_sbuff_current(_sbuff_or_marker), \ fr_sbuff_end(_sbuff_or_marker), \ + fr_sbuff_ptr(_sbuff_or_marker)->extend, \ 0x01) /** Create a new sbuff pointing to the same underlying buffer @@ -472,6 +477,7 @@ do { \ fr_sbuff_start(_sbuff_or_marker), \ fr_sbuff_current(_sbuff_or_marker), \ fr_sbuff_end(_sbuff_or_marker), \ + fr_sbuff_ptr(_sbuff_or_marker)->extend, \ 0x01) /** Creates a compound literal to pass into functions which accept a sbuff @@ -1465,6 +1471,12 @@ fr_slen_t fr_sbuff_out_uint32(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbu fr_slen_t fr_sbuff_out_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing); fr_slen_t fr_sbuff_out_size(fr_sbuff_parse_error_t *err, size_t *out, fr_sbuff_t *sbuff, bool no_trailing); +fr_slen_t fr_sbuff_out_uint8_dec(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing); +fr_slen_t fr_sbuff_out_uint16_dec(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing); +fr_slen_t fr_sbuff_out_uint32_dec(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing); +fr_slen_t fr_sbuff_out_uint64_dec(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing); +fr_slen_t fr_sbuff_out_size_dec(fr_sbuff_parse_error_t *err, size_t *out, fr_sbuff_t *sbuff, bool no_trailing); + fr_slen_t fr_sbuff_out_uint8_oct(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing); fr_slen_t fr_sbuff_out_uint16_oct(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing); fr_slen_t fr_sbuff_out_uint32_oct(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing); diff --git a/src/lib/util/value.c b/src/lib/util/value.c index 02867dce429..54abe4cccdb 100644 --- a/src/lib/util/value.c +++ b/src/lib/util/value.c @@ -37,7 +37,7 @@ * - PRESENTATION format is what we print to the screen, and what we get from the user, databases * and configuration files. * - #fr_value_box_aprint is used to convert from INTERNAL to PRESENTATION format. - * - #fr_value_box_from_str is used to convert from PRESENTATION to INTERNAL format. + * - #fr_value_box_from_substr is used to convert from PRESENTATION to INTERNAL format. * * @copyright 2014-2017 The FreeRADIUS server project * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org) @@ -2251,7 +2251,8 @@ static inline int fr_value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, fr_value_box_t switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); default: break; @@ -2359,7 +2360,8 @@ static inline int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_ switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); default: break; @@ -2470,7 +2472,8 @@ static inline int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); default: break; @@ -2575,7 +2578,8 @@ static inline int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_ switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); default: break; @@ -2665,7 +2669,8 @@ static inline int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); case FR_TYPE_OCTETS: return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src); @@ -2724,7 +2729,8 @@ static inline int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); case FR_TYPE_OCTETS: return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src); @@ -3007,7 +3013,8 @@ static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t * switch (src->type) { case FR_TYPE_STRING: return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); case FR_TYPE_OCTETS: return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src); @@ -3096,7 +3103,7 @@ bad_cast: * * This should be the canonical function used to convert between INTERNAL data formats. * - * If you want to convert from PRESENTATION format, use #fr_value_box_from_str. + * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr. * * @note src and dst must not be the same box. We do not support casting in place. * @@ -3219,8 +3226,8 @@ int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, * Deserialise a fr_value_box_t */ if (src->type == FR_TYPE_STRING) return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv, - src->vb_strvalue, - src->vb_length, '\0', src->tainted); + src->vb_strvalue, src->vb_length, + NULL, src->tainted); if (src->type == FR_TYPE_OCTETS) { fr_value_box_t tmp; @@ -3271,7 +3278,7 @@ int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, * * This should be the canonical function used to convert between INTERNAL data formats. * - * If you want to convert from PRESENTATION format, use #fr_value_box_from_str. + * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr. * * @param ctx to allocate buffers in (usually the same as dst) * @param vb to cast. @@ -4361,127 +4368,64 @@ void fr_value_box_increment(fr_value_box_t *vb) * @param[out] dst where to write parsed value. * @param[in] dst_type type of integer to convert string to. * @param[in] in String to convert to integer. + * @param[in] tainted Whether the value came from a trusted source. * @return - * - 0 on success. - * - -1 on parse error. + * - >= 0 on success (number of bytes parsed). + * - < 0 on error (where the parse error ocurred). */ -static int fr_value_box_from_integer_str(fr_value_box_t *dst, fr_type_t dst_type, char const *in) +static inline CC_HINT(always_inline) +fr_slen_t fr_value_box_from_numeric_substr(fr_value_box_t *dst, fr_type_t dst_type, + fr_dict_attr_t const *dst_enumv, + fr_sbuff_t *in, bool tainted) { - uint64_t uinteger = 0; - int64_t sinteger = 0; - char *p = NULL; - - switch (dst_type) { - case FR_TYPE_UINT8: - case FR_TYPE_UINT16: - case FR_TYPE_UINT32: - case FR_TYPE_UINT64: - fr_skip_whitespace(in); - - if (*in == '-') { - fr_strerror_printf("Invalid negative value \"%s\" for unsigned integer", in); - return -1; - } - - /* - * fr_strtoull checks for overflows and calls - * fr_strerror_printf to set an error. - */ - if (fr_strtoull(&uinteger, &p, in) < 0) return -1; - if (*p != '\0') { - fr_strerror_printf("Invalid integer value \"%s\"", in); - - return -1; - } - if (errno == ERANGE) { - + fr_slen_t slen; + fr_sbuff_parse_error_t err; - return -1; - } - break; - - case FR_TYPE_INT8: - case FR_TYPE_INT16: - case FR_TYPE_INT32: - case FR_TYPE_INT64: - /* - * fr_strtoll checks for overflows and calls - * fr_strerror_printf to set an error. - */ - if (fr_strtoll(&sinteger, &p, in) < 0) return -1; - if (*p != '\0') { - fr_strerror_printf("Invalid integer value \"%s\"", in); - - return -1; - } - break; - - default: - fr_assert_fail(NULL); - return -1; - } - -#define IN_RANGE_UNSIGNED(_type) \ - do { \ - if (uinteger > _type ## _MAX) { \ - fr_strerror_printf("Value %" PRIu64 " is invalid for type %s (must be in range " \ - "0...%" PRIu64 ")", \ - uinteger, fr_table_str_by_value(fr_value_box_type_table, dst_type, ""), \ - (uint64_t) _type ## _MAX); \ - return -1; \ - } \ - } while (0) - -#define IN_RANGE_SIGNED(_type) \ - do { \ - if ((sinteger > _type ## _MAX) || (sinteger < _type ## _MIN)) { \ - fr_strerror_printf("Value %" PRId64 " is invalid for type %s (must be in range " \ - "%" PRId64 "...%" PRId64 ")", \ - sinteger, fr_table_str_by_value(fr_value_box_type_table, dst_type, ""), \ - (int64_t) _type ## _MIN, (int64_t) _type ## _MAX); \ - return -1; \ - } \ - } while (0) + fr_value_box_init(dst, dst_type, dst_enumv, tainted); switch (dst_type) { case FR_TYPE_UINT8: - IN_RANGE_UNSIGNED(UINT8); - dst->vb_uint8 = (uint8_t)uinteger; + slen = fr_sbuff_out(&err, &dst->vb_uint8, in); break; case FR_TYPE_UINT16: - IN_RANGE_UNSIGNED(UINT16); - dst->vb_uint16 = (uint16_t)uinteger; + slen = fr_sbuff_out(&err, &dst->vb_uint16, in); break; case FR_TYPE_UINT32: - IN_RANGE_UNSIGNED(UINT32); - dst->vb_uint32 = (uint32_t)uinteger; + slen = fr_sbuff_out(&err, &dst->vb_uint32, in); break; case FR_TYPE_UINT64: - /* IN_RANGE_UNSIGNED doesn't work here */ - dst->vb_uint64 = (uint64_t)uinteger; + slen = fr_sbuff_out(&err, &dst->vb_uint64, in); break; case FR_TYPE_INT8: - IN_RANGE_SIGNED(INT8); - dst->vb_int8 = (int8_t)sinteger; + slen = fr_sbuff_out(&err, &dst->vb_int8, in); break; case FR_TYPE_INT16: - IN_RANGE_SIGNED(INT16); - dst->vb_int16 = (int16_t)sinteger; + slen = fr_sbuff_out(&err, &dst->vb_int16, in); break; case FR_TYPE_INT32: - IN_RANGE_SIGNED(INT32); - dst->vb_int32 = (int32_t)sinteger; + slen = fr_sbuff_out(&err, &dst->vb_int32, in); break; case FR_TYPE_INT64: - /* IN_RANGE_SIGNED doesn't work here */ - dst->vb_int64 = (int64_t)sinteger; + slen = fr_sbuff_out(&err, &dst->vb_int64, in); + break; + + case FR_TYPE_SIZE: + slen = fr_sbuff_out(&err, &dst->vb_size, in); + break; + + case FR_TYPE_FLOAT32: + slen = fr_sbuff_out(&err, &dst->vb_float32, in); + break; + + case FR_TYPE_FLOAT64: + slen = fr_sbuff_out(&err, &dst->vb_float64, in); break; default: @@ -4489,7 +4433,9 @@ static int fr_value_box_from_integer_str(fr_value_box_t *dst, fr_type_t dst_type return -1; } - return 0; + if (slen < 0) fr_sbuff_parse_error_to_strerror(err); + + return slen; } /** Convert string value to a fr_value_box_t type @@ -4498,34 +4444,26 @@ static int fr_value_box_from_integer_str(fr_value_box_t *dst, fr_type_t dst_type * @param[out] dst where to write parsed value. * @param[in,out] dst_type of value data to create/dst_type of value created. * @param[in] dst_enumv fr_dict_attr_t with string names for uint32 values. - * @param[in] in String to convert. Binary safe for variable length values - * if len is provided. - * @param[in] inlen may be < 0 in which case strlen(len) is used to determine - * length, else inlen should be the length of the string or - * sub string to parse. - * @param[in] quote character used set unescape mode. @see fr_value_str_unescape. + * @param[in] in sbuff to read data from. + * @param[in] rules unescape and termination rules. * @param[in] tainted Whether the value came from a trusted source. * @return - * - 0 on success. - * - -1 on parse error. + * - >0 on success. + * - <= 0 on parse error. */ -int fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, - fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, - char const *in, ssize_t inlen, char quote, bool tainted) +ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst, + fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, + fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted) { - size_t len; - ssize_t ret; - char buffer[256]; + static fr_sbuff_parse_rules_t default_rules; + fr_sbuff_t *unescaped = NULL; + fr_sbuff_t our_in = FR_SBUFF(in); + ssize_t ret; + char buffer[256]; if (!fr_cond_assert(dst_type != FR_TYPE_NULL)) return -1; - len = (inlen < 0) ? strlen(in) : (size_t)inlen; - - /* - * If the data is tainted, then the data should never be - * quoted. - */ - fr_assert(!tainted || (quote == 0)); + if (!rules) rules = &default_rules; /* * Set size for all fixed length attributes. @@ -4536,30 +4474,38 @@ int fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, * Lookup any names before continuing */ if (dst_enumv) { - char *tmp = NULL; - char *name; - size_t name_len; + size_t name_len; fr_dict_enum_value_t *enumv; - if (len > (sizeof(buffer) - 1)) { - name_len = fr_value_str_aunescape(NULL, &tmp, - &FR_SBUFF_IN(in, len), SIZE_MAX, quote); - name = tmp; - } else { - name_len = fr_value_str_unescape(&FR_SBUFF_OUT(buffer, sizeof(buffer)), - &FR_SBUFF_IN(in, len), SIZE_MAX, quote); - name = buffer; + /* + * Create a thread-local extensible buffer to + * store unescaped data. + * + * This is created once per-thread (the first time + * this function is called), and freed when the + * thread exits. + */ + FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096); + + name_len = fr_sbuff_out_unescape_until(unescaped, &our_in, SIZE_MAX, + rules->terminals, rules->escapes); + if (!name_len) { + fr_sbuff_set_to_start(&our_in); + goto parse; /* Zero length name can't match enum */ } - fr_assert(name); - enumv = fr_dict_enum_by_name(dst_enumv, name, name_len); - if (tmp) talloc_free(tmp); - if (!enumv) goto parse; + enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_start(unescaped), fr_sbuff_used(unescaped)); + if (!enumv) { + fr_sbuff_set_to_start(&our_in); + goto parse; /* No enumeration matches escaped string */ + } - fr_value_box_copy(ctx, dst, enumv->value); - dst->enumv = dst_enumv; + /* + * dst_type may not match enumv type + */ + if (fr_value_box_cast(ctx, dst, dst_type, dst_enumv, enumv->value) < 0) return -1; - return 0; + return fr_sbuff_set(in, &our_in); } parse: @@ -4569,57 +4515,110 @@ parse: */ switch (dst_type) { case FR_TYPE_STRING: - { - char *buff; + /* + * We've not unescaped the string yet, produce an unescaped version + */ + if (!dst_enumv) { + char *buff; - ret = fr_value_str_aunescape(ctx, &buff, &FR_SBUFF_IN(in, len), SIZE_MAX, quote); - talloc_get_type_abort(buff, char); - dst->vb_strvalue = buff; - } - goto finish; + fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX, rules->terminals, rules->escapes); + fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, buff, tainted); + /* + * We already have an unescaped version, just use that + */ + } else { + fr_value_box_bstrndup(ctx, dst, dst_enumv, + fr_sbuff_start(unescaped), fr_sbuff_used(unescaped), tainted); + } + return fr_sbuff_set(in, &our_in); /* raw octets: 0x01020304... */ case FR_TYPE_OCTETS: { - uint8_t *p; + fr_sbuff_marker_t hex_start; + size_t hex_len; + uint8_t *bin_buff; /* - * No 0x prefix, just copy verbatim. + * If there's escape sequences that need to be processed + * or the string doesn't start with 0x, then assume this + * is literal data, not hex encoded data. */ - if ((len < 2) || (strncasecmp(in, "0x", 2) != 0)) { - dst->vb_octets = talloc_memdup(ctx, (uint8_t const *)in, len); - talloc_set_type(dst->vb_octets, uint8_t); - ret = len; - goto finish; + if (rules->escapes || !fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) { + if (!dst_enumv) { + char *buff; + uint8_t *bin; + + fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX, + rules->terminals, rules->escapes); + + bin = talloc_realloc(ctx, buff, uint8_t, talloc_array_length(buff) - 1); + if (unlikely(!bin)) { + fr_strerror_const("Failed trimming string buffer"); + talloc_free(buff); + return -1; + } + + fr_value_box_memdup_buffer_shallow(NULL, dst, dst_enumv, bin, tainted); + /* + * We already have an unescaped version, just use that + */ + } else { + fr_value_box_memdup(ctx, dst, dst_enumv, + (uint8_t *)fr_sbuff_start(unescaped), + fr_sbuff_used(unescaped), tainted); + } + return fr_sbuff_set(in, &our_in); } - len -= 2; + fr_sbuff_marker(&hex_start, &our_in); /* Record where the hexits start */ /* - * Invalid. + * Find the end of the hex sequence. + * + * We don't technically need to do this, fr_base16_decode + * will find the end on its own. + * + * We do this so we can alloc the correct sized + * output buffer. */ - if ((len & 0x01) != 0) { - fr_strerror_printf("Length of hex string is not even, got %zu bytes", len); - return -1; + hex_len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_class_hex, rules->terminals); + if (hex_len == 0) { + if (fr_value_box_memdup(ctx, dst, dst_enumv, (uint8_t[]){ 0x00 }, 0, tainted) < 0) return -1; + return fr_sbuff_set(in, &our_in); } - ret = len >> 1; - p = talloc_array(ctx, uint8_t, ret); - if (fr_base16_decode(NULL, &FR_DBUFF_TMP(p, ret), &FR_SBUFF_IN(in + 2, len), false) != (ssize_t)ret) { - talloc_free(p); - fr_strerror_const("Invalid hex data"); - return -1; + if ((hex_len & 0x01) != 0) { + fr_strerror_printf("Length of hex string is not even, got %zu bytes", hex_len); + return fr_sbuff_error(&our_in); } - dst->vb_octets = p; + /* + * Pre-allocate the bin buff and initialise the box + */ + if (fr_value_box_mem_alloc(ctx, &bin_buff, dst, dst_enumv, (hex_len >> 1), tainted) < 0) return -1; + + /* + * Reset to the start of the hex string + */ + fr_sbuff_set(&our_in, &hex_start); + + if (unlikely(fr_base16_decode(NULL, + &FR_DBUFF_TMP(bin_buff, hex_len), + &our_in, false) != (ssize_t)ret) < 0) { + talloc_free(bin_buff); + return fr_sbuff_error(&our_in); + } + + return fr_sbuff_set(in, &our_in); } - goto finish; case FR_TYPE_IPV4_ADDR: { fr_ipaddr_t addr; - if (fr_inet_pton4(&addr, in, inlen, fr_hostname_lookups, false, true) < 0) return -1; + if (fr_inet_pton4(&addr, fr_sbuff_current(in), fr_sbuff_remaining(in), + fr_hostname_lookups, false, true) < 0) return -1; /* * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL) @@ -4636,14 +4635,16 @@ parse: goto finish; case FR_TYPE_IPV4_PREFIX: - if (fr_inet_pton4(&dst->vb_ip, in, inlen, fr_hostname_lookups, false, true) < 0) return -1; + if (fr_inet_pton4(&dst->vb_ip, fr_sbuff_current(in), fr_sbuff_remaining(in), + fr_hostname_lookups, false, true) < 0) return -1; goto finish; case FR_TYPE_IPV6_ADDR: { fr_ipaddr_t addr; - if (fr_inet_pton6(&addr, in, inlen, fr_hostname_lookups, false, true) < 0) return -1; + if (fr_inet_pton6(&addr, fr_sbuff_current(in), fr_sbuff_remaining(in), + fr_hostname_lookups, false, true) < 0) return -1; /* * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL) @@ -4660,98 +4661,110 @@ parse: goto finish; case FR_TYPE_IPV6_PREFIX: - if (fr_inet_pton6(&dst->vb_ip, in, inlen, fr_hostname_lookups, false, true) < 0) return -1; + if (fr_inet_pton6(&dst->vb_ip, fr_sbuff_current(in), fr_sbuff_remaining(in), + fr_hostname_lookups, false, true) < 0) return -1; goto finish; + case FR_TYPE_UINT8: + case FR_TYPE_UINT16: + case FR_TYPE_UINT32: + case FR_TYPE_UINT64: + case FR_TYPE_INT8: + case FR_TYPE_INT16: + case FR_TYPE_INT32: + case FR_TYPE_INT64: + case FR_TYPE_FLOAT32: + case FR_TYPE_FLOAT64: + return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, tainted); + + case FR_TYPE_BOOL: + { + fr_slen_t slen; + + fr_value_box_init(dst, dst_type, dst_enumv, tainted); + + /* + * Quoted boolean values are "yes", "no", "true", "false" + */ + slen = fr_sbuff_out(NULL, &dst->vb_bool, in); + if (slen >= 0) return slen; + + /* + * For barewords we also allow 0 for false and any other + * integer value for true. + */ + if ((slen < 0) && (!rules->escapes)) { + int64_t stmp; + uint64_t utmp; + + slen = fr_sbuff_out(NULL, &stmp, in); + if (slen >= 0) { + dst->vb_bool = (stmp != 0); + return slen; + } + + slen = fr_sbuff_out(NULL, &utmp, in); + if (slen >= 0) { + dst->vb_bool = (utmp != 0); + return slen; + } + } + + fr_strerror_const("Invalid boolean value. Accepted values are " + "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer"); + + return slen; /* Just whatever the last error offset was */ + } + + case FR_TYPE_NULL: + if (!rules->escapes && fr_sbuff_adv_past_str_literal(in, "NULL")) { + fr_value_box_init(dst, dst_type, dst_enumv, tainted); + return fr_sbuff_set(in, &our_in); + } + + fr_strerror_const("String value was not NULL"); + return -1; + /* * Dealt with below */ default: break; - - case FR_TYPE_STRUCTURAL: - case FR_TYPE_MAX: - case FR_TYPE_NULL: - fr_strerror_printf("Invalid dst_type %s", - fr_table_str_by_value(fr_value_box_type_table, dst_type, "")); - return -1; } /* * It's a fixed size src->dst_type, copy to a temporary buffer and * \0 terminate if insize >= 0. */ - if (inlen > 0) { - if (len >= sizeof(buffer)) { + if (fr_sbuff_remaining(in) > 0) { + if (fr_sbuff_remaining(in) >= sizeof(buffer)) { fr_strerror_const("Temporary buffer too small"); return -1; } - memcpy(buffer, in, inlen); - buffer[inlen] = '\0'; - in = buffer; + memcpy(buffer, fr_sbuff_current(in), fr_sbuff_remaining(in)); + buffer[fr_sbuff_remaining(in)] = '\0'; } switch (dst_type) { - case FR_TYPE_IPV4_ADDR: - case FR_TYPE_IPV4_PREFIX: - case FR_TYPE_IPV6_ADDR: - case FR_TYPE_IPV6_PREFIX: - break; - - case FR_TYPE_UINT8: - case FR_TYPE_UINT16: - case FR_TYPE_UINT32: - case FR_TYPE_UINT64: - case FR_TYPE_INT8: - case FR_TYPE_INT16: - case FR_TYPE_INT32: - case FR_TYPE_INT64: - if (fr_value_box_from_integer_str(dst, dst_type, in) < 0) return -1; - break; - case FR_TYPE_SIZE: - if (fr_size_from_str(&dst->datum.size, in) < 0) return -1; + if (fr_size_from_str(&dst->datum.size, buffer) < 0) return -1; break; case FR_TYPE_TIME_DELTA: if (dst_enumv) { - if (fr_time_delta_from_str(&dst->datum.time_delta, in, dst_enumv->flags.flag_time_res) < 0) return -1; + if (fr_time_delta_from_str(&dst->datum.time_delta, buffer, dst_enumv->flags.flag_time_res) < 0) return -1; } else { - if (fr_time_delta_from_str(&dst->datum.time_delta, in, FR_TIME_RES_SEC) < 0) return -1; + if (fr_time_delta_from_str(&dst->datum.time_delta, buffer, FR_TIME_RES_SEC) < 0) return -1; } break; - case FR_TYPE_FLOAT32: - { - float f; - - if (sscanf(in, "%f", &f) != 1) { - fr_strerror_printf("Failed parsing \"%s\" as a float32", in); - return -1; - } - dst->vb_float32 = f; - } - break; - - case FR_TYPE_FLOAT64: - { - double d; - - if (sscanf(in, "%lf", &d) != 1) { - fr_strerror_printf("Failed parsing \"%s\" as a float64", in); - return -1; - } - dst->vb_float64 = d; - } - break; - case FR_TYPE_DATE: { if (dst_enumv) { - if (fr_unix_time_from_str(&dst->vb_date, in, dst_enumv->flags.flag_time_res) < 0) return -1; + if (fr_unix_time_from_str(&dst->vb_date, buffer, dst_enumv->flags.flag_time_res) < 0) return -1; } else { - if (fr_unix_time_from_str(&dst->vb_date, in, FR_TIME_RES_SEC) < 0) return -1; + if (fr_unix_time_from_str(&dst->vb_date, buffer, FR_TIME_RES_SEC) < 0) return -1; } dst->enumv = dst_enumv; @@ -4759,8 +4772,8 @@ parse: break; case FR_TYPE_IFID: - if (fr_inet_ifid_pton((void *) dst->vb_ifid, in) == NULL) { - fr_strerror_printf("Failed to parse interface-id string \"%s\"", in); + if (fr_inet_ifid_pton((void *) dst->vb_ifid, buffer) == NULL) { + fr_strerror_printf("Failed to parse interface-id string \"%s\"", buffer); return -1; } break; @@ -4782,14 +4795,14 @@ parse: * 8-byte number, and then the lower bytes of * that get copied to the ethernet address. */ - if (is_integer(in)) { - uint64_t lvalue = htonll(atoll(in)); + if (is_integer(buffer)) { + uint64_t lvalue = htonll(atoll(buffer)); memcpy(dst->vb_ether, ((uint8_t *) &lvalue) + 2, sizeof(dst->vb_ether)); break; } - cp = in; + cp = buffer; while (*cp) { if (cp[1] == ':') { c1 = hextab; @@ -4804,7 +4817,7 @@ parse: c1 = c2 = NULL; } if (!c1 || !c2 || (p_len >= sizeof(dst->vb_ether))) { - fr_strerror_printf("failed to parse Ethernet address \"%s\"", in); + fr_strerror_printf("failed to parse Ethernet address \"%s\"", buffer); return -1; } dst->vb_ether[p_len] = ((c1-hextab)<<4) + (c2-hextab); @@ -4823,7 +4836,7 @@ parse: * and attribute as the original. */ case FR_TYPE_COMBO_IP_ADDR: - if (fr_inet_pton(&dst->vb_ip, in, inlen, AF_UNSPEC, fr_hostname_lookups, true) < 0) return -1; + if (fr_inet_pton(&dst->vb_ip, buffer, strlen(buffer), AF_UNSPEC, fr_hostname_lookups, true) < 0) return -1; switch (dst->vb_ip.af) { case AF_INET: ret = network_max_size(FR_TYPE_IPV4_ADDR); @@ -4840,7 +4853,7 @@ parse: break; case FR_TYPE_COMBO_IP_PREFIX: - if (fr_inet_pton(&dst->vb_ip, in, inlen, AF_UNSPEC, fr_hostname_lookups, true) < 0) return -1; + if (fr_inet_pton(&dst->vb_ip, buffer, strlen(buffer), AF_UNSPEC, fr_hostname_lookups, true) < 0) return -1; switch (dst->vb_ip.af) { case AF_INET: ret = network_max_size(FR_TYPE_IPV4_PREFIX); @@ -4856,28 +4869,7 @@ parse: } break; - case FR_TYPE_BOOL: - if ((strcmp(in, "yes") == 0) || (strcmp(in, "true") == 0) || (strcmp(in, "1") == 0)) { - dst->datum.boolean = true; - } else if ((strcmp(in, "no") == 0) || (strcmp(in, "false") == 0) || (strcmp(in, "0") == 0)) { - dst->datum.boolean = false; - } else { - fr_strerror_printf("\"%s\" is not a valid boolean value", in); - return -1; - } - break; - - case FR_TYPE_NULL: - if ((quote == '\0') && (strcmp(in, "NULL") == 0)) goto finish; - fr_strerror_const("String value was not NULL"); - break; - - case FR_TYPE_VALUE_BOX: - case FR_TYPE_VARIABLE_SIZE: /* Should have been dealt with above */ - case FR_TYPE_STRUCTURAL: /* Listed again to suppress compiler warnings */ - case FR_TYPE_VOID: - case FR_TYPE_MAX: - + default: fr_strerror_printf("Unknown attribute dst_type %d", dst_type); return -1; } @@ -4896,6 +4888,27 @@ finish: return 0; } +ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, + fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, + char const *in, size_t inlen, + fr_sbuff_unescape_rules_t const *erules, bool tainted) +{ + ssize_t slen; + fr_sbuff_parse_rules_t prules = { .escapes = erules }; + + slen = fr_value_box_from_substr(ctx, dst, dst_type, dst_enumv, &FR_SBUFF_IN(in, inlen), &prules, tainted); + if (slen <= 0) return slen; + + if (slen != (ssize_t)inlen) { + fr_strerror_printf("%zu bytes of trailing data after string value \"%pV\"", + inlen - slen, + fr_box_strvalue_len(in + slen, inlen - slen)); + return (slen - inlen) - 1; + } + + return slen; +} + /** Print one boxed value to a string * * This function should primarily be used when a #fr_value_box_t is being diff --git a/src/lib/util/value.h b/src/lib/util/value.h index 42bd9278cae..9d1569ef441 100644 --- a/src/lib/util/value.h +++ b/src/lib/util/value.h @@ -811,9 +811,15 @@ void fr_value_box_increment(fr_value_box_t *vb); * * @{ */ -int fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, +ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst, + fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, + fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted) + CC_HINT(nonnull(2,5)); + +ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, - char const *src, ssize_t src_len, char quote, bool tainted) + char const *in, size_t inlen, + fr_sbuff_unescape_rules_t const *erules, bool tainted) CC_HINT(nonnull(2,5)); /** @} */ diff --git a/src/modules/rlm_client/rlm_client.c b/src/modules/rlm_client/rlm_client.c index 017b7fea0e3..1fd00e54a3c 100644 --- a/src/modules/rlm_client/rlm_client.c +++ b/src/modules/rlm_client/rlm_client.c @@ -83,7 +83,7 @@ static int _map_proc_client_get_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request char const *value = cf_pair_value(cp); MEM(vp = fr_pair_afrom_da(ctx, da)); - if (fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, '\0', false) < 0) { + if (fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, NULL, false) < 0) { RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue(value), tmpl_da(map->lhs)->name, fr_strerror()); talloc_free(vp); diff --git a/src/modules/rlm_csv/rlm_csv.c b/src/modules/rlm_csv/rlm_csv.c index 84a95a359b6..8237740fc53 100644 --- a/src/modules/rlm_csv/rlm_csv.c +++ b/src/modules/rlm_csv/rlm_csv.c @@ -230,8 +230,8 @@ static bool duplicate_entry(CONF_SECTION *conf, rlm_csv_t *inst, rlm_csv_entry_t sizeof(*e) + (inst->used_fields * sizeof(e->data[0])))); talloc_set_type(e, rlm_csv_entry_t); - e->key = talloc_zero(e, fr_value_box_t); - if (fr_value_box_from_str(e->key, e->key, type, NULL, p, -1, 0, false) < 0) { + e->key = fr_value_box_alloc_null(e); + if (fr_value_box_from_str(e->key, e->key, type, NULL, p, strlen(p), NULL, false) < 0) { cf_log_err(conf, "Failed parsing key field in file %s line %d - %s", inst->filename, lineno, fr_strerror()); return false; @@ -313,8 +313,9 @@ static bool file2csv(CONF_SECTION *conf, rlm_csv_t *inst, int lineno, char *buff /* * Set the last entry to use 'e' */ - e->key = talloc_zero(e, fr_value_box_t); - if (fr_value_box_from_str(e->key, e->key, type, NULL, p, -1, 0, false) < 0) { + e->key = fr_value_box_alloc_null(e); + if (fr_value_box_from_str(e->key, e->key, type, NULL, + p, strlen(p), NULL, false) < 0) { cf_log_err(conf, "Failed parsing key field in file %s line %d - %s", inst->filename, lineno, fr_strerror()); fail: @@ -336,7 +337,8 @@ static bool file2csv(CONF_SECTION *conf, rlm_csv_t *inst, int lineno, char *buff fr_value_box_t box; fr_type_t type = inst->field_types[i]; - if (fr_value_box_from_str(e, &box, type, NULL, p, -1, 0, false) < 0) { + if (fr_value_box_from_str(e, &box, type, NULL, + p, strlen(p), NULL, false) < 0) { cf_log_err(conf, "Failed parsing field '%s' in file %s line %d - %s", inst->field_names[i], inst->filename, lineno, fr_strerror()); goto fail; @@ -867,7 +869,7 @@ static int csv_map_getvalue(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *req vp = fr_pair_afrom_da(ctx, da); fr_assert(vp); - if (fr_pair_value_from_str(vp, str, talloc_array_length(str) - 1, '\0', true) < 0) { + if (fr_pair_value_from_str(vp, str, talloc_array_length(str) - 1, NULL, true) < 0) { RPWDEBUG("Failed parsing value \"%pV\" for attribute %s", fr_box_strvalue_buffer(str), tmpl_da(map->lhs)->name); talloc_free(vp); diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c index 61ab96b29b0..195a966a3d5 100644 --- a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c +++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c @@ -601,7 +601,7 @@ static fr_radius_packet_code_t eap_fast_eap_payload(request_t *request, eap_sess * Tell the request that it's a fake one. */ MEM(fr_pair_prepend_by_da(fake->request_ctx, &vp, &fake->request_pairs, attr_freeradius_proxied_to) >= 0); - fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1"), '\0', false); + fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1") - 1, NULL, false); /* * If there's no User-Name in the stored data, look for diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c index 1d597e5d8b7..7483eb157d2 100644 --- a/src/modules/rlm_eap/types/rlm_eap_peap/peap.c +++ b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c @@ -750,7 +750,7 @@ static int CC_HINT(nonnull) setup_fake_request(request_t *request, request_t *fa * Tell the request that it's a fake one. */ MEM(fr_pair_prepend_by_da(fake->request_ctx, &vp, &fake->request_pairs, attr_freeradius_proxied_to) >= 0); - fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1"), '\0', false); + fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1") - 1, NULL, false); if (t->username) { vp = fr_pair_copy(fake->request_ctx, t->username); diff --git a/src/modules/rlm_files/rlm_files.c b/src/modules/rlm_files/rlm_files.c index ffa3c7760f6..a58789516bd 100644 --- a/src/modules/rlm_files/rlm_files.c +++ b/src/modules/rlm_files/rlm_files.c @@ -299,7 +299,8 @@ static int getusersfile(TALLOC_CTX *ctx, char const *filename, fr_htrie_t **ptre /* * Has to be of the correct data type. */ - if (fr_value_box_from_str(box, box, data_type, NULL, entry->name, -1, 0, false) < 0) { + if (fr_value_box_from_str(box, box, data_type, NULL, + entry->name, strlen(entry->name), NULL, false) < 0) { ERROR("%s[%d] Failed parsing key %s - %s", entry->filename, entry->lineno, entry->name, fr_strerror()); goto error; diff --git a/src/modules/rlm_isc_dhcp/rlm_isc_dhcp.c b/src/modules/rlm_isc_dhcp/rlm_isc_dhcp.c index 05d62819396..57b4b398164 100644 --- a/src/modules/rlm_isc_dhcp/rlm_isc_dhcp.c +++ b/src/modules/rlm_isc_dhcp/rlm_isc_dhcp.c @@ -694,7 +694,7 @@ redo_multi: info->argv[info->argc] = talloc_zero(info, fr_value_box_t); ret = fr_value_box_from_str(info, info->argv[info->argc], type, NULL, - state->token, state->token_len, 0, false); + state->token, state->token_len, NULL, false); if (ret < 0) return ret; info->argc++; @@ -884,7 +884,7 @@ static int parse_option_definition(rlm_isc_dhcp_info_t *parent, rlm_isc_dhcp_tok type = FR_TYPE_UINT32; ret = fr_value_box_from_str(NULL, &box, type, NULL, - state->token, state->token_len, 0, false); + state->token, state->token_len, NULL, false); if (ret < 0) goto error; /* @@ -1014,7 +1014,7 @@ static int parse_option(rlm_isc_dhcp_info_t *parent, rlm_isc_dhcp_tokenizer_t *s /* * Add in the first value. */ - ret = fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, '\0', false); + ret = fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, NULL, false); if (ret < 0) { talloc_free(value); return ret; @@ -1043,7 +1043,7 @@ static int parse_option(rlm_isc_dhcp_info_t *parent, rlm_isc_dhcp_tokenizer_t *s MEM(vp = fr_pair_afrom_da(parent, da)); - ret = fr_pair_value_from_str(vp, state->token, state->token_len, '\0', false); + ret = fr_pair_value_from_str(vp, state->token, state->token_len, NULL, false); if (ret < 0) return ret; vp->op = T_OP_EQ; diff --git a/src/modules/rlm_mruby/rlm_mruby.c b/src/modules/rlm_mruby/rlm_mruby.c index 85808ded94c..21b3d9e8a17 100644 --- a/src/modules/rlm_mruby/rlm_mruby.c +++ b/src/modules/rlm_mruby/rlm_mruby.c @@ -377,7 +377,7 @@ static void add_vp_tuple(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vp talloc_free(dst); vp->op = op; - if (fr_pair_value_from_str(vp, cval, -1, '\0', false) < 0) { + if (fr_pair_value_from_str(vp, cval, strlen(cval), NULL, false) < 0) { REDEBUG("%s: %s %s %s failed", function_name, ckey, fr_table_str_by_value(fr_tokens_table, op, "="), cval); } else { DEBUG("%s: %s %s %s OK", function_name, ckey, fr_table_str_by_value(fr_tokens_table, op, "="), cval); diff --git a/src/modules/rlm_perl/rlm_perl.c b/src/modules/rlm_perl/rlm_perl.c index e4cd5023a5b..63a9fbc0d39 100644 --- a/src/modules/rlm_perl/rlm_perl.c +++ b/src/modules/rlm_perl/rlm_perl.c @@ -804,7 +804,7 @@ static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, break; default: - if (fr_pair_value_from_str(vp, val, len, '\0', false) < 0) goto fail; + if (fr_pair_value_from_str(vp, val, len, NULL, false) < 0) goto fail; } PAIR_VERIFY(vp); diff --git a/src/modules/rlm_python/rlm_python.c b/src/modules/rlm_python/rlm_python.c index 7c1ff236e31..cd42b8cd417 100644 --- a/src/modules/rlm_python/rlm_python.c +++ b/src/modules/rlm_python/rlm_python.c @@ -344,7 +344,7 @@ static void mod_vptuple(TALLOC_CTX *ctx, rlm_python_t const *inst, request_t *re talloc_free(dst); vp->op = op; - if (fr_pair_value_from_str(vp, s2, -1, '\0', false) < 0) { + if (fr_pair_value_from_str(vp, s2, strlen(s2), NULL, false) < 0) { DEBUG("%s - Failed: '%s.%s' %s '%s'", funcname, list_name, s1, fr_table_str_by_value(fr_tokens_table, op, "="), s2); } else { diff --git a/src/modules/rlm_rest/rest.c b/src/modules/rlm_rest/rest.c index 4dee4d459f0..cf5e63784f4 100644 --- a/src/modules/rlm_rest/rest.c +++ b/src/modules/rlm_rest/rest.c @@ -802,7 +802,7 @@ static int rest_decode_post(UNUSED rlm_rest_t const *instance, UNUSED rlm_rest_s return count; } - ret = fr_pair_value_from_str(vp, expanded, -1, '\0', true); + ret = fr_pair_value_from_str(vp, expanded, strlen(value), NULL, true); TALLOC_FREE(expanded); if (ret < 0) { RWDEBUG("Incompatible value assignment, skipping"); diff --git a/src/modules/rlm_sql/rlm_sql.c b/src/modules/rlm_sql/rlm_sql.c index a8d50a84563..0a477a3c44b 100644 --- a/src/modules/rlm_sql/rlm_sql.c +++ b/src/modules/rlm_sql/rlm_sql.c @@ -288,7 +288,7 @@ static int _sql_map_proc_get_value(TALLOC_CTX *ctx, fr_pair_list_t *out, * Buffer not always talloced, sometimes it's * just a pointer to a field in a result struct. */ - if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) { + if (fr_pair_value_from_str(vp, value, strlen(value), NULL, true) < 0) { RPEDEBUG("Failed parsing value \"%pV\" for attribute %s", fr_box_strvalue_buffer(value), tmpl_da(map->lhs)->name); talloc_free(vp); diff --git a/src/modules/rlm_sql/sql.c b/src/modules/rlm_sql/sql.c index 0f4a55ce580..78e7b380c97 100644 --- a/src/modules/rlm_sql/sql.c +++ b/src/modules/rlm_sql/sql.c @@ -262,7 +262,7 @@ static int sql_pair_afrom_row(TALLOC_CTX *ctx, request_t *request, fr_pair_list_ * specific to the SQL module. */ } else { - if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) { + if (fr_pair_value_from_str(vp, value, strlen(value), NULL, true) < 0) { RPEDEBUG("Error parsing value"); talloc_free(vp); diff --git a/src/modules/rlm_sqlippool/rlm_sqlippool.c b/src/modules/rlm_sqlippool/rlm_sqlippool.c index f689018e040..a0e6450cc27 100644 --- a/src/modules/rlm_sqlippool/rlm_sqlippool.c +++ b/src/modules/rlm_sqlippool/rlm_sqlippool.c @@ -627,7 +627,7 @@ static unlang_action_t CC_HINT(nonnull) mod_alloc(rlm_rcode_t *p_result, module_ * error out. If so, add it to the list. */ MEM(vp = fr_pair_afrom_da(request->reply_ctx, inst->allocated_address_da)); - if (fr_pair_value_from_str(vp, allocation, allocation_len, '\0', true) < 0) { + if (fr_pair_value_from_str(vp, allocation, allocation_len, NULL, true) < 0) { DO_PART(alloc_commit); RDEBUG2("Invalid IP number [%s] returned from instbase query.", allocation); diff --git a/src/protocols/tacacs/decode.c b/src/protocols/tacacs/decode.c index a1b0af3e460..c4207d0c64c 100644 --- a/src/protocols/tacacs/decode.c +++ b/src/protocols/tacacs/decode.c @@ -187,7 +187,7 @@ static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr * * And if that fails, just ignore it completely. */ - if (fr_pair_value_from_str(vp, (char const *) value, arg_end - value, 0, true) < 0) { + if (fr_pair_value_from_str(vp, (char const *) value, arg_end - value, NULL, true) < 0) { fail: talloc_free(vp); if (da != parent) goto raw; diff --git a/src/tests/keywords/date b/src/tests/keywords/date index 53c22b52f31..f25fecd3a91 100644 --- a/src/tests/keywords/date +++ b/src/tests/keywords/date @@ -68,10 +68,10 @@ update request { } update request { - &Tmp-Integer-3 := "%(sqldate:%{Tmp-String-3})" + &Tmp-String-0 := "%(sqldate:%{Tmp-String-3})" } -if (&Tmp-Integer-3 != 0) { +if (&Tmp-String-0 != "") { test_fail } @@ -96,4 +96,4 @@ if (&Module-Failure-Message != "Can't convert type ipaddr into date") { test_fail } -success \ No newline at end of file +success diff --git a/src/tests/keywords/foreach-nested.attrs b/src/tests/keywords/foreach-nested.attrs index d04f62f24ac..9d875795c23 100644 --- a/src/tests/keywords/foreach-nested.attrs +++ b/src/tests/keywords/foreach-nested.attrs @@ -15,12 +15,12 @@ Calling-Station-Id += "bar" # Expected answer # Packet-Type == Access-Accept -Called-Station-Id == '1 foo\n' +Called-Station-Id == "1 foo\n" Called-Station-Id == '1 bar' -Called-Station-Id == '2 foo\n' +Called-Station-Id == "2 foo\n" Called-Station-Id == '2 bar' -Called-Station-Id == '3 foo\n' +Called-Station-Id == "3 foo\n" Called-Station-Id == '3 bar' -Called-Station-Id == '4 foo\n' +Called-Station-Id == "4 foo\n" Called-Station-Id == '4 bar' diff --git a/src/tests/keywords/rand b/src/tests/keywords/rand index 2dc748e703b..54053292434 100644 --- a/src/tests/keywords/rand +++ b/src/tests/keywords/rand @@ -1,28 +1,34 @@ update request { - &Tmp-Integer-0 := "%{rand:-1}" - &Tmp-Integer-1 := "%{rand:hello world}" - &Tmp-Integer-2 := "%{rand:123}" + &Tmp-String-0 := "%{rand:-1}" } # # Negative limit should have failed # -if (&Tmp-Integer-0 != 0) { +if (&Tmp-String-0 != '') { test_fail } +update request { + &Tmp-String-0 := "%{rand:hello world}" +} + # # Invalid limit should have failed # -if (&Tmp-Integer-1 != 0) { +if (&Tmp-String-0 != 0) { test_fail } +update request { + &Tmp-Integer-0 := "%{rand:123}" +} + # # Make sure random number is whithin limit # -if (&Tmp-Integer-2 < 0 || &Tmp-Integer-2 > 123) { +if (&Tmp-Integer-0 < 0 || &Tmp-Integer-0 > 123) { test_fail } diff --git a/src/tests/keywords/truncation b/src/tests/keywords/truncation index 45b58528150..20afeef66cd 100644 --- a/src/tests/keywords/truncation +++ b/src/tests/keywords/truncation @@ -2,7 +2,7 @@ # 8192 - 0x (2) - '' (2) there are unlikely to be any static buffers this big outside of the conffile parser update request { - &Tmp-Octets-0 := '0x\ + &Tmp-Octets-0 := 0x\ d8abccb7834711af1de1812be2579febe946f5d7beef6fa5c7074c0cb917e9b91e23e14b016f27610097c16c0e0fad88176e077b24198c770746159\ 05b8810d1c8b774d98889fa5c6027cde5e9c56dd4f7c48298c7713aeca5ba5dcfd506032ad05b1396f50e825b633d5a6af0dce6181b640287e03a65\ 8734df46a86341556f28455b3f377313a5a2ac8c8267b8a5de559b95f9b493a68b9e0278485f9e3914d702b2b7b90ee85ff393461f197386d09b836\ @@ -71,7 +71,7 @@ fc813bd2e58c6d0dfd951570dbff4b5e73ce547cd100ab320b6944e887d611b3425bfcdf3bfa852f 5ccf45c5af9c05a47905ac8bfe55f9b912c3fca856abe7863f87392b6f6b0069e3d8412a056b1034aaac506bf2ca51760aa180c5f43a751beb06e88\ fc6afab4c5dd4aae4a2e6f0293c15278d557c2925acba90c73eeea09ebb95f0d469aa77ae983a0e69dacd55bd8a7e78a41df5227de35af05127fa3b\ a02f4a3ab98d75992d68a15d393387fe9ef01041569570ad6fe884764e55567311bcacfcffae76554dcfebfde607500f50ec85f589eaade607500f5\ -3ae4bcef324b9a3f47ba5c835b54a010ca42f3b9cc5368278c148c9b02ea8c4c9f244fd49f' +3ae4bcef324b9a3f47ba5c835b54a010ca42f3b9cc5368278c148c9b02ea8c4c9f244fd49f } # Actual length of octet string is 4083 bytes diff --git a/src/tests/unit/condition/base.txt b/src/tests/unit/condition/base.txt index 99027016951..aeb5602ea0a 100644 --- a/src/tests/unit/condition/base.txt +++ b/src/tests/unit/condition/base.txt @@ -331,7 +331,7 @@ condition 127.0.0.1/32 == 127.0.0.1 match true condition 127.0.0.1/327 == 127.0.0.1 -match ERROR offset 8: Failed parsing value as type 'ipv4prefix' +match ERROR offset 8: Failed parsing value as type 'ipaddr' condition 127.0.0.1/32 == 127.0.0.1 match true diff --git a/src/tests/unit/data_types.txt b/src/tests/unit/data_types.txt index 640debb296d..b9b54089412 100644 --- a/src/tests/unit/data_types.txt +++ b/src/tests/unit/data_types.txt @@ -77,19 +77,19 @@ match -3600 # uint8 # value uint8 256 -match Value 256 is invalid for type uint8 (must be in range 0...255) +match integer overflow value uint8 -128 -match Invalid negative value "-128" for unsigned integer +match integer underflow value int8 128 -match Value 128 is invalid for type int8 (must be in range -128...127) +match integer overflow value int8 -128 match -128 value int8 -130 -match Value -130 is invalid for type int8 (must be in range -128...127) +match integer underflow value date Jan 1 1970 12:00:00 UTC match Jan 1 1970 12:00:00 UTC diff --git a/src/tests/unit/xlat/base.txt b/src/tests/unit/xlat/base.txt index bb2b790b78b..bd95052e9e7 100644 --- a/src/tests/unit/xlat/base.txt +++ b/src/tests/unit/xlat/base.txt @@ -64,7 +64,7 @@ xlat %{33} match ERROR offset 2: Invalid regex reference. Must be in range 0-32 xlat %{3a} -match ERROR offset 2: Unexpected text after attribute reference +match ERROR offset 2: Invalid regex reference. Must be in range 0-32 xlat %{-3} match ERROR offset 2: Unresolved attributes not allowed in expansions here