From: Nick Porter Date: Mon, 29 Mar 2021 09:18:04 +0000 (+0100) Subject: v4: convert %(config :) to new xlat api (#4033) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b29eb31aaf8d485c7093d394689745ec1d8002ca;p=thirdparty%2Ffreeradius-server.git v4: convert %(config :) to new xlat api (#4033) * Convert %{config: } to new xlat api * Update documentation for new %(config: ) xlat syntax * Remove former config xlat escape function * Add test for %(config: ) xlat --- diff --git a/doc/antora/modules/reference/pages/xlat/builtin.adoc b/doc/antora/modules/reference/pages/xlat/builtin.adoc index 8110544100b..38bdac403e4 100644 --- a/doc/antora/modules/reference/pages/xlat/builtin.adoc +++ b/doc/antora/modules/reference/pages/xlat/builtin.adoc @@ -166,7 +166,7 @@ The string value of 0x7465737431 is test1 == Server Manipulation -=== %{config:} +=== %(config:) Refers to a variable in the configuration file. See the documentation on configuration file references. @@ -177,8 +177,8 @@ on configuration file references. [source,unlang] ---- -"Server installed in %{config:prefix}" -"Module rlm_exec.shell_escape = %{config:modules.exec.shell_escape}" +"Server installed in %(config:prefix)" +"Module rlm_exec.shell_escape = %(config:modules.exec.shell_escape)" ---- .Output diff --git a/src/lib/server/main_config.c b/src/lib/server/main_config.c index 3b777bd9d8e..8c5c569ba90 100644 --- a/src/lib/server/main_config.c +++ b/src/lib/server/main_config.c @@ -437,101 +437,109 @@ static int num_workers_parse(TALLOC_CTX *ctx, void *out, void *parent, } -static size_t config_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg) +static int xlat_config_escape(UNUSED request_t *request, fr_value_box_t *vb, UNUSED void *uctx) { - size_t len = 0; - static char const disallowed[] = "%{}\\'\"`"; - - while (in[0]) { + static char const disallowed[] = "%{}\\'\"`"; + size_t outmax = vb->vb_length * 3; + size_t outlen = 0; + char escaped[outmax]; + char const *in, *end; + char *out = escaped; + + fr_assert(vb->type == FR_TYPE_STRING); + in = vb->vb_strvalue; + end = in + vb->vb_length; + + do { /* * Non-printable characters get replaced with their * mime-encoded equivalents. */ if ((in[0] < 32)) { - if (outlen <= 3) break; + if (outlen >= (outmax - 3)) return -1; snprintf(out, outlen, "=%02X", (unsigned char) in[0]); - in++; out += 3; - outlen -= 3; - len += 3; + outlen += 3; continue; } else if (strchr(disallowed, *in) != NULL) { - if (outlen <= 2) break; + if (outlen >= (outmax - 2)) return -1; out[0] = '\\'; out[1] = *in; - in++; out += 2; - outlen -= 2; - len += 2; + outlen += 2; continue; } /* * Only one byte left. */ - if (outlen <= 1) { - break; - } + if (outlen >= (outmax - 1)) return -1; /* * Allowed character. */ *out = *in; out++; - in++; - outlen--; - len++; - } + outlen++; + } while (++in < end); *out = '\0'; - return len; + + /* + * If the output length is greater than the input length + * something has been escaped - replace the original string + */ + if (outlen > vb->vb_length) { + char *outbuff; + fr_value_box_bstr_realloc(vb, &outbuff, vb, outlen); + memcpy(outbuff, escaped, outlen); + } + + return 0; + } +static xlat_arg_parser_t const xlat_config_args[] = { + { .required = true, .concat = true, .type = FR_TYPE_STRING, .always_escape = true, .func = xlat_config_escape }, + XLAT_ARG_PARSER_TERMINATOR +}; + /** xlat to get config values * @verbatim -%{config:section.subsection.attribute} +%(config:section.subsection.attribute) @endverbatim * * @ingroup xlat_functions */ -static ssize_t xlat_config(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 xlat_config(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) { - char const *value; - CONF_PAIR *cp; - CONF_ITEM *ci; - char buffer[1024]; - - /* - * Expand it safely. - */ - if (xlat_eval(buffer, sizeof(buffer), request, fmt, config_escape_func, NULL) < 0) return 0; + char const *value; + CONF_PAIR *cp; + CONF_ITEM *ci; + fr_value_box_t *in_head = fr_dlist_head(in); + fr_value_box_t *vb; - ci = cf_reference_item(main_config->root_cs, main_config->root_cs, buffer); + ci = cf_reference_item(main_config->root_cs, main_config->root_cs, in_head->vb_strvalue); if (!ci || !cf_item_is_pair(ci)) { - REDEBUG("Config item \"%s\" does not exist", fmt); - return -1; + REDEBUG("Config item \"%pV\" does not exist", in_head); + return XLAT_ACTION_FAIL; } cp = cf_item_to_pair(ci); - /* - * Ensure that we only copy what's necessary. - * - * If 'outlen' is too small, then the output is chopped to fit. - */ value = cf_pair_value(cp); - if (!value) return 0; - - if (outlen > strlen(value)) outlen = strlen(value) + 1; + if (!value) return XLAT_ACTION_DONE; - strlcpy(*out, value, outlen); + MEM(vb = fr_value_box_alloc_null(ctx)); + fr_value_box_bstrndup(ctx, vb, NULL, value, strlen(value), false); + fr_dcursor_append(out, vb); - return strlen(*out); + return XLAT_ACTION_DONE; } #ifdef HAVE_SETUID @@ -862,11 +870,12 @@ static int _dlhandle_free(void **dl_handle) */ int main_config_init(main_config_t *config) { - char const *p = NULL; - CONF_SECTION *cs = NULL, *subcs; - struct stat statbuf; - bool can_colourise = false; - char buffer[1024]; + char const *p = NULL; + CONF_SECTION *cs = NULL, *subcs; + struct stat statbuf; + bool can_colourise = false; + char buffer[1024]; + xlat_t *xlat; if (stat(config->raddb_dir, &statbuf) < 0) { ERROR("Error checking raddb_dir \"%s\": %s", config->raddb_dir, fr_syserror(errno)); @@ -1195,9 +1204,10 @@ do {\ if (!client_list_parse_section(cs, 0, false)) goto failure; /* - * Register the %{config:section.subsection} xlat function. + * Register the %(config:section.subsection) xlat function. */ - xlat_register_legacy(NULL, "config", xlat_config, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN); + xlat = xlat_register(NULL, "config", xlat_config, false); + xlat_func_args(xlat, xlat_config_args); /* * Ensure cwd is inside the chroot. diff --git a/src/tests/keywords/xlat-config b/src/tests/keywords/xlat-config new file mode 100644 index 00000000000..01850ac230f --- /dev/null +++ b/src/tests/keywords/xlat-config @@ -0,0 +1,25 @@ +# +# PRE: update if +# + +update request { + &Tmp-String-0 := "%(config:modules.test.boolean)" +} + +if (&Tmp-String-0 != "no") { + test_fail +} + +update request { + &Tmp-String-0 := "test" +} + +update request { + &Tmp-Integer-0 := "%(config:modules.%{Tmp-String-0}.integer)" +} + +if (&Tmp-Integer-0 != 1) { + test_fail +} + +success \ No newline at end of file