]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: db_ldap_set_attrs() - Handle braces nesting while splitting on commas
authorMarco Bettini <marco.bettini@open-xchange.com>
Thu, 11 May 2023 09:24:37 +0000 (09:24 +0000)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Wed, 31 May 2023 19:27:43 +0000 (19:27 +0000)
src/auth/Makefile.am
src/auth/db-ldap.c
src/auth/db-ldap.h
src/auth/test-auth.h
src/auth/test-db-ldap.c [new file with mode: 0644]
src/auth/test-main.c

index c2ee34d00307cb42661bc880d1916f454cad44f0..80a9c61ec530cd8dcc1b5a56df4f4b6dd42bb0d9 100644 (file)
@@ -228,6 +228,7 @@ test_auth_SOURCES = \
        test-auth-request-fields.c \
        test-username-filter.c \
        test-db-dict.c \
+       test-db-ldap.c \
        test-lua.c \
        test-mock.c \
        test-main.c
index 2050c4df28fa8148597f65d505be40f15446b555..d636673e9c0b8cc20e8e203089797b0b8e7436ef 100644 (file)
@@ -1381,6 +1381,48 @@ db_ldap_field_find(const char *data, void *context,
        return 1;
 }
 
+const char *const *db_ldap_parse_attrs(const char *cstr)
+{
+       ARRAY_TYPE(const_string) entries;
+       t_array_init(&entries, 32);
+
+       char *ptr = t_strdup_noconst(cstr);
+       const char *start = ptr;
+       unsigned int nesting = 0;
+       while (*ptr != '\0') {
+               switch (*ptr) {
+               case '{':
+                       nesting++;
+                       ptr++;
+                       break;
+               case '}':
+                       if (nesting > 0)
+                               nesting--;
+                       ptr++;
+                       break;
+               case ',':
+                       if (nesting > 0)
+                               ptr++;
+                       else {
+                               *ptr = '\0';
+                               if (*start != '\0')
+                                       array_push_back(&entries, &start);
+                               start = ++ptr;
+                       }
+                       break;
+               default:
+                       ptr++;
+                       break;
+               }
+       }
+       if (*start != '\0')
+               array_push_back(&entries, &start);
+
+       unsigned int count ATTR_UNUSED;
+       array_append_zero(&entries);
+       return array_get(&entries, &count);
+}
+
 void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
                       char ***attr_names_r, ARRAY_TYPE(ldap_field) *attr_map,
                       const char *skip_attr)
@@ -1397,11 +1439,10 @@ void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
        char *ldap_attr, *name, *templ;
        unsigned int i;
 
-       if (*attrlist == '\0')
+       attr = db_ldap_parse_attrs(attrlist);
+       if (*attr == NULL)
                return;
 
-       attr = t_strsplit_spaces(attrlist, ",");
-
        tmp_str = t_str_new(128);
        ctx.pool = conn->pool;
        p_array_init(&ctx.attr_names, conn->pool, 16);
index 82dc31b6dc23cfe8faf12f690e8a8292a38f45c4..1ccc47e76a4b85a02eed0f6c4ea26cf82e7b4916 100644 (file)
@@ -219,4 +219,8 @@ bool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx,
                                 const char *const **values_r);
 void db_ldap_result_iterate_deinit(struct db_ldap_result_iterate_context **ctx);
 
+/* exposed only for unit tests */
+
+const char *const *db_ldap_parse_attrs(const char *cstr);
+
 #endif
index 4641fe35616f02b20bf2d800b659ab60623f9ef9..195ff9c279d3b56ecb341e6eea9b7b20fefcf911 100644 (file)
@@ -21,5 +21,7 @@ struct auth_passdb *passdb_mock(void);
 void passdb_mock_mod_init(void);
 void passdb_mock_mod_deinit(void);
 
+void test_db_ldap_parse_attrs(void);
+
 #endif
 
diff --git a/src/auth/test-db-ldap.c b/src/auth/test-db-ldap.c
new file mode 100644 (file)
index 0000000..35bc416
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (c) 2023 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "test-common.h"
+#include "test-auth.h"
+#include "db-ldap.h"
+#include <stdio.h>
+
+void test_db_ldap_parse_attrs(void)
+{
+       struct vectors {
+               const char *inp;
+               const char *out;
+       } vectors[] = {
+               { .inp = "",                    .out = ""},
+               { .inp = "a",                   .out = "a"},
+
+               /* tests with leading/trailing/no spaces*/
+               { .inp = "a,b,c",               .out = "a|b|c"},
+               { .inp = "a, b, c",             .out = "a| b| c"},
+               { .inp = "a ,b ,c",             .out = "a |b |c"},
+
+               /* leading empty field */
+               { .inp = ",a,b",                .out = "a|b"},
+               /* trailing empty field */
+               { .inp = "a,b,",                .out = "a|b"},
+               /* middle empty field */
+               { .inp = "a,,b",                .out = "a|b"},
+
+
+               /* simple nesting at begining/end of field */
+               { .inp = "a,{b,c},d",           .out = "a|{b,c}|d"},
+
+               /* simple nesting in the middle of the field */
+               { .inp = "a,b{c,d}e,f",         .out = "a|b{c,d}e|f"},
+
+               /* multiple nesting, balanced, prefixed and suffixed */
+               { .inp = "a, {{b, c}, d}, e",   .out = "a| {{b, c}, d}| e"},
+               { .inp = "a, {b, {c, d}}, e",   .out = "a| {b, {c, d}}| e"},
+
+               /* unbalanced nesting, excess of {s */
+               { .inp = "{",                   .out = "{"},
+               { .inp = "a, {b, {c, d}, e",    .out = "a| {b, {c, d}, e"},
+
+               /* unbalanced nesting, excess of }s */
+               { .inp = "}",                   .out = "}"},
+               { .inp = "a, {b, {c, d}}}, e",  .out = "a| {b, {c, d}}}| e"},
+
+               {}
+       };
+
+       test_begin("db ldap parse attrs");
+       unsigned int index = 0;
+       for (struct vectors *vector = vectors; vector->inp != NULL; vector++, index++) {
+               const char *const *array = db_ldap_parse_attrs(vector->inp);
+               const char *out = t_strarray_join(array, "|");
+               test_assert_strcmp_idx(vector->out, out, index);
+       }
+       test_end();
+}
index 762c34bc3510314290d7bb467af4f16fedf4787b..f149eaa56ac1c501211793d04820a4a10b1b25d2 100644 (file)
@@ -12,6 +12,7 @@ int main(int argc, const char *argv[])
        const char *match = "";
        int ret;
        static const struct named_test test_functions[] = {
+               TEST_NAMED(test_db_ldap_parse_attrs)
                TEST_NAMED(test_auth_request_var_expand)
                TEST_NAMED(test_auth_request_fields)
                TEST_NAMED(test_db_dict_parse_cache_key)