diff --git a/src/include/radiusd.h b/src/include/radiusd.h index cc1136621333..c39b5ed565a8 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -609,6 +609,7 @@ void paircompare_unregister(DICT_ATTR const *attr, RAD_COMPARE_FUNC func); void paircompare_unregister_instance(void *instance); int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check, VALUE_PAIR **rep_list); +value_pair_tmpl_t *radius_xlat2tmpl(TALLOC_CTX *ctx, xlat_exp_t *xlat); int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp); void radius_xlat_move(REQUEST *, VALUE_PAIR **to, VALUE_PAIR **from); int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp); diff --git a/src/main/modcall.c b/src/main/modcall.c index 025d96511ec3..04ea2f32517d 100644 --- a/src/main/modcall.c +++ b/src/main/modcall.c @@ -2689,12 +2689,15 @@ void add_to_modcallable(modcallable *parent, modcallable *this) #ifdef WITH_UNLANG static char const spaces[] = " "; -static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt) +static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert) { ssize_t slen; char *fmt; char const *error; xlat_exp_t *head; + value_pair_tmpl_t *vpt; + + vpt = *pvpt; rad_assert(vpt->type == VPT_TYPE_XLAT); @@ -2721,6 +2724,30 @@ static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt) return false; } + if (convert) { + value_pair_tmpl_t *attr; + + attr = radius_xlat2tmpl(talloc_parent(vpt), head); + if (attr) { + if (cf_item_is_pair(ci)) { + CONF_PAIR *cp = cf_itemtopair(ci); + + WDEBUG("%s[%d] Please change \"%%{%s}\" to just %s", + cf_pair_filename(cp), cf_pair_lineno(cp), + attr->name, attr->name); + } else { + CONF_SECTION *cs = cf_itemtosection(ci); + + WDEBUG("%s[%d] Please change \"%%{%s}\" to just %s", + cf_section_filename(cs), cf_section_lineno(cs), + attr->name, attr->name); + } + TALLOC_FREE(*pvpt); + *pvpt = attr; + return true; + } + } + /* * Re-write it to be a pre-parsed XLAT structure. */ @@ -2770,7 +2797,7 @@ static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c) if (c->type == COND_TYPE_EXISTS) { if (c->data.vpt->type == VPT_TYPE_XLAT) { - return pass2_xlat_compile(c->ci, c->data.vpt); + return pass2_xlat_compile(c->ci, &c->data.vpt, true); } rad_assert(c->data.vpt->type != VPT_TYPE_REGEX); @@ -2859,14 +2886,29 @@ static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c) /* * Precompile xlat's */ - if (map->src->type == VPT_TYPE_XLAT) { - if (!pass2_xlat_compile(map->ci, map->src)) { + if (map->dst->type == VPT_TYPE_XLAT) { + /* + * Don't compile the LHS to an attribute + * reference for now. When we do that, we've got + * to check the RHS for type-specific data, and + * parse it to a VPT_TYPE_DATA. + */ + if (!pass2_xlat_compile(map->ci, &map->dst, false)) { return false; } } - if (map->dst->type == VPT_TYPE_XLAT) { - if (!pass2_xlat_compile(map->ci, map->dst)) { + if (map->src->type == VPT_TYPE_XLAT) { + /* + * Convert the RHS to an attribute reference only + * if the LHS is an attribute reference, too. + * + * We can fix this when the code in evaluate.c + * can handle strings on the LHS, and attributes + * on the RHS. For now, the code in parser.c + * forbids this. + */ + if (!pass2_xlat_compile(map->ci, &map->src, (map->dst->type == VPT_TYPE_ATTR))) { return false; } } @@ -2938,7 +2980,11 @@ static bool modcall_pass2_update(modgroup *g) if (map->src->type == VPT_TYPE_XLAT) { rad_assert(map->src->vpd == NULL); - if (!pass2_xlat_compile(map->ci, map->src)) { + /* + * FIXME: compile to attribute && handle + * the conversion in radius_map2vp(). + */ + if (!pass2_xlat_compile(map->ci, &map->src, false)) { return false; } } @@ -3126,7 +3172,7 @@ bool modcall_pass2(modcallable *mc) if (g->vpt && (g->vpt->type == VPT_TYPE_XLAT) && (!pass2_xlat_compile(cf_sectiontoitem(g->cs), - g->vpt))) { + &g->vpt, true))) { return false; } diff --git a/src/main/xlat.c b/src/main/xlat.c index 08529c5fd37b..5a5fe4e71b19 100644 --- a/src/main/xlat.c +++ b/src/main/xlat.c @@ -2285,6 +2285,33 @@ static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char con return len; } +/* + * Try to convert an xlat to a tmpl + */ +value_pair_tmpl_t *radius_xlat2tmpl(TALLOC_CTX *ctx, xlat_exp_t *xlat) +{ + value_pair_tmpl_t *vpt; + + if (xlat->next || (xlat->type != XLAT_ATTRIBUTE)) return NULL; + + /* + * Can't convert Nth reference, or tags to templates. + * They have no such fields. + */ + if ((xlat->num != 0) || (xlat->tag != TAG_ANY)) return NULL; + + vpt = talloc(ctx, value_pair_tmpl_t); + if (!vpt) return NULL; + + vpt->type = VPT_TYPE_ATTR; + vpt->name = talloc_strdup(vpt, xlat->fmt); + vpt->request = xlat->ref; + vpt->list = xlat->list; + vpt->da = xlat->da; + + return vpt; +} + ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx) { return xlat_expand(&out, outlen, request, fmt, escape, ctx);