db-ldap.c revision 594d203bdcbd160688bce5d5a6d65783b919ad49
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce/* Copyright (C) 2003-2006 Timo Sirainen */
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "common.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "network.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "ioloop.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "hash.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "str.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "settings.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "userdb.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include "db-ldap.h"
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include <stddef.h>
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#include <stdlib.h>
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#define HAVE_LDAP_SASL
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#ifdef HAVE_SASL_SASL_H
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce# include <sasl/sasl.h>
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#elif defined (HAVE_SASL_H)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce# include <sasl.h>
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#else
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce# undef HAVE_LDAP_SASL
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#endif
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#if SASL_VERSION_MAJOR < 2
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce# undef HAVE_LDAP_SASL
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#endif
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#ifndef LDAP_SASL_QUIET
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio#endif
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio/* Older versions may require calling ldap_result() twice */
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio#if LDAP_VENDOR_VERSION <= 20112
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce# define OPENLDAP_ASYNC_WORKAROUND
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek#endif
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek#ifndef LDAP_OPT_SUCCESS
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek# define LDAP_OPT_SUCCESS LDAP_SUCCESS
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek#endif
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek#define DEF(type, name) \
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek { type, #name, offsetof(struct ldap_settings, name) }
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstatic struct setting_def setting_defs[] = {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, hosts),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, uris),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, dn),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, dnpass),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_BOOL, auth_bind),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, auth_bind_userdn),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_BOOL, tls),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_BOOL, sasl_bind),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, sasl_mech),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, sasl_realm),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, sasl_authz_id),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, deref),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, scope),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, base),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_INT, ldap_version),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, user_attrs),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, user_filter),
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce DEF(SET_STR, pass_attrs),
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio DEF(SET_STR, pass_filter),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, default_pass_scheme),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, user_global_uid),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek DEF(SET_STR, user_global_gid),
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio { 0, NULL, 0 }
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio};
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstruct ldap_settings default_ldap_settings = {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(hosts) NULL,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(uris) NULL,
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio MEMBER(dn) NULL,
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio MEMBER(dnpass) NULL,
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio MEMBER(auth_bind) FALSE,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(auth_bind_userdn) NULL,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(tls) FALSE,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(sasl_bind) FALSE,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(sasl_mech) NULL,
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio MEMBER(sasl_realm) NULL,
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio MEMBER(sasl_authz_id) NULL,
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio MEMBER(deref) "never",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(scope) "subtree",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(base) NULL,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(ldap_version) 2,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(user_attrs) "uid,homeDirectory,,,uidNumber,gidNumber",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(pass_attrs) "uid,userPassword",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(default_pass_scheme) "crypt",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(user_global_uid) "",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek MEMBER(user_global_gid) ""
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek};
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstatic struct ldap_connection *ldap_connections = NULL;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstatic int db_ldap_bind(struct ldap_connection *conn);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstatic int deref2str(const char *str)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek{
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "never") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_DEREF_NEVER;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "searching") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_DEREF_SEARCHING;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "finding") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_DEREF_FINDING;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "always") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_DEREF_ALWAYS;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek i_fatal("LDAP: Unknown deref option '%s'", str);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek}
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekstatic int scope2str(const char *str)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek{
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "base") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_SCOPE_BASE;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "onelevel") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_SCOPE_ONELEVEL;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (strcasecmp(str, "subtree") == 0)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return LDAP_SCOPE_SUBTREE;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek i_fatal("LDAP: Unknown scope option '%s'", str);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek}
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncioconst char *ldap_get_error(struct ldap_connection *conn)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek{
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek int ret, err;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (ret != LDAP_SUCCESS) {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek i_error("LDAP: Can't get error number: %s",
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek ldap_err2string(ret));
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return "??";
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek }
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return ldap_err2string(err);
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio}
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekvoid db_ldap_add_delayed_request(struct ldap_connection *conn,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek struct ldap_request *request)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek{
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek i_assert(!conn->connected);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek request->next = NULL;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (conn->delayed_requests_head == NULL)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek conn->delayed_requests_head = request;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek else
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek conn->delayed_requests_tail->next = request;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek conn->delayed_requests_tail = request;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek}
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozekvoid db_ldap_search(struct ldap_connection *conn, struct ldap_request *request,
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek int scope)
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek{
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek int msgid;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (db_ldap_connect(conn) < 0) {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek request->callback(conn, request, NULL);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek }
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio if (conn->connected) {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (conn->last_auth_bind) {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek /* switch back to the default dn before doing the
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek search request. */
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek if (db_ldap_bind(conn) < 0) {
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek request->callback(conn, request, NULL);
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek return;
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek }
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio }
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio
4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9Jakub Hrozek msgid = ldap_search(conn->ld, request->base, scope,
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio request->filter, request->attributes, 0);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek if (msgid == -1) {
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek i_error("LDAP: ldap_search() failed (filter %s): %s",
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek request->filter, ldap_get_error(conn));
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek request->callback(conn, request, NULL);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek return;
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek }
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek hash_insert(conn->requests, POINTER_CAST(msgid), request);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek } else {
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek db_ldap_add_delayed_request(conn, request);
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek }
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek}
197da163943868216f704fb34031e7d5576e8aeeJakub Hrozek
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidênciostatic void ldap_conn_retry_requests(struct ldap_connection *conn)
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio{
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct hash_table *old_requests;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct hash_iterate_context *iter;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct ldap_request *request, **p, *next;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce void *key, *value;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce bool have_hash_binds = FALSE;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_assert(conn->connected);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (hash_size(conn->requests) == 0 &&
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce conn->delayed_requests_head == NULL)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce return;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce old_requests = conn->requests;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce conn->requests = hash_create(default_pool, conn->pool, 0, NULL, NULL);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce conn->retrying = TRUE;
4358d76475f0292461a2a479d2149472db103c1dFabiano Fidêncio /* first retry all the search requests */
4358d76475f0292461a2a479d2149472db103c1dFabiano Fidêncio iter = hash_iterate_init(old_requests);
4358d76475f0292461a2a479d2149472db103c1dFabiano Fidêncio while (hash_iterate(iter, &key, &value)) {
4358d76475f0292461a2a479d2149472db103c1dFabiano Fidêncio request = value;
4358d76475f0292461a2a479d2149472db103c1dFabiano Fidêncio
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (request->filter == NULL) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* bind request */
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce have_hash_binds = TRUE;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce } else {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_assert(conn->connected);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce db_ldap_search(conn, request, conn->set.ldap_scope);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce hash_iterate_deinit(iter);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* then delayed search requests */
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce p = &conn->delayed_requests_head;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce while (*p != NULL) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request = *p;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (request->filter != NULL) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce *p = request->next;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_assert(conn->connected);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce db_ldap_search(conn, request, conn->set.ldap_scope);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce } else {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce p = &(*p)->next;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (have_hash_binds && conn->set.auth_bind) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* next retry all the bind requests. without auth binds the
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce only bind request can be the initial connection binding,
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce which we don't care to retry. */
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce iter = hash_iterate_init(old_requests);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce while (hash_iterate(iter, &key, &value)) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request = value;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (request->filter == NULL)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request->callback(conn, request, NULL);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
b1829f05cf9bdc3d89c1058481281198ebc968d0Fabiano Fidêncio hash_iterate_deinit(iter);
b1829f05cf9bdc3d89c1058481281198ebc968d0Fabiano Fidêncio }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (conn->delayed_requests_head != NULL && conn->set.auth_bind) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request = conn->delayed_requests_head;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce for (; request != NULL; request = next) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce next = request->next;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_assert(request->filter == NULL);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request->callback(conn, request, NULL);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce hash_destroy(old_requests);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_assert(conn->delayed_requests_head == NULL);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce conn->delayed_requests_tail = NULL;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce conn->retrying = FALSE;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce}
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorcestatic void ldap_conn_reconnect(struct ldap_connection *conn)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce{
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ldap_conn_close(conn, FALSE);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (db_ldap_connect(conn) < 0) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* failed to reconnect. fail all requests. */
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ldap_conn_close(conn, TRUE);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce}
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorcestatic void ldap_input(void *context)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce{
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct ldap_connection *conn = context;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct ldap_request *request;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct timeval timeout;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce LDAPMessage *res;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce int ret, msgid;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce while (conn->ld != NULL) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce memset(&timeout, 0, sizeof(timeout));
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#ifdef OPENLDAP_ASYNC_WORKAROUND
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (ret == 0) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* try again, there may be another in buffer */
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ret = ldap_result(conn->ld, LDAP_RES_ANY, 1,
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce &timeout, &res);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#endif
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (ret <= 0) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (ret < 0) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_error("LDAP: ldap_result() failed: %s",
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ldap_get_error(conn));
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ldap_conn_reconnect(conn);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce return;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce msgid = ldap_msgid(res);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request = hash_lookup(conn->requests, POINTER_CAST(msgid));
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (request == NULL) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce i_error("LDAP: Reply with unknown msgid %d",
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce msgid);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce } else {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce hash_remove(conn->requests, POINTER_CAST(msgid));
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce request->callback(conn, request, res);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce ldap_msgfree(res);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce}
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#ifdef HAVE_LDAP_SASL
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorcestatic int
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorcesasl_interact(LDAP *ld __attr_unused__, unsigned flags __attr_unused__,
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce void *defaults, void *interact)
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce{
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce struct ldap_sasl_bind_context *context = defaults;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce sasl_interact_t *in;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce const char *str;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce for (in = interact; in->id != SASL_CB_LIST_END; in++) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce switch (in->id) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce case SASL_CB_GETREALM:
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce str = context->realm;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce break;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce case SASL_CB_AUTHNAME:
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce str = context->authcid;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce break;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce case SASL_CB_USER:
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce str = context->authzid;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce break;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce case SASL_CB_PASS:
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce str = context->passwd;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce break;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce default:
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce str = NULL;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce break;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
if (str != NULL) {
in->len = strlen(str);
in->result = str;
}
}
return LDAP_SUCCESS;
}
#endif
static int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
{
if (ret == LDAP_SERVER_DOWN) {
i_error("LDAP: Can't connect to server: %s",
conn->set.uris != NULL ?
conn->set.uris : conn->set.hosts);
return -1;
}
if (ret != LDAP_SUCCESS) {
i_error("LDAP: binding failed (dn %s): %s",
conn->set.dn == NULL ? "(none)" : conn->set.dn,
ldap_get_error(conn));
return -1;
}
if (!conn->connected) {
conn->connected = TRUE;
/* in case there are requests waiting, retry them */
ldap_conn_retry_requests(conn);
}
return 0;
}
static void db_ldap_bind_callback(struct ldap_connection *conn,
struct ldap_request *ldap_request,
LDAPMessage *res)
{
int ret;
conn->connecting = FALSE;
i_free(ldap_request);
if (res == NULL) {
/* aborted */
return;
}
ret = ldap_result2error(conn->ld, res, FALSE);
if (db_ldap_connect_finish(conn, ret) < 0) {
/* lost connection, close it */
ldap_conn_close(conn, TRUE);
}
}
static int db_ldap_bind(struct ldap_connection *conn)
{
struct ldap_request *ldap_request;
int msgid;
ldap_request = i_new(struct ldap_request, 1);
ldap_request->callback = db_ldap_bind_callback;
ldap_request->context = conn;
msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.
dnpass, LDAP_AUTH_SIMPLE);
if (msgid == -1) {
i_error("ldap_bind(%s) failed: %s",
conn->set.dn, ldap_get_error(conn));
i_free(ldap_request);
return -1;
}
conn->connecting = TRUE;
hash_insert(conn->requests, POINTER_CAST(msgid), ldap_request);
/* we're binding back to the original DN, not doing an
authentication bind */
conn->last_auth_bind = FALSE;
return 0;
}
static void db_ldap_get_fd(struct ldap_connection *conn)
{
int ret;
/* get the connection's fd */
ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
if (ret != LDAP_SUCCESS) {
i_fatal("LDAP: Can't get connection fd: %s",
ldap_err2string(ret));
}
i_assert(conn->fd != -1);
net_set_nonblock(conn->fd, TRUE);
}
int db_ldap_connect(struct ldap_connection *conn)
{
unsigned int ldap_version;
int ret;
if (conn->connected || conn->connecting)
return 0;
if (conn->ld == NULL) {
if (conn->set.uris != NULL) {
#ifdef LDAP_HAVE_INITIALIZE
if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
conn->ld = NULL;
#else
i_fatal("LDAP: Your LDAP library doesn't support "
"'uris' setting, use 'hosts' instead.");
#endif
} else
conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
if (conn->ld == NULL)
i_fatal("LDAP: ldap_init() failed with hosts: %s",
conn->set.hosts);
ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
(void *)&conn->set.ldap_deref);
if (ret != LDAP_SUCCESS) {
i_fatal("LDAP: Can't set deref option: %s",
ldap_err2string(ret));
}
/* If SASL binds are used, the protocol version needs to be
at least 3 */
ldap_version = conn->set.sasl_bind &&
conn->set.ldap_version < 3 ? 3 :
conn->set.ldap_version;
ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
(void *)&ldap_version);
if (ret != LDAP_OPT_SUCCESS) {
i_fatal("LDAP: Can't set protocol version %u: %s",
ldap_version, ldap_err2string(ret));
}
}
if (conn->set.tls) {
#ifdef LDAP_HAVE_START_TLS_S
ret = ldap_start_tls_s(conn->ld, NULL, NULL);
if (ret != LDAP_SUCCESS) {
i_error("LDAP: ldap_start_tls_s() failed: %s",
ldap_err2string(ret));
return -1;
}
#else
i_error("LDAP: Your LDAP library doesn't support TLS");
return -1;
#endif
}
if (conn->set.sasl_bind) {
#ifdef HAVE_LDAP_SASL
struct ldap_sasl_bind_context context;
memset(&context, 0, sizeof(context));
context.authcid = conn->set.dn;
context.passwd = conn->set.dnpass;
context.realm = conn->set.sasl_realm;
context.authzid = conn->set.sasl_authz_id;
/* There doesn't seem to be a way to do SASL binding
asynchronously.. */
ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
conn->set.sasl_mech,
NULL, NULL, LDAP_SASL_QUIET,
sasl_interact, &context);
if (db_ldap_connect_finish(conn, ret) < 0)
return -1;
db_ldap_get_fd(conn);
#else
i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
#endif
} else {
if (db_ldap_bind(conn) < 0)
return -1;
db_ldap_get_fd(conn);
}
conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
return 0;
}
static void ldap_conn_close(struct ldap_connection *conn, bool flush_requests)
{
struct hash_iterate_context *iter;
struct ldap_request *request, *next;
void *key, *value;
if (flush_requests) {
iter = hash_iterate_init(conn->requests);
while (hash_iterate(iter, &key, &value)) {
request = value;
request->callback(conn, request, NULL);
}
hash_iterate_deinit(iter);
hash_clear(conn->requests, FALSE);
request = conn->delayed_requests_head;
for (; request != NULL; request = next) {
next = request->next;
request->callback(conn, request, NULL);
}
conn->delayed_requests_head = NULL;
conn->delayed_requests_tail = NULL;
}
conn->connected = FALSE;
if (conn->io != NULL)
io_remove(&conn->io);
if (conn->ld != NULL) {
ldap_unbind(conn->ld);
conn->ld = NULL;
}
conn->fd = -1;
}
void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
char ***attr_names_r, struct hash_table *attr_map,
const char *const default_attr_map[],
const char *skip_attr)
{
const char *const *attr;
char *name, *value, *p;
unsigned int i, j, size;
if (*attrlist == '\0')
return;
t_push();
attr = t_strsplit(attrlist, ",");
/* @UNSAFE */
for (size = 0; attr[size] != NULL; size++) ;
*attr_names_r = p_new(conn->pool, char *, size + 1);
for (i = j = 0; i < size; i++) {
p = strchr(attr[i], '=');
if (p == NULL) {
name = p_strdup(conn->pool, attr[i]);
value = *default_attr_map == NULL ? name :
p_strdup(conn->pool, *default_attr_map);
} else {
name = p_strdup_until(conn->pool, attr[i], p);
value = p_strdup(conn->pool, p + 1);
}
if (skip_attr != NULL && strcmp(skip_attr, value) == 0)
name = "";
if (*name != '\0') {
hash_insert(attr_map, name, value);
(*attr_names_r)[j++] = name;
}
if (*default_attr_map != NULL)
default_attr_map++;
}
t_pop();
}
#define IS_LDAP_ESCAPED_CHAR(c) \
((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
const char *ldap_escape(const char *str,
const struct auth_request *auth_request __attr_unused__)
{
const char *p;
string_t *ret;
for (p = str; *p != '\0'; p++) {
if (IS_LDAP_ESCAPED_CHAR(*p))
break;
}
if (*p == '\0')
return str;
ret = t_str_new((size_t) (p - str) + 64);
str_append_n(ret, str, (size_t) (p - str));
for (; *p != '\0'; p++) {
if (IS_LDAP_ESCAPED_CHAR(*p))
str_append_c(ret, '\\');
str_append_c(ret, *p);
}
return str_c(ret);
}
static const char *parse_setting(const char *key, const char *value,
void *context)
{
struct ldap_connection *conn = context;
return parse_setting_from_defs(conn->pool, setting_defs,
&conn->set, key, value);
}
static struct ldap_connection *ldap_conn_find(const char *config_path)
{
struct ldap_connection *conn;
for (conn = ldap_connections; conn != NULL; conn = conn->next) {
if (strcmp(conn->config_path, config_path) == 0)
return conn;
}
return NULL;
}
struct ldap_connection *db_ldap_init(const char *config_path)
{
struct ldap_connection *conn;
pool_t pool;
/* see if it already exists */
conn = ldap_conn_find(config_path);
if (conn != NULL) {
conn->refcount++;
return conn;
}
if (*config_path == '\0')
i_fatal("LDAP: Configuration file path not given");
pool = pool_alloconly_create("ldap_connection", 1024);
conn = p_new(pool, struct ldap_connection, 1);
conn->pool = pool;
conn->refcount = 1;
conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
conn->fd = -1;
conn->config_path = p_strdup(pool, config_path);
conn->set = default_ldap_settings;
if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
exit(FATAL_DEFAULT);
if (conn->set.base == NULL)
i_fatal("LDAP: No base given");
if (conn->set.uris == NULL && conn->set.hosts == NULL)
i_fatal("LDAP: No uris or hosts set");
#ifndef LDAP_HAVE_INITIALIZE
if (conn->set.uris != NULL) {
i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
"(ldap_initialize not found)");
}
#endif
conn->set.ldap_deref = deref2str(conn->set.deref);
conn->set.ldap_scope = scope2str(conn->set.scope);
if (*conn->set.user_global_uid == '\0')
conn->set.uid = (uid_t)-1;
else {
conn->set.uid =
userdb_parse_uid(NULL, conn->set.user_global_uid);
if (conn->set.uid == (uid_t)-1) {
i_fatal("LDAP: Invalid user_global_uid: %s",
conn->set.user_global_uid);
}
}
if (*conn->set.user_global_gid == '\0')
conn->set.gid = (gid_t)-1;
else {
conn->set.gid =
userdb_parse_gid(NULL, conn->set.user_global_gid);
if (conn->set.gid == (gid_t)-1) {
i_fatal("LDAP: Invalid user_global_gid: %s",
conn->set.user_global_gid);
}
}
conn->next = ldap_connections;
ldap_connections = conn;
return conn;
}
void db_ldap_unref(struct ldap_connection **_conn)
{
struct ldap_connection *conn = *_conn;
struct ldap_connection **p;
*_conn = NULL;
i_assert(conn->refcount >= 0);
if (--conn->refcount > 0)
return;
for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
if (*p == conn) {
*p = conn->next;
break;
}
}
ldap_conn_close(conn, TRUE);
hash_destroy(conn->requests);
if (conn->pass_attr_map != NULL)
hash_destroy(conn->pass_attr_map);
if (conn->user_attr_map != NULL)
hash_destroy(conn->user_attr_map);
pool_unref(conn->pool);
}
#endif