#include <freeradius-devel/server/base.h>
#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/calc.h>
#include <freeradius-devel/server/pairmove.h>
#include <freeradius-devel/protocol/radius/rfc2865.h>
talloc_free(deleted);
}
-/** Move a map using the operators from the old pairmove API.
+/** Move a map using the operators from the old pairmove functionality.
*
*/
-int fr_pairmove_map(request_t *request, map_t const *map)
+int radius_legacy_map_apply(request_t *request, map_t const *map)
{
int rcode;
fr_pair_t *vp, *next;
TALLOC_FREE(to_free);
return 0;
}
+
+int radius_legacy_map_cmp(request_t *request, map_t const *map)
+{
+ int rcode;
+ fr_pair_t *vp;
+ fr_value_box_t const *box;
+ fr_value_box_t *to_free = NULL;
+ fr_value_box_t dst;
+
+ fr_assert(tmpl_is_attr(map->lhs));
+ fr_assert(fr_comparison_op[map->op]);
+
+ if (tmpl_find_vp(&vp, request, map->lhs) < 0) {
+ return 0;
+ }
+
+ if (tmpl_is_data(map->rhs)) {
+ box = tmpl_value(map->rhs);
+
+ } else if (tmpl_is_attr(map->rhs)) {
+ fr_pair_t *rhs;
+
+ if (tmpl_find_vp(&rhs, request, map->rhs) < 0) return -1;
+
+ box = &rhs->data;
+
+ } else if (tmpl_contains_xlat(map->rhs)) {
+ if (tmpl_aexpand(request, &to_free, request, map->rhs, NULL, NULL) < 0) return -1;
+
+ box = to_free;
+
+ } else if (tmpl_is_regex(map->rhs)) {
+ /*
+ * @todo - why box it and parse it again, when we can just run the regex?
+ */
+ box = fr_box_strvalue(map->rhs->name);
+
+ } else {
+ fr_strerror_const("Unknown RHS");
+ return -1;
+ }
+
+ /*
+ * The RHS is a compiled regex, which we don't yet
+ * support. So just re-parse it at run time for
+ * programmer laziness.
+ */
+ if ((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)) {
+ if (box->type != FR_TYPE_STRING) {
+ fr_strerror_const("Invalid type for regular expression");
+ return -1;
+ }
+
+ rcode = fr_regex_cmp_op(map->op, &vp->data, box);
+ TALLOC_FREE(to_free);
+ if (rcode < 0) return rcode;
+
+ return (rcode == 1);
+ }
+
+ /*
+ * Let the calculation code do upcasting as necessary.
+ */
+ rcode = fr_value_calc_binary_op(request, &dst, FR_TYPE_BOOL, &vp->data, map->op, box);
+ TALLOC_FREE(to_free);
+
+ if (rcode < 0) return rcode;
+
+ return dst.vb_bool;
+}
void radius_pairmove(request_t *request, fr_pair_list_t *to, fr_pair_list_t *from) CC_HINT(nonnull);
-int fr_pairmove_map(request_t *request, map_t const *map);
+int radius_legacy_map_apply(request_t *request, map_t const *map) CC_HINT(nonnull);
+
+int radius_legacy_map_cmp(request_t *request, map_t const *map) CC_HINT(nonnull);
#ifdef __cplusplus
}
lhs_rules = (tmpl_rules_t) {
.attr = {
.dict_def = dict,
- .prefix = TMPL_ATTR_REF_PREFIX_NO,
+ .prefix = TMPL_ATTR_REF_PREFIX_AUTO,
.list_def = request_attr_request,
- .list_presence = TMPL_ATTR_LIST_FORBID,
+ .list_presence = TMPL_ATTR_LIST_ALLOW,
/*
* Otherwise the tmpl code returns 0 when asked
.dict_def = dict,
.prefix = TMPL_ATTR_REF_PREFIX_YES,
.list_def = request_attr_request,
- .list_presence = TMPL_ATTR_LIST_FORBID,
+ .list_presence = TMPL_ATTR_LIST_ALLOW,
}
};
goto do_insert;
}
- if (!tmpl_is_data(new_map->rhs) && !tmpl_is_exec(new_map->rhs) &&
- !tmpl_contains_xlat(new_map->rhs)) {
- ERROR("%s[%d]: Invalid RHS '%s' for check item",
- file, lineno, new_map->rhs->name);
- goto fail_entry;
- }
-
do_insert:
fr_assert(!new_map->parent);
map_list_insert_tail(&t->check, new_map);
*/
lhs_rules.attr.list_def = request_attr_reply;
- lhs_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_AUTO;
- lhs_rules.attr.list_presence = TMPL_ATTR_LIST_ALLOW;
-
comma = false;
rhs_rules.attr.list_def = request_attr_request;
- rhs_rules.attr.list_presence = TMPL_ATTR_LIST_ALLOW;
reply_item:
/*
map = prev;
break;
- case T_OP_REG_EQ:
- case T_OP_REG_NE:
- if (tmpl_contains_xlat(map->rhs)) {
- ERROR("%s[%d] Right side of check item %s is not a static value",
- entry->filename, entry->lineno, map->lhs->name);
- return -1;
- }
- break;
-
default:
- /*
- * Comparisons must be with data.
- */
- if (!tmpl_is_data(map->rhs)) {
- ERROR("%s[%d] Right side of check item %s is not a leaf value",
- entry->filename, entry->lineno, map->lhs->name);
- return -1;
- }
break;
}
} /* end of loop over check items */
return 0;
}
-static bool files_eval_map(request_t *request, map_t *map)
-{
- fr_pair_t *vp;
-
- fr_assert(tmpl_is_attr(map->lhs));
- fr_assert(fr_comparison_op[map->op]);
-
- if (tmpl_find_vp(&vp, request, map->lhs) < 0) return false;
-
- /*
- * The RHS is a compiled regex, which we don't yet
- * support. So just re-parse it at run time for
- * programmer laziness.
- */
- if ((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)) {
- return (fr_regex_cmp_op(map->op, &vp->data, fr_box_strvalue(map->rhs->name)) == 1);
- }
-
- fr_assert(tmpl_is_data(map->rhs));
-
- return (fr_value_box_cmp_op(map->op, &vp->data, tmpl_value(map->rhs)) == 1);
-}
-
-
/*
* Common code called by everything below.
*/
* Run the check items.
*/
while ((map = map_list_next(&pl->check, map))) {
+ int rcode;
+
RDEBUG3(" %s %s %s", map->lhs->name, fr_tokens[map->op], map->rhs->name);
/*
* Evaluate the map, including regexes.
*/
default:
- if (!files_eval_map(request, map)) {
+ rcode = radius_legacy_map_cmp(request, map);
+ if (rcode < 0) {
+ RPWARN("Failed parsing map for check item %s, skipping it", map->lhs->name);
+ match = false;
+ break;
+ }
+
+ if (!rcode) {
RDEBUG3(" failed match");
match = false;
}
continue;
}
- if (fr_pairmove_map(request, map) < 0) {
+ if (radius_legacy_map_apply(request, map) < 0) {
RPWARN("Failed parsing map for reply item %s, skipping it", map->lhs->name);
break;
}
--- /dev/null
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = "attrref_check"
+User-Password = "whoops"
+Filter-Id = "magic"
+NAS-Identifier = "magic"
+NAS-IP-Address = 127.0.0.1
+Calling-Station-Id = "127.0.0.1"
+
+#
+# Expected answer
+#
+Packet-Type == Access-Accept
+Reply-Message == 'success'
xlat Password.Cleartext := "open"
Reply-Message := "Hello, %{User-Name}"
+#
+# Inter-attribute comparisons and xlats for comparisons
+#
+attrref_check Filter-Id == &NAS-Identifier, NAS-IP-Address == "%{Calling-Station-Id}", Password.Cleartext := "whoops"
+ Reply-Message := "success"
+
DEFAULT User-Name == "cmp_eq", Password.Cleartext := "hopping"
Reply-Message := "success-cmp_eq"