diff --git a/src/include/map.h b/src/include/map.h index fc4402d5c27c..8596832e5519 100644 --- a/src/include/map.h +++ b/src/include/map.h @@ -78,11 +78,14 @@ typedef enum vpt_type { VPT_TYPE_LIST, //!< Is a list. VPT_TYPE_REGEX, //!< Is a regex. VPT_TYPE_EXEC, //!< Needs to be executed. - VPT_TYPE_DATA //!< is a value_data_t + VPT_TYPE_DATA, //!< is a value_data_t + VPT_TYPE_XLAT_STRUCT, //!< pre-parsed xlat_exp_t in vpd.ptr } vpt_type_t; extern const FR_NAME_NUMBER vpt_types[]; +typedef struct xlat_exp xlat_exp_t; + /** A pre-parsed template attribute * * Value pair template, used when processing various mappings sections @@ -102,6 +105,7 @@ typedef struct value_pair_tmpl_t { DICT_ATTR const *da; //!< Resolved dictionary attribute. value_data_t const *vpd; //!< actual data + xlat_exp_t *xlat; //!< pre-parsed xlat_exp_t size_t length; //!< of the vpd data } value_pair_tmpl_t; diff --git a/src/include/parser.h b/src/include/parser.h index 4adff2ad9e76..f583a4021b31 100644 --- a/src/include/parser.h +++ b/src/include/parser.h @@ -106,7 +106,6 @@ bool fr_condition_walk(fr_cond_t *head, bool (*callback)(void *, fr_cond_t *), v /* * In xlat.c for now */ -typedef struct xlat_exp xlat_exp_t; ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error); size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node); diff --git a/src/main/modcall.c b/src/main/modcall.c index aa1f6d0cc97d..0e9c70dd976a 100644 --- a/src/main/modcall.c +++ b/src/main/modcall.c @@ -2652,7 +2652,6 @@ static bool modcall_pass2_update(modgroup *g) fmt = talloc_strdup(map->src, map->src->name); slen = xlat_tokenize(map->src, fmt, &head, &error); - talloc_free(fmt); if (slen < 0) { size_t offset; @@ -2671,7 +2670,12 @@ static bool modcall_pass2_update(modgroup *g) free(spbuf); return false; } - talloc_free(head); + + /* + * Re-write it to be a pre-parsed XLAT structure. + */ + map->src->type = VPT_TYPE_XLAT_STRUCT; + map->src->xlat = head; } return true; diff --git a/src/main/valuepair.c b/src/main/valuepair.c index 9bad0ee84903..f17f35bb7c02 100644 --- a/src/main/valuepair.c +++ b/src/main/valuepair.c @@ -1003,6 +1003,7 @@ int radius_map2request(REQUEST *request, value_pair_map_t const *map, break; case VPT_TYPE_XLAT: + case VPT_TYPE_XLAT_STRUCT: vp_prints_value(buffer, sizeof(buffer), vp, '"'); value = buffer; break; @@ -1219,6 +1220,7 @@ int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *ma switch (map->src->type) { case VPT_TYPE_XLAT: + case VPT_TYPE_XLAT_STRUCT: case VPT_TYPE_LITERAL: case VPT_TYPE_DATA: vp = pairalloc(request, da); @@ -1234,6 +1236,42 @@ int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *ma * And parse the RHS */ switch (map->src->type) { + case VPT_TYPE_XLAT_STRUCT: + rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */ + /* + * Don't call unnecessary expansions + */ + if (strchr(map->src->name, '%') != NULL) { + ssize_t slen; + char *str = NULL; + + rad_assert(map->src->xlat != NULL); + slen = radius_axlat_struct(&str, request, map->src->xlat, NULL, NULL); + if (slen < 0) { + rcode = slen; + goto error; + } + + /* + * We do the debug printing because radius_axlat_struct + * doesn't have access to the original string. It's been + * mangled during the parsing to xlat_exp_t + */ + RDEBUG2("EXPAND %s", map->src->name); + RDEBUG2(" --> %s", str); + + rcode = pairparsevalue(vp, str); + talloc_free(str); + if (!rcode) { + pairfree(&vp); + rcode = -1; + goto error; + } + + break; + } + goto parse_literal; + case VPT_TYPE_XLAT: rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */ /* @@ -1261,6 +1299,7 @@ int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *ma /* FALL-THROUGH */ case VPT_TYPE_LITERAL: + parse_literal: if (!pairparsevalue(vp, map->src->name)) { rcode = -2; goto error;