]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add undocumented immutable xlat, and test based on it
authorAlan T. DeKok <aland@freeradius.org>
Sun, 20 Aug 2023 15:33:40 +0000 (11:33 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 20 Aug 2023 15:33:40 +0000 (11:33 -0400)
src/lib/unlang/xlat_builtin.c
src/tests/keywords/immutable [new file with mode: 0644]

index b1ee8fb8d95b1e658c1db3cc57fc135aa393a020..a4384d46d7cca8ad634cf920dfa597961a26cfb0 100644 (file)
@@ -534,6 +534,64 @@ static xlat_action_t xlat_func_explode(TALLOC_CTX *ctx, fr_dcursor_t *out,
        return XLAT_ACTION_DONE;
 }
 
+static xlat_arg_parser_t const xlat_func_immutable_attr_args[] = {
+       { .required = true, .single = true, .type = FR_TYPE_STRING },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
+/** Mark one or more attributes as immutable
+ *
+ * Example:
+@verbatim
+"%(immutable:&request.State[*])"
+@endverbatim
+ *
+ * @ingroup xlat_functions
+ */
+static xlat_action_t xlat_func_immutable_attr(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
+                                         UNUSED xlat_ctx_t const *xctx,
+                                         request_t *request, fr_value_box_list_t *args)
+{
+       fr_pair_t               *vp;
+       fr_dcursor_t            cursor;
+       tmpl_dcursor_ctx_t      cc;
+       tmpl_t                  *vpt;
+       fr_value_box_t          *attr;
+       char const              *fmt;
+
+       XLAT_ARGS(args, &attr);
+
+       fmt = attr->vb_strvalue;
+
+       if (tmpl_afrom_attr_str(request, NULL, &vpt, fmt,
+                               &(tmpl_rules_t){
+                                       .attr = {
+                                               .dict_def = request->dict,
+                                               .list_def = request_attr_request,
+                                               .allow_wildcard = true,
+                                               .prefix = TMPL_ATTR_REF_PREFIX_AUTO
+                                       }
+                               }) <= 0) {
+               RPEDEBUG("Invalid input");
+               return XLAT_ACTION_FAIL;
+       }
+
+       RIDEBUG("Attributes matching \"%s\"", fmt);
+
+       RINDENT();
+       for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
+            vp;
+            vp = fr_dcursor_next(&cursor)) {
+               if (fr_type_is_leaf(vp->vp_type)) fr_value_box_set_immutable(&vp->data);
+       }
+       tmpl_dcursor_clear(&cc);
+       REXDENT();
+
+       talloc_free(vpt);
+
+       return XLAT_ACTION_DONE;
+}
+
 static xlat_arg_parser_t const xlat_func_integer_args[] = {
        { .required = true, .single = true, .type = FR_TYPE_VOID },
        XLAT_ARG_PARSER_TERMINATOR
@@ -3328,6 +3386,7 @@ do { \
 
        XLAT_REGISTER_ARGS("debug", xlat_func_debug, FR_TYPE_INT8, xlat_func_debug_args);
        XLAT_REGISTER_ARGS("debug_attr", xlat_func_debug_attr, FR_TYPE_NULL, xlat_func_debug_attr_args);
+       XLAT_REGISTER_ARGS("immutable", xlat_func_immutable_attr, FR_TYPE_NULL, xlat_func_immutable_attr_args);
        XLAT_REGISTER_ARGS("nexttime", xlat_func_next_time, FR_TYPE_UINT64, xlat_func_next_time_args);
        XLAT_REGISTER_ARGS("pairs", xlat_func_pairs, FR_TYPE_STRING, xlat_func_pairs_args);
        XLAT_REGISTER_ARGS("subst", xlat_func_subst, FR_TYPE_STRING, xlat_func_subst_args);
diff --git a/src/tests/keywords/immutable b/src/tests/keywords/immutable
new file mode 100644 (file)
index 0000000..8f5af3c
--- /dev/null
@@ -0,0 +1,42 @@
+#
+#  Tests for immutable values.
+#
+#  They can't be modified or deleted.
+#
+&NAS-Port := 1812
+
+#
+#  Editing it is fine.
+#
+&NAS-Port += 1
+if !(&NAS-Port == 1813) {
+       test_fail
+}
+
+#
+#  Mark it as immutable.  The value shouldn't change.
+#
+%(immutable:&request.NAS-Port[*])
+if !(&NAS-Port == 1813) {
+       test_fail
+}
+
+#
+#  Try to edit it.  The value shouldn't change.
+#
+#  @todo - we don't have run-time exceptions... maybe this should return "fail"?
+#
+&NAS-Port += 1
+if !(&NAS-Port == 1813) {
+       test_fail
+}
+
+#
+#  We can't delete it.  Deletion is a noop
+#
+&request -= &NAS-Port[*]
+if !(&NAS-Port == 1813) {
+       test_fail
+}
+
+success