Allow inter-attribute comparisons in the "users" file.
Allow list references in the reply list.
fr_dict_attr_t const *da;
fr_pair_list_t *list;
TALLOC_CTX *ctx;
+ fr_value_box_t const *box;
/*
* Finds both the correct ctx and nested list.
da = tmpl_attr_tail_da(map->lhs);
- fr_assert(tmpl_is_data(map->rhs));
+ if (tmpl_is_data(map->rhs)) {
+ box = tmpl_value(map->rhs);
+
+ } else if (tmpl_is_attr(map->rhs)) {
+ if (tmpl_find_vp(&vp, request, map->rhs) < 0) return -1;
+
+ if (vp->vp_type != da->type) {
+ fr_strerror_const("Incompatible data types");
+ return -1;
+ }
+
+ box = &vp->data;
+
+ } else {
+ fr_strerror_const("Unknown RHS");
+ return -1;
+ }
switch (map->op) {
case T_OP_CMP_FALSE: /* delete all */
vp = fr_pair_afrom_da_nested(ctx, list, da);
if (!vp) return -1;
- if (fr_value_box_copy(vp, &vp->data, tmpl_value(map->rhs)) < 0) {
+ if (fr_value_box_copy(vp, &vp->data, box) < 0) {
talloc_free(vp);
return -1;
}
vp = fr_pair_afrom_da(ctx, da);
if (!vp) return -1;
- if (fr_value_box_copy(vp, &vp->data, tmpl_value(map->rhs)) < 0) {
+ if (fr_value_box_copy(vp, &vp->data, box) < 0) {
talloc_free(vp);
return -1;
}
redo_sub:
next = fr_pair_find_by_da(list, vp, da);
- rcode = fr_value_box_cmp_op(T_OP_CMP_EQ, &vp->data, tmpl_value(map->rhs));
+ rcode = fr_value_box_cmp_op(T_OP_CMP_EQ, &vp->data, box);
if (rcode < 0) return -1;
if (!vp) goto add;
redo_filter:
- rcode = fr_value_box_cmp_op(map->op, &vp->data, tmpl_value(map->rhs));
+ rcode = fr_value_box_cmp_op(map->op, &vp->data, box);
if (rcode < 0) return -1;
if (rcode == 0) {
- if (fr_value_box_copy(vp, &vp->data, tmpl_value(map->rhs)) < 0) {
+ if (fr_value_box_copy(vp, &vp->data, box) < 0) {
return -1;
}
}
* Setup the reply items.
*/
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_presence = TMPL_ATTR_LIST_REQUIRE;
+
reply_item:
/*
* Reply items start with spaces. If there's no
}
/*
- * RHS can be NULL if it's a structural type.
+ * We no longer really care what the RHS is, or what the list is on the LHS. The caller
+ * takes care of checking that for us.
*/
- if (new_map->rhs) {
- 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 reply item",
- file, lineno, new_map->rhs->name);
- goto fail_entry;
- }
- }
-
- fr_assert(tmpl_list(new_map->lhs) == request_attr_reply);
if (!new_map->parent) map_list_insert_tail(&t->reply, new_map);
return -1;
}
+ if (tmpl_list(map->rhs) != request_attr_reply) {
+ ERROR("%s[%d] Left side of filter %s is not in the reply list",
+ filename, entry->lineno, map->lhs->name);
+ return -1;
+ }
+
/*
* Make sure that bad things don't happen.
*/
*/
if ((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)) {
fr_assert(tmpl_is_regex(map->rhs));
-
- /*
- * Disallow inter-attribute comparisons.
- */
- } else 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;
}
/*
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 -1;
}
+ /*
+ * Regex assignments aren't allowed.
+ *
+ * Execs are being deprecated.
+ */
+ if (tmpl_contains_regex(map->rhs) || tmpl_is_exec(map->rhs)) {
+ ERROR("%s[%d] Invalid right-hand side of assignment for attribute %s",
+ entry->filename, entry->lineno, da->name);
+ return -1;
+ }
+
/*
* Check for Fall-Through in the reply list. If so, delete it and set the flag
* in the entry.
--- /dev/null
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = "attrref"
+User-Password = "hopefully"
+Filter-Id = "hello"
+
+#
+# Expected answer
+#
+Packet-Type == Access-Accept
+Reply-Message == 'hello'
--- /dev/null
+#
+# Test inter-attribute comparisons
+#
+files
+
+#
+# The "reply" items can now update any list.
+#
+if (&control.Filter-Id != "foo") {
+ test_fail
+}
Cisco.AVPair := "1",
Cisco.AVPair += "2"
+#
+# Compare attribute references
+#
+attrref Password.Cleartext := "hopefully"
+ Reply-Message := &request.Filter-Id,
+ &control.Filter-Id := "foo"
+
DEFAULT User-Name == "cmp_eq", Password.Cleartext := "hopping"
Reply-Message := "success-cmp_eq"