]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add xlat_purify() function
authorAlan T. DeKok <aland@freeradius.org>
Thu, 19 May 2022 18:28:50 +0000 (14:28 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 19 May 2022 18:28:50 +0000 (14:28 -0400)
for now, it calls unlang_interpret_synchronous().  We'll fix
that later.

src/lib/unlang/all.mk
src/lib/unlang/xlat_priv.h
src/lib/unlang/xlat_purify.c [new file with mode: 0644]

index 11ff07fce2975b312e63d41478800c5b87b07027..4b60200183f2a6b5cb5fc8e04d42629919b7a74d 100644 (file)
@@ -28,7 +28,8 @@ SOURCES       :=      base.c \
                xlat_expr.c \
                xlat_inst.c \
                xlat_tokenize.c \
-               xlat_pair.c
+               xlat_pair.c \
+               xlat_purify.c
 
 HEADERS                := $(subst src/lib/,,$(wildcard src/lib/unlang/*.h))
 
index 4ce34148576c13ca3279ec7249fbb850d1c6c73e..9c70701e4470a3d2f66c94418c97ada146f26b79 100644 (file)
@@ -31,6 +31,7 @@ extern "C" {
 #endif
 
 #include <freeradius-devel/io/pair.h>
+#include <freeradius-devel/unlang/interpret.h>
 
 #ifdef DEBUG_XLAT
 #  define XLAT_DEBUG RDEBUG3
@@ -333,6 +334,10 @@ int                xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in,
 
 ssize_t                xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t const *node, fr_sbuff_escape_rules_t const *e_rules);
 
+/*
+ *     xlat_purify.c
+ */
+int            xlat_purify(xlat_exp_head_t *head, unlang_interpret_t *intp);
 
 
 static inline xlat_exp_t *xlat_exp_head(xlat_exp_head_t const *head)
diff --git a/src/lib/unlang/xlat_purify.c b/src/lib/unlang/xlat_purify.c
new file mode 100644 (file)
index 0000000..5e2c7c6
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file xlat_purify.c
+ * @brief Purification functions for xlats
+ *
+ * @copyright 2022 The FreeRADIUS server project
+ * @copyright 2022 Network RADIUS SAS (legal@networkradius.com)
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/server/base.h>
+#include <freeradius-devel/unlang/xlat_priv.h>
+
+static void xlat_value_list_to_xlat(xlat_exp_head_t *head, fr_value_box_list_t *list)
+{
+       fr_value_box_t *box;
+       xlat_exp_t *node;
+
+       while ((box = fr_dlist_pop_head(list)) != NULL) {
+               MEM(node = xlat_exp_alloc_null(head));
+               node->type = XLAT_BOX;
+               node->fmt = ""; /* @todo - fixme? */
+               fr_value_box_copy(node, &node->data, box);
+               talloc_free(box);
+
+               xlat_exp_insert_tail(head, node);
+       }
+}
+
+
+static int xlat_purify_list(xlat_exp_head_t *head, request_t *request)
+{
+       int rcode;
+       bool success;
+       xlat_exp_head_t *group;
+       fr_value_box_list_t list;
+
+       if (!head->flags.can_purify) return 0;
+
+       /*
+        *      We can't purify things which need resolving,
+        */
+       if (head->flags.needs_resolving) return -1;
+
+       xlat_exp_foreach(head, node) {
+               if (!node->flags.can_purify) continue;
+
+               switch (node->type) {
+               default:
+                       fr_strerror_printf("Internal error - cannot purify xlat");
+                       return -1;
+                       
+               case XLAT_GROUP:
+                       rcode = xlat_purify_list(node->group, request);
+                       if (rcode < 0) return rcode;
+
+                       xlat_flags_merge(&node->flags, &node->group->flags);
+                       break;
+
+
+               case XLAT_ALTERNATE:
+                       if (node->alternate[0]->flags.can_purify) {
+                               rcode = xlat_purify_list(node->alternate[0], request);
+                               if (rcode < 0) return rcode;
+                       }
+
+                       /*
+                        *      @todo - If the RHS of the alternation
+                        *      is now pure, then we can statically
+                        *      evaluate it, and replace this node
+                        *      with the children.  But only if the
+                        *      child list is not empty.
+                        */
+                       
+                       if (node->alternate[1]->flags.can_purify) {
+                               rcode = xlat_purify_list(node->alternate[1], request);
+                               if (rcode < 0) return rcode;
+                       }
+                       break;
+                       
+               case XLAT_FUNC:
+                       if (unlang_xlat_push_node(node->call.args, &success, &list, request, node) < 0) {
+                               return -1;
+                       }
+
+                       /*
+                        *      Hope to god it doesn't yield. :)
+                        */
+                       success = false;
+                       (void) unlang_interpret_synchronous(NULL, request);
+                       if (!success) return -1;
+
+                       /*
+                        *      The function call becomes a GROUP of
+                        *      boxes.  We just re-use the argument head, which is already of the type we need.
+                        */
+                       group = node->call.args;
+                       fr_dlist_talloc_free(&group->dlist);
+                       node->type = XLAT_GROUP;
+                       node->group = group;
+
+                       xlat_value_list_to_xlat(group, &list);
+                       break;
+               }
+
+               node->flags.can_purify = false;
+               xlat_flags_merge(&head->flags, &node->flags);
+       }
+
+       head->flags.can_purify = false;
+       return 0;
+}
+
+/**  Purify an xlat
+ *
+ *  @param head                the xlat to be purified
+ *  @param intp                the interpreter to use.
+ *
+ */
+int xlat_purify(xlat_exp_head_t *head, unlang_interpret_t *intp)
+{
+       int rcode;
+       request_t *request;
+
+       if (!head->flags.can_purify) return 0;
+
+       request = request_alloc_internal(NULL, (&(request_init_args_t){ .namespace = head->dict }));
+       if (!request) return -1;
+
+       if (intp) unlang_interpret_set(request, intp);
+
+       rcode = xlat_purify_list(head, request);
+       talloc_free(request);
+
+       return rcode;
+}