]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add safe for functions for ldap and rest
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 17 Feb 2024 22:59:15 +0000 (16:59 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 17 Feb 2024 23:33:53 +0000 (17:33 -0600)
Just use uri.escape and uri.unescape for all CURL based modules

14 files changed:
doc/antora/modules/raddb/pages/mods-available/ldap.adoc
raddb/mods-available/ldap
src/lib/curl/base.c
src/lib/curl/xlat.c
src/lib/curl/xlat.h
src/lib/ldap/base.h
src/lib/ldap/util.c
src/lib/unlang/xlat.h
src/lib/unlang/xlat_builtin.c
src/modules/rlm_ldap/groups.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_rest/rlm_rest.c
src/tests/modules/ldap/xlat.unlang
src/tests/modules/rest/rest_xlat.unlang

index 1fc1b45ce69b4c87dd996c15c3b6b80cce82b82a..95d28b19ce365afb67c84e1ca44ae62b13c4ef27 100644 (file)
@@ -744,7 +744,7 @@ binds which there can be on a single thread.
 
 The rlm_ldap provides the below xlat's functions.
 
-### %ldap.escape(...}
+### %ldap.uri.escape(...}
 
 Escape a string for use in an LDAP filter or DN.
 
@@ -755,7 +755,7 @@ Escape a string for use in an LDAP filter or DN.
 [source,unlang]
 ----
 &my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
-&reply.Reply-Message := "The LDAP url is %ldap.escape(%{my-string}}"
+&reply.Reply-Message := "The LDAP url is %ldap.uri.escape(%{my-string}}"
 ----
 
 .Output
@@ -764,7 +764,7 @@ Escape a string for use in an LDAP filter or DN.
 "The LDAP url is ldap:///ou=profiles,dc=example,dc=com??sub?\28objectClass=radiusprofile\29"
 ```
 
-### %ldap.unescape(...)
+### %ldap.uri.unescape(...)
 
 Unescape a string for use in an LDAP filter or DN.
 
@@ -775,7 +775,7 @@ Unescape a string for use in an LDAP filter or DN.
 [source,unlang]
 ----
 &my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?\28objectClass=radiusprofile\29"
-&reply.Reply-Message := "The LDAP url is %ldap.unescape(%{my-string})"
+&reply.Reply-Message := "The LDAP url is %ldap.uri.unescape(%{my-string})"
 ----
 
 .Output
index ec45c5cfe9ada39ffd05727bb6ff851ae4fb611b..76ffbe57603104abc7c561d584ba557f33f48f0e 100644 (file)
@@ -884,9 +884,10 @@ ldap {
 #
 #  The rlm_ldap provides the below xlat's functions.
 #
-#  ### %ldap.escape(...}
+#  ### %ldap.uri.escape(...}
 #
-#  Escape a string for use in an LDAP filter or DN.
+#  Escape a string for use in an LDAP filter or DN.  The value will then be marked as safe for use
+#  in LDAP URIs and DNs, and will not be escaped or modified.
 #
 #  .Return: _string_
 #
@@ -895,7 +896,7 @@ ldap {
 #  [source,unlang]
 #  ----
 #  &my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
-#  &reply.Reply-Message := "The LDAP url is %ldap.escape(%{my-string}}"
+#  &reply.Reply-Message := "The LDAP url is %ldap.uri.escape(%{my-string}}"
 #  ----
 #
 #  .Output
@@ -904,7 +905,22 @@ ldap {
 #  "The LDAP url is ldap:///ou=profiles,dc=example,dc=com??sub?\28objectClass=radiusprofile\29"
 #  ```
 #
-#  ### %ldap.unescape(...)
+#  ### %ldap.uri.safe(...}
+#
+#  Mark a string as safe for use in an LDAP filter or DN.  Values marked as safe for use in LDAP
+#  URIs will not be escaped or modified, and will be allowed in places where dynamic values are
+#  usually prohibited.
+#
+#  .Return: _string_
+#
+#  .Example
+#
+#  [source,unlang]
+#  ----
+#  &my-int := "%ldap.profile(ldap://%ldap.uri.safe(%{LDAP-Host}):%ldap.uri.safe(%{LDAP-Port})/ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
+#  ----
+#
+#  ### %ldap.uri.unescape(...)
 #
 #  Unescape a string for use in an LDAP filter or DN.
 #
@@ -915,7 +931,7 @@ ldap {
 #  [source,unlang]
 #  ----
 #  &my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?\28objectClass=radiusprofile\29"
-#  &reply.Reply-Message := "The LDAP url is %ldap.unescape(%{my-string})"
+#  &reply.Reply-Message := "The LDAP url is %ldap.uri.unescape(%{my-string})"
 #  ----
 #
 #  .Output
index fc23f0066f6d414f8bceb4b8aecf2512f1b2a0a6..7428ff6b3783cd24315d43c52ce8bfa0bea90d82 100644 (file)
@@ -265,6 +265,7 @@ static int fr_curl_init(void)
        ret = curl_global_init(CURL_GLOBAL_ALL);
        if (ret != CURLE_OK) {
                ERROR("CURL init returned error: %i - %s", ret, curl_easy_strerror(ret));
+       error:
                fr_dict_autofree(curl_dict);
                return -1;
        }
@@ -277,6 +278,47 @@ static int fr_curl_init(void)
 
        INFO("libcurl version: %s", curl_version());
 
+       {
+               xlat_t *xlat;
+
+               /*
+                *      Generic escape function for all CURL based modules
+                *      Use CURL_URI_SAFE_FOR within the module.
+                */
+               xlat = xlat_func_register(NULL, "uri.escape", fr_curl_xlat_uri_escape, FR_TYPE_STRING);
+               if (unlikely(!xlat)) {
+                       ERROR("Failed registering \"uri.escape\" xlat");
+                       goto error;
+               }
+               xlat_func_args_set(xlat, fr_curl_xlat_uri_args);
+               xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE);
+               xlat_func_safe_for_set(xlat, CURL_URI_SAFE_FOR);
+
+               /*
+                *      Generic safe function for all CURL based modules
+                *      Use CURL_URI_SAFE_FOR within the module.
+                */
+               xlat = xlat_func_register(NULL, "uri.safe", xlat_transparent, FR_TYPE_STRING);
+               if (unlikely(!xlat)) {
+                       ERROR("Failed registering \"uri.safe\" xlat");
+                       goto error;
+               }
+               xlat_func_args_set(xlat, fr_curl_xlat_safe_args);
+               xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE);
+               xlat_func_safe_for_set(xlat, CURL_URI_SAFE_FOR);
+
+               /*
+                *      Generic unescape function for all CURL based modules
+                */
+               xlat = xlat_func_register(NULL, "uri.unescape", fr_curl_xlat_uri_unescape, FR_TYPE_STRING);
+               if (unlikely(!xlat)) {
+                       ERROR("Failed registering \"uri.unescape\" xlat");
+                       goto error;
+               }
+               xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE);
+               xlat_func_args_set(xlat, fr_curl_xlat_uri_args);
+       }
+
        return 0;
 }
 
