db-ldap.c revision e434abb86a137bbe710320b5f5431804f05c6e26
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
f242fa00989e452ecffba917f20f885f509d0f8fTimo Sirainen#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* Older versions may require calling ldap_result() twice */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen const char *name, *value, *template, *val_1_arr[2];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *static_attrs;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#define DEF_STR(name) DEF_STRUCT_STR(name, ldap_settings)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#define DEF_INT(name) DEF_STRUCT_INT(name, ldap_settings)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, ldap_settings)
13307d0b3f41c6d940ae263f4828cf557258f9b9Timo Sirainenstatic struct ldap_settings default_ldap_settings = {
13307d0b3f41c6d940ae263f4828cf557258f9b9Timo Sirainen MEMBER(user_attrs) "homeDirectory=home,uidNumber=uid,gidNumber=gid",
13307d0b3f41c6d940ae263f4828cf557258f9b9Timo Sirainen MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
13307d0b3f41c6d940ae263f4828cf557258f9b9Timo Sirainen MEMBER(pass_attrs) "uid=user,userPassword=password",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct ldap_connection *ldap_connections = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int db_ldap_bind(struct ldap_connection *conn);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void db_ldap_conn_close(struct ldap_connection *conn);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_fatal("LDAP: Unknown deref option '%s'", str);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen i_fatal("LDAP: Unknown scope option '%s'", str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int tls_require_cert2str(const char *str)
1dd054126238349e1a7d3d1ffe7f8bc5fdbacb7aTimo Sirainen i_fatal("LDAP: Unknown tls_require_cert value '%s'", str);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainenstatic int ldap_get_errno(struct ldap_connection *conn)
1dd054126238349e1a7d3d1ffe7f8bc5fdbacb7aTimo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
d22301419109ed4a38351715e6760011421dadecTimo Sirainenconst char *ldap_get_error(struct ldap_connection *conn)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *ret;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, (void *)&str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ldap_set_option(conn->ld, LDAP_OPT_ERROR_STRING, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void ldap_conn_reconnect(struct ldap_connection *conn)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int ldap_handle_error(struct ldap_connection *conn)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* invalid input */
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen /* connection problems */
6d2c938f017a2fc55ae476f88839f03a3d3c5fbdTimo Sirainenstatic int db_ldap_request_bind(struct ldap_connection *conn,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(request->type == LDAP_REQUEST_TYPE_BIND);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_AUTH ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen request->msgid = ldap_bind(conn->ld, brequest->dn,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen auth_request_log_error(request->auth_request, "ldap",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "ldap_bind(%s) failed: %s",
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen /* broken request, remove it */
fa7c76955c6bc62689fbdf39318194f85905e6e2Timo Sirainenstatic int db_ldap_request_search(struct ldap_connection *conn,
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen ldap_search(conn->ld, srequest->base, conn->set.ldap_scope,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen auth_request_log_error(request->auth_request, "ldap",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "ldap_search() failed (filter %s): %s",
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen /* broken request, remove it */
888ab4e17f7441b4dcca4a01886d055b57f4586dTimo Sirainenstatic bool db_ldap_request_queue_next(struct ldap_connection *conn)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct ldap_request *const *requestp, *request;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int queue_size = aqueue_count(conn->request_queue);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen /* no non-pending requests */
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (queue_size > DB_LDAP_MAX_PENDING_REQUESTS) {
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen /* wait until server has replied to some requests */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* we can't do binds until all existing requests are finished */
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen /* wait until we're in bound state */
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen /* bind to default dn first */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we can do anything in this state */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* success */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen } else if (ret < 0) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen /* disconnected */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen /* broken request, remove from queue */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainendb_ldap_check_limits(struct ldap_connection *conn, struct ldap_request *request)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int count;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen first_requestp = array_idx(&conn->request_array,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen secs_diff = ioloop_time - (*first_requestp)->create_time;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (secs_diff > DB_LDAP_REQUEST_LOST_TIMEOUT_SECS) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen auth_request_log_error(request->auth_request, "ldap",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen "Connection appears to be hanging, reconnecting");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (conn->request_queue->full && count >= DB_LDAP_MAX_QUEUE_SIZE) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* Queue is full already, fail this request */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen auth_request_log_error(request->auth_request, "ldap",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Request queue is full (oldest added %d secs ago)",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid db_ldap_request(struct ldap_connection *conn,
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainenstatic int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen conn->set.dn == NULL ? "(none)" : conn->set.dn,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void db_ldap_default_bind_finished(struct ldap_connection *conn,
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen ret = ldap_result2error(conn->ld, res, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* lost connection, close it */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void db_ldap_abort_requests(struct ldap_connection *conn,
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen struct ldap_request *const *requestp, *request;
if (error) {
max_count--;
unsigned int i, count;
for (i = 0; i < count; i++) {
T_BEGIN {
} T_END;
int ret;
#ifdef OPENLDAP_ASYNC_WORKAROUND
if (ret == 0) {
if (ret <= 0)
if (ret == 0) {
#ifdef HAVE_LDAP_SASL
const char *str;
case SASL_CB_GETREALM:
case SASL_CB_AUTHNAME:
case SASL_CB_USER:
case SASL_CB_PASS:
return LDAP_SUCCESS;
int msgid;
int ret;
int ret;
const char *optname)
#ifdef OPENLDAP_TLS_OPTIONS
unsigned int ldap_version;
int value;
#ifdef LDAP_OPT_DEBUG_LEVEL
if (value != 0) {
int ret;
#ifdef LDAP_HAVE_INITIALIZE
#ifdef LDAP_HAVE_START_TLS_S
#ifdef HAVE_LDAP_SASL
const char *skip_attr)
unsigned int i, j, size;
for (i = j = 0; i < size; i++) {
if (p == NULL)
else if (p != attr_data) {
name);
struct var_expand_table *
unsigned int count;
count++;
return table;
#define IS_LDAP_ESCAPED_CHAR(c) \
if (IS_LDAP_ESCAPED_CHAR(*p))
return str;
if (IS_LDAP_ESCAPED_CHAR(*p))
struct db_ldap_result_iterate_context *
const char *static_data;
return ctx;
if (!first)
return TRUE;
if (p == NULL) {
return TRUE;
return FALSE;
return FALSE;
return TRUE;
const char **name_r,
const char *const **values_r)
return FALSE;
return TRUE;
return conn;
return NULL;
const char *str;
return conn;
#ifndef LDAP_HAVE_INITIALIZE
return conn;
struct ldap_connection **p;
if (*p == conn) {
#ifndef BUILTIN_LDAP
void authdb_ldap_init(void);
void authdb_ldap_deinit(void);
void authdb_ldap_init(void)
void authdb_ldap_deinit(void)