]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
the files module now supports "undo" for failed operations
authorAlan T. DeKok <aland@freeradius.org>
Sun, 24 Dec 2023 17:04:59 +0000 (12:04 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 24 Dec 2023 17:04:59 +0000 (12:04 -0500)
src/lib/server/pairmove.c
src/lib/server/pairmove.h
src/lib/util/value.c
src/modules/rlm_exec/rlm_exec.c
src/modules/rlm_files/rlm_files.c
src/modules/rlm_sql/rlm_sql.c
src/tests/modules/files/authorize
src/tests/modules/files/undo.attrs [new file with mode: 0644]
src/tests/modules/files/undo.unlang [new file with mode: 0644]

index a1bc1da709211733d62ff381daf6a99492e6192f..c2467c04303665a519c0534669cd790fea77e371 100644 (file)
@@ -504,7 +504,7 @@ static fr_pair_t *legacy_pair_build(fr_pair_t *parent, fr_dcursor_t *cursor, fr_
 /** Move a map using the operators from the old pairmove functionality.
  *
  */
-int radius_legacy_map_apply(request_t *request, map_t const *map)
+int radius_legacy_map_apply(request_t *request, map_t const *map, fr_edit_list_t *el)
 {
        int16_t                 num;
        int                     err, rcode;
@@ -515,7 +515,6 @@ int radius_legacy_map_apply(request_t *request, map_t const *map)
        TALLOC_CTX              *ctx;
        fr_value_box_t          *to_free = NULL;
        fr_value_box_t const    *box;
-       fr_edit_list_t          *el = NULL;
        tmpl_dcursor_ctx_t      cc;
        fr_dcursor_t            cursor;
 
@@ -770,7 +769,7 @@ int radius_legacy_map_apply(request_t *request, map_t const *map)
        return 0;
 }
 
-int radius_legacy_map_list_apply(request_t *request, map_list_t const *list)
+int radius_legacy_map_list_apply(request_t *request, map_list_t const *list, fr_edit_list_t *el)
 {
        map_t const *map;
 
@@ -780,7 +779,10 @@ int radius_legacy_map_list_apply(request_t *request, map_list_t const *list)
                RDEBUG2("&%s %s %s", map->lhs->name, fr_tokens[map->op],
                        map->rhs ? map->rhs->name : "{ ... }");
 
-               if (radius_legacy_map_apply(request, map) < 0) return -1;
+               if (radius_legacy_map_apply(request, map, el) < 0) {
+                       RPEDEBUG("Failed applying result");
+                       return -1;
+               }
        }
 
        return 0;
index d6b226b5046a50aac9d6b1b158e193ba4efbd0ae..17c1068defc9216ccf1a6dcf05d32d50b0f44111 100644 (file)
@@ -28,6 +28,7 @@ RCSIDH(pairmove_h, "$Id$")
 
 #include <freeradius-devel/server/request.h>
 #include <freeradius-devel/server/map.h>
+#include <freeradius-devel/util/edit.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -35,9 +36,9 @@ extern "C" {
 
 void   radius_pairmove(request_t *request, fr_pair_list_t *to, fr_pair_list_t *from) CC_HINT(nonnull);
 
-int    radius_legacy_map_apply(request_t *request, map_t const *map) CC_HINT(nonnull);
+int    radius_legacy_map_apply(request_t *request, map_t const *map, fr_edit_list_t *el) CC_HINT(nonnull(1,2));
 
-int    radius_legacy_map_list_apply(request_t *request, map_list_t const *list) CC_HINT(nonnull);
+int    radius_legacy_map_list_apply(request_t *request, map_list_t const *list, fr_edit_list_t *el) CC_HINT(nonnull(1,2));
 
 int    radius_legacy_map_cmp(request_t *request, map_t const *map) CC_HINT(nonnull);
 
index fb8f5fb6b97d3ef91e7056bd3dcdf8888a78ac1e..eb6a36106b245519d244a91e246835da1569eb22 100644 (file)
@@ -545,22 +545,26 @@ fr_sbuff_parse_rules_t const value_parse_rules_bareword_quoted = {
 
 fr_sbuff_parse_rules_t const value_parse_rules_double_quoted = {
        .escapes = &fr_value_unescape_double,
-       .terminals = &FR_SBUFF_TERM("\"")
+       .terminals = &FR_SBUFF_TERMS(
+               L(""), L("\n"), L("\r"), L("\""))
 };
 
 fr_sbuff_parse_rules_t const value_parse_rules_single_quoted = {
        .escapes = &fr_value_unescape_single,
-       .terminals = &FR_SBUFF_TERM("'")
+       .terminals = &FR_SBUFF_TERMS(
+               L(""), L("\n"), L("\r"), L("'"))
 };
 
 fr_sbuff_parse_rules_t const value_parse_rules_solidus_quoted = {
        .escapes = &fr_value_unescape_solidus,
-       .terminals = &FR_SBUFF_TERM("/")
+       .terminals = &FR_SBUFF_TERMS(
+               L(""), L("\n"), L("\r"), L("/"))
 };
 
 fr_sbuff_parse_rules_t const value_parse_rules_backtick_quoted = {
        .escapes = &fr_value_unescape_backtick,
-       .terminals = &FR_SBUFF_TERM("`")
+       .terminals = &FR_SBUFF_TERMS(
+               L(""), L("\n"), L("\r"), L("`"))
 };
 
 /** Parse rules for quoted strings
index c2bb3feaec7e8c313d6d72f76613111ed342348d..33441a7b8933dad8ec1ae86eaffbc13c7d52bcfc 100644 (file)
@@ -342,7 +342,7 @@ static unlang_action_t mod_exec_oneshot_wait_resume(rlm_rcode_t *p_result, modul
                                RDEBUG("applying %s %s %s",
                                       map->lhs->name, fr_tokens[map->op], map->rhs->name);
 
-                               if (radius_legacy_map_apply(request, map) < 0) {
+                               if (radius_legacy_map_apply(request, map, NULL) < 0) {
                                        RPEDEBUG("Failed applying assignment");
 
                                        TALLOC_FREE(map);
index a392d38daca57101fad7d0241787b0f71a9b3491..90009e23581a6ee35ae651f6b4e0487eb8632fcc 100644 (file)
@@ -30,6 +30,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/users_file.h>
 #include <freeradius-devel/util/htrie.h>
 #include <freeradius-devel/unlang/call_env.h>
+#include <freeradius-devel/unlang/transaction.h>
 
 #include <ctype.h>
 #include <fcntl.h>
@@ -445,11 +446,15 @@ static unlang_action_t file_common(rlm_rcode_t *p_result, UNUSED rlm_files_t con
        PAIR_LIST_LIST          my_list;
        uint8_t                 key_buffer[16], *key;
        size_t                  keylen = 0;
+       fr_edit_list_t          *el, *child;
 
        if (!tree && !default_list) RETURN_MODULE_NOOP;
 
        RDEBUG2("Looking for key \"%pV\"", &env->key);
 
+       el = unlang_interpret_edit_list(request);
+       MEM(child = fr_edit_list_alloc(request, 50, el));
+
        if (tree) {
                my_list.name = NULL;
                my_list.box = &env->key;
@@ -535,7 +540,7 @@ redo:
                        case T_OP_SET:
                        case T_OP_ADD_EQ:
                                fr_assert(0);
-                               return -1;
+                               goto fail;
 
                                /*
                                 *      Evaluate the map, including regexes.
@@ -544,8 +549,9 @@ redo:
                                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;
+                               fail:
+                                       fr_edit_list_abort(child);
+                                       RETURN_MODULE_FAIL;
                                }
 
                                if (!rcode) {
@@ -564,9 +570,9 @@ redo:
                found = true;
 
                /* ctx may be reply */
-               if (radius_legacy_map_list_apply(request, &pl->reply) < 0) {
+               if (radius_legacy_map_list_apply(request, &pl->reply, child) < 0) {
                        RPWARN("Failed parsing reply item");
-                       RETURN_MODULE_FAIL;
+                       goto fail;
                }
 
                if (pl->fall_through) {
@@ -612,11 +618,13 @@ redo:
        /*
         *      See if we succeeded.
         */
-       if (!found)
+       if (!found) {
+               fr_edit_list_abort(child);
                RETURN_MODULE_NOOP; /* on to the next module */
+       }
 
+       fr_edit_list_commit(child);
        RETURN_MODULE_OK;
-
 }
 
 
index 18f39273550b20f7a61ef3a498ddf5019a56dcdd..b7b957c80d97eb925330fb24c5be220c7928de34 100644 (file)
@@ -978,7 +978,7 @@ static int sql_check_groupmemb(rlm_sql_t const *inst, request_t *request, rlm_sq
                RDEBUG2("Group \"%s\": Merging reply items", group_name);
                *rcode = RLM_MODULE_UPDATED;
 
-               if (radius_legacy_map_list_apply(request, &reply_tmp) < 0) {
+               if (radius_legacy_map_list_apply(request, &reply_tmp, NULL) < 0) {
                        RPEDEBUG("Failed applying reply item");
                        map_list_talloc_free(&reply_tmp);
                        return -1;
@@ -1428,7 +1428,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                RDEBUG2("User found in radreply table, merging reply items");
                user_found = true;
 
-               if (radius_legacy_map_list_apply(request, &reply_tmp) < 0) {
+               if (radius_legacy_map_list_apply(request, &reply_tmp, NULL) < 0) {
                        RPEDEBUG("Failed applying reply item");
                        map_list_talloc_free(&reply_tmp);
                        rcode = RLM_MODULE_FAIL;
index 7247c1967f003dca4f66747df9b68f4cce950d81..a115ca1f9e74cef2b6449e598e322ab3655ba1d9 100644 (file)
@@ -141,6 +141,21 @@ digest     Password.Cleartext := "woo"
 DEFAULT        User-Name == "cmp_eq",  Password.Cleartext := "hopping"
        Reply-Message := "success-cmp_eq"
 
+#
+#  Do something, and then undo it
+#
+undo   Password.Cleartext := "hello"
+       Reply-Message := "hello %{User-Name}",
+       Fall-Through := yes
+
+#
+#  This should fail, which means that the previous Reply-Message
+#  gets deleted as part of the "undo" operation.
+#
+undo
+       Framed-IP-Address := "this is not an IP address"
+
+
 $INCLUDE cmp
 
 DEFAULT        Password.Cleartext := "stuffnsuch"
diff --git a/src/tests/modules/files/undo.attrs b/src/tests/modules/files/undo.attrs
new file mode 100644 (file)
index 0000000..a3c6645
--- /dev/null
@@ -0,0 +1,12 @@
+#
+#  Input packet
+#
+Packet-Type = Access-Request
+User-Name = "undo"
+User-Password = "hello"
+NAS-IP-Address = 192.0.2.1
+
+#
+#  Expected answer
+#
+Packet-Type == Access-Accept
diff --git a/src/tests/modules/files/undo.unlang b/src/tests/modules/files/undo.unlang
new file mode 100644 (file)
index 0000000..ac7d33b
--- /dev/null
@@ -0,0 +1,11 @@
+try {
+       files
+}
+catch fail {
+       #
+       #  Make it accept, but the accept should be empty!
+       #  see undo.attrs
+       #
+       &control.Password.Cleartext := "hello"
+       ok
+}