From ac8ab7cd69196a27b0875ea34bca75ff6f02348c Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Wed, 30 Dec 2015 11:27:42 -0500 Subject: [PATCH] Escape special characters in regex expansion. Fixes #1474 --- src/main/evaluate.c | 52 ++++++++++++++++++++++++++++++++++++++--- src/tests/keywords/regex-escape | 29 +++++++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/tests/keywords/regex-escape diff --git a/src/main/evaluate.c b/src/main/evaluate.c index bd49e8b..d3fbccc 100644 --- a/src/main/evaluate.c +++ b/src/main/evaluate.c @@ -30,6 +30,8 @@ RCSID("$Id$") #include +#define WITH_EVAL_DEBUG (1) + #ifdef WITH_UNLANG #ifdef WITH_EVAL_DEBUG # define EVAL_DEBUG(fmt, ...) printf("EVAL: ");printf(fmt, ## __VA_ARGS__);printf("\n");fflush(stdout) @@ -346,6 +348,39 @@ finish: } +static size_t regex_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg) +{ + char *p = out; + + while (*in && (outlen > 2)) { + switch (*in) { + case '\\': + case '.': + case '*': + case '+': + case '?': + case '|': + case '^': + case '$': + case '[': /* we don't list close braces */ + case '{': + case '(': + if (outlen < 3) goto done; + + *(p++) = '\\'; + /* FALL-THROUGH */ + + default: + *(p++) = *(in++); + break; + } + } + +done: + *(p++) = '\0'; + return p - out; +} + /** Convert both operands to the same type * @@ -372,6 +407,8 @@ static int cond_normalise_and_cmp(REQUEST *request, fr_cond_t const *c, value_data_t lhs_cast, rhs_cast; void *lhs_cast_buff = NULL, *rhs_cast_buff = NULL; + xlat_escape_t escape = NULL; + /* * Cast operand to correct type. * @@ -415,7 +452,10 @@ do {\ * Regular expressions need both operands to be strings */ #ifdef HAVE_REGEX - if (map->op == T_OP_REG_EQ) cast_type = PW_TYPE_STRING; + if (map->op == T_OP_REG_EQ) { + cast_type = PW_TYPE_STRING; + escape = regex_escape; + } else #endif /* @@ -519,7 +559,7 @@ do {\ if (map->rhs->type != TMPL_TYPE_LITERAL) { char *p; - ret = tmpl_aexpand(request, &p, request, map->rhs, NULL, NULL); + ret = tmpl_aexpand(request, &p, request, map->rhs, escape, NULL); if (ret < 0) { EVAL_DEBUG("FAIL [%i]", __LINE__); rcode = -1; @@ -574,6 +614,7 @@ finish: return rcode; } + /** Evaluate a map * * @param[in] request the REQUEST @@ -642,8 +683,13 @@ int radius_evaluate_map(REQUEST *request, UNUSED int modreturn, UNUSED int depth if (map->lhs->type != TMPL_TYPE_LITERAL) { char *p; + xlat_escape_t escape = NULL; + + if (map->op == T_OP_REG_EQ) { + escape = regex_escape; + } - ret = tmpl_aexpand(request, &p, request, map->lhs, NULL, NULL); + ret = tmpl_aexpand(request, &p, request, map->lhs, escape, NULL); if (ret < 0) { EVAL_DEBUG("FAIL [%i]", __LINE__); return ret; diff --git a/src/tests/keywords/regex-escape b/src/tests/keywords/regex-escape new file mode 100644 index 0000000..4ab1e5b --- /dev/null +++ b/src/tests/keywords/regex-escape @@ -0,0 +1,29 @@ +# +# PRE: update if +# + +# +# Strings which are expanded in a regex have regex special +# characters escaped. Because the input strings are unsafe. +# +update request { + Tmp-String-0 := "example.com" + Tmp-String-1 := "exampleXcom" +} + +if ("exampleXcom" =~ /%{Tmp-String-0}/) { + update reply { + Filter-Id := "fail 1" + } +} + +elsif (&Tmp-String-1 =~ /%{Tmp-String-0}/) { + update reply { + Filter-Id := "fail 2" + } +} +else { + update reply { + Filter-Id := "filter" + } +} \ No newline at end of file -- 2.1.4