]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add fr_value_box_from_substr
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 27 Oct 2021 16:15:47 +0000 (12:15 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 27 Oct 2021 16:16:18 +0000 (12:16 -0400)
it's not yet complete, but even the addition of the function caused significant issues.  It should now be safe at least...

59 files changed:
src/bin/dhcpclient.c
src/bin/radclient.c
src/bin/radmin.c
src/bin/radsniff.c
src/bin/radsnmp.c
src/bin/unit_test_attribute.c
src/lib/curl/base.c
src/lib/eap/chbind.c
src/lib/eap/crypto.c
src/lib/ldap/map.c
src/lib/server/command.c
src/lib/server/cond_tokenize.c
src/lib/server/map.c
src/lib/server/map_async.c
src/lib/server/paircmp.c
src/lib/server/tmpl.h
src/lib/server/tmpl_eval.c
src/lib/server/tmpl_tokenize.c
src/lib/soh/soh.c
src/lib/tls/pairs.c
src/lib/tls/session.c
src/lib/unlang/tmpl.c
src/lib/unlang/xlat_builtin.c
src/lib/unlang/xlat_eval.c
src/lib/util/dict_fixup.c
src/lib/util/dict_tokenize.c
src/lib/util/dict_util.c
src/lib/util/dpair_legacy.c
src/lib/util/fuzzer.c
src/lib/util/pair.c
src/lib/util/pair.h
src/lib/util/pair_legacy.c
src/lib/util/pair_tests.c
src/lib/util/pair_tokenize.c
src/lib/util/sbuff.c
src/lib/util/sbuff.h
src/lib/util/value.c
src/lib/util/value.h
src/modules/rlm_client/rlm_client.c
src/modules/rlm_csv/rlm_csv.c
src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c
src/modules/rlm_eap/types/rlm_eap_peap/peap.c
src/modules/rlm_files/rlm_files.c
src/modules/rlm_isc_dhcp/rlm_isc_dhcp.c
src/modules/rlm_mruby/rlm_mruby.c
src/modules/rlm_perl/rlm_perl.c
src/modules/rlm_python/rlm_python.c
src/modules/rlm_rest/rest.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_sql/sql.c
src/modules/rlm_sqlippool/rlm_sqlippool.c
src/protocols/tacacs/decode.c
src/tests/keywords/date
src/tests/keywords/foreach-nested.attrs
src/tests/keywords/rand
src/tests/keywords/truncation
src/tests/unit/condition/base.txt
src/tests/unit/data_types.txt
src/tests/unit/xlat/base.txt

index bec2348a1af641ea617ee101727476c83d91fb46..8596e3781cba9e5aac1fed34393e5e7990fa9149 100644 (file)
@@ -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);
index 8125b7cf879f4e100aa80923b1261bbd7e8c75d3..2e4977bdd787da51b7659a2c8d6a540b53aacc99 100644 (file)
@@ -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;
                                }
index 566132043188ca096115283ad7f1d9230a254ba5..9f364aeddd8acaafeb574a23c7c87d1c0e84b5f0 100644 (file)
@@ -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;
        }
index 6380d0096922e50e1c5af8342ee8bf60541de6d0..fa67aba7c1495c5658176364db1c732c9081a309 100644 (file)
@@ -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;
                        }
index ed39b3f7e0c98ac174d4211edc536831298483dc..92beb9fb9afa0172234f418ac1efb982c6de2980 100644 (file)
@@ -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;
index 2857bcc2a2fea9290704bc4954602963afaee993..7afc9858d5cc54905857b53fb90c507d95527790 100644 (file)
@@ -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();
index e71bcef91a0bcf49d93f1d1a525bcd04cacc8335..417d0af5e3a124be699975668a5097e81f658278 100644 (file)
@@ -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);
                }
index ad73659e7ac1b29a554840613cd78a395753d188..7fcb3f5023663092c24e1654d26558098ba2113c 100644 (file)
@@ -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) {
index c813ec8088aae758285099a472db051bddfa263c..ebe9ebc794431f8ca585b9b2f3780a1c8c0e324d 100644 (file)
@@ -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;
index 1ad59110156eea88da30486451ad633756639cb3..9e43e5714c868671b45dbc24efc62d73d7d14947 100644 (file)
@@ -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);
index 6d7bf0ffa6e87baab3b557e66557642776ccad48..c42384e8e51b19dd428f4feba260158856f5f031 100644 (file)
@@ -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;
index c648b1a812c9f05e8fbda27deab7e9fbfd062131..db3e0621682e9fb4a3d494406e5f6c87f8d3fa42 100644 (file)
@@ -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;
        }
