]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict-ldap: ldap_dict_init() - Use settings from settings_get()
authorMarco Bettini <marco.bettini@open-xchange.com>
Thu, 3 Oct 2024 13:46:32 +0000 (13:46 +0000)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:40:01 +0000 (10:40 +0200)
src/lib-dict-backend/dict-ldap-settings.c
src/lib-dict-backend/dict-ldap-settings.h
src/lib-dict-backend/dict-ldap.c

index 94e473a5dca43d063f5d6058c1fbe704d1cff177..e306d8c03ac2baa10cd03c9d0c9853a5e9d7e074 100644 (file)
 
 #include "array.h"
 #include "str.h"
-#include "settings-legacy.h"
+#include "settings.h"
+#include "settings-parser.h"
 #include "dict-ldap-settings.h"
 
 #include <ctype.h>
 
-static const char *dict_ldap_commonName = "cn";
-static const char *dict_ldap_empty_filter = "";
+/* <settings checks> */
+#include "ldap-settings-parse.h"
+/* </settings checks> */
 
-enum section_type {
-       SECTION_ROOT = 0,
-       SECTION_MAP,
-       SECTION_FIELDS
+#undef DEF
+#undef DEFN
+#define DEF(type, name) \
+       SETTING_DEFINE_STRUCT_##type("dict_map_"#name, name, struct dict_ldap_map_settings)
+#define DEFN(type, field, name) \
+       SETTING_DEFINE_STRUCT_##type(#name, field, struct dict_ldap_map_settings)
+static const struct setting_define dict_ldap_map_setting_defines[] = {
+       DEF(STR, pattern),
+       DEFN(STR, base, ldap_base),
+       DEFN(STR, filter, ldap_filter),
+       DEFN(ENUM, scope, ldap_scope),
+       DEF(STR, username_attribute),
+       DEF(STR, value_attribute),
+       DEF(STRLIST, fields),
+       SETTING_DEFINE_LIST_END
 };
 
-struct dict_ldap_map_attribute {
-       const char *name;
-       const char *variable;
+static const struct dict_ldap_map_settings dict_ldap_map_default_settings = {
+       .pattern = "",
+       .filter = "",
+       .username_attribute = "cn",
+       .value_attribute = "",
+       .base = "",
+       .scope = "subtree:onelevel:base",
+       .fields = ARRAY_INIT,
+       .parsed_pattern_keys = ARRAY_INIT,
 };
 
-struct setting_parser_ctx {
-       pool_t pool;
-       struct dict_ldap_settings *set;
-       enum section_type type;
+const struct setting_parser_info dict_ldap_map_setting_parser_info = {
+       .name = "dict_ldap_map",
+
+       .defines = dict_ldap_map_setting_defines,
+       .defaults = &dict_ldap_map_default_settings,
+
+       .struct_size = sizeof(struct dict_ldap_map_settings),
+       .pool_offset1 = 1 + offsetof(struct dict_ldap_map_settings, pool),
+};
 
-       struct dict_ldap_map_settings cur_map;
-       ARRAY(struct dict_ldap_map_attribute) cur_attributes;
+#undef DEF
+#define DEF(type, name) \
+       SETTING_DEFINE_STRUCT_##type("ldap_"#name, name, struct dict_ldap_settings)
+static const struct setting_define dict_ldap_setting_defines[] = {
+       { .type = SET_FILTER_ARRAY, .key = "dict_map",
+         .offset = offsetof(struct dict_ldap_settings, maps),
+         .filter_array_field_name = "dict_map_pattern", },
+       SETTING_DEFINE_LIST_END
 };
 
-#undef DEF_STR
-#undef DEF_BOOL
-#undef DEF_UINT
-
-#define DEF_STR(name) DEF_STRUCT_STR(name, dict_ldap_map_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, dict_ldap_map_settings)
-#define DEF_UINT(name) DEF_STRUCT_UINT(name ,dict_ldap_map_settings)
-
-static const struct setting_def dict_ldap_map_setting_defs[] = {
-       DEF_STR(parsed_pattern),
-       DEF_STR(filter),
-       DEF_STR(username_attribute),
-       DEF_STR(value_attribute),
-       DEF_STR(base),
-       DEF_STR(scope),
-       { 0, NULL, 0 }
+static const struct dict_ldap_settings dict_ldap_default_settings = {
+       .maps = ARRAY_INIT,
 };
 
+const struct setting_parser_info dict_ldap_setting_parser_info = {
+       .name = "dict_ldap",
+
+       .defines = dict_ldap_setting_defines,
+       .defaults = &dict_ldap_default_settings,
+
+       .struct_size = sizeof(struct dict_ldap_settings),
+       .pool_offset1 = 1 + offsetof(struct dict_ldap_settings, pool),
+};
+
+static int
+dict_ldap_map_settings_postcheck(struct dict_ldap_map_settings *set,
+                            const char **error_r)
+{
+       if (!str_begins_with(pre->filter, "(")) {
+               *error_r = "ldap_filter must start with '('";
+               return -1;
+       }
+       if (set->filter[strlen(set->filter) - 1]!= ')') {
+               *error_r = "ldap_filter must end with ')'";
+               return -1;
+       }
+
+       if (*set->pattern == '\0') {
+               *error_r = "ldap_map_pattern not set";
+               return -1;
+       }
+
+       if (*set->username_attribute == '\0') {
+               *error_r = "username_attribute not set";
+               return -1;
+       }
+
+       if (*set->value_attribute == '\0') {
+               *error_r = "value_attribute  not set";
+               return -1;
+       }
+
+       if (array_is_empty(&set->fields)) {
+               if (strchr(set->pattern, '$') != NULL) {
+                       *error_r = "ldap_attributes missing for pattern variables";
+                       return -1;
+               }
+               p_array_init(&set->fields, set->pool, 1);
+       } else {
+               unsigned int count;
+               const char *const *fields = array_get(&set->fields, &count);
+               for (unsigned index = 0; index < count; index += 2, fields += 2) {
+                       if (**fields != '$') {
+                               *error_r = t_strdup_printf(
+                                       "value not starting with '$' for attribute %s",
+                                       *fields);
+                               return -1;
+                       }
+               }
+       }
+
+       if (ldap_parse_scope(set->scope, &set->parsed_scope) < 0) {
+               *error_r = t_strdup_printf("Unknown ldap_scope: %s",
+                                          set->scope);
+               return -1;
+       }
+
+       return 0;
+}
+
 static const char *pattern_read_name(const char **pattern)
 {
        const char *p = *pattern, *name;
@@ -79,20 +161,32 @@ static const char *pattern_read_name(const char **pattern)
        return name;
 }
 
-static const char *dict_ldap_attributes_map(struct setting_parser_ctx *ctx)
+static int
+dict_ldap_settings_parse_pattern(struct dict_ldap_map_settings *map,
+                                const char **error_r)
 {
-       struct dict_ldap_map_attribute *attributes;
-       string_t *pattern;
-       const char *p, *name;
-       unsigned int i, count;
+       const char *attribute, *variable, *p;
+       unsigned int count, index;
+
+       const char **const fields = array_get_modifiable(&map->fields, &count);
+       p_array_init(&map->parsed_pattern_keys, map->pool, count / 2);
+       string_t *pattern = t_str_new(strlen(map->pattern) + 1);
+
+       for (index = 0; index < count; ) {
+               attribute = fields[index++];
+               variable = fields[index++];
+               if (*variable != '$') {
+                       *error_r = t_strdup_printf(
+                               "value not starting with '$' for attribute %s",
+                               attribute);
+                       return -1;
+               }
+       }
 
        /* go through the variables in the pattern, replace them with plain
           '$' character and add its ldap attribute */
-       pattern = t_str_new(strlen(ctx->cur_map.parsed_pattern) + 1);
-       attributes = array_get_modifiable(&ctx->cur_attributes, &count);
 
-       p_array_init(&ctx->cur_map.parsed_pattern_keys, ctx->pool, count);
-       for (p = ctx->cur_map.parsed_pattern; *p != '\0';) {
+       for (p = map->pattern; *p != '\0';) {
                if (*p != '$') {
                        str_append_c(pattern, *p);
                        p++;
@@ -101,154 +195,96 @@ static const char *dict_ldap_attributes_map(struct setting_parser_ctx *ctx)
                p++;
                str_append_c(pattern, '$');
 
-               name = pattern_read_name(&p);
-               for (i = 0; i < count; i++) {
-                       if (attributes[i].variable != NULL &&
-                           strcmp(attributes[i].variable, name) == 0)
+               const char *name = pattern_read_name(&p);
+               for (index = 0; index < count; ) {
+                       attribute = fields[index++];
+                       variable = fields[index++];
+                       if (variable != NULL &&
+                           strcmp(variable, name) == 0)
                                break;
                }
-               if (i == count) {
-                       return t_strconcat("Missing LDAP attribute for variable: ",
-                                          name, NULL);
+               if (index == count) {
+                       *error_r = t_strdup_printf(
+                               "Missing LDAP attribute for variable: %s", name);
+                       return -1;
                }
 
                /* mark this attribute as used */
-               attributes[i].variable = NULL;
-               array_push_back(&ctx->cur_map.parsed_pattern_keys,
-                               &attributes[i].name);
+               array_push_back(&map->parsed_pattern_keys, &attribute);
+               variable = NULL;
        }
 
        /* make sure there aren't any unused attributes */
-       for (i = 0; i < count; i++) {
-               if (attributes[i].variable != NULL) {
-                       return t_strconcat("Unused variable: ",
-                                          attributes[i].variable, NULL);
+       for (index = 1; index < count; index += 2) {
+               variable = fields[index];
+               if (variable != NULL) {
+                       *error_r = t_strdup_printf("Unused variable: %s",
+                                                  variable);
+                       return -1;
                }
        }
 
-       ctx->cur_map.parsed_pattern = p_strdup(ctx->pool, str_c(pattern));
-       return NULL;
+       map->parsed_pattern = p_strdup(map->pool, str_c(pattern));
+       return 0;
 }
 
-static const char *dict_ldap_map_finish(struct setting_parser_ctx *ctx)
+static int
+dict_ldap_settings_parse_maps(struct event *event, struct dict_ldap_settings *set,
+                             const char **error_r)
 {
-       if (ctx->cur_map.parsed_pattern == NULL)
-               return "Missing setting: pattern";
-       if (ctx->cur_map.filter == NULL)
-               ctx->cur_map.filter = dict_ldap_empty_filter;
-       if (*ctx->cur_map.filter != '\0') {
-               const char *ptr = ctx->cur_map.filter;
-               if (*ptr != '(')
-                       return "Filter must start with (";
-               while(*ptr != '\0') ptr++;
-               ptr--;
-               if (*ptr != ')')
-                       return "Filter must end with )";
+       if (array_is_empty(&set->maps)) {
+               *error_r = "no dict_maps found by dict ldap driver";
+               return -1;
        }
-       if (ctx->cur_map.value_attribute == NULL)
-               return "Missing setting: value_attribute";
 
-       if (ctx->cur_map.username_attribute == NULL) {
-               /* default to commonName */
-               ctx->cur_map.username_attribute = dict_ldap_commonName;
-       }
-       if (ctx->cur_map.scope == NULL) {
-               ctx->cur_map.parsed_scope = 2; /* subtree */
-       } else {
-               if (strcasecmp(ctx->cur_map.scope, "one") == 0) ctx->cur_map.parsed_scope = 1;
-               else if (strcasecmp(ctx->cur_map.scope, "base") == 0) ctx->cur_map.parsed_scope = 0;
-               else if (strcasecmp(ctx->cur_map.scope, "subtree") == 0) ctx->cur_map.parsed_scope = 2;
-               else return "Scope must be one, base or subtree";
-       }
-       if (!array_is_created(&ctx->cur_map.parsed_pattern_keys)) {
-               /* no attributes besides value. allocate the array anyway. */
-               p_array_init(&ctx->cur_map.parsed_pattern_keys, ctx->pool, 1);
-               if (strchr(ctx->cur_map.parsed_pattern, '$') != NULL)
-                       return "Missing attributes for pattern variables";
-       }
-       array_push_back(&ctx->set->parsed_maps, &ctx->cur_map);
-       i_zero(&ctx->cur_map);
-       return NULL;
-}
+       p_array_init(&set->parsed_maps, set->pool, array_count(&set->maps));
 
-static const char *
-parse_setting(const char *key, const char *value,
-             struct setting_parser_ctx *ctx)
-{
-       struct dict_ldap_map_attribute *attribute;
-
-       switch (ctx->type) {
-       case SECTION_ROOT:
-               break;
-       case SECTION_MAP:
-               return parse_setting_from_defs(ctx->pool,
-                                              dict_ldap_map_setting_defs,
-                                              &ctx->cur_map, key, value);
-       case SECTION_FIELDS:
-               if (*value != '$') {
-                       return t_strconcat("Value is missing '$' for attribute: ",
-                                          key, NULL);
+       const char *name;
+       array_foreach_elem(&set->maps, name) {
+               struct dict_ldap_map_settings *map;
+               if (settings_get_filter(event, "dict_map", name,
+                                       &dict_ldap_map_setting_parser_info,
+                                       SETTINGS_GET_FLAG_NO_EXPAND, &map,
+                                       error_r) < 0) {
+                       *error_r = t_strdup_printf("Failed to get dict_map %s: %s",
+                                                  name, *error_r);
+                       return -1;
                }
-               attribute = array_append_space(&ctx->cur_attributes);
-               attribute->name = p_strdup(ctx->pool, key);
-               attribute->variable = p_strdup(ctx->pool, value + 1);
-               return NULL;
-       }
-       return t_strconcat("Unknown setting: ", key, NULL);
-}
 
-static bool
-parse_section(const char *type, const char *name ATTR_UNUSED,
-             struct setting_parser_ctx *ctx, const char **error_r)
-{
-       switch (ctx->type) {
-       case SECTION_ROOT:
-               if (type == NULL)
-                       return FALSE;
-               if (strcmp(type, "map") == 0) {
-                       array_clear(&ctx->cur_attributes);
-                       ctx->type = SECTION_MAP;
-                       return TRUE;
-               }
-               break;
-       case SECTION_MAP:
-               if (type == NULL) {
-                       ctx->type = SECTION_ROOT;
-                       *error_r = dict_ldap_map_finish(ctx);
-                       return FALSE;
-               }
-               if (strcmp(type, "fields") == 0) {
-                       ctx->type = SECTION_FIELDS;
-                       return TRUE;
+               if (dict_ldap_map_settings_postcheck(map, error_r) < 0) {
+                       settings_free(map);
+                       return -1;
                }
-               break;
-       case SECTION_FIELDS:
-               if (type == NULL) {
-                       ctx->type = SECTION_MAP;
-                       *error_r = dict_ldap_attributes_map(ctx);
-                       return FALSE;
+
+               if (dict_ldap_settings_parse_pattern(map, error_r) < 0) {
+                       settings_free(map);
+                       return -1;
                }
-               break;
+
+               pool_add_external_ref(set->pool, map->pool);
+               pool_t pool_copy = map->pool;
+               pool_unref(&pool_copy);
+
+               array_push_back(&set->parsed_maps, map);
        }
-       *error_r = t_strconcat("Unknown section: ", type, NULL);
-       return FALSE;
+
+       return 0;
 }
 
-struct dict_ldap_settings *
-dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r)
+int dict_ldap_settings_get(struct event *event,
+                          const struct dict_ldap_settings **set_r,
+                          const char **error_r)
 {
-       struct setting_parser_ctx ctx;
-
-       i_zero(&ctx);
-       ctx.pool = pool;
-       ctx.set = p_new(pool, struct dict_ldap_settings, 1);
-       t_array_init(&ctx.cur_attributes, 16);
-       p_array_init(&ctx.set->parsed_maps, pool, 8);
-
-       if (!settings_read(path, NULL, parse_setting, parse_section,
-                          &ctx, error_r))
-               return NULL;
-       return ctx.set;
+       struct dict_ldap_settings *set = NULL;
+       if (settings_get(event, &dict_ldap_setting_parser_info, 0, &set, error_r) < 0 ||
+           dict_ldap_settings_parse_maps(event, set, error_r) < 0) {
+               settings_free(set);
+               return -1;
+       }
+
+       *set_r = set;
+       *error_r = NULL;
+       return 0;
 }
 
 #endif
index 74835265b18f9873806e991e60efeb25db65200c..6a1bb4c51c7b188811be2dd7482298db740f53e8 100644 (file)
@@ -2,14 +2,19 @@
 #define DICT_LDAP_SETTINGS_H
 
 struct dict_ldap_map_settings {
+       pool_t pool;
+
+       const char *pattern;
        const char *filter;
        const char *username_attribute;
        const char *value_attribute;
        const char *base;
        const char *scope;
-       unsigned int timeout;
+       ARRAY_TYPE(const_string) fields;
 
        /* parsed */
+
+       /* attributes sorted by the position in parsed_pattern. */
        ARRAY_TYPE(const_string) parsed_pattern_keys;
        int parsed_scope;
 
@@ -18,10 +23,18 @@ struct dict_ldap_map_settings {
 };
 
 struct dict_ldap_settings {
-       ARRAY(struct dict_ldap_map_settings) parsed_maps;
+       pool_t pool;
+       ARRAY_TYPE(const_string) maps;
+
+       /* parsed */
+       ARRAY(const struct dict_ldap_map_settings) parsed_maps;
 };
 
-struct dict_ldap_settings *
-dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r);
+extern const struct setting_parser_info dict_ldap_map_setting_parser_info;
+extern const struct setting_parser_info dict_ldap_setting_parser_info;
+
+int dict_ldap_settings_get(struct event *event,
+                          const struct dict_ldap_settings **set_r,
+                          const char **error_r);
 
 #endif
index be140f1bd7ca2794958feb1c904e1fdb2af27101..b3ecaad128d42b7bf6070d329440ce93ca80c19d 100644 (file)
@@ -15,6 +15,7 @@
 #include "ldap-client.h"
 #include "dict.h"
 #include "dict-private.h"
+#include "settings.h"
 #include "dict-ldap-settings.h"
 
 static const char *LDAP_ESCAPE_CHARS = "*,\\#+<>;\"()= ";
@@ -34,7 +35,7 @@ struct dict_ldap_op {
 
 struct ldap_dict {
        struct dict dict;
-       struct dict_ldap_settings *set;
+       const struct dict_ldap_settings *set;
 
        const char *uri;
        const char *base_dn;
@@ -190,31 +191,28 @@ ldap_dict_build_query(const struct dict_op_settings *set,
 }
 
 static
-int ldap_dict_init_legacy(struct dict *dict_driver, const char *uri,
-                         const struct dict_legacy_settings *set ATTR_UNUSED,
-                         struct dict **dict_r, const char **error_r)
+int ldap_dict_init(const struct dict *dict_driver, struct event *event,
+                  struct dict **dict_r, const char **error_r)
 {
+       const struct dict_ldap_settings *set;
+       if (dict_ldap_settings_get(event, &set, error_r) < 0)
+               return -1;
+
        pool_t pool = pool_alloconly_create("ldap dict", 2048);
        struct ldap_dict *dict = p_new(pool, struct ldap_dict, 1);
        dict->pool = pool;
-       dict->event = event_create(dict_driver->event);
+       dict->event = event_create(event);
        dict->dict = *dict_driver;
-       dict->uri = p_strdup(pool, uri);
-       dict->set = dict_ldap_settings_read(pool, uri, error_r);
-
-       if (dict->set == NULL) {
-               event_unref(&dict->event);
-               pool_unref(&pool);
-               return -1;
-       }
+       dict->set = set;
 
        if (dict_ldap_connect(dict, error_r) < 0) {
                event_unref(&dict->event);
+               settings_free(set);
                pool_unref(&pool);
                return -1;
        }
 
-       *dict_r = (struct dict*)dict;
+       *dict_r = &dict->dict;
        *error_r = NULL;
        return 0;
 }
@@ -226,6 +224,7 @@ void ldap_dict_deinit(struct dict *dict)
 
        ldap_client_deinit(&ctx->client);
        event_unref(&dict->event);
+       settings_free(ctx->set);
        pool_unref(&ctx->pool);
 }
 
@@ -442,7 +441,7 @@ void ldap_dict_lookup_async(struct dict *dict,
 struct dict dict_driver_ldap = {
        .name = "ldap",
        .v = {
-               .init_legacy = ldap_dict_init_legacy,
+               .init = ldap_dict_init,
                .deinit = ldap_dict_deinit,
                .wait = ldap_dict_wait,
                .lookup = ldap_dict_lookup,