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;
#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.
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);
done_init = false;
}
-
/** Return whether or not async is required for this xlat.
*
* If the xlat is needs_async, then it MAY yield
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;
-}
types.c \
udp.c \
udpfromto.c \
+ uri.c \
value.c \
version.c
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
#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"
/** 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;
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 },
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);
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
*/