@@ -288,6 +330,10 @@ static void fr_curl_free(void)
        fr_openssl_free();
 #endif
        curl_global_cleanup();
+
+       xlat_func_unregister("uri.escape");
+       xlat_func_unregister("uri.safe");
+       xlat_func_unregister("uri.unescape");
 }
 
 /*
index b31ce06f3561ed1065a82f509bc956c0592f00c2..99fcba1fbc2de4196c4eac9f1e08ecacfc144447 100644 (file)
@@ -36,6 +36,11 @@ xlat_arg_parser_t const fr_curl_xlat_uri_args[] = {
        XLAT_ARG_PARSER_TERMINATOR
 };
 
+xlat_arg_parser_t const fr_curl_xlat_safe_args[] = {
+       { .required = true, .concat = true, .type = FR_TYPE_STRING },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
 /** xlat function to escape URI encoded strings
  *
  */
index b08a2abbc8b8a5d212060a83008e8185d6bc2c3e..75e6ea3cce20a84cd339cc3b43b8eb1e03b27a54 100644 (file)
@@ -30,7 +30,13 @@ extern "C" {
 #include <curl/curl.h>
 #include <freeradius-devel/unlang/xlat.h>
 
+/** safe for value suitable for all users of the curl library
+ *
+ */
+#define CURL_URI_SAFE_FOR ((fr_value_box_safe_for_t)fr_curl_xlat_uri_escape)
+
 extern xlat_arg_parser_t const fr_curl_xlat_uri_args[];
+extern xlat_arg_parser_t const fr_curl_xlat_safe_args[];
 
 xlat_action_t          fr_curl_xlat_uri_escape(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
                                                UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request,
index 8e346e14432fca79fff7265b820c44d54144e3cc..5b31227464be2161dd399ac5eead7413caf115a8 100644 (file)
@@ -754,10 +754,10 @@ unlang_action_t fr_ldap_trunk_extended(TALLOC_CTX *ctx,
 void           fr_ldap_timeout_debug(request_t *request, fr_ldap_connection_t const *conn,
                                      fr_time_delta_t timeout, char const *prefix);
 
-size_t         fr_ldap_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+size_t         fr_ldap_uri_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
                CC_HINT(nonnull(2,4));
 
-size_t         fr_ldap_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+size_t         fr_ldap_uri_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
                CC_HINT(nonnull(2,4));
 
 ssize_t                fr_ldap_xlat_filter(request_t *request, char const **sub, size_t sublen, char *out, size_t outlen);
index 17e43704ef8571afb63917edfb5a236487b6ea4b..963b0b6cf4283f1c321421967d63f29a832ed1e0 100644 (file)
@@ -67,7 +67,7 @@ static const bool escapes[UINT8_MAX + 1] = {
  * @param in Raw unescaped string.
  * @param arg Any additional arguments (unused).
  */
-size_t fr_ldap_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+size_t fr_ldap_uri_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
 {
        size_t left = outlen;
 
@@ -122,7 +122,7 @@ size_t fr_ldap_escape_func(UNUSED request_t *request, char *out, size_t outlen,
  * @param in Escaped string string.
  * @param arg Any additional arguments (unused).
  */
-size_t fr_ldap_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+size_t fr_ldap_uri_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
 {
        char const *p;
        char *c1, *c2, c3;
@@ -532,7 +532,7 @@ ssize_t fr_ldap_xlat_filter(request_t *request, char const **sub, size_t sublen,
                in = buffer;
        }
 
-       len = xlat_eval(out, outlen, request, in, fr_ldap_escape_func, NULL);
+       len = xlat_eval(out, outlen, request, in, fr_ldap_uri_escape_func, NULL);
        if (len < 0) {
                REDEBUG("Failed creating filter");
 
index a59317cacb922c376aaa37bfa8c6e6f0690ef1fd..729592a2773f02d8ea8291e2db9f43968eb4c195 100644 (file)
@@ -427,6 +427,10 @@ int                xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules);
 
 void           xlat_debug_attr_list(request_t *request, fr_pair_list_t const *list);
 void           xlat_debug_attr_vp(request_t *request, fr_pair_t *vp, tmpl_t const *vpt);
+
+xlat_action_t  xlat_transparent(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out,
+                                UNUSED xlat_ctx_t const *xctx,
+                                request_t *request, fr_value_box_list_t *args);
 /*
  *     xlat_tokenize.c
  */
index 677570e0bf5217abdffd680058c5c77ec16fa5ef..206830590df44c060f852ef5e867fe55a5246df8 100644 (file)
@@ -255,6 +255,24 @@ void xlat_debug_attr_list(request_t *request, fr_pair_list_t const *list)
        }
 }
 
+/** Common function to move boxes form input list to output list
+ *
+ * This can be used to implement safe_for functions, as the xlat framework
+ * can be used for concatenation, casting, and marking up output boxes as
+ * safe_for.
+ */
+xlat_action_t xlat_transparent(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out,
+                              UNUSED xlat_ctx_t const *xctx,
+                              UNUSED request_t *request, fr_value_box_list_t *args)
+{
+       fr_value_box_list_foreach_safe(args, vb) {
+               fr_value_box_list_remove(args, vb);
+               fr_dcursor_append(out, vb);
+       }}
+
+       return XLAT_ACTION_DONE;
+}
+
 /** Print out attribute info
  *
  * Prints out all instances of a current attribute, or all attributes in a list.
index e83235132bd8e50f2b35a957bcb4a6952d15b486..2f342e1a86b49077515ba7adaf1bc9b7ba3c4931 100644 (file)
@@ -137,7 +137,7 @@ static unlang_action_t ldap_group_name2dn_start(rlm_rcode_t *p_result, UNUSED in
                                 inst->groupobj_filter ? inst->groupobj_filter : "",
                                 group_ctx->group_name[0] && group_ctx->group_name[1] ? "(|" : "");
        while (*name) {
-               fr_ldap_escape_func(request, buffer, sizeof(buffer), *name++, NULL);
+               fr_ldap_uri_escape_func(request, buffer, sizeof(buffer), *name++, NULL);
                filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->groupobj_name_attr, buffer);
 
                group_ctx->name_cnt++;
index bdf3881d697871cecfd9089af4f7178b71d09e43..81286197801346b04a92cb850b3afc4a39984915 100644 (file)
@@ -363,20 +363,25 @@ static size_t ldap_uri_scheme_table_len = NUM_ELEMENTS(ldap_uri_scheme_table);
 
 /** This is the common function that actually ends up doing all the URI escaping
  */
-#define LDAP_URI_SAFE_FOR (fr_value_box_safe_for_t)fr_ldap_escape_func
+#define LDAP_URI_SAFE_FOR (fr_value_box_safe_for_t)fr_ldap_uri_escape_func
 
-static xlat_arg_parser_t const ldap_escape_xlat_arg[] = {
+static xlat_arg_parser_t const ldap_uri_escape_xlat_arg[] = {
        { .required = true, .concat = true, .type = FR_TYPE_STRING, .safe_for = LDAP_URI_SAFE_FOR },
        XLAT_ARG_PARSER_TERMINATOR
 };
 
+static xlat_arg_parser_t const ldap_safe_xlat_arg[] = {
+       { .required = true, .concat = true, .type = FR_TYPE_STRING },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
 /** Escape LDAP string
  *
  * @ingroup xlat_functions
  */
-static xlat_action_t ldap_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
-                                     UNUSED xlat_ctx_t const *xctx,
-                                     request_t *request, fr_value_box_list_t *in)
+static xlat_action_t ldap_uri_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
+                                         UNUSED xlat_ctx_t const *xctx,
+                                         request_t *request, fr_value_box_list_t *in)
 {
        fr_value_box_t          *vb, *in_vb = fr_value_box_list_head(in);
        fr_sbuff_t              sbuff;
@@ -388,7 +393,7 @@ static xlat_action_t ldap_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
        /*
         *      If it's already safe, just copy it over.
         */
-       if (fr_value_box_is_safe_for(in_vb, ldap_escape_xlat)) {
+       if (fr_value_box_is_safe_for(in_vb, LDAP_URI_SAFE_FOR)) {
                fr_value_box_copy(vb, vb, in_vb);
 
                fr_dcursor_append(out, vb);
@@ -408,7 +413,7 @@ static xlat_action_t ldap_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
        /*
         *      Call the escape function, including the space for the trailing NULL
         */
-       len = fr_ldap_escape_func(request, fr_sbuff_buff(&sbuff), in_vb->vb_length * 3 + 1, in_vb->vb_strvalue, NULL);
+       len = fr_ldap_uri_escape_func(request, fr_sbuff_buff(&sbuff), in_vb->vb_length * 3 + 1, in_vb->vb_strvalue, NULL);
 
        /*
         *      Trim buffer to fit used space and assign to box
@@ -420,13 +425,18 @@ static xlat_action_t ldap_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
        return XLAT_ACTION_DONE;
 }
 
+static xlat_arg_parser_t const ldap_uri_unescape_xlat_arg[] = {
+       { .required = true, .concat = true, .type = FR_TYPE_STRING },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
 /** Unescape LDAP string
  *
  * @ingroup xlat_functions
  */
-static xlat_action_t ldap_unescape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
-                                       UNUSED xlat_ctx_t const *xctx,
-                                       request_t *request, fr_value_box_list_t *in)
+static xlat_action_t ldap_uri_unescape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
+                                           UNUSED xlat_ctx_t const *xctx,
+                                           request_t *request, fr_value_box_list_t *in)
 {
        fr_value_box_t          *vb, *in_vb = fr_value_box_list_head(in);
        fr_sbuff_t              sbuff;
@@ -446,7 +456,7 @@ static xlat_action_t ldap_unescape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
        /*
         *      Call the unescape function, including the space for the trailing NULL
         */
-       len = fr_ldap_unescape_func(request, fr_sbuff_buff(&sbuff), in_vb->vb_length + 1, in_vb->vb_strvalue, NULL);
+       len = fr_ldap_uri_unescape_func(request, fr_sbuff_buff(&sbuff), in_vb->vb_length + 1, in_vb->vb_strvalue, NULL);
 
        /*
         *      Trim buffer to fit used space and assign to box
@@ -479,7 +489,7 @@ static int ldap_uri_part_escape(fr_value_box_t *vb, UNUSED void *uctx)
        /*
         *      Call the escape function, including the space for the trailing NULL
         */
-       len = fr_ldap_escape_func(NULL, fr_sbuff_buff(&sbuff), vb->vb_length * 3 + 1, vb->vb_strvalue, NULL);
+       len = fr_ldap_uri_escape_func(NULL, fr_sbuff_buff(&sbuff), vb->vb_length * 3 + 1, vb->vb_strvalue, NULL);
 
        fr_sbuff_trim_talloc(&sbuff, len);
        fr_value_box_clear_value(vb);
@@ -2593,13 +2603,18 @@ static int mod_load(void)
 {
        xlat_t  *xlat;
 
-       if (unlikely(!(xlat = xlat_func_register(NULL, "ldap.escape", ldap_escape_xlat, FR_TYPE_STRING)))) return -1;
-       xlat_func_mono_set(xlat, ldap_escape_xlat_arg);
+       if (unlikely(!(xlat = xlat_func_register(NULL, "ldap.uri.escape", ldap_uri_escape_xlat, FR_TYPE_STRING)))) return -1;
+       xlat_func_mono_set(xlat, ldap_uri_escape_xlat_arg);
        xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE);
        xlat_func_safe_for_set(xlat, LDAP_URI_SAFE_FOR);        /* Used for all LDAP escaping */
 
-       if (unlikely(!(xlat = xlat_func_register(NULL, "ldap.unescape", ldap_unescape_xlat, FR_TYPE_STRING)))) return -1;
-       xlat_func_mono_set(xlat, ldap_escape_xlat_arg);
+       if (unlikely(!(xlat = xlat_func_register(NULL, "ldap.uri.safe", xlat_transparent, FR_TYPE_STRING)))) return -1;
+       xlat_func_args_set(xlat, ldap_safe_xlat_arg);
+       xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE);
+       xlat_func_safe_for_set(xlat, LDAP_URI_SAFE_FOR);
+
+       if (unlikely(!(xlat = xlat_func_register(NULL, "ldap.uri.unescape", ldap_uri_unescape_xlat, FR_TYPE_STRING)))) return -1;
+       xlat_func_mono_set(xlat, ldap_uri_unescape_xlat_arg);
        xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE);
 
        return 0;
@@ -2607,8 +2622,9 @@ static int mod_load(void)
 
 static void mod_unload(void)
 {
-       xlat_func_unregister("ldap.escape");
-       xlat_func_unregister("ldap.unescape");
+       xlat_func_unregister("ldap.uri.escape");
+       xlat_func_unregister("ldap.uri.safe");
+       xlat_func_unregister("ldap.uri.unescape");
 }
 
 /* globally exported name */
index 1dc539bb3b7ac9f0de1a5e699d9ea02716bd4431..1bdf65233f373a33020beba6c8ca5d49a377162d 100644 (file)
@@ -52,14 +52,12 @@ RCSID("$Id$")
 static int rest_uri_part_escape(fr_value_box_t *vb, void *uctx);
 static void *rest_uri_part_escape_uctx_alloc(UNUSED request_t *request, void const *uctx);
 
-#define REST_URI_SAFE_FOR (fr_value_box_safe_for_t)fr_curl_xlat_uri_escape
-
 static fr_uri_part_t const rest_uri_parts[] = {
-       { .name = "scheme", .safe_for = REST_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L(":")), .part_adv = { [':'] = 1 }, .extra_skip = 2 },
-       { .name = "host", .safe_for = REST_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L(":"), L("/")), .part_adv = { [':'] = 1, ['/'] = 2 }, .func = rest_uri_part_escape },
-       { .name = "port", .safe_for = REST_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L("/")), .part_adv = { ['/'] = 1 } },
-       { .name = "method", .safe_for = REST_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L("?")), .part_adv = { ['?'] = 1 }, .func = rest_uri_part_escape },
-       { .name = "param", .safe_for = REST_URI_SAFE_FOR, .func = rest_uri_part_escape },
+       { .name = "scheme", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L(":")), .part_adv = { [':'] = 1 }, .extra_skip = 2 },
+       { .name = "host", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L(":"), L("/")), .part_adv = { [':'] = 1, ['/'] = 2 }, .func = rest_uri_part_escape },
+       { .name = "port", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L("/")), .part_adv = { ['/'] = 1 } },
+       { .name = "method", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L("?")), .part_adv = { ['?'] = 1 }, .func = rest_uri_part_escape },
+       { .name = "param", .safe_for = CURL_URI_SAFE_FOR, .func = rest_uri_part_escape },
        XLAT_URI_PART_TERMINATOR
 };
 
