From: Arran Cudbard-Bell Date: Wed, 16 May 2018 05:20:37 +0000 (+0600) Subject: Move the escape expansions into their own module X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bbd58ea4b55dffb53284a43906ac6dfa2574cd41;p=thirdparty%2Ffreeradius-server.git Move the escape expansions into their own module --- diff --git a/raddb/all.mk b/raddb/all.mk index 2c64245dfe9..a1b79df2e68 100644 --- a/raddb/all.mk +++ b/raddb/all.mk @@ -9,7 +9,7 @@ LOCAL_SITES := $(addprefix raddb/sites-enabled/,$(DEFAULT_SITES)) DEFAULT_MODULES := always attr_filter cache_eap chap client \ detail detail.log digest dhcpv4 eap \ - eap_inner echo exec expiration expr files linelog logintime \ + eap_inner echo escape exec expiration expr files linelog logintime \ mschap ntlm_auth pam pap passwd radius radutmp \ soh sradutmp stats unix unpack utf8 diff --git a/raddb/mods-available/escape b/raddb/mods-available/escape new file mode 100644 index 00000000000..e78d0b5904e --- /dev/null +++ b/raddb/mods-available/escape @@ -0,0 +1,12 @@ +# -*- text -*- +# +# $Id$ + +# +# This module registers two xlat functions +# - Replaces characters not in the safe_characters list with escaped versions +# - un Replaces escape sequences with the original character. +# +escape { + safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /äéöüàâæçèéêëîïôœùûüaÿÄÉÖÜßÀÂÆÇÈÉÊËÎÏÔŒÙÛÜŸ" +} diff --git a/src/modules/rlm_escape/README.md b/src/modules/rlm_escape/README.md new file mode 100644 index 00000000000..5b3ee8228c2 --- /dev/null +++ b/src/modules/rlm_escape/README.md @@ -0,0 +1,8 @@ +# rlm_escape +## Metadata +
+
category
policy
+
+ +## Summary +Escapes and unescapes strings using the MIME escape format diff --git a/src/modules/rlm_escape/all.mk b/src/modules/rlm_escape/all.mk new file mode 100644 index 00000000000..9cb0ce3b343 --- /dev/null +++ b/src/modules/rlm_escape/all.mk @@ -0,0 +1,2 @@ +TARGET := rlm_escape.a +SOURCES := rlm_escape.c diff --git a/src/modules/rlm_escape/rlm_escape.c b/src/modules/rlm_escape/rlm_escape.c new file mode 100644 index 00000000000..868424065e2 --- /dev/null +++ b/src/modules/rlm_escape/rlm_escape.c @@ -0,0 +1,199 @@ +/* + * This program is 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 + */ + +/** + * $Id$ + * @file rlm_escape.c + * @brief Register escape/unescape xlat functions. + * + * @copyright 2018 Arran Cudbard-Bell + */ +RCSID("$Id$") +USES_APPLE_DEPRECATED_API + +#include + +#include +#include + +#include + +/* + * Define a structure for our module configuration. + */ +typedef struct { + char const *xlat_name; + char const *allowed_chars; +} rlm_escape_t; + +static const CONF_PARSER module_config[] = { + { FR_CONF_OFFSET("safe_characters", FR_TYPE_STRING, rlm_escape_t, allowed_chars), .dflt = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" }, + CONF_PARSER_TERMINATOR +}; + +static char const hextab[] = "0123456789abcdef"; + +/** Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support + * + * @verbatim Example: "%{escape:foo.jpg}" == "=60img=62foo.jpg=60/img=62" @endverbatim + */ +static ssize_t escape_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, + void const *mod_inst, UNUSED void const *xlat_inst, + UNUSED REQUEST *request, char const *fmt) +{ + rlm_escape_t const *inst = mod_inst; + char const *p = fmt; + char *out_p = *out; + size_t freespace = outlen; + + while (p[0]) { + int chr_len = 1; + int ret = 1; /* -Werror=uninitialized */ + + if (fr_utf8_strchr(&chr_len, inst->allowed_chars, p) == NULL) { + /* + * '=' 1 + ([hex]{2}) * chr_len) + */ + if (freespace <= (size_t)(1 + (chr_len * 3))) break; + + switch (chr_len) { + case 4: + ret = snprintf(out_p, freespace, "=%02X=%02X=%02X=%02X", + (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); + break; + + case 3: + ret = snprintf(out_p, freespace, "=%02X=%02X=%02X", + (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2]); + break; + + case 2: + ret = snprintf(out_p, freespace, "=%02X=%02X", (uint8_t)p[0], (uint8_t)p[1]); + break; + + case 1: + ret = snprintf(out_p, freespace, "=%02X", (uint8_t)p[0]); + break; + } + + p += chr_len; + out_p += ret; + freespace -= ret; + continue; + } + + /* + * Only one byte left. + */ + if (freespace <= 1) break; + + /* + * Allowed character (copy whole mb chars at once) + */ + memcpy(out_p, p, chr_len); + out_p += chr_len; + p += chr_len; + freespace -= chr_len; + } + *out_p = '\0'; + + return outlen - freespace; +} + +/** Equivalent to the old safe_characters functionality in rlm_sql + * + * @verbatim Example: "%{unescape:=60img=62foo.jpg=60/img=62}" == "foo.jpg" @endverbatim + */ +static ssize_t unescape_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, + UNUSED void const *mod_inst, UNUSED void const *xlat_inst, + UNUSED REQUEST *request, char const *fmt) +{ + char const *p; + char *out_p = *out; + char *c1, *c2, c3; + size_t freespace = outlen; + + if (outlen <= 1) return 0; + + p = fmt; + while (*p && (--freespace > 0)) { + if (*p != '=') { + next: + + *out_p++ = *p++; + continue; + } + + /* Is a = char */ + + if (!(c1 = memchr(hextab, tolower(*(p + 1)), 16)) || + !(c2 = memchr(hextab, tolower(*(p + 2)), 16))) goto next; + c3 = ((c1 - hextab) << 4) + (c2 - hextab); + + *out_p++ = c3; + p += 3; + } + + *out_p = '\0'; + + return outlen - freespace; +} + +/* + * Do any per-module initialization that is separate to each + * configured instance of the module. e.g. set up connections + * to external databases, read configuration files, set up + * dictionary entries, etc. + * + * If configuration information is given in the config section + * that must be referenced in later calls, store a handle to it + * in *instance otherwise put a null pointer there. + */ +static int mod_bootstrap(void *instance, CONF_SECTION *conf) +{ + rlm_escape_t *inst = instance; + char *unescape; + + inst->xlat_name = cf_section_name2(conf); + if (!inst->xlat_name) { + inst->xlat_name = cf_section_name1(conf); + } + + MEM(unescape = talloc_asprintf(NULL, "un%s", inst->xlat_name)); + xlat_register(inst, inst->xlat_name, escape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true); + xlat_register(inst, unescape, unescape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true); + talloc_free(unescape); + + return 0; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + * + * If the module needs to temporarily modify it's instantiation + * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. + * The server will then take care of ensuring that the module + * is single-threaded. + */ +extern rad_module_t rlm_escape; +rad_module_t rlm_escape = { + .magic = RLM_MODULE_INIT, + .name = "escape", + .inst_size = sizeof(rlm_escape_t), + .config = module_config, + .bootstrap = mod_bootstrap, +}; diff --git a/src/modules/rlm_expr/rlm_expr.c b/src/modules/rlm_expr/rlm_expr.c index 051e59a9f15..fc8f4238bab 100644 --- a/src/modules/rlm_expr/rlm_expr.c +++ b/src/modules/rlm_expr/rlm_expr.c @@ -17,7 +17,7 @@ /** * $Id$ * @file rlm_expr.c - * @brief Register many xlat expansions including the expr expansion. + * @brief Register an xlat expansion to perform basic mathematical operations. * * @copyright 2001,2006 The FreeRADIUS server project * @copyright 2002 Alan DeKok @@ -39,16 +39,8 @@ USES_APPLE_DEPRECATED_API */ typedef struct rlm_expr_t { char const *xlat_name; - char const *allowed_chars; } rlm_expr_t; -static const CONF_PARSER module_config[] = { - { FR_CONF_OFFSET("safe_characters", FR_TYPE_STRING, rlm_expr_t, allowed_chars), .dflt = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" }, - CONF_PARSER_TERMINATOR -}; - -static char const hextab[] = "0123456789abcdef"; - /** Calculate powers * * @author Orson Peters @@ -531,112 +523,6 @@ static ssize_t expr_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, return strlen(*out); } -/** Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support - * - * @verbatim Example: "%{escape:foo.jpg}" == "=60img=62foo.jpg=60/img=62" @endverbatim - */ -static ssize_t escape_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, - void const *mod_inst, UNUSED void const *xlat_inst, - UNUSED REQUEST *request, char const *fmt) -{ - rlm_expr_t const *inst = mod_inst; - char const *p = fmt; - char *out_p = *out; - size_t freespace = outlen; - - while (p[0]) { - int chr_len = 1; - int ret = 1; /* -Werror=uninitialized */ - - if (fr_utf8_strchr(&chr_len, inst->allowed_chars, p) == NULL) { - /* - * '=' 1 + ([hex]{2}) * chr_len) - */ - if (freespace <= (size_t)(1 + (chr_len * 3))) break; - - switch (chr_len) { - case 4: - ret = snprintf(out_p, freespace, "=%02X=%02X=%02X=%02X", - (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); - break; - - case 3: - ret = snprintf(out_p, freespace, "=%02X=%02X=%02X", - (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2]); - break; - - case 2: - ret = snprintf(out_p, freespace, "=%02X=%02X", (uint8_t)p[0], (uint8_t)p[1]); - break; - - case 1: - ret = snprintf(out_p, freespace, "=%02X", (uint8_t)p[0]); - break; - } - - p += chr_len; - out_p += ret; - freespace -= ret; - continue; - } - - /* - * Only one byte left. - */ - if (freespace <= 1) break; - - /* - * Allowed character (copy whole mb chars at once) - */ - memcpy(out_p, p, chr_len); - out_p += chr_len; - p += chr_len; - freespace -= chr_len; - } - *out_p = '\0'; - - return outlen - freespace; -} - -/** Equivalent to the old safe_characters functionality in rlm_sql - * - * @verbatim Example: "%{unescape:=60img=62foo.jpg=60/img=62}" == "foo.jpg" @endverbatim - */ -static ssize_t unescape_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, - UNUSED void const *mod_inst, UNUSED void const *xlat_inst, - UNUSED REQUEST *request, char const *fmt) -{ - char const *p; - char *out_p = *out; - char *c1, *c2, c3; - size_t freespace = outlen; - - if (outlen <= 1) return 0; - - p = fmt; - while (*p && (--freespace > 0)) { - if (*p != '=') { - next: - - *out_p++ = *p++; - continue; - } - - /* Is a = char */ - - if (!(c1 = memchr(hextab, tolower(*(p + 1)), 16)) || - !(c2 = memchr(hextab, tolower(*(p + 2)), 16))) goto next; - c3 = ((c1 - hextab) << 4) + (c2 - hextab); - - *out_p++ = c3; - p += 3; - } - - *out_p = '\0'; - - return outlen - freespace; -} - /* * Do any per-module initialization that is separate to each * configured instance of the module. e.g. set up connections @@ -657,8 +543,6 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf) } xlat_register(inst, inst->xlat_name, expr_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true); - xlat_register(inst, "escape", escape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true); - xlat_register(inst, "unescape", unescape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true); /* * Initialize various paircompare functions @@ -681,6 +565,5 @@ rad_module_t rlm_expr = { .magic = RLM_MODULE_INIT, .name = "expr", .inst_size = sizeof(rlm_expr_t), - .config = module_config, .bootstrap = mod_bootstrap, }; diff --git a/src/tests/keywords/unit_test_module.conf b/src/tests/keywords/unit_test_module.conf index 33a420ff090..5fdb0859305 100644 --- a/src/tests/keywords/unit_test_module.conf +++ b/src/tests/keywords/unit_test_module.conf @@ -19,6 +19,8 @@ modules { $INCLUDE ${raddb}/mods-enabled/pap $INCLUDE ${raddb}/mods-enabled/expr + + $INCLUDE ${raddb}/mods-enabled/escape delay reschedule { force_reschedule = yes