};
+static xlat_arg_parser_t const ldap_escape_xlat_arg = { .required = true, .concat = true, .type = FR_TYPE_STRING };
+
/** Escape LDAP string
*
* @ingroup xlat_functions
*/
-static ssize_t ldap_escape_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen,
- UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
- request_t *request, char const *fmt)
+static xlat_action_t ldap_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request,
+ UNUSED void const *xlat_inst, UNUSED void *xlat_thread_inst,
+ fr_value_box_list_t *in)
{
- return fr_ldap_escape_func(request, *out, outlen, fmt, NULL);
+ fr_value_box_t *vb, *in_vb = fr_dlist_head(in);
+ fr_sbuff_t sbuff;
+ fr_sbuff_uctx_talloc_t sbuff_ctx;
+ size_t len;
+
+ MEM(vb = fr_value_box_alloc_null(ctx));
+ /*
+ * Maximum space needed for output would be 3 times the input if every
+ * char needed escaping
+ */
+ if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, in_vb->length * 3, in_vb->length * 3)) {
+ REDEBUG("Failed to allocate buffer for escaped string");
+ talloc_free(vb);
+ return XLAT_ACTION_FAIL;
+ }
+
+ /*
+ * Call the escape function, including the space for the trailing NULL
+ */
+ len = fr_ldap_escape_func(request, fr_sbuff_buff(&sbuff), in_vb->length * 3 + 1, in_vb->vb_strvalue, NULL);
+
+ /*
+ * Trim buffer to fit used space and assign to box
+ */
+ fr_sbuff_trim_talloc(&sbuff, len);
+ fr_value_box_strdup_shallow(vb, NULL, fr_sbuff_buff(&sbuff), in_vb->tainted);
+ fr_dcursor_append(out, vb);
+ return XLAT_ACTION_DONE;
}
/** Unescape LDAP string
*
* @ingroup xlat_functions
*/
-static ssize_t ldap_unescape_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen,
- UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
- request_t *request, char const *fmt)
+static xlat_action_t ldap_unescape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request,
+ UNUSED void const *xlat_inst, UNUSED void *xlat_thread_inst,
+ fr_value_box_list_t *in)
{
- return fr_ldap_unescape_func(request, *out, outlen, fmt, NULL);
+ fr_value_box_t *vb, *in_vb = fr_dlist_head(in);
+ fr_sbuff_t sbuff;
+ fr_sbuff_uctx_talloc_t sbuff_ctx;
+ size_t len;
+
+ MEM(vb = fr_value_box_alloc_null(ctx));
+ /*
+ * Maximum space needed for output will be the same as the input
+ */
+ if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, in_vb->length, in_vb->length)) {
+ REDEBUG("Failed to allocate buffer for unescaped string");
+ talloc_free(vb);
+ return XLAT_ACTION_FAIL;
+ }
+
+ /*
+ * Call the unescape function, including the space for the trailing NULL
+ */
+ len = fr_ldap_unescape_func(request, fr_sbuff_buff(&sbuff), in_vb->length + 1, in_vb->vb_strvalue, NULL);
+
+ /*
+ * Trim buffer to fit used space and assign to box
+ */
+ fr_sbuff_trim_talloc(&sbuff, len);
+ fr_value_box_strdup_shallow(vb, NULL, fr_sbuff_buff(&sbuff), in_vb->tainted);
+ fr_dcursor_append(out, vb);
+ return XLAT_ACTION_DONE;
}
/** Expand an LDAP URL into a query, and return a string result from that query.
rlm_ldap_t *inst = instance;
char buffer[256];
char const *group_attribute;
+ xlat_t *xlat;
inst->name = cf_section_name2(conf);
if (!inst->name) inst->name = cf_section_name1(conf);
}
xlat_register_legacy(inst, inst->name, ldap_xlat, fr_ldap_escape_func, NULL, 0, XLAT_DEFAULT_BUF_LEN);
- xlat_register_legacy(inst, "ldap_escape", ldap_escape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
- xlat_register_legacy(inst, "ldap_unescape", ldap_unescape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
+ xlat = xlat_register(NULL, "ldap_escape", ldap_escape_xlat, false);
+ xlat_func_mono(xlat, &ldap_escape_xlat_arg);
+ xlat = xlat_register(NULL, "ldap_unescape", ldap_unescape_xlat, false);
+ xlat_func_mono(xlat, &ldap_escape_xlat_arg);
map_proc_register(inst, inst->name, mod_map_proc, ldap_map_verify, 0);
return 0;
--- /dev/null
+#
+# Test the "ldap" module xlat escape functions
+#
+
+update request {
+ &Tmp-String-0 := "safe string"
+ &Tmp-String-1 := 'non safe,+"\<>;*=() string'
+ &Tmp-String-2 := ',+"\<>;*=()'
+}
+
+# String with no escaping
+update control {
+ &Tmp-String-0 := "%{ldap_escape:%{Tmp-String-0}}"
+}
+
+if (&control.Tmp-String-0 != "safe string") {
+ test_fail
+}
+
+# String with some characters to escape
+update control {
+ &Tmp-String-1 := "%{ldap_escape:%{Tmp-String-1}}"
+}
+
+if (&control.Tmp-String-1 != 'non safe\2c\2b\22\5c\3c\3e\3b\2a\3d\28\29 string') {
+ test_fail
+}
+
+# String where all characters require escaping
+update control {
+ &Tmp-String-2 := "%{ldap_escape:%{Tmp-String-2}}"
+}
+
+if (&control.Tmp-String-2 != '\2c\2b\22\5c\3c\3e\3b\2a\3d\28\29') {
+ test_fail
+}
+
+update request {
+ &Tmp-String-3 := "%{ldap_unescape:%{control.Tmp-String-0}}"
+}
+
+if (&Tmp-String-3 != 'safe string') {
+ test_fail
+}
+
+update request {
+ &Tmp-String-4 := "%{ldap_unescape:%{control.Tmp-String-1}}"
+}
+
+if (&Tmp-String-4 != 'non safe,+"\<>;*=() string') {
+ test_fail
+}
+
+update request {
+ &Tmp-String-5 := "%{ldap_unescape:%{control.Tmp-String-2}}"
+}
+
+if (&Tmp-String-5 != ',+"\<>;*=()') {
+ test_fail
+}
+
+test_pass