@@ -215,9 +213,9 @@ static const call_env_method_t _var = { \
                                                                                                } , \
                                                                                                .type = TMPL_ESCAPE_UCTX_ALLOC_FUNC\
                                                                                        }, \
-                                                                                       .safe_for = REST_URI_SAFE_FOR \
+                                                                                       .safe_for = CURL_URI_SAFE_FOR \
                                                                                      }, \
-                                                                                     .pair.literals_safe_for = REST_URI_SAFE_FOR}, /* Do not concat */ \
+                                                                                     .pair.literals_safe_for = CURL_URI_SAFE_FOR}, /* Do not concat */ \
                                                                REST_CALL_ENV_REQUEST_COMMON(_dflt_username, _dflt_password) \
                                                                CALL_ENV_TERMINATOR \
                                                        })) }, \
@@ -497,7 +495,7 @@ finish:
 }
 
 static xlat_arg_parser_t const rest_xlat_args[] = {
-       { .required = true, .safe_for = REST_URI_SAFE_FOR, .type = FR_TYPE_STRING },
+       { .required = true, .safe_for = CURL_URI_SAFE_FOR, .type = FR_TYPE_STRING },
        { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_STRING },
        XLAT_ARG_PARSER_TERMINATOR
 };
@@ -1378,33 +1376,9 @@ static int mod_load(void)
        fr_json_version_print();
 #endif
 
