From 8c22e14493050742fd7b63f3e0682bdf570ac0f1 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Thu, 28 Oct 2010 12:12:12 -0400
Subject: [PATCH 1/9] Add utility function to sanitize LDAP/LDB filters

Also adds a unit test.
---
 src/tests/util-tests.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/util.c        |   52 ++++++++++++++++++++++++++++++++++++
 src/util/util.h        |   11 ++++++++
 3 files changed, 131 insertions(+), 0 deletions(-)

diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c
index bfc48bbac4e2a9ec12ff1a7c6cbe87bd14580881..cf96f0e356942c2bcd2667a2b778a65a91f46e2d 100644
--- a/src/tests/util-tests.c
+++ b/src/tests/util-tests.c
@@ -175,6 +175,73 @@ START_TEST(test_diff_string_lists)
 }
 END_TEST
 
+
+START_TEST(test_sss_filter_sanitize)
+{
+    errno_t ret;
+    char *sanitized = NULL;
+
+    TALLOC_CTX *test_ctx = talloc_new(NULL);
+    fail_if (test_ctx == NULL, "Out of memory");
+
+    const char no_specials[] = "username";
+    ret = sss_filter_sanitize(test_ctx, no_specials, &sanitized);
+    fail_unless(ret == EOK, "no_specials error [%d][%s]",
+                ret, strerror(ret));
+    fail_unless(strcmp(no_specials, sanitized)==0,
+                "Expected [%s], got [%s]",
+                no_specials, sanitized);
+
+    const char has_asterisk[] = "*username";
+    const char has_asterisk_expected[] = "\\2ausername";
+    ret = sss_filter_sanitize(test_ctx, has_asterisk, &sanitized);
+    fail_unless(ret == EOK, "has_asterisk error [%d][%s]",
+                ret, strerror(ret));
+    fail_unless(strcmp(has_asterisk_expected, sanitized)==0,
+                "Expected [%s], got [%s]",
+                has_asterisk_expected, sanitized);
+
+    const char has_lparen[] = "user(name";
+    const char has_lparen_expected[] = "user\\28name";
+    ret = sss_filter_sanitize(test_ctx, has_lparen, &sanitized);
+    fail_unless(ret == EOK, "has_lparen error [%d][%s]",
+                ret, strerror(ret));
+    fail_unless(strcmp(has_lparen_expected, sanitized)==0,
+                "Expected [%s], got [%s]",
+                has_lparen_expected, sanitized);
+
+    const char has_rparen[] = "user)name";
+    const char has_rparen_expected[] = "user\\29name";
+    ret = sss_filter_sanitize(test_ctx, has_rparen, &sanitized);
+    fail_unless(ret == EOK, "has_rparen error [%d][%s]",
+                ret, strerror(ret));
+    fail_unless(strcmp(has_rparen_expected, sanitized)==0,
+                "Expected [%s], got [%s]",
+                has_rparen_expected, sanitized);
+
+    const char has_backslash[] = "username\\";
+    const char has_backslash_expected[] = "username\\5c";
+    ret = sss_filter_sanitize(test_ctx, has_backslash, &sanitized);
+    fail_unless(ret == EOK, "has_backslash error [%d][%s]",
+                ret, strerror(ret));
+    fail_unless(strcmp(has_backslash_expected, sanitized)==0,
+                "Expected [%s], got [%s]",
+                has_backslash_expected, sanitized);
+
+    const char has_all[] = "\\(user)*name";
+    const char has_all_expected[] = "\\5c\\28user\\29\\2aname";
+    ret = sss_filter_sanitize(test_ctx, has_all, &sanitized);
+    fail_unless(ret == EOK, "has_all error [%d][%s]",
+                ret, strerror(ret));
+    fail_unless(strcmp(has_all_expected, sanitized)==0,
+                "Expected [%s], got [%s]",
+                has_all_expected, sanitized);
+
+    talloc_free(test_ctx);
+}
+END_TEST
+
+
 Suite *util_suite(void)
 {
     Suite *s = suite_create("util");
@@ -182,6 +249,7 @@ Suite *util_suite(void)
     TCase *tc_util = tcase_create("util");
 
     tcase_add_test (tc_util, test_diff_string_lists);
+    tcase_add_test (tc_util, test_sss_filter_sanitize);
     tcase_set_timeout(tc_util, 60);
 
     suite_add_tcase (s, tc_util);
diff --git a/src/util/util.c b/src/util/util.c
index 06eea283770601997e3ff90df73db58a4fb25bba..20b8c78a72611335be77d36e7b3dc420f26989d2 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -515,3 +515,55 @@ errno_t sss_hash_create(TALLOC_CTX *mem_ctx,
     talloc_free(internal_ctx);
     return ret;
 }
+
+errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
+                            const char *input,
+                            char **sanitized)
+{
+    char *output;
+    size_t i = 0;
+    size_t j = 0;
+
+    /* Assume the worst-case. We'll resize it later, once */
+    output = talloc_array(mem_ctx, char, strlen(input) * 3 + 1);
+    if (!output) {
+        return ENOMEM;
+    }
+
+    while (input[i]) {
+        switch(input[i]) {
+        case '*':
+            output[j++] = '\\';
+            output[j++] = '2';
+            output[j++] = 'a';
+            break;
+        case '(':
+            output[j++] = '\\';
+            output[j++] = '2';
+            output[j++] = '8';
+            break;
+        case ')':
+            output[j++] = '\\';
+            output[j++] = '2';
+            output[j++] = '9';
+            break;
+        case '\\':
+            output[j++] = '\\';
+            output[j++] = '5';
+            output[j++] = 'c';
+            break;
+        default:
+            output[j++] = input[i];
+        }
+
+        i++;
+    }
+    output[j] = '\0';
+    *sanitized = talloc_realloc(mem_ctx, output, char, strlen(output)+1);
+    if (!*sanitized) {
+        talloc_free(output);
+        return ENOMEM;
+    }
+
+    return EOK;
+}
diff --git a/src/util/util.h b/src/util/util.h
index e93f6f86373aa3679b01e6f4ade7dfe5118006c7..53a6b1c97dc42459c9bcb99424fd75a4b3d8e107 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -366,4 +366,15 @@ errno_t diff_string_lists(TALLOC_CTX *memctx,
                           char ***string1_only,
                           char ***string2_only,
                           char ***both_strings);
+
+/* Sanitize an input string (e.g. a username) for use in
+ * an LDAP/LDB filter
+ * Returns a newly-constructed string attached to mem_ctx
+ * It will fail only on an out of memory condition, where it
+ * will return ENOMEM.
+ */
+errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
+                            const char *input,
+                            char **sanitized);
+
 #endif /* __SSSD_UTIL_H__ */
-- 
1.7.3.2

