Skip to content

Commit

Permalink
Add safe for functions for ldap and rest
Browse files Browse the repository at this point in the history
Just use uri.escape and uri.unescape for all CURL based modules
  • Loading branch information
arr2036 committed Feb 17, 2024
1 parent b6dad73 commit 5a6a668
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 87 deletions.
8 changes: 4 additions & 4 deletions doc/antora/modules/raddb/pages/mods-available/ldap.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand All @@ -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.

Expand All @@ -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
Expand Down
26 changes: 21 additions & 5 deletions raddb/mods-available/ldap
Original file line number Diff line number Diff line change
Expand Up @@ -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_
#
Expand All @@ -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
Expand All @@ -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.
#
Expand All @@ -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
Expand Down
46 changes: 46 additions & 0 deletions src/lib/curl/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}

Expand All @@ -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");
}

/*
Expand Down
5 changes: 5 additions & 0 deletions src/lib/curl/xlat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
*/
Expand Down
6 changes: 6 additions & 0 deletions src/lib/curl/xlat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/ldap/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/ldap/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");

Expand Down
4 changes: 4 additions & 0 deletions src/lib/unlang/xlat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
18 changes: 18 additions & 0 deletions src/lib/unlang/xlat_builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/modules/rlm_ldap/groups.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
Expand Down
52 changes: 34 additions & 18 deletions src/modules/rlm_ldap/rlm_ldap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2593,22 +2603,28 @@ 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;
}

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 */
Expand Down
Loading

0 comments on commit 5a6a668

Please sign in to comment.