# HG changeset patch # User Aki Tuomi # Date 1462942949 -10800 # Node ID 21366617ffe2ff74b204609b9572df8141aa5669 # Parent 74a77830259b4abe8126fd6b770dfe9cbe4b053e ldap: Fix cyclic dependency diff -r 74a77830259b -r 21366617ffe2 configure.ac --- a/configure.ac Mon Jun 13 12:18:07 2016 +0300 +++ b/configure.ac Wed May 11 08:02:29 2016 +0300 @@ -2929,6 +2929,7 @@ src/plugins/acl/Makefile src/plugins/imap-acl/Makefile src/plugins/autocreate/Makefile +src/plugins/dict-ldap/Makefile src/plugins/expire/Makefile src/plugins/fs-compress/Makefile src/plugins/fts/Makefile diff -r 74a77830259b -r 21366617ffe2 src/Makefile.am --- a/src/Makefile.am Mon Jun 13 12:18:07 2016 +0300 +++ b/src/Makefile.am Wed May 11 08:02:29 2016 +0300 @@ -23,9 +23,9 @@ SUBDIRS = \ $(LIBDOVECOT_SUBDIRS) \ - $(LIB_LDAP) \ lib-dict-extra \ lib-dovecot \ + $(LIB_LDAP) \ lib-fts \ lib-imap-client \ lib-imap-urlauth \ diff -r 74a77830259b -r 21366617ffe2 src/lib-dict-extra/Makefile.am --- a/src/lib-dict-extra/Makefile.am Mon Jun 13 12:18:07 2016 +0300 +++ b/src/lib-dict-extra/Makefile.am Wed May 11 08:02:29 2016 +0300 @@ -6,7 +6,6 @@ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib-dict \ -I$(top_srcdir)/src/lib-fs \ - -I$(top_srcdir)/src/lib-ldap \ -I$(top_srcdir)/src/lib-settings libdict_extra_la_SOURCES = \ @@ -14,19 +13,3 @@ dict-register.c NOPLUGIN_LDFLAGS = - -if HAVE_LDAP -LIBDICT_LDAP = libdict_ldap.la -endif -libdict_ldap_la_LDFLAGS = -module -avoid-version $(LIBDOVECOT_LDAP) - -module_dictdir = $(moduledir)/dict -module_dict_LTLIBRARIES = \ - $(LIBDICT_LDAP) - -libdict_ldap_la_SOURCES = \ - dict-ldap.c \ - dict-ldap-settings.c - -noinst_HEADERS = \ - dict-ldap-settings.h diff -r 74a77830259b -r 21366617ffe2 src/lib-dict-extra/dict-ldap-settings.c --- a/src/lib-dict-extra/dict-ldap-settings.c Mon Jun 13 12:18:07 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/* Copyright (c) 2008-2016 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "str.h" -#include "settings.h" -#include "dict-ldap-settings.h" - -#include - -static const char *dict_ldap_commonName = "cn"; -static const char *dict_ldap_empty_filter = ""; - -enum section_type { - SECTION_ROOT = 0, - SECTION_MAP, - SECTION_FIELDS -}; - -struct dict_ldap_map_attribute { - const char *name; - const char *variable; -}; - -struct setting_parser_ctx { - pool_t pool; - struct dict_ldap_settings *set; - enum section_type type; - - struct dict_ldap_map cur_map; - ARRAY(struct dict_ldap_map_attribute) cur_attributes; -}; - -#undef DEF_STR -#undef DEF_BOOL -#undef DEF_UINT - -#define DEF_STR(name) DEF_STRUCT_STR(name, dict_ldap_map) -#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, dict_ldap_map) -#define DEF_UINT(name) DEF_STRUCT_UINT(name ,dict_ldap_map) - -static const struct setting_def dict_ldap_map_setting_defs[] = { - DEF_STR(pattern), - DEF_STR(filter), - DEF_STR(filter_iter), - DEF_STR(username_attribute), - DEF_STR(value_attribute), - DEF_STR(base_dn), - DEF_STR(scope), - { 0, NULL, 0 } -}; - -static const char *pattern_read_name(const char **pattern) -{ - const char *p = *pattern, *name; - - if (*p == '{') { - /* ${name} */ - name = ++p; - p = strchr(p, '}'); - if (p == NULL) { - /* error, but allow anyway */ - *pattern += strlen(*pattern); - return ""; - } - *pattern = p + 1; - } else { - /* $name - ends at the first non-alnum_ character */ - name = p; - for (; *p != '\0'; p++) { - if (!i_isalnum(*p) && *p != '_') - break; - } - *pattern = p; - } - name = t_strdup_until(name, p); - return name; -} - -static const char *dict_ldap_attributes_map(struct setting_parser_ctx *ctx) -{ - struct dict_ldap_map_attribute *attributes; - string_t *pattern; - const char *p, *name; - unsigned int i, count; - - /* 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.pattern) + 1); - attributes = array_get_modifiable(&ctx->cur_attributes, &count); - - p_array_init(&ctx->cur_map.ldap_attributes, ctx->pool, count); - for (p = ctx->cur_map.pattern; *p != '\0';) { - if (*p != '$') { - str_append_c(pattern, *p); - p++; - continue; - } - 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) - break; - } - if (i == count) { - return t_strconcat("Missing LDAP attribute for variable: ", - name, NULL); - } - - /* mark this attribute as used */ - attributes[i].variable = NULL; - array_append(&ctx->cur_map.ldap_attributes, - &attributes[i].name, 1); - } - - /* 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); - } - } - - if (ctx->set->max_attribute_count < count) - ctx->set->max_attribute_count = count; - ctx->cur_map.pattern = p_strdup(ctx->pool, str_c(pattern)); - return NULL; -} - -static const char *dict_ldap_map_finish(struct setting_parser_ctx *ctx) -{ - if (ctx->cur_map.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 (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.scope_val = 2; /* subtree */ - } else { - if (!strcasecmp(ctx->cur_map.scope, "one")) ctx->cur_map.scope_val = 1; - else if (!strcasecmp(ctx->cur_map.scope, "base")) ctx->cur_map.scope_val = 0; - else if (!strcasecmp(ctx->cur_map.scope, "subtree")) ctx->cur_map.scope_val = 2; - else return "Scope must be one, base or subtree"; - } - if (!array_is_created(&ctx->cur_map.ldap_attributes)) { - /* no attributes besides value. allocate the array anyway. */ - p_array_init(&ctx->cur_map.ldap_attributes, ctx->pool, 1); - if (strchr(ctx->cur_map.pattern, '$') != NULL) - return "Missing attributes for pattern variables"; - } - array_append(&ctx->set->maps, &ctx->cur_map, 1); - memset(&ctx->cur_map, 0, sizeof(ctx->cur_map)); - return NULL; -} - -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: - if (strcmp(key, "uri") == 0) { - ctx->set->uri = p_strdup(ctx->pool, value); - return NULL; - } - if (strcmp(key, "bind_dn") == 0) { - ctx->set->bind_dn = p_strdup(ctx->pool, value); - return NULL; - } - if (strcmp(key, "password") == 0) { - ctx->set->password = p_strdup(ctx->pool, value); - return NULL; - } - if (strcmp(key, "timeout") == 0) { - if (str_to_uint(value, &ctx->set->timeout) != 0) { - return "Invalid timeout value"; - } - return NULL; - } - if (strcmp(key, "max_idle_time") == 0) { - if (str_to_uint(value, &ctx->set->max_idle_time) != 0) { - return "Invalid max_idle_time value"; - } - return NULL; - } - if (strcmp(key, "debug") == 0) { - if (str_to_uint(value, &ctx->set->debug) != 0) { - return "invalid debug value"; - } - return NULL; - } - if (strcmp(key, "tls") == 0) { - if (strcasecmp(value, "yes") == 0) { - ctx->set->require_ssl = TRUE; - ctx->set->start_tls = TRUE; - } else if (strcasecmp(value, "no") == 0) { - ctx->set->require_ssl = FALSE; - ctx->set->start_tls = FALSE; - } else if (strcasecmp(value, "try") == 0) { - ctx->set->require_ssl = FALSE; - ctx->set->start_tls = TRUE; - } else { - return "tls must be yes, try or no"; - } - return NULL; - } - 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); - } - 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; - } - break; - case SECTION_FIELDS: - if (type == NULL) { - ctx->type = SECTION_MAP; - *error_r = dict_ldap_attributes_map(ctx); - return FALSE; - } - break; - } - *error_r = t_strconcat("Unknown section: ", type, NULL); - return FALSE; -} - -struct dict_ldap_settings * -dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r) -{ - struct setting_parser_ctx ctx; - - memset(&ctx, 0, sizeof(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->maps, pool, 8); - - ctx.set->timeout = 30; /* default timeout */ - ctx.set->require_ssl = FALSE; /* try to start SSL */ - ctx.set->start_tls = TRUE; - - if (!settings_read(path, NULL, parse_setting, parse_section, - &ctx, error_r)) - return NULL; - - if (ctx.set->uri == NULL) { - *error_r = t_strdup_printf("Error in configuration file %s: " - "Missing ldap uri", path); - return NULL; - } - - return ctx.set; -} diff -r 74a77830259b -r 21366617ffe2 src/lib-dict-extra/dict-ldap-settings.h --- a/src/lib-dict-extra/dict-ldap-settings.h Mon Jun 13 12:18:07 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -#ifndef DICT_LDAP_SETTINGS_H -#define DICT_LDAP_SETTINGS_H - -struct dict_ldap_map { - /* pattern is in simplified form: all variables are stored as simple - '$' character. fields array is sorted by the variable index. */ - const char *pattern; - const char *filter; - const char *filter_iter; - const char *username_attribute; - const char *value_attribute; - const char *base_dn; - const char *scope; - int scope_val; - unsigned int timeout; - - ARRAY_TYPE(const_string) ldap_attributes; -}; - -struct dict_ldap_settings { - const char *uri; - const char *bind_dn; - const char *password; - unsigned int timeout; - unsigned int max_idle_time; - unsigned int debug; - unsigned int max_attribute_count; - bool require_ssl; - bool start_tls; - ARRAY(struct dict_ldap_map) maps; -}; - -struct dict_ldap_settings * -dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r); - -#endif diff -r 74a77830259b -r 21366617ffe2 src/lib-dict-extra/dict-ldap.c --- a/src/lib-dict-extra/dict-ldap.c Mon Jun 13 12:18:07 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,450 +0,0 @@ -/* Copyright (c) 2016 Dovecot authors, see the included COPYING memcached */ - -#include "lib.h" -#include "array.h" -#include "module-dir.h" -#include "str.h" -#include "istream.h" -#include "ostream.h" -#include "var-expand.h" -#include "connection.h" -#include "llist.h" -#include "ldap-client.h" -#include "dict.h" -#include "dict-private.h" -#include "dict-ldap-settings.h" - -struct ldap_dict; - -struct dict_ldap_op { - struct ldap_dict *dict; - const struct dict_ldap_map *map; - pool_t pool; - unsigned long txid; - struct dict_lookup_result res; - dict_lookup_callback_t *callback; - void *callback_ctx; -}; - -struct ldap_dict { - struct dict dict; - struct dict_ldap_settings *set; - - const char *uri; - const char *username; - const char *base_dn; - enum ldap_scope scope; - - pool_t pool; - - struct ldap_client *client; - struct ioloop *ioloop, *prev_ioloop; - - unsigned long last_txid; - unsigned int pending; - - struct ldap_dict *prev,*next; -}; - -static -void ldap_dict_lookup_async(struct dict *dict, const char *key, - dict_lookup_callback_t *callback, void *context); - - -static bool -dict_ldap_map_match(const struct dict_ldap_map *map, const char *path, - ARRAY_TYPE(const_string) *values, unsigned int *pat_len_r, - unsigned int *path_len_r, bool partial_ok, bool recurse) -{ - const char *path_start = path; - const char *pat, *attribute, *p; - unsigned int len; - - array_clear(values); - pat = map->pattern; - while (*pat != '\0' && *path != '\0') { - if (*pat == '$') { - /* variable */ - pat++; - if (*pat == '\0') { - /* pattern ended with this variable, - it'll match the rest of the path */ - len = strlen(path); - if (partial_ok) { - /* iterating - the last field never - matches fully. if there's a trailing - '/', drop it. */ - pat--; - if (path[len-1] == '/') { - attribute = t_strndup(path, len-1); - array_append(values, &attribute, 1); - } else { - array_append(values, &path, 1); - } - } else { - array_append(values, &path, 1); - path += len; - } - *path_len_r = path - path_start; - *pat_len_r = pat - map->pattern; - return TRUE; - } - /* pattern matches until the next '/' in path */ - p = strchr(path, '/'); - if (p != NULL) { - attribute = t_strdup_until(path, p); - array_append(values, &attribute, 1); - path = p; - } else { - /* no '/' anymore, but it'll still match a - partial */ - array_append(values, &path, 1); - path += strlen(path); - pat++; - } - } else if (*pat == *path) { - pat++; - path++; - } else { - return FALSE; - } - } - - *path_len_r = path - path_start; - *pat_len_r = pat - map->pattern; - - if (*pat == '\0') - return *path == '\0'; - else if (!partial_ok) - return FALSE; - else { - /* partial matches must end with '/'. */ - if (pat != map->pattern && pat[-1] != '/') - return FALSE; - /* if we're not recursing, there should be only one $variable - left. */ - if (recurse) - return TRUE; - return pat[0] == '$' && strchr(pat, '/') == NULL; - } -} - -static const struct dict_ldap_map * -ldap_dict_find_map(struct ldap_dict *dict, const char *path, - ARRAY_TYPE(const_string) *values) -{ - const struct dict_ldap_map *maps; - unsigned int i, count, len; - - t_array_init(values, dict->set->max_attribute_count); - maps = array_get(&dict->set->maps, &count); - for (i = 0; i < count; i++) { - if (dict_ldap_map_match(&maps[i], path, values, - &len, &len, FALSE, FALSE)) - return &maps[i]; - } - return NULL; -} - -static -int dict_ldap_connect(struct ldap_dict *dict, const char **error_r) -{ - struct ldap_client_settings set; - memset(&set, 0, sizeof(set)); - set.uri = dict->set->uri; - set.bind_dn = dict->set->bind_dn; - set.password = dict->set->password; - set.timeout_secs = dict->set->timeout; - set.max_idle_time_secs = dict->set->max_idle_time; - set.debug = dict->set->debug; - set.require_ssl = dict->set->require_ssl; - set.start_tls = dict->set->start_tls; - return ldap_client_init(&set, &dict->client, error_r); -} - -static void -ldap_dict_build_query(struct ldap_dict *dict, const struct dict_ldap_map *map, - ARRAY_TYPE(const_string) *values, bool priv, - string_t *query_r) -{ - const char *template; - ARRAY(struct var_expand_table) exp; - struct var_expand_table entry; - - t_array_init(&exp, 8); - entry.key = '\0'; - entry.value = dict->username; - entry.long_key = "username"; - array_append(&exp, &entry, 1); - - if (priv) { - template = t_strdup_printf("(&(%s=%s)%s)", map->username_attribute, "%{username}", map->filter); - } else { - template = map->filter; - } - - for(size_t i = 0; i < array_count(values) && i < array_count(&(map->ldap_attributes)); i++) { - struct var_expand_table entry; - entry.value = *array_idx(values, i); - entry.long_key = *array_idx(&(map->ldap_attributes), i); - array_append(&exp, &entry, 1); - } - - array_append_zero(&exp); - - var_expand(query_r, template, array_idx(&exp, 0)); -} - -static -int ldap_dict_init(struct dict *dict_driver, const char *uri, - const struct dict_settings *set, - struct dict **dict_r, const char **error_r) -{ - pool_t pool = pool_alloconly_create("ldap dict", 2048); - struct ldap_dict *dict = p_new(pool, struct ldap_dict, 1); - dict->pool = pool; - dict->dict = *dict_driver; - dict->username = p_strdup(pool, set->username); - dict->uri = p_strdup(pool, uri); - dict->set = dict_ldap_settings_read(pool, uri, error_r); - - if (dict->set == NULL) { - pool_unref(&pool); - return -1; - } - - if (dict_ldap_connect(dict, error_r) < 0) { - pool_unref(&pool); - return -1; - } - - *dict_r = (struct dict*)dict; - *error_r = NULL; - return 0; -} - -static -void ldap_dict_deinit(struct dict *dict) -{ - struct ldap_dict *ctx = (struct ldap_dict *)dict; - - ldap_client_deinit(&ctx->client); - pool_unref(&ctx->pool); -} - -static -int ldap_dict_wait(struct dict *dict) { - struct ldap_dict *ctx = (struct ldap_dict *)dict; - - i_assert(ctx->ioloop == NULL); - - ctx->prev_ioloop = current_ioloop; - ctx->ioloop = io_loop_create(); - ldap_client_switch_ioloop(ctx->client); - - do { - io_loop_run(current_ioloop); - } while (ctx->pending > 0); - - io_loop_set_current(ctx->prev_ioloop); - ldap_client_switch_ioloop(ctx->client); - io_loop_set_current(ctx->ioloop); - io_loop_destroy(&ctx->ioloop); - ctx->prev_ioloop = NULL; - - return 0; -} - -static -void ldap_dict_lookup_done(const struct dict_lookup_result *result, void *ctx) -{ - struct dict_lookup_result *res = ctx; - res->ret = result->ret; - res->value = t_strdup(result->value); - res->error = t_strdup(result->error); -} - -static void -ldap_dict_lookup_callback(struct ldap_result *result, struct dict_ldap_op *op) -{ - pool_t pool = op->pool; - struct ldap_search_iterator *iter; - const struct ldap_entry *entry; - - op->dict->pending--; - - if (ldap_result_has_failed(result)) { - op->res.ret = -1; - op->res.error = ldap_result_get_error(result); - } else { - iter = ldap_search_iterator_init(result); - entry = ldap_search_iterator_next(iter); - if (entry != NULL) { - if (op->dict->set->debug > 0) - i_debug("ldap_dict_lookup_callback got dn %s", ldap_entry_dn(entry)); - /* try extract value */ - const char *const *values = ldap_entry_get_attribute(entry, op->map->value_attribute); - if (values != NULL) { - if (op->dict->set->debug > 0) - i_debug("ldap_dict_lookup_callback got attribute %s", op->map->value_attribute); - op->res.ret = 1; - op->res.value = p_strdup(op->pool, values[0]); - } else { - if (op->dict->set->debug > 0) - i_debug("ldap_dict_lookup_callback dit not get attribute %s", op->map->value_attribute); - op->res.value = NULL; - } - } - ldap_search_iterator_deinit(&iter); - } - op->callback(&(op->res), op->callback_ctx); - pool_unref(&pool); -} - -static -int ldap_dict_lookup(struct dict *dict, pool_t pool, - const char *key, const char **value_r) -{ - struct dict_lookup_result res; - pool_t orig_pool = pool; - int ret; - - T_BEGIN { - ldap_dict_lookup_async(dict, key, ldap_dict_lookup_done, &res); - - if ((ret = ldap_dict_wait(dict)) == 0) { - if (res.ret == 0) { - *value_r = p_strdup(orig_pool, res.value); - } else ret = res.ret; - } - } T_END; - return ret; -} - -/* -static -struct dict_iterate_context *ldap_dict_iterate_init(struct dict *dict, - const char *const *paths, - enum dict_iterate_flags flags) -{ - return NULL; -} - -static -bool ldap_dict_iterate(struct dict_iterate_context *ctx, - const char **key_r, const char **value_r) -{ - return FALSE; -} - -static -int ldap_dict_iterate_deinit(struct dict_iterate_context *ctx) -{ - return -1; -} - -static -struct dict_transaction_context ldap_dict_transaction_init(struct dict *dict); - -static -int ldap_dict_transaction_commit(struct dict_transaction_context *ctx, - bool async, - dict_transaction_commit_callback_t *callback, - void *context); -static -void ldap_dict_transaction_rollback(struct dict_transaction_context *ctx); - -static -void ldap_dict_set(struct dict_transaction_context *ctx, - const char *key, const char *value); -static -void ldap_dict_unset(struct dict_transaction_context *ctx, - const char *key); -static -void ldap_dict_append(struct dict_transaction_context *ctx, - const char *key, const char *value); -static -void ldap_dict_atomic_inc(struct dict_transaction_context *ctx, - const char *key, long long diff); -*/ - -static -void ldap_dict_lookup_async(struct dict *dict, const char *key, - dict_lookup_callback_t *callback, void *context) -{ - struct ldap_search_input input; - struct ldap_dict *ctx = (struct ldap_dict*)dict; - struct dict_ldap_op *op; - pool_t oppool = pool_alloconly_create("ldap dict lookup", 64); - string_t *query = str_new(oppool, 64); - op = p_new(oppool, struct dict_ldap_op, 1); - op->pool = oppool; - op->dict = ctx; - op->callback = callback; - op->callback_ctx = context; - op->txid = ctx->last_txid++; - - /* key needs to be transformed into something else */ - ARRAY_TYPE(const_string) values; - T_BEGIN { - const char *attributes[2] = {0, 0}; - t_array_init(&values, 8); - const struct dict_ldap_map *map = ldap_dict_find_map(ctx, key, &values); - - if (map != NULL) { - op->map = map; - attributes[0] = map->value_attribute; - /* build lookup */ - memset(&input, 0, sizeof(input)); - input.base_dn = map->base_dn; - input.scope = map->scope_val; - ldap_dict_build_query(ctx, map, &values, strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE))==0, query); - input.filter = str_c(query); - input.attributes = attributes; - input.timeout_secs = ctx->set->timeout; - ctx->pending++; - ldap_search_start(ctx->client, &input, ldap_dict_lookup_callback, op); - } else { - op->res.error = "no such key"; - callback(&(op->res), context); - pool_unref(&oppool); - } - } T_END; -} - -struct dict dict_driver_ldap = { - .name = "ldap", - { - ldap_dict_init, - ldap_dict_deinit, - ldap_dict_wait, - ldap_dict_lookup, - NULL, /*ldap_dict_iterate_init,*/ - NULL, /*ldap_dict_iterate,*/ - NULL, /*ldap_dict_iterate_deinit,*/ - NULL, /*ldap_transaction_init,*/ - NULL, /*ldap_transaction_commit,*/ - NULL, /*ldap_transaction_rollback,*/ - NULL, /*ldap_set,*/ - NULL, /*ldap_unset,*/ - NULL, /*ldap_append,*/ - NULL, /*ldap_atomic_inc,*/ - ldap_dict_lookup_async - } -}; - -void dict_ldap_init(struct module *module ATTR_UNUSED); -void dict_ldap_deinit(void); - -void dict_ldap_init(struct module *module ATTR_UNUSED) -{ - dict_driver_register(&dict_driver_ldap); -} - -void dict_ldap_deinit(void) -{ - ldap_clients_cleanup(); - dict_driver_unregister(&dict_driver_ldap); -} - -const char *dict_ldap_plugin_dependencies[] = { NULL }; diff -r 74a77830259b -r 21366617ffe2 src/plugins/Makefile.am --- a/src/plugins/Makefile.am Mon Jun 13 12:18:07 2016 +0300 +++ b/src/plugins/Makefile.am Wed May 11 08:02:29 2016 +0300 @@ -10,6 +10,10 @@ FTS_SOLR = fts-solr endif +if HAVE_LDAP +DICT_LDAP = dict-ldap +endif + SUBDIRS = \ acl \ imap-acl \ @@ -38,4 +42,5 @@ $(ZLIB) \ $(FTS_LUCENE) \ $(FTS_SOLR) \ + $(DICT_LDAP) \ fs-compress diff -r 74a77830259b -r 21366617ffe2 src/plugins/dict-ldap/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/dict-ldap/Makefile.am Wed May 11 08:02:29 2016 +0300 @@ -0,0 +1,21 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-dict \ + -I$(top_srcdir)/src/lib-ldap \ + -I$(top_srcdir)/src/lib-settings + +LIBDICT_LDAP = libdict_ldap.la +libdict_ldap_la_DEPENDENCIES = $(LIBDOVECOT_LDAP) +libdict_ldap_la_LDFLAGS = -module -avoid-version +libdict_ldap_la_LIBADD = $(LIBDOVECOT_LDAP) + +module_dictdir = $(moduledir)/dict +module_dict_LTLIBRARIES = \ + $(LIBDICT_LDAP) + +libdict_ldap_la_SOURCES = \ + dict-ldap.c \ + dict-ldap-settings.c + +noinst_HEADERS = \ + dict-ldap-settings.h diff -r 74a77830259b -r 21366617ffe2 src/plugins/dict-ldap/dict-ldap-settings.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/dict-ldap/dict-ldap-settings.c Wed May 11 08:02:29 2016 +0300 @@ -0,0 +1,308 @@ +/* Copyright (c) 2008-2016 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "settings.h" +#include "dict-ldap-settings.h" + +#include + +static const char *dict_ldap_commonName = "cn"; +static const char *dict_ldap_empty_filter = ""; + +enum section_type { + SECTION_ROOT = 0, + SECTION_MAP, + SECTION_FIELDS +}; + +struct dict_ldap_map_attribute { + const char *name; + const char *variable; +}; + +struct setting_parser_ctx { + pool_t pool; + struct dict_ldap_settings *set; + enum section_type type; + + struct dict_ldap_map cur_map; + ARRAY(struct dict_ldap_map_attribute) cur_attributes; +}; + +#undef DEF_STR +#undef DEF_BOOL +#undef DEF_UINT + +#define DEF_STR(name) DEF_STRUCT_STR(name, dict_ldap_map) +#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, dict_ldap_map) +#define DEF_UINT(name) DEF_STRUCT_UINT(name ,dict_ldap_map) + +static const struct setting_def dict_ldap_map_setting_defs[] = { + DEF_STR(pattern), + DEF_STR(filter), + DEF_STR(filter_iter), + DEF_STR(username_attribute), + DEF_STR(value_attribute), + DEF_STR(base_dn), + DEF_STR(scope), + { 0, NULL, 0 } +}; + +static const char *pattern_read_name(const char **pattern) +{ + const char *p = *pattern, *name; + + if (*p == '{') { + /* ${name} */ + name = ++p; + p = strchr(p, '}'); + if (p == NULL) { + /* error, but allow anyway */ + *pattern += strlen(*pattern); + return ""; + } + *pattern = p + 1; + } else { + /* $name - ends at the first non-alnum_ character */ + name = p; + for (; *p != '\0'; p++) { + if (!i_isalnum(*p) && *p != '_') + break; + } + *pattern = p; + } + name = t_strdup_until(name, p); + return name; +} + +static const char *dict_ldap_attributes_map(struct setting_parser_ctx *ctx) +{ + struct dict_ldap_map_attribute *attributes; + string_t *pattern; + const char *p, *name; + unsigned int i, count; + + /* 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.pattern) + 1); + attributes = array_get_modifiable(&ctx->cur_attributes, &count); + + p_array_init(&ctx->cur_map.ldap_attributes, ctx->pool, count); + for (p = ctx->cur_map.pattern; *p != '\0';) { + if (*p != '$') { + str_append_c(pattern, *p); + p++; + continue; + } + 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) + break; + } + if (i == count) { + return t_strconcat("Missing LDAP attribute for variable: ", + name, NULL); + } + + /* mark this attribute as used */ + attributes[i].variable = NULL; + array_append(&ctx->cur_map.ldap_attributes, + &attributes[i].name, 1); + } + + /* 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); + } + } + + if (ctx->set->max_attribute_count < count) + ctx->set->max_attribute_count = count; + ctx->cur_map.pattern = p_strdup(ctx->pool, str_c(pattern)); + return NULL; +} + +static const char *dict_ldap_map_finish(struct setting_parser_ctx *ctx) +{ + if (ctx->cur_map.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 (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.scope_val = 2; /* subtree */ + } else { + if (!strcasecmp(ctx->cur_map.scope, "one")) ctx->cur_map.scope_val = 1; + else if (!strcasecmp(ctx->cur_map.scope, "base")) ctx->cur_map.scope_val = 0; + else if (!strcasecmp(ctx->cur_map.scope, "subtree")) ctx->cur_map.scope_val = 2; + else return "Scope must be one, base or subtree"; + } + if (!array_is_created(&ctx->cur_map.ldap_attributes)) { + /* no attributes besides value. allocate the array anyway. */ + p_array_init(&ctx->cur_map.ldap_attributes, ctx->pool, 1); + if (strchr(ctx->cur_map.pattern, '$') != NULL) + return "Missing attributes for pattern variables"; + } + array_append(&ctx->set->maps, &ctx->cur_map, 1); + memset(&ctx->cur_map, 0, sizeof(ctx->cur_map)); + return NULL; +} + +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: + if (strcmp(key, "uri") == 0) { + ctx->set->uri = p_strdup(ctx->pool, value); + return NULL; + } + if (strcmp(key, "bind_dn") == 0) { + ctx->set->bind_dn = p_strdup(ctx->pool, value); + return NULL; + } + if (strcmp(key, "password") == 0) { + ctx->set->password = p_strdup(ctx->pool, value); + return NULL; + } + if (strcmp(key, "timeout") == 0) { + if (str_to_uint(value, &ctx->set->timeout) != 0) { + return "Invalid timeout value"; + } + return NULL; + } + if (strcmp(key, "max_idle_time") == 0) { + if (str_to_uint(value, &ctx->set->max_idle_time) != 0) { + return "Invalid max_idle_time value"; + } + return NULL; + } + if (strcmp(key, "debug") == 0) { + if (str_to_uint(value, &ctx->set->debug) != 0) { + return "invalid debug value"; + } + return NULL; + } + if (strcmp(key, "tls") == 0) { + if (strcasecmp(value, "yes") == 0) { + ctx->set->require_ssl = TRUE; + ctx->set->start_tls = TRUE; + } else if (strcasecmp(value, "no") == 0) { + ctx->set->require_ssl = FALSE; + ctx->set->start_tls = FALSE; + } else if (strcasecmp(value, "try") == 0) { + ctx->set->require_ssl = FALSE; + ctx->set->start_tls = TRUE; + } else { + return "tls must be yes, try or no"; + } + return NULL; + } + 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); + } + 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; + } + break; + case SECTION_FIELDS: + if (type == NULL) { + ctx->type = SECTION_MAP; + *error_r = dict_ldap_attributes_map(ctx); + return FALSE; + } + break; + } + *error_r = t_strconcat("Unknown section: ", type, NULL); + return FALSE; +} + +struct dict_ldap_settings * +dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r) +{ + struct setting_parser_ctx ctx; + + memset(&ctx, 0, sizeof(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->maps, pool, 8); + + ctx.set->timeout = 30; /* default timeout */ + ctx.set->require_ssl = FALSE; /* try to start SSL */ + ctx.set->start_tls = TRUE; + + if (!settings_read(path, NULL, parse_setting, parse_section, + &ctx, error_r)) + return NULL; + + if (ctx.set->uri == NULL) { + *error_r = t_strdup_printf("Error in configuration file %s: " + "Missing ldap uri", path); + return NULL; + } + + return ctx.set; +} diff -r 74a77830259b -r 21366617ffe2 src/plugins/dict-ldap/dict-ldap-settings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/dict-ldap/dict-ldap-settings.h Wed May 11 08:02:29 2016 +0300 @@ -0,0 +1,36 @@ +#ifndef DICT_LDAP_SETTINGS_H +#define DICT_LDAP_SETTINGS_H + +struct dict_ldap_map { + /* pattern is in simplified form: all variables are stored as simple + '$' character. fields array is sorted by the variable index. */ + const char *pattern; + const char *filter; + const char *filter_iter; + const char *username_attribute; + const char *value_attribute; + const char *base_dn; + const char *scope; + int scope_val; + unsigned int timeout; + + ARRAY_TYPE(const_string) ldap_attributes; +}; + +struct dict_ldap_settings { + const char *uri; + const char *bind_dn; + const char *password; + unsigned int timeout; + unsigned int max_idle_time; + unsigned int debug; + unsigned int max_attribute_count; + bool require_ssl; + bool start_tls; + ARRAY(struct dict_ldap_map) maps; +}; + +struct dict_ldap_settings * +dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r); + +#endif diff -r 74a77830259b -r 21366617ffe2 src/plugins/dict-ldap/dict-ldap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/dict-ldap/dict-ldap.c Wed May 11 08:02:29 2016 +0300 @@ -0,0 +1,450 @@ +/* Copyright (c) 2016 Dovecot authors, see the included COPYING memcached */ + +#include "lib.h" +#include "array.h" +#include "module-dir.h" +#include "str.h" +#include "istream.h" +#include "ostream.h" +#include "var-expand.h" +#include "connection.h" +#include "llist.h" +#include "ldap-client.h" +#include "dict.h" +#include "dict-private.h" +#include "dict-ldap-settings.h" + +struct ldap_dict; + +struct dict_ldap_op { + struct ldap_dict *dict; + const struct dict_ldap_map *map; + pool_t pool; + unsigned long txid; + struct dict_lookup_result res; + dict_lookup_callback_t *callback; + void *callback_ctx; +}; + +struct ldap_dict { + struct dict dict; + struct dict_ldap_settings *set; + + const char *uri; + const char *username; + const char *base_dn; + enum ldap_scope scope; + + pool_t pool; + + struct ldap_client *client; + struct ioloop *ioloop, *prev_ioloop; + + unsigned long last_txid; + unsigned int pending; + + struct ldap_dict *prev,*next; +}; + +static +void ldap_dict_lookup_async(struct dict *dict, const char *key, + dict_lookup_callback_t *callback, void *context); + + +static bool +dict_ldap_map_match(const struct dict_ldap_map *map, const char *path, + ARRAY_TYPE(const_string) *values, unsigned int *pat_len_r, + unsigned int *path_len_r, bool partial_ok, bool recurse) +{ + const char *path_start = path; + const char *pat, *attribute, *p; + unsigned int len; + + array_clear(values); + pat = map->pattern; + while (*pat != '\0' && *path != '\0') { + if (*pat == '$') { + /* variable */ + pat++; + if (*pat == '\0') { + /* pattern ended with this variable, + it'll match the rest of the path */ + len = strlen(path); + if (partial_ok) { + /* iterating - the last field never + matches fully. if there's a trailing + '/', drop it. */ + pat--; + if (path[len-1] == '/') { + attribute = t_strndup(path, len-1); + array_append(values, &attribute, 1); + } else { + array_append(values, &path, 1); + } + } else { + array_append(values, &path, 1); + path += len; + } + *path_len_r = path - path_start; + *pat_len_r = pat - map->pattern; + return TRUE; + } + /* pattern matches until the next '/' in path */ + p = strchr(path, '/'); + if (p != NULL) { + attribute = t_strdup_until(path, p); + array_append(values, &attribute, 1); + path = p; + } else { + /* no '/' anymore, but it'll still match a + partial */ + array_append(values, &path, 1); + path += strlen(path); + pat++; + } + } else if (*pat == *path) { + pat++; + path++; + } else { + return FALSE; + } + } + + *path_len_r = path - path_start; + *pat_len_r = pat - map->pattern; + + if (*pat == '\0') + return *path == '\0'; + else if (!partial_ok) + return FALSE; + else { + /* partial matches must end with '/'. */ + if (pat != map->pattern && pat[-1] != '/') + return FALSE; + /* if we're not recursing, there should be only one $variable + left. */ + if (recurse) + return TRUE; + return pat[0] == '$' && strchr(pat, '/') == NULL; + } +} + +static const struct dict_ldap_map * +ldap_dict_find_map(struct ldap_dict *dict, const char *path, + ARRAY_TYPE(const_string) *values) +{ + const struct dict_ldap_map *maps; + unsigned int i, count, len; + + t_array_init(values, dict->set->max_attribute_count); + maps = array_get(&dict->set->maps, &count); + for (i = 0; i < count; i++) { + if (dict_ldap_map_match(&maps[i], path, values, + &len, &len, FALSE, FALSE)) + return &maps[i]; + } + return NULL; +} + +static +int dict_ldap_connect(struct ldap_dict *dict, const char **error_r) +{ + struct ldap_client_settings set; + memset(&set, 0, sizeof(set)); + set.uri = dict->set->uri; + set.bind_dn = dict->set->bind_dn; + set.password = dict->set->password; + set.timeout_secs = dict->set->timeout; + set.max_idle_time_secs = dict->set->max_idle_time; + set.debug = dict->set->debug; + set.require_ssl = dict->set->require_ssl; + set.start_tls = dict->set->start_tls; + return ldap_client_init(&set, &dict->client, error_r); +} + +static void +ldap_dict_build_query(struct ldap_dict *dict, const struct dict_ldap_map *map, + ARRAY_TYPE(const_string) *values, bool priv, + string_t *query_r) +{ + const char *template; + ARRAY(struct var_expand_table) exp; + struct var_expand_table entry; + + t_array_init(&exp, 8); + entry.key = '\0'; + entry.value = dict->username; + entry.long_key = "username"; + array_append(&exp, &entry, 1); + + if (priv) { + template = t_strdup_printf("(&(%s=%s)%s)", map->username_attribute, "%{username}", map->filter); + } else { + template = map->filter; + } + + for(size_t i = 0; i < array_count(values) && i < array_count(&(map->ldap_attributes)); i++) { + struct var_expand_table entry; + entry.value = *array_idx(values, i); + entry.long_key = *array_idx(&(map->ldap_attributes), i); + array_append(&exp, &entry, 1); + } + + array_append_zero(&exp); + + var_expand(query_r, template, array_idx(&exp, 0)); +} + +static +int ldap_dict_init(struct dict *dict_driver, const char *uri, + const struct dict_settings *set, + struct dict **dict_r, const char **error_r) +{ + pool_t pool = pool_alloconly_create("ldap dict", 2048); + struct ldap_dict *dict = p_new(pool, struct ldap_dict, 1); + dict->pool = pool; + dict->dict = *dict_driver; + dict->username = p_strdup(pool, set->username); + dict->uri = p_strdup(pool, uri); + dict->set = dict_ldap_settings_read(pool, uri, error_r); + + if (dict->set == NULL) { + pool_unref(&pool); + return -1; + } + + if (dict_ldap_connect(dict, error_r) < 0) { + pool_unref(&pool); + return -1; + } + + *dict_r = (struct dict*)dict; + *error_r = NULL; + return 0; +} + +static +void ldap_dict_deinit(struct dict *dict) +{ + struct ldap_dict *ctx = (struct ldap_dict *)dict; + + ldap_client_deinit(&ctx->client); + pool_unref(&ctx->pool); +} + +static +int ldap_dict_wait(struct dict *dict) { + struct ldap_dict *ctx = (struct ldap_dict *)dict; + + i_assert(ctx->ioloop == NULL); + + ctx->prev_ioloop = current_ioloop; + ctx->ioloop = io_loop_create(); + ldap_client_switch_ioloop(ctx->client); + + do { + io_loop_run(current_ioloop); + } while (ctx->pending > 0); + + io_loop_set_current(ctx->prev_ioloop); + ldap_client_switch_ioloop(ctx->client); + io_loop_set_current(ctx->ioloop); + io_loop_destroy(&ctx->ioloop); + ctx->prev_ioloop = NULL; + + return 0; +} + +static +void ldap_dict_lookup_done(const struct dict_lookup_result *result, void *ctx) +{ + struct dict_lookup_result *res = ctx; + res->ret = result->ret; + res->value = t_strdup(result->value); + res->error = t_strdup(result->error); +} + +static void +ldap_dict_lookup_callback(struct ldap_result *result, struct dict_ldap_op *op) +{ + pool_t pool = op->pool; + struct ldap_search_iterator *iter; + const struct ldap_entry *entry; + + op->dict->pending--; + + if (ldap_result_has_failed(result)) { + op->res.ret = -1; + op->res.error = ldap_result_get_error(result); + } else { + iter = ldap_search_iterator_init(result); + entry = ldap_search_iterator_next(iter); + if (entry != NULL) { + if (op->dict->set->debug > 0) + i_debug("ldap_dict_lookup_callback got dn %s", ldap_entry_dn(entry)); + /* try extract value */ + const char *const *values = ldap_entry_get_attribute(entry, op->map->value_attribute); + if (values != NULL) { + if (op->dict->set->debug > 0) + i_debug("ldap_dict_lookup_callback got attribute %s", op->map->value_attribute); + op->res.ret = 1; + op->res.value = p_strdup(op->pool, values[0]); + } else { + if (op->dict->set->debug > 0) + i_debug("ldap_dict_lookup_callback dit not get attribute %s", op->map->value_attribute); + op->res.value = NULL; + } + } + ldap_search_iterator_deinit(&iter); + } + op->callback(&(op->res), op->callback_ctx); + pool_unref(&pool); +} + +static +int ldap_dict_lookup(struct dict *dict, pool_t pool, + const char *key, const char **value_r) +{ + struct dict_lookup_result res; + pool_t orig_pool = pool; + int ret; + + T_BEGIN { + ldap_dict_lookup_async(dict, key, ldap_dict_lookup_done, &res); + + if ((ret = ldap_dict_wait(dict)) == 0) { + if (res.ret == 0) { + *value_r = p_strdup(orig_pool, res.value); + } else ret = res.ret; + } + } T_END; + return ret; +} + +/* +static +struct dict_iterate_context *ldap_dict_iterate_init(struct dict *dict, + const char *const *paths, + enum dict_iterate_flags flags) +{ + return NULL; +} + +static +bool ldap_dict_iterate(struct dict_iterate_context *ctx, + const char **key_r, const char **value_r) +{ + return FALSE; +} + +static +int ldap_dict_iterate_deinit(struct dict_iterate_context *ctx) +{ + return -1; +} + +static +struct dict_transaction_context ldap_dict_transaction_init(struct dict *dict); + +static +int ldap_dict_transaction_commit(struct dict_transaction_context *ctx, + bool async, + dict_transaction_commit_callback_t *callback, + void *context); +static +void ldap_dict_transaction_rollback(struct dict_transaction_context *ctx); + +static +void ldap_dict_set(struct dict_transaction_context *ctx, + const char *key, const char *value); +static +void ldap_dict_unset(struct dict_transaction_context *ctx, + const char *key); +static +void ldap_dict_append(struct dict_transaction_context *ctx, + const char *key, const char *value); +static +void ldap_dict_atomic_inc(struct dict_transaction_context *ctx, + const char *key, long long diff); +*/ + +static +void ldap_dict_lookup_async(struct dict *dict, const char *key, + dict_lookup_callback_t *callback, void *context) +{ + struct ldap_search_input input; + struct ldap_dict *ctx = (struct ldap_dict*)dict; + struct dict_ldap_op *op; + pool_t oppool = pool_alloconly_create("ldap dict lookup", 64); + string_t *query = str_new(oppool, 64); + op = p_new(oppool, struct dict_ldap_op, 1); + op->pool = oppool; + op->dict = ctx; + op->callback = callback; + op->callback_ctx = context; + op->txid = ctx->last_txid++; + + /* key needs to be transformed into something else */ + ARRAY_TYPE(const_string) values; + T_BEGIN { + const char *attributes[2] = {0, 0}; + t_array_init(&values, 8); + const struct dict_ldap_map *map = ldap_dict_find_map(ctx, key, &values); + + if (map != NULL) { + op->map = map; + attributes[0] = map->value_attribute; + /* build lookup */ + memset(&input, 0, sizeof(input)); + input.base_dn = map->base_dn; + input.scope = map->scope_val; + ldap_dict_build_query(ctx, map, &values, strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE))==0, query); + input.filter = str_c(query); + input.attributes = attributes; + input.timeout_secs = ctx->set->timeout; + ctx->pending++; + ldap_search_start(ctx->client, &input, ldap_dict_lookup_callback, op); + } else { + op->res.error = "no such key"; + callback(&(op->res), context); + pool_unref(&oppool); + } + } T_END; +} + +struct dict dict_driver_ldap = { + .name = "ldap", + { + ldap_dict_init, + ldap_dict_deinit, + ldap_dict_wait, + ldap_dict_lookup, + NULL, /*ldap_dict_iterate_init,*/ + NULL, /*ldap_dict_iterate,*/ + NULL, /*ldap_dict_iterate_deinit,*/ + NULL, /*ldap_transaction_init,*/ + NULL, /*ldap_transaction_commit,*/ + NULL, /*ldap_transaction_rollback,*/ + NULL, /*ldap_set,*/ + NULL, /*ldap_unset,*/ + NULL, /*ldap_append,*/ + NULL, /*ldap_atomic_inc,*/ + ldap_dict_lookup_async + } +}; + +void dict_ldap_init(struct module *module ATTR_UNUSED); +void dict_ldap_deinit(void); + +void dict_ldap_init(struct module *module ATTR_UNUSED) +{ + dict_driver_register(&dict_driver_ldap); +} + +void dict_ldap_deinit(void) +{ + ldap_clients_cleanup(); + dict_driver_unregister(&dict_driver_ldap); +} + +const char *dict_ldap_plugin_dependencies[] = { NULL };