From 7c05d5e069c1a068de67d99aa51cd6f4e3be8082 Mon Sep 17 00:00:00 2001
From: Graham Leggett <minfrin@apache.org>
Date: Fri, 25 Apr 2014 10:55:04 +0000
Subject: [PATCH] Add the ldap function to the expression API, allowing LDAP
 filters and distinguished names based on expressions to be escaped correctly
 to guard against LDAP injection.

Note: this requires at least APR v1.6.0 or above for the apr_escape API.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1589986 13f79535-47bb-0310-9956-ffa450edef68
---
 CHANGES                             |  4 ++++
 docs/manual/expr.xml                |  3 +++
 docs/manual/mod/mod_authnz_ldap.xml | 10 ++++++++++
 server/util_expr_eval.c             |  8 ++++++++
 4 files changed, 25 insertions(+)

diff --git a/CHANGES b/CHANGES
index ff880bacc8..d7e90a06b7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) Add the ldap function to the expression API, allowing LDAP filters and
+     distinguished names based on expressions to be escaped correctly to
+     guard against LDAP injection. [Graham Leggett]
+
   *) Add module mod_ssl_ct, which provides an implementation of Certificate
      Transparency (RFC 6962) for httpd.  [Jeff Trawick]
 
diff --git a/docs/manual/expr.xml b/docs/manual/expr.xml
index c8be338d4c..bd3956f46a 100644
--- a/docs/manual/expr.xml
+++ b/docs/manual/expr.xml
@@ -514,6 +514,9 @@ listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
     <tr><td><code>filesize</code></td>
         <td>Return size of a file (or 0 if file does not exist or is not
             regular file)</td><td>yes</td></tr>
+    <tr><td><code>ldap</code></td>
+        <td>Escape characters as required by LDAP distinguished name escaping
+            (RFC4514) and LDAP filter escaping (RFC4515).</td><td></td></tr>
 
     </table>
 
diff --git a/docs/manual/mod/mod_authnz_ldap.xml b/docs/manual/mod/mod_authnz_ldap.xml
index 652deffbe6..2e29e5d14e 100644
--- a/docs/manual/mod/mod_authnz_ldap.xml
+++ b/docs/manual/mod/mod_authnz_ldap.xml
@@ -496,6 +496,16 @@ AuthLDAPMaxSubGroupDepth 1
     <code>ldap-attribute</code> will be faster than the search operation
     used by <code>ldap-filter</code> especially within a large directory.</p>
 
+    <p>When using an <a href="../expr.html">expression</a> within the filter, care
+    must be taken to ensure that LDAP filters are escaped correctly to guard against
+    LDAP injection. The ldap function can be used for this purpose.</p>
+
+<highlight language="config">
+&lt;LocationMatch ^/dav/(?<SITENAME>[^/]+)/&gt;
+  Require ldap-filter (memberOf=cn=%{ldap:%{unescape:%{env:MATCH_SITENAME}},ou=Websites,o=Example)
+&lt;/LocationMatch&gt;
+</highlight>
+
 </section>
 
 </section>
diff --git a/server/util_expr_eval.c b/server/util_expr_eval.c
index aa7e971279..96be20e12b 100644
--- a/server/util_expr_eval.c
+++ b/server/util_expr_eval.c
@@ -31,6 +31,7 @@
 #include "apr_fnmatch.h"
 #include "apr_base64.h"
 #include "apr_sha1.h"
+#include "apr_escape.h"
 
 #include <limits.h>     /* for INT_MAX */
 
@@ -1061,6 +1062,12 @@ static const char *md5_func(ap_expr_eval_ctx_t *ctx, const void *data,
 	return ap_md5(ctx->p, (const unsigned char *)arg);
 }
 
+static const char *ldap_func(ap_expr_eval_ctx_t *ctx, const void *data,
+                               const char *arg)
+{
+        return apr_pescape_ldap(ctx->p, arg, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_ALL);
+}
+
 
 #define MAX_FILE_SIZE 10*1024*1024
 static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
@@ -1645,6 +1652,7 @@ static const struct expr_provider_single string_func_providers[] = {
     { unbase64_func,        "unbase64",       NULL, 0 },
     { sha1_func,            "sha1",           NULL, 0 },
     { md5_func,             "md5",            NULL, 0 },
+    { ldap_func,            "ldap",           NULL, 0 },
     { NULL, NULL, NULL}
 };
 
-- 
2.40.0