]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Escape special characters in regex expansion. Fixes #1474
authorAlan T. DeKok <aland@freeradius.org>
Wed, 30 Dec 2015 16:27:42 +0000 (11:27 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 30 Dec 2015 16:28:33 +0000 (11:28 -0500)
src/main/evaluate.c
src/tests/keywords/regex-escape [new file with mode: 0644]

index bd49e8bb2d4ffda36cea380f3355d2a291ee968a..d3fbccc08c94b45f4a8137e6a88ad2ec27fb0236 100644 (file)
@@ -30,6 +30,8 @@ RCSID("$Id$")
 
 #include <ctype.h>
 
+#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 (file)
index 0000000..4ab1e5b
--- /dev/null
@@ -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