-       {
-               xlat_t *xlat;
-
-               xlat = xlat_func_register(NULL, "rest.escape", fr_curl_xlat_uri_escape, FR_TYPE_STRING);
-               if (unlikely(!xlat)) {
-                       ERROR("Failed registering \"rest.escape\" xlat");
-                       return -1;
-               }
-               xlat_func_args_set(xlat, fr_curl_xlat_uri_args);
-               xlat_func_safe_for_set(xlat, REST_URI_SAFE_FOR); /* Each instance of the uri_escape xlat has its own safe_for value */
-               xlat = xlat_func_register(NULL, "rest.unescape", fr_curl_xlat_uri_unescape, FR_TYPE_STRING);
-               if (unlikely(!xlat)) {
-                       ERROR("Failed registering \"rest.unescape\" xlat");
-                       return -1;
-               }
-               xlat_func_args_set(xlat, fr_curl_xlat_uri_args);
-       }
-
        return 0;
 }
 
-static void mod_unload(void)
-{
-       xlat_func_unregister("rest.escape");
-       xlat_func_unregister("rest.unescape");
-}
-
 /*
  *     The module name should be the only globally exported symbol.
  *     That is, everything else should be 'static'.
@@ -1424,7 +1398,6 @@ module_rlm_t rlm_rest = {
                .thread_inst_size       = sizeof(rlm_rest_thread_t),
                .config                 = module_config,
                .onload                 = mod_load,
-               .unload                 = mod_unload,
                .bootstrap              = mod_bootstrap,
                .instantiate            = instantiate,
                .thread_instantiate     = mod_thread_instantiate,
index 409f842ba40223463081d1d44dfbe12412057e7a..753d225906bfffd44599ead21915ea7f086281dd 100644 (file)
@@ -8,13 +8,13 @@ string result_string
 &test_string := "safe string"
 
 # String with no escaping
-&result_string := %ldap.escape(%{test_string})
+&result_string := %ldap.uri.escape(%{test_string})
 
 if (!(&result_string == "safe string")) {
         test_fail
 }
 
-&result_string := %ldap.unescape(%{result_string})
+&result_string := %ldap.uri.unescape(%{result_string})
 
 if (!(&result_string == 'safe string')) {
         test_fail
@@ -22,13 +22,13 @@ if (!(&result_string == 'safe string')) {
 
 # String with some characters to escape
 &test_string := 'non safe,+"\<>;*=() string'
-&result_string := %ldap.escape(%{test_string})
+&result_string := %ldap.uri.escape(%{test_string})
 
 if (!(&result_string == 'non safe\2c\2b\22\5c\3c\3e\3b\2a\3d\28\29 string')) {
         test_fail
 }
 
-&result_string := %ldap.unescape(%{result_string})
+&result_string := %ldap.uri.unescape(%{result_string})
 
 if (!(&result_string == 'non safe,+"\<>;*=() string')) {
         test_fail
@@ -36,13 +36,13 @@ if (!(&result_string == 'non safe,+"\<>;*=() string')) {
 
 # String where all characters require escaping
 &test_string := ',+"\<>;*=()'
-&result_string := %ldap.escape(%{test_string})
+&result_string := %ldap.uri.escape(%{test_string})
 
 if (!(&result_string == '\2c\2b\22\5c\3c\3e\3b\2a\3d\28\29')) {
         test_fail
 }
 
-&result_string := %ldap.unescape(%{result_string})
+&result_string := %ldap.uri.unescape(%{result_string})
 
 if (!(&result_string == ',+"\<>;*=()')) {
         test_fail
@@ -90,7 +90,7 @@ if (!(&result_string == "Fred Jones")) {
 }
 
 # Reference an alternative LDAP server in the xlat
-&result_string := %ldap("ldap://$ENV{LDAP_TEST_SERVER}:%ldap.escape(%{$ENV{LDAP_TEST_SERVER_PORT} + 1})/dc=subdept,dc=example,dc=com?displayName?sub?(uid=fred)")
+&result_string := %ldap("ldap://$ENV{LDAP_TEST_SERVER}:%ldap.uri.escape(%{$ENV{LDAP_TEST_SERVER_PORT} + 1})/dc=subdept,dc=example,dc=com?displayName?sub?(uid=fred)")
 
 if (!(&result_string == "Fred Jones")) {
         test_fail
index 465e22eee7a64de4699b24bcedb712acf4fd2bb6..2b70e7295c6790bf89c7fec22d7556c67b2dccfd 100644 (file)
@@ -13,7 +13,7 @@ string result_string
 &test_string := 'notfound'
 
 # Retrieve a plain text file
-&result_string := %rest('GET', "http://%{server_host}:%rest.escape(%{server_port})/test.txt")
+&result_string := %rest('GET', "http://%{server_host}:%uri.safe(%{server_port})/test.txt")
 
 if (!(&REST-HTTP-Status-Code == 200)) {
        test_fail
@@ -24,13 +24,13 @@ if (!(&result_string == "Sample text response\n")) {
 }
 
 # Take host from incoming packet
-&result_string := %rest("http://%{Login-IP-Host}:%rest.escape(%{server_port})/test.txt")
+&result_string := %rest("http://%{Login-IP-Host}:%uri.safe(%{server_port})/test.txt")
 
 if (!(&REST-HTTP-Status-Code == 200) || !(&result_string == "Sample text response\n")) {
        test_fail
 }
 
-# Port is not allowed from incoming packet
+# Port is not allowed from incoming packets
 &result_string := %rest("http://%{server_host}:%{NAS-Port}/test.txt")
 
 if (!(&Module-Failure-Message == "Failed escaping URI: Unsafe input \"8080\" not allowed in URI part port") || &result_string) {
@@ -38,14 +38,14 @@ if (!(&Module-Failure-Message == "Failed escaping URI: Unsafe input \"8080\" not
 }
 
 # Check a "not found" gives a 404 status code
-&result_string := %rest('GET', "http://%{server_host}:%rest.escape(%{server_port})/%{test_string}")
+&result_string := %rest('GET', "http://%{server_host}:%uri.safe(%{server_port})/%{test_string}")
 
 if (!(&REST-HTTP-Status-Code == 404)) {
        test_fail
 }
 
 # GET with URL parameters
-&test_string := %rest('GET', "http://%{server_host}:%rest.escape(%{server_port})/user/%{User-Name}/mac/%{Called-Station-Id}")
+&test_string := %rest('GET', "http://%{server_host}:%uri.safe(%{server_port})/user/%{User-Name}/mac/%{Called-Station-Id}")
 
 if (!(&REST-HTTP-Status-Code == 200)) {
        test_fail
@@ -67,7 +67,7 @@ if (!(&control.User-Name == "Bob")) {
 &control.User-Name := 'dummy'
 
 # Directly use json map and prepend the returned value
-map json %rest('GET', "http://%{server_host}:%rest.escape(%{server_port})/user/%{User-Name}/mac/%{Called-Station-Id}") {
+map json %rest('GET', "http://%{server_host}:%uri.safe(%{server_port})/user/%{User-Name}/mac/%{Called-Station-Id}") {
        &control.User-Name ^= '$.control\.User-Name.value'
 }
 
@@ -78,7 +78,7 @@ if (!(&control.User-Name[0] == 'Bob') || !(&control.User-Name[1] == 'dummy')) {
 &test_string := %json.encode('&request.NAS-IP-Address')
 
 # POST to https with JSON body data
-&result_string := %rest('POST', "https://%{server_host}:%rest.escape(%{server_ssl_port})/user/%{User-Name}/mac/%{Called-Station-Id}?section=accounting", %{test_string})
+&result_string := %rest('POST', "https://%{server_host}:%uri.safe(%{server_ssl_port})/user/%{User-Name}/mac/%{Called-Station-Id}?section=accounting", %{test_string})
 
 if (!(&REST-HTTP-Status-Code == 200)) {
        test_fail
@@ -105,7 +105,7 @@ if (!(&control.NAS-IP-Address == "192.168.1.1")) {
 &result_string := "NAS=%{NAS-IP-Address}&user=%{User-Name}"
 
 # POST to https with POST body data
-&result_string := %rest('POST', "https://%{server_host}:%rest.escape(%{server_ssl_port})/post/test?section=dummy", %{result_string})
+&result_string := %rest('POST', "https://%{server_host}:%uri.safe(%{server_ssl_port})/post/test?section=dummy", %{result_string})
 
 if (!(&REST-HTTP-Status-Code == 200)) {
        test_fail
@@ -122,7 +122,7 @@ group {
        string arguments
        string body
 
-       map json %rest('POST', "http://%{server_host}:%rest.escape(%{server_port})/user/%{User-Name}/reflect/?station=%{Calling-Station-Id}", "{\"test\":\"foo\"}") {
+       map json %rest('POST', "http://%{server_host}:%uri.safe(%{server_port})/user/%{User-Name}/reflect/?station=%{Calling-Station-Id}", "{\"test\":\"foo\"}") {
                &headers := '$.reply\.Reply-Message.value[0]'
                &arguments := '$.reply\.Reply-Message.value[1]'
                &body := '$.reply\.Reply-Message.value[2]'
@@ -160,7 +160,7 @@ group {
 
        &test_string := ""
 
-       map json %rest(http://%{server_host}:%rest.escape(%{server_port})/user/%{User-Name}/reflect/%{test_string}?station=%{User-Name}) {
+       map json %rest(http://%{server_host}:%uri.safe(%{server_port})/user/%{User-Name}/reflect/%{test_string}?station=%{User-Name}) {
                &headers := '$.reply\.Reply-Message.value[0]'
                &arguments := '$.reply\.Reply-Message.value[1]'
        }
@@ -190,7 +190,7 @@ group {
 group {
        string arguments
 
-       map json %rest("http://%{server_host}:%rest.escape(%{server_port})/user/%{User-Name}/reflect/%{NAS-Identifier}?station=%{Called-Station-Id}") {
+       map json %rest("http://%{server_host}:%uri.safe(%{server_port})/user/%{User-Name}/reflect/%{NAS-Identifier}?station=%{Called-Station-Id}") {
                &arguments := '$.reply\.Reply-Message.value[1]'
        }
 
@@ -202,7 +202,7 @@ group {
 }
 
 # Test against endpoint which will time out
-&result_string := %restshorttimeout("http://%{server_host}:%rest.escape(%{server_port})/delay")
+&result_string := %restshorttimeout("http://%{server_host}:%uri.safe(%{server_port})/delay")
 
 if (&REST-HTTP-Status-Code) {
        test_fail