cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING memcached */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "lib.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "array.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "module-dir.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "str.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "istream.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "ostream.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "var-expand.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "connection.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "llist.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "ldap-client.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "dict.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "dict-private.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "dict-ldap-settings.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic const char *LDAP_ESCAPE_CHARS = "*,\\#+<>;\"()= ";
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct ldap_dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct dict_ldap_op {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_dict *dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const struct dict_ldap_map *map;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_t pool;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi unsigned long txid;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct dict_lookup_result res;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict_lookup_callback_t *callback;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi void *callback_ctx;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi};
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct ldap_dict {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct dict dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct dict_ldap_settings *set;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *uri;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *username;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *base_dn;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi enum ldap_scope scope;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_t pool;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_client *client;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ioloop *ioloop, *prev_ioloop;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi unsigned long last_txid;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi unsigned int pending;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_dict *prev,*next;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi};
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumivoid ldap_dict_lookup_async(struct dict *dict, const char *key,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict_lookup_callback_t *callback, void *context);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic bool
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumidict_ldap_map_match(const struct dict_ldap_map *map, const char *path,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ARRAY_TYPE(const_string) *values, size_t *pat_len_r,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi size_t *path_len_r, bool partial_ok, bool recurse)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *path_start = path;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *pat, *attribute, *p;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi size_t len;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_clear(values);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pat = map->pattern;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi while (*pat != '\0' && *path != '\0') {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (*pat == '$') {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* variable */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pat++;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (*pat == '\0') {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* pattern ended with this variable,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi it'll match the rest of the path */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi len = strlen(path);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (partial_ok) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* iterating - the last field never
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi matches fully. if there's a trailing
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi '/', drop it. */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pat--;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (path[len-1] == '/') {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi attribute = t_strndup(path, len-1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(values, &attribute, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(values, &path, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(values, &path, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi path += len;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *path_len_r = path - path_start;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *pat_len_r = pat - map->pattern;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return TRUE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* pattern matches until the next '/' in path */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi p = strchr(path, '/');
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (p != NULL) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi attribute = t_strdup_until(path, p);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(values, &attribute, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi path = p;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* no '/' anymore, but it'll still match a
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi partial */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(values, &path, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi path += strlen(path);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pat++;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else if (*pat == *path) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pat++;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi path++;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return FALSE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *path_len_r = path - path_start;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *pat_len_r = pat - map->pattern;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (*pat == '\0')
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return *path == '\0';
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi else if (!partial_ok)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return FALSE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi else {
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi /* partial matches must end with '/'. */
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi if (pat != map->pattern && pat[-1] != '/')
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi return FALSE;
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi /* if we're not recursing, there should be only one $variable
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi left. */
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi if (recurse)
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi return TRUE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return pat[0] == '$' && strchr(pat, '/') == NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic const struct dict_ldap_map *
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumildap_dict_find_map(struct ldap_dict *dict, const char *path,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ARRAY_TYPE(const_string) *values)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const struct dict_ldap_map *maps;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi unsigned int i, count;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi size_t len;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi t_array_init(values, dict->set->max_attribute_count);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi maps = array_get(&dict->set->maps, &count);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi for (i = 0; i < count; i++) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (dict_ldap_map_match(&maps[i], path, values,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi &len, &len, FALSE, FALSE))
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return &maps[i];
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumiint dict_ldap_connect(struct ldap_dict *dict, const char **error_r)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_client_settings set;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_zero(&set);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.uri = dict->set->uri;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.bind_dn = dict->set->bind_dn;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.password = dict->set->password;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.timeout_secs = dict->set->timeout;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.max_idle_time_secs = dict->set->max_idle_time;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.debug = dict->set->debug;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.require_ssl = dict->set->require_ssl;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi set.start_tls = dict->set->start_tls;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return ldap_client_init(&set, &dict->client, error_r);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#define IS_LDAP_ESCAPED_CHAR(c) \
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ((((unsigned char)(c)) & 0x80) != 0 || strchr(LDAP_ESCAPE_CHARS, (c)) != NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic const char *ldap_escape(const char *str)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi string_t *ret = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi for (const char *p = str; *p != '\0'; p++) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (IS_LDAP_ESCAPED_CHAR(*p)) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (ret == NULL) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ret = t_str_new((size_t) (p - str) + 64);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi str_append_n(ret, str, (size_t) (p - str));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi str_printfa(ret, "\\%02X", (unsigned char)*p);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else if (ret != NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi str_append_c(ret, *p);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return ret == NULL ? str : str_c(ret);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic bool
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumildap_dict_build_query(struct ldap_dict *dict, const struct dict_ldap_map *map,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ARRAY_TYPE(const_string) *values, bool priv,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi string_t *query_r, const char **error_r)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
a1e4c206d5373b8ecd7906bff37f2601d65f022cKATOH Yasufumi const char *template, *error;
0dc296145715c36795ad0ad561f115afdd758223KATOH Yasufumi ARRAY(struct var_expand_table) exp;
a1e4c206d5373b8ecd7906bff37f2601d65f022cKATOH Yasufumi struct var_expand_table entry;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi t_array_init(&exp, 8);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi entry.key = '\0';
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi entry.value = ldap_escape(dict->username);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi entry.long_key = "username";
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(&exp, &entry, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (priv) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi template = t_strdup_printf("(&(%s=%s)%s)", map->username_attribute, "%{username}", map->filter);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi template = map->filter;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi for(size_t i = 0; i < array_count(values) && i < array_count(&map->ldap_attributes); i++) {
41e8e807c8e85289bb717a365056b9437555e25aKATOH Yasufumi struct var_expand_table entry;
41e8e807c8e85289bb717a365056b9437555e25aKATOH Yasufumi const char *const *valuep = array_idx(values, i);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *const *long_keyp = array_idx(&map->ldap_attributes, i);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi entry.value = ldap_escape(*valuep);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi entry.long_key = *long_keyp;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append(&exp, &entry, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi array_append_zero(&exp);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (var_expand(query_r, template, array_idx(&exp, 0), &error) <= 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error_r = t_strdup_printf("Failed to expand %s: %s", template, error);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return FALSE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return TRUE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumiint ldap_dict_init(struct dict *dict_driver, const char *uri,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const struct dict_settings *set,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct dict **dict_r, const char **error_r)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_t pool = pool_alloconly_create("ldap dict", 2048);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_dict *dict = p_new(pool, struct ldap_dict, 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict->pool = pool;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict->dict = *dict_driver;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict->username = p_strdup(pool, set->username);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict->uri = p_strdup(pool, uri);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict->set = dict_ldap_settings_read(pool, uri, error_r);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (dict->set == NULL) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_unref(&pool);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return -1;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (dict_ldap_connect(dict, error_r) < 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_unref(&pool);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return -1;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *dict_r = (struct dict*)dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error_r = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return 0;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumivoid ldap_dict_deinit(struct dict *dict)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_dict *ctx = (struct ldap_dict *)dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ldap_client_deinit(&ctx->client);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_unref(&ctx->pool);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic void ldap_dict_wait(struct dict *dict)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_dict *ctx = (struct ldap_dict *)dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_assert(ctx->ioloop == NULL);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ctx->prev_ioloop = current_ioloop;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ctx->ioloop = io_loop_create();
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict_switch_ioloop(dict);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi do {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi io_loop_run(current_ioloop);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } while (ctx->pending > 0);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi io_loop_set_current(ctx->prev_ioloop);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi dict_switch_ioloop(dict);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi io_loop_set_current(ctx->ioloop);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi io_loop_destroy(&ctx->ioloop);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ctx->prev_ioloop = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic bool ldap_dict_switch_ioloop(struct dict *dict)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_dict *ctx = (struct ldap_dict *)dict;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ldap_client_switch_ioloop(ctx->client);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return ctx->pending > 0;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumivoid ldap_dict_lookup_done(const struct dict_lookup_result *result, void *ctx)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct dict_lookup_result *res = ctx;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi res->ret = result->ret;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi res->value = t_strdup(result->value);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi res->error = t_strdup(result->error);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic void
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumildap_dict_lookup_callback(struct ldap_result *result, struct dict_ldap_op *op)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_t pool = op->pool;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct ldap_search_iterator *iter;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const struct ldap_entry *entry;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->dict->pending--;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (ldap_result_has_failed(result)) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->res.ret = -1;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->res.error = ldap_result_get_error(result);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi iter = ldap_search_iterator_init(result);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi entry = ldap_search_iterator_next(iter);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (entry != NULL) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (op->dict->set->debug > 0)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_debug("ldap_dict_lookup_callback got dn %s", ldap_entry_dn(entry));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* try extract value */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *const *values = ldap_entry_get_attribute(entry, op->map->value_attribute);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (values != NULL) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char **new_values;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (op->dict->set->debug > 0)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_debug("ldap_dict_lookup_callback got attribute %s", op->map->value_attribute);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->res.ret = 1;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi new_values = p_new(op->pool, const char *, 2);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi new_values[0] = p_strdup(op->pool, values[0]);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->res.values = new_values;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->res.value = op->res.values[0];
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (op->dict->set->debug > 0)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_debug("ldap_dict_lookup_callback dit not get attribute %s", op->map->value_attribute);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->res.value = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ldap_search_iterator_deinit(&iter);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi op->callback(&op->res, op->callback_ctx);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pool_unref(&pool);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic int
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumildap_dict_lookup(struct dict *dict, pool_t pool, const char *key,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char **value_r, const char **error_r)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct dict_lookup_result res;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ldap_dict_lookup_async(dict, key, ldap_dict_lookup_done, &res);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ldap_dict_wait(dict);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (res.ret < 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error_r = res.error;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return -1;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (res.ret > 0)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *value_r = p_strdup(pool, res.value);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return res.ret;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi/*
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct dict_iterate_context *ldap_dict_iterate_init(struct dict *dict,
853d58fdf5af0960b7b6edc9dea0fadddb8535f1Elan Ruusamäe const char *const *paths,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi enum dict_iterate_flags flags)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumibool ldap_dict_iterate(struct dict_iterate_context *ctx,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char **key_r, const char **value_r)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return FALSE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumiint ldap_dict_iterate_deinit(struct dict_iterate_context *ctx)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return -1;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct dict_transaction_context ldap_dict_transaction_init(struct dict *dict);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumiint ldap_dict_transaction_commit(struct dict_transaction_context *ctx,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi 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_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;
const char *error;
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;
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 */
i_zero(&input);
input.base_dn = map->base_dn;
input.scope = map->scope_val;
if (!ldap_dict_build_query(ctx, map, &values, strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE))==0, query, &error)) {
op->res.error = error;
callback(&op->res, context);
pool_unref(&oppool);
}
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);
}
}
struct dict dict_driver_ldap = {
.name = "ldap",
{
.init = ldap_dict_init,
.deinit = ldap_dict_deinit,
.wait = ldap_dict_wait,
.lookup = ldap_dict_lookup,
.lookup_async = ldap_dict_lookup_async,
.switch_ioloop = ldap_dict_switch_ioloop,
}
};
#ifndef BUILTIN_LDAP
/* Building a plugin */
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 };
#endif
#endif