]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Pull URI escaping code into util library
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 19 Jul 2021 21:23:54 +0000 (16:23 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 19 Jul 2021 21:28:33 +0000 (16:28 -0500)
We'll likely need this for utilities at some point

src/lib/curl/base.h
src/lib/unlang/xlat.h
src/lib/unlang/xlat_eval.c
src/lib/util/libfreeradius-util.mk
src/lib/util/uri.c [new file with mode: 0644]
src/lib/util/uri.h [new file with mode: 0644]
src/modules/rlm_rest/rlm_rest.c

index 3d406eaf05f314edf2d6db762c5745e76aa9991e..4f2b01f447080105f85f0eaa9bc1d84884300356 100644 (file)
@@ -98,7 +98,7 @@ typedef struct {
 typedef struct {
        CURL                    *candle;                //!< Request specific handle.
        CURLcode                result;                 //!< Result of executing the request.
-       request_t                       *request;               //!< Current request.
+       request_t               *request;               //!< Current request.
        void                    *uctx;                  //!< Private data for the module using the API.
 } fr_curl_io_request_t;
 
index 4b3b3948e1dbe851e03554b4a05b9bcd381f892f..b6cdf4c60556471ccbd9269b39c29df72533233b 100644 (file)
@@ -126,21 +126,6 @@ typedef struct {
 #define XLAT_ARG_PARSER_TERMINATOR { .required = false, .concat = false, .single = false, .variadic = false, \
                                        .type = FR_TYPE_NULL, .func = NULL, .uctx = NULL }
 
-/** Definition for a single part of a URI
- *
- */
-typedef struct {
-       char const              *name;                          //!< Name of this part of the URI
-       fr_sbuff_term_t const   *terminals;                     //!< Characters that mark the end of this part.
-       uint8_t const           part_adv[UINT8_MAX + 1];        //!< How many parts to advance for a specific terminal
-       size_t                  extra_skip;                     //!< How many additional characters to skip after
-                                                               ///< the terminal
-       bool                    tainted_allowed;                //!< Do we accept tainted values for this part
-       xlat_escape_func_t      func;                           //!< Function to use to escape tainted values
-} xlat_uri_part_t;
-
-#define XLAT_URI_PART_TERMINATOR { .name = NULL, .terminals = NULL, .tainted_allowed = false, .func = NULL }
-
 /** A callback when the the timeout occurs
  *
  * Used when a xlat needs wait for an event.
@@ -343,8 +328,6 @@ int         xlat_eval_pair(request_t *request, fr_pair_t *vp);
 
 bool           xlat_async_required(xlat_exp_t const *xlat);
 
-int            xlat_parse_uri(request_t *request, fr_value_box_list_t *uri, xlat_uri_part_t const *uri_parts, void *uctx);
-
 ssize_t                xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags,
                                        fr_sbuff_t *in,
                                        fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules);
index 357f76363cb1e12536e5d27bc10959b0bccd6202..02c8bf9d6806ac6edbd3b5916fa85f7c07995f47 100644 (file)
@@ -2191,7 +2191,6 @@ void xlat_eval_free(void)
        done_init = false;
 }
 
-
 /** Return whether or not async is required for this xlat.
  *
  *     If the xlat is needs_async, then it MAY yield
@@ -2216,84 +2215,3 @@ bool xlat_async_required(xlat_exp_t const *xlat)
 
        return false;
 }
-
-
-/** Parse a list of value boxes representing a URI
- *
- * Reads a URI from a list of value boxes and parses it according to the
- * definition in uri_parts.  Tainted values, where allowed, are escaped
- * using the function specified for the uri part.
- *
- * @param request      currently being processed
- * @param uri          to parse
- * @param uri_parts    definition of URI structure
- * @param uctx         to pass to escaping function
- * @return
- *     - 0 on success
- *     - -1 on failure
- */
-int xlat_parse_uri(request_t *request, fr_value_box_list_t *uri, xlat_uri_part_t const *uri_parts, void *uctx)
-{
-       fr_value_box_t          *uri_vb = NULL;
-       xlat_uri_part_t const   *uri_part;
-       fr_sbuff_t              sbuff;
-       char const              *p;
-
-       uri_part = uri_parts;
-
-       while ((uri_vb = fr_dlist_next(uri, uri_vb))){
-               if (uri_vb->tainted && !uri_part->tainted_allowed) {
-                       REDEBUG("Tainted value not allowed for %s", uri_part->name);
-                       return -1;
-               }
-
-               /*
-                *      Tainted boxes can only belong to a single part of the URI
-                */
-               if (uri_vb->tainted) {
-                       if ((uri_part->func) && (uri_part->func(request, uri_vb, uctx) < 0)) {
-                               REDEBUG("Unable to escape tainted input %pV", uri_vb);
-                               return -1;
-                       }
-                       continue;
-               }
-
-               /*
-                *      This URI part has no term chars - so no need to look for them
-                */
-               if (!uri_part->terminals) continue;
-
-               /*
-                *      Zero length box - no terminators here
-                */
-               if (uri_vb->length == 0) continue;
-
-               /*
-                *      Look for URI part terminator
-                */
-               fr_sbuff_init(&sbuff, uri_vb->vb_strvalue, uri_vb->length);
-
-               do {
-                       fr_sbuff_adv_until(&sbuff, SIZE_MAX, uri_part->terminals, '\0');
-                       p = fr_sbuff_current(&sbuff);
-
-                       /*
-                        *      We've not found a terminal in the current box
-                        */
-                       if (uri_part->part_adv[(uint8_t)*p] == 0) continue;
-
-                       /*
-                        *      This terminator has trailing characters to skip
-                        */
-                       if (uri_part->extra_skip) fr_sbuff_advance(&sbuff, uri_part->extra_skip);
-
-                       /*
-                        *      Move to the next part
-                        */
-                       uri_part += uri_part->part_adv[(uint8_t)*p];
-                       if (!uri_part->terminals) break;
-               } while (fr_sbuff_advance(&sbuff, 1) > 0);
-       }
-
-       return 0;
-}
index a1cd4fff5e5444d4b0978ead95c913a589f71bcf..c9a193f48ca052a2ddb0125a74d5ad05da2ba12f 100644 (file)
@@ -79,6 +79,7 @@ SOURCES               := \
                   types.c \
                   udp.c \
                   udpfromto.c \
+                  uri.c \
                   value.c \
                   version.c
 
diff --git a/src/lib/util/uri.c b/src/lib/util/uri.c
new file mode 100644 (file)
index 0000000..48df1ff
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *   This library is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU Lesser General Public
+ *   License as published by the Free Software Foundation; either
+ *   version 2.1 of the License, or (at your option) any later version.
+ *
+ *   This library 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
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Functions for dealing with URIs
+ *
+ * @file src/lib/util/uri.c
+ *
+ * @copyright 2021 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include "uri.h"
+
+/** Parse a list of value boxes representing a URI
+ *
+ * Reads a URI from a list of value boxes and parses it according to the
+ * definition in uri_parts.  Tainted values, where allowed, are escaped
+ * using the function specified for the uri part.
+ *
+ * @param uri          to parse.  A list of string type value boxes containing
+ *                     fragments of a URI.
+ * @param uri_parts    definition of URI structure
+ * @param uctx         to pass to escaping function
+ * @return
+ *     - 0 on success
+ *     - -1 on failure
+ */
+int fr_uri_escape(fr_value_box_list_t *uri, fr_uri_part_t const *uri_parts, void *uctx)
+{
+       fr_value_box_t          *uri_vb = NULL;
+       fr_uri_part_t const     *uri_part;
+       fr_sbuff_t              sbuff;
+       char const              *p;
+
+       uri_part = uri_parts;
+
+       fr_strerror_clear();
+
+       while ((uri_vb = fr_dlist_next(uri, uri_vb))){
+               if (uri_vb->tainted && !uri_part->tainted_allowed) {
+                       fr_strerror_printf_push("Tainted value not allowed for %s", uri_part->name);
+                       return -1;
+               }
+
+               /*
+                *      Tainted boxes can only belong to a single part of the URI
+                */
+               if (uri_vb->tainted) {
+                       if ((uri_part->func) && (uri_part->func(uri_vb, uctx) < 0)) {
+                               fr_strerror_printf_push("Unable to escape tainted input %pV", uri_vb);
+                               return -1;
+                       }
+                       continue;
+               }
+
+               /*
+                *      This URI part has no term chars - so no need to look for them
+                */
+               if (!uri_part->terminals) continue;
+
+               /*
+                *      Zero length box - no terminators here
+                */
+               if (uri_vb->length == 0) continue;
+
+               /*
+                *      Look for URI part terminator
+                */
+               fr_sbuff_init(&sbuff, uri_vb->vb_strvalue, uri_vb->length);
+
+               do {
+                       fr_sbuff_adv_until(&sbuff, SIZE_MAX, uri_part->terminals, '\0');
+                       p = fr_sbuff_current(&sbuff);
+
+                       /*
+                        *      We've not found a terminal in the current box
+                        */
+                       if (uri_part->part_adv[(uint8_t)*p] == 0) continue;
+
+                       /*
+                        *      This terminator has trailing characters to skip
+                        */
+                       if (uri_part->extra_skip) fr_sbuff_advance(&sbuff, uri_part->extra_skip);
+
+                       /*
+                        *      Move to the next part
+                        */
+                       uri_part += uri_part->part_adv[(uint8_t)*p];
+                       if (!uri_part->terminals) break;
+               } while (fr_sbuff_advance(&sbuff, 1) > 0);
+       }
+
+       return 0;
+}
diff --git a/src/lib/util/uri.h b/src/lib/util/uri.h
new file mode 100644 (file)
index 0000000..e634d87
--- /dev/null
@@ -0,0 +1,62 @@
+#pragma once
+/*
+ *  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
+ */
+
+/** Functions for dealing with URIs
+ *
+ * @file src/lib/util/uri.c
+ *
+ * @copyright 2021 The FreeRADIUS server project
+ */
+RCSIDH(uri_h, "$Id$")
+
+#include <freeradius-devel/util/value.h>
+#include <freeradius-devel/util/sbuff.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** A function used to escape an argument passed to an xlat
+ *
+ * @param[in,out] vb           to escape
+ * @param[in] uctx             a "context" for the escaping
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+typedef int (*fr_uri_escape_func_t)(fr_value_box_t *vb, void *uctx);
+
+/** Definition for a single part of a URI
+ *
+ */
+typedef struct {
+       char const              *name;                          //!< Name of this part of the URI
+       fr_sbuff_term_t const   *terminals;                     //!< Characters that mark the end of this part.
+       uint8_t const           part_adv[UINT8_MAX + 1];        //!< How many parts to advance for a specific terminal
+       size_t                  extra_skip;                     //!< How many additional characters to skip after
+                                                               ///< the terminal
+       bool                    tainted_allowed;                //!< Do we accept tainted values for this part
+       fr_uri_escape_func_t    func;                           //!< Function to use to escape tainted values
+} fr_uri_part_t;
+
+#define XLAT_URI_PART_TERMINATOR { .name = NULL, .terminals = NULL, .tainted_allowed = false, .func = NULL }
+
+int fr_uri_escape(fr_value_box_list_t *uri, fr_uri_part_t const *uri_parts, void *uctx);
+
+#ifdef __cplusplus
+}
+#endif
index 20790d98d39dca176284cd87d4cf22212ff5de85..487f43b244ab8c3bde680897bcf8a58f8927cf8b 100644 (file)
@@ -27,10 +27,11 @@ RCSID("$Id$")
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/module.h>
 #include <freeradius-devel/server/pairmove.h>
-#include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/tls/base.h>
 #include <freeradius-devel/unlang/base.h>
+#include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/table.h>
+#include <freeradius-devel/util/uri.h>
 
 #include <ctype.h>
 #include "rest.h"
@@ -295,18 +296,18 @@ finish:
 
 /** URL escape a single box forming part of a URL
  *
- * @param request      being processed
- * @param vb           to escape
- * @param uctx         context containing CURL handle
+ * @param[in] vb               to escape
+ * @param[in] uctx             context containing CURL handle
  * @return
  *     - 0 on success
  *     - -1 on failure
  */
-static int uri_part_escape(request_t *request, fr_value_box_t *vb, void *uctx)
+static int uri_part_escape(fr_value_box_t *vb, void *uctx)
 {
        char                    *escaped;
        fr_curl_io_request_t    *randle = talloc_get_type_abort(uctx, fr_curl_io_request_t);
        fr_dlist_t              entry;
+       request_t               *request = randle->request;
 
        escaped = curl_easy_escape(randle->candle, vb->vb_strvalue, vb->length);
        if (!escaped) return -1;
@@ -337,7 +338,7 @@ static int uri_part_escape(request_t *request, fr_value_box_t *vb, void *uctx)
        return 0;
 }
 
-static xlat_uri_part_t const rest_uri_parts[] = {
+static fr_uri_part_t const rest_uri_parts[] = {
        { .name = "scheme", .terminals = &FR_SBUFF_TERMS(L(":")), .part_adv = { [':'] = 1 },
          .tainted_allowed = false, .extra_skip = 2 },
        { .name = "host", .terminals = &FR_SBUFF_TERMS(L(":"), L("/")), .part_adv = { [':'] = 1, ['/'] = 2 },
@@ -435,12 +436,9 @@ static xlat_action_t rest_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
 
        fr_assert(in_vb->type == FR_TYPE_GROUP);
 
-       if (xlat_parse_uri(request, &in_vb->vb_group, rest_uri_parts, randle) < 0) return XLAT_ACTION_FAIL;
+       if (fr_uri_escape(&in_vb->vb_group, rest_uri_parts, randle) < 0) {
+               RPEDEBUG("Failed escaping URI");
 
-       uri_vb = fr_dlist_head(&in_vb->vb_group);
-
-       if (fr_value_box_list_concat(uri_vb, uri_vb, &in_vb->vb_group, FR_TYPE_STRING, true) < 0) {
-               REDEBUG("Failed to concatenate URI");
        error:
                rest_request_cleanup(mod_inst, randle);
                fr_pool_connection_release(t->pool, request, randle);
@@ -449,6 +447,12 @@ static xlat_action_t rest_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
                return XLAT_ACTION_FAIL;
        }
 
+       uri_vb = fr_dlist_head(&in_vb->vb_group);
+       if (fr_value_box_list_concat(uri_vb, uri_vb, &in_vb->vb_group, FR_TYPE_STRING, true) < 0) {
+               REDEBUG("Concatenating URI");
+               goto error;
+       }
+
        /*
         *      Any additional arguments are freeform data
         */