index 84f7093110d44c30b89aa403e3aee145f810d5ad..c19708177501f8bf59198e4d60458545e20ee554 100644 (file)
@@ -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;
index 5a042e84107df2867a84830d8c15356cb213c76b..629ffa621dde720853ff2f1042d892b0438b129c 100644 (file)
@@ -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;
                }
index 819c4c3850f3e2688138d1d8716c09f597e479b9..39114849b946fb49a9204d3109a0e1a354d0ec5a 100644 (file)
@@ -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.
index 192da0a750924b7c85ffb3f2950ce87e55345296..da1cf385e237cff4b9f2d62b34862dabf32398b8 100644 (file)
@@ -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,
index d8ca18f0218441eaa06e7b69d836f28decd92972..7130ccddde78c54671477474d4396614012362f2 100644 (file)
@@ -28,11 +28,12 @@ RCSID("$Id$")
 
 #define _TMPL_PRIVATE 1
 
-#include <freeradius-devel/server/tmpl.h>
 #include <freeradius-devel/server/exec.h>
 #include <freeradius-devel/server/exec_legacy.h>
-#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/server/tmpl.h>
 #include <freeradius-devel/util/dlist.h>
+#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/value.h>
 
 /** 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);
index 26222f30ae3db9195f01fa0c2d8f32bb57172a23..03231c9ac87d90e5a16d8e5dbc591b44301d683d 100644 (file)
@@ -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;
 }
 
index 4320c1cc488e737186cd02e9fe1828f93080307a..9666b16e71213abeab4ea6f6c1a4ad0ba2e7887c 100644 (file)
@@ -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);
index 098f31bc7be8192e0130a942b42fc1fe79d535f9..50709a1430f41ad56787a62b2830b46bace53b5c 100644 (file)
@@ -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)));
index 8abaa46ebfaca7cde701a4966a2d27d4b1342ee3..57eb6b21dfd401ef679009e2ee6ddfe2f7fcc1ad 100644 (file)
@@ -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;
index ec91e669a55de8b39964d2da22a273a173951209..12c30e8ff566388d3c934f12dbb347cf148f1fd6 100644 (file)
@@ -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;
index e9a54896eef37585d0c1d60a989ffd67dff70389..80cea64ea73697484ac2fde1cd8d531319f0e6d7 100644 (file)
@@ -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:
index 5d63d98d6e76b6cc2ea3fe29a32be1361b6562dc..be04f023fc8de7ebb62976697295026dfb0d9cce 100644 (file)
@@ -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;
        }
index eef6db26ac3c37e597e0f3ef6a7fad85b61f30f9..9ef2c58c359ba113f21ba0730432ec7cd491a0ee 100644 (file)
@@ -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;
index e0180cf4c3b386f2420ff1b3345039a3a429a12d..fe142d8201a671324f58541c9a40b22b127e34bd 100644 (file)
@@ -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, "<INVALID>"));
                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;
        }
index 3550502785dbba1960cdb6aa253339b5a22efc49..ed6ee86d087f0524d410c2a3cd892c1476efb768 100644 (file)
@@ -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, "<INVALID>"),
                                   (int)fr_sbuff_remaining(in), fr_sbuff_current(in));
                if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
                return -fr_sbuff_marker_release_behind(&start);
index 4f59f5d0fac48256c892f43cdab2833f508b3d76..712de64c12695a6b7e1b77b06b32e9491e9dd4c4 100644 (file)
@@ -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;
                                }
index fdd78b4b9f81e78e1c88251384fda229147664b0..5e6b8bf707c1ed220287fec7376347acc47df18e 100644 (file)
@@ -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;
 }
index 375ceba7353ba7dece5d96dcfe534acf1b768584..d6f88e262740f97461d9ba5e8846fce35a7ca55a 100644 (file)
@@ -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);
index 187bb942ed6187852a01e8c8fe7b35b4ee97792f..4d652aa7612a9cf3145737942e5dffad90883d7b 100644 (file)
@@ -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);
 
index e997a90b39696e9efc8acf17b08ff19d1df93e25..a91ae20dde4a06e72f782634f6018d8e69cb8733 100644 (file)
@@ -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;
                        }
index 92eff8b49a866fd3f3f26a1a28c1b83f53cde899..072773ca0e0bd8f46b35ec71b683d00318a1dd94 100644 (file)
@@ -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);
index 58310f61f069773cb38a2eefaf67554c37c75b2b..ae63e2a776023447251fece726f524dd09ab274f 100644 (file)
@@ -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);
index b35cb19b0305d35db91d85797264ea599851b775..d5bd4ab58917701361ef5e218a2ae359660c6670 100644 (file)
@@ -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 <stdint.h>.
+ * @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 <stdint.h>.
- * @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) { \
index e87780db9e6b405aab138a2ec361c6785ca6926c..f0f068aaa7102aa22bbfdacb04063bf1a40e5e48 100644 (file)
@@ -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);
index 02867dce42964f81c1731d6e3c816debc89c49b6..54abe4cccdba4213d48c63621be20a707d170983 100644 (file)
@@ -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, "<INVALID>"), \
-                                          (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, "<INVALID>"), \
-                                          (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, "<INVALID>"));
-               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
index 42bd9278caeb0064d8618add71bc97c3bed6586e..9d1569ef441797b6509c9d836a2360ceddbbff02 100644 (file)
@@ -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));
 /** @} */
 
