]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
enable expressions in attribute array indexes
authorAlan T. DeKok <aland@freeradius.org>
Mon, 2 Sep 2024 21:33:49 +0000 (17:33 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 2 Sep 2024 21:38:58 +0000 (17:38 -0400)
alonw with test and documentation

doc/antora/modules/reference/pages/unlang/attr.adoc
src/lib/server/tmpl_dcursor.c
src/tests/keywords/attr-index-expr [new file with mode: 0644]

index bb6080fef1d2977bf31b70d59a0abf70f1669165..ca3e06e93d3a621dc7a6148d26692961716a0e8f 100644 (file)
@@ -51,7 +51,7 @@ you to address the attributes as if they were array entries.  The
 refers to the first attributes, `[1]` refers to the second attribute,
 etc.
 
-The `<index>` can be an integer (0..1000), as in the example below.
+The `<index>` can be an integer (0..1000).
 
 The indexes are limited to 1000, because there are essentially no
 protocols which have more than 1000 attributes.
@@ -63,7 +63,15 @@ protocols which have more than 1000 attributes.
 &reply.NAS-IP-Address[2]
 ----
 
-The `<index>` can also be a reference to a numerical attribute, as in the example below.
+The `<index>` can also be a special value `n`, which means "the last attribute in the list.
+
+.Last attribute in a list
+[source,unlang]
+----
+&EAP-Message[n]
+----
+
+The `<index>` can also be a reference to a numerical attribute.
 
 The reference *must* be to an attribute of numerical data type.  Structural data types and `string` or `octets` types are not allowed.  If the index is out of bounds (e.g. negative), then the reference fails.
 
@@ -79,12 +87,18 @@ uint32 foo
 &EAP-Message[&foo]
 ----
 
-The `<index>` can also be a special value `n`, which means "the last attribute in the list.
+The `<index>` can also be an expression which is calculated at run time.  The expression _must_ not cause the server to call an external database, script, etc.  The main purpose of these expressions is to calculated an index without first placing it into another attribute.
 
-.Last attribute in a list
+If the index must be calculated from an external database call or script, simply place that value into an attribute first, and then use that attribute as in index.
+
+The expression _must_ be in an expansion block: `%{...}`.
+
+.Expression as an Array index
 [source,unlang]
 ----
-&EAP-Message[n]
+&index = 0
+
+&EAP-Message[%{&index + 1}]
 ----
 
 === Array References in lists
index 18f1d13d7a1629c94a1b286a599276c2da47f1d5..375e55b909f0e4ca8cc1f8373e5ea6e02c838c4a 100644 (file)
@@ -175,6 +175,19 @@ fr_pair_t *_tmpl_cursor_eval(fr_pair_t *curr, tmpl_dcursor_ctx_t *cc)
        if (ar_filter_is_none(ar)) {
                num = 0;
 
+       } else if (ar_filter_is_expr(ar)) {
+               fr_value_box_t box;
+               request_t *request = cc->request;
+
+               if (unlang_xlat_eval_type(request, &box, FR_TYPE_UINT8, NULL, request, ar->ar_expr) < 0) {
+                       RPEDEBUG("Failed evaluating expression");
+                       vp = NULL;
+                       pop = true;
+                       goto done;
+               }
+
+               num = box.vb_uint8;
+
        } else if (!ar_filter_is_num(ar)) {
                request_t *request = cc->request;
 
diff --git a/src/tests/keywords/attr-index-expr b/src/tests/keywords/attr-index-expr
new file mode 100644 (file)
index 0000000..c7e883c
--- /dev/null
@@ -0,0 +1,29 @@
+#
+#  PRE: attr-index
+#
+#  Tests for using attribute references as array index
+#
+uint32 index
+
+&request += {
+       &Class = 0x01020304,
+       &Class = 0x05060708,
+       &Class = 0x090a0b0c,
+}
+
+#
+#  Computed indexes, with some limitations
+#
+&index := 1
+
+if (&Class[%{&index - 1}] != 0x01020304) {
+       test_fail
+}
+
+&index := 4
+
+if (&Class[%{&index - 2}] != 0x090a0b0c) {
+       test_fail
+}
+
+success