index 017b7fea0e323125fcf79c46c22cb4800be1d3c6..1fd00e54a3c4f2ef2bfe208da4d757a1afd9bc95 100644 (file)
@@ -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);
index 84a95a359b69920ade33060bd840fa4dfa653bf4..8237740fc53b2f4cd8446b7c97d674b3c06b0abb 100644 (file)
@@ -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);
index 61ab96b29b0453fe00eb6c56370a71e3702101ec..195a966a3d50419a97aaa7a29a874ad995b05e3a 100644 (file)
@@ -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
index 1d597e5d8b74af79eab214201d501190aadb23e3..7483eb157d2307ceac1dd25fcfbb9ed590527a37 100644 (file)
@@ -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);
index ffa3c7760f6bc7895e462b0ecebafaa2c17e15f6..a58789516bd07c01a45a23dd91476cea45397eb4 100644 (file)
@@ -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;
index 05d6281939665dcfda2e9318119ddc5437e1058f..57b4b3981646a29f0a174a0290d2d5243f2558a8 100644 (file)
@@ -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;
index 85808ded94c45a426c974963770a20edaec23f8a..21b3d9e8a175a3631a81816591e2dd3390c85317 100644 (file)
@@ -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);
index e4cd5023a5bcb6f5b1b5a4d441c07c7ad9a93de8..63a9fbc0d39b42b5fd6daab371e866cb1e6c5367 100644 (file)
@@ -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);
index 7c1ff236e31e10c8a66b68cc49258b5ef70f308e..cd42b8cd4171fae0615614950701eba1ad70ec39 100644 (file)
@@ -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 {
index 4dee4d459f0fb845f215290f9c0d458bdc502eb3..cf5e63784f4bd9a57efa3b4d7671832fe9182f2b 100644 (file)
@@ -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");
index a8d50a84563958c4202a03f068dc3156d43eb5d1..0a477a3c44bb9ed0fc8e3431b46e1e13e0e54dce 100644 (file)
@@ -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);
index 0f4a55ce5808afe98267263956af815e6cb011db..78e7b380c97b2be3b601a6f47a05433bc35c9e82 100644 (file)
@@ -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);
index f689018e04077c8135b28dd5249bc01a09a578bc..a0e6450cc27294e7a1ea5fc2583412ed0c62b7bf 100644 (file)
@@ -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);
index a1b0af3e460becc5fb97d62f6680689490e05d66..c4207d0c64c0cc24b253ed58b8f9f0996f2795a7 100644 (file)
@@ -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;
index 53c22b52f317c0992cc6f9a394c755dd55ca123c..f25fecd3a91dfa46d244e215ae9c0b4d3d43cf7b 100644 (file)
@@ -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
index d04f62f24ac711fcd4cfe290a71d8fcce26210c5..9d875795c2334fca8463c54a16b1c64ad876c8a1 100644 (file)
@@ -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'
 
index 2dc748e703b68744ede95afaf1309de2814159da..54053292434c28b8a58afdd81d94d8c7e812dba6 100644 (file)
@@ -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
 }
 
index 45b58528150813a510224551e14b3d3e93a34c93..20afeef66cd030f47423d3b6509dd5b7e026d7df 100644 (file)
@@ -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
index 990270169513206cde5441023aa6d49b76bf1655..aeb5602ea0a2089075f52b61bf57bbe2cdfe5607 100644 (file)
@@ -331,7 +331,7 @@ condition <ipaddr>127.0.0.1/32 == 127.0.0.1
 match true
 
 condition <ipaddr>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 <ipaddr>127.0.0.1/32 == 127.0.0.1
 match true
index 640debb296db618d82fdbe92aeb101e592ecd4cf..b9b54089412c13ce235ce91245644cc85517be24 100644 (file)
@@ -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
index bb2b790b78b8038a84688222604bbd548c183342..bd95052e9e7c77517666c5b9e19aba41442b550c 100644 (file)
@@ -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