db-ldap.c revision fc4ff2356fee6389d4cf2b3f12f4098a436f0502
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "common.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "network.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "ioloop.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "array.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "hash.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "queue.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "str.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "var-expand.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "settings.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "userdb.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include "db-ldap.h"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <stddef.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <stdlib.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#define HAVE_LDAP_SASL
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#ifdef HAVE_SASL_SASL_H
0591ddd0694c4d7ab3ad339419da215a732587f8Prakash Jalan# include <sasl/sasl.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#elif defined (HAVE_SASL_H)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng# include <sasl.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#else
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng# undef HAVE_LDAP_SASL
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#if SASL_VERSION_MAJOR < 2
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng# undef HAVE_LDAP_SASL
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#ifndef LDAP_SASL_QUIET
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/* Older versions may require calling ldap_result() twice */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#if LDAP_VENDOR_VERSION <= 20112
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng# define OPENLDAP_ASYNC_WORKAROUND
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore#ifndef LDAP_OPT_SUCCESS
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng# define LDAP_OPT_SUCCESS LDAP_SUCCESS
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstruct db_ldap_result_iterate_context {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_connection *conn;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng LDAPMessage *entry;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct auth_request *auth_request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct hash_table *attr_map;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct var_expand_table *var_table;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng char *attr, **vals;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const char *name, *value, *template, *val_1_arr[2];
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const char *const *static_attrs;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng BerElement *ber;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng string_t *var, *debug;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int value_idx;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng};
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstruct db_ldap_sasl_bind_context {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *authcid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *passwd;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *realm;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *authzid;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai};
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#define DEF_STR(name) DEF_STRUCT_STR(name, ldap_settings)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#define DEF_INT(name) DEF_STRUCT_INT(name, ldap_settings)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, ldap_settings)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaistatic struct setting_def setting_defs[] = {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DEF_STR(hosts),
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DEF_STR(uris),
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai DEF_STR(dn),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(dnpass),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_BOOL(auth_bind),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(auth_bind_userdn),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_BOOL(tls),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_BOOL(sasl_bind),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(sasl_mech),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(sasl_realm),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(sasl_authz_id),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(deref),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(scope),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(base),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_INT(ldap_version),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(user_attrs),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(user_filter),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(pass_attrs),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(pass_filter),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DEF_STR(default_pass_scheme),
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng { 0, NULL, 0 }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng};
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstruct ldap_settings default_ldap_settings = {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(hosts) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(uris) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(dn) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(dnpass) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(auth_bind) FALSE,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(auth_bind_userdn) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(tls) FALSE,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(sasl_bind) FALSE,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(sasl_mech) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(sasl_realm) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(sasl_authz_id) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(deref) "never",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(scope) "subtree",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(base) NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(ldap_version) 2,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(user_attrs) "homeDirectory=home,uidNumber=uid,gidNumber=gid",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(pass_attrs) "uid=user,userPassword=password",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng MEMBER(default_pass_scheme) "crypt"
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng};
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic struct ldap_connection *ldap_connections = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int db_ldap_bind(struct ldap_connection *conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void db_ldap_conn_close(struct ldap_connection *conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int deref2str(const char *str)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (strcasecmp(str, "never") == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_DEREF_NEVER;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (strcasecmp(str, "searching") == 0)
ee94b1c37a34b758315666dcd0bc7c46d1aea15cSebastien Roy return LDAP_DEREF_SEARCHING;
ee94b1c37a34b758315666dcd0bc7c46d1aea15cSebastien Roy if (strcasecmp(str, "finding") == 0)
ee94b1c37a34b758315666dcd0bc7c46d1aea15cSebastien Roy return LDAP_DEREF_FINDING;
ee94b1c37a34b758315666dcd0bc7c46d1aea15cSebastien Roy if (strcasecmp(str, "always") == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_DEREF_ALWAYS;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_fatal("LDAP: Unknown deref option '%s'", str);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int scope2str(const char *str)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (strcasecmp(str, "base") == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_SCOPE_BASE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (strcasecmp(str, "onelevel") == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_SCOPE_ONELEVEL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (strcasecmp(str, "subtree") == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_SCOPE_SUBTREE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_fatal("LDAP: Unknown scope option '%s'", str);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int ldap_get_errno(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int ret, err;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret != LDAP_SUCCESS) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("LDAP: Can't get error number: %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_err2string(ret));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_UNAVAILABLE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return err;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengconst char *ldap_get_error(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return ldap_err2string(ldap_get_errno(conn));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void ldap_conn_reconnect(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_conn_close(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (db_ldap_connect(conn) < 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_conn_close(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int ldap_handle_error(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int err = ldap_get_errno(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng switch (err) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_SUCCESS:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_unreached();
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_SIZELIMIT_EXCEEDED:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_TIMELIMIT_EXCEEDED:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_NO_SUCH_ATTRIBUTE:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_UNDEFINED_TYPE:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_INAPPROPRIATE_MATCHING:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_CONSTRAINT_VIOLATION:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_TYPE_OR_VALUE_EXISTS:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_INVALID_SYNTAX:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_NO_SUCH_OBJECT:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_ALIAS_PROBLEM:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_INVALID_DN_SYNTAX:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_IS_LEAF:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_ALIAS_DEREF_PROBLEM:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai case LDAP_FILTER_ERROR:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* invalid input */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_SERVER_DOWN:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_TIMEOUT:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_UNAVAILABLE:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_BUSY:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#ifdef LDAP_CONNECT_ERROR
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_CONNECT_ERROR:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_LOCAL_ERROR:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_INVALID_CREDENTIALS:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng default:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* connection problems */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_conn_reconnect(conn);
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark return 0;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark }
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark}
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmarkstatic int db_ldap_request_bind(struct ldap_connection *conn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request *request)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark struct ldap_request_bind *brequest =
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (struct ldap_request_bind *)request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(request->type == LDAP_REQUEST_TYPE_BIND);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(request->msgid == -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_AUTH ||
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count == 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->msgid = ldap_bind(conn->ld, brequest->dn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->auth_request->mech_password,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng LDAP_AUTH_SIMPLE);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->msgid == -1) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng auth_request_log_error(request->auth_request, "ldap",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "ldap_bind(%s) failed: %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng brequest->dn, ldap_get_error(conn));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ldap_handle_error(conn) < 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* broken request, remove it */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state = LDAP_CONN_STATE_BINDING;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int db_ldap_request_search(struct ldap_connection *conn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request *request)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request_search *srequest =
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (struct ldap_request_search *)request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(request->msgid == -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->msgid =
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_search(conn->ld, srequest->base, conn->set.ldap_scope,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng srequest->filter, srequest->attributes, 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->msgid == -1) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng auth_request_log_error(request->auth_request, "ldap",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "ldap_search() failed (filter %s): %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng srequest->filter, ldap_get_error(conn));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ldap_handle_error(conn) < 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* broken request, remove it */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 0;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic bool db_ldap_request_queue_next(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request *const *requestp, *request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int queue_size = queue_count(conn->request_queue);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int ret = -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (conn->pending_count == queue_size) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* no non-pending requests */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return FALSE;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy }
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (queue_size > DB_LDAP_MAX_PENDING_REQUESTS) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* wait until server has replied to some requests */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return FALSE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (db_ldap_connect(conn) < 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return FALSE;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy requestp = array_idx(&conn->request_array,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy queue_idx(conn->request_queue,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy conn->pending_count));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy request = *requestp;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (conn->pending_count > 0 &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy request->type == LDAP_REQUEST_TYPE_BIND) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* we can't do binds until all existing requests are finished */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return FALSE;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy }
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy switch (conn->conn_state) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy case LDAP_CONN_STATE_DISCONNECTED:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_CONN_STATE_BINDING:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* wait until we're in bound state */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return FALSE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_CONN_STATE_BOUND_AUTH:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->type == LDAP_REQUEST_TYPE_BIND)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* bind to default dn first */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count == 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (void)db_ldap_bind(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return FALSE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_CONN_STATE_BOUND_DEFAULT:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* we can do anything in this state */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng switch (request->type) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case LDAP_REQUEST_TYPE_BIND:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = db_ldap_request_bind(conn, request);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou case LDAP_REQUEST_TYPE_SEARCH:
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou ret = db_ldap_request_search(conn, request);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret > 0) {
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore /* success */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(request->msgid != -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->pending_count++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return TRUE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else if (ret < 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* disconnected */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return FALSE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* broken request, remove from queue */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng queue_delete_tail(conn->request_queue);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->callback(conn, request, NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return TRUE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyervoid db_ldap_request(struct ldap_connection *conn,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer struct ldap_request *request)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->msgid = -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->create_time = ioloop_time;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->request_queue->full &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng queue_count(conn->request_queue) >= DB_LDAP_MAX_QUEUE_SIZE) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* Queue is full already, fail this request */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng auth_request_log_error(request->auth_request, "ldap",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "Request queue is full");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->callback(conn, request, NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng queue_append(conn->request_queue, &request);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (void)db_ldap_request_queue_next(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret == LDAP_SERVER_DOWN) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("LDAP: Can't connect to server: %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->set.uris != NULL ?
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->set.uris : conn->set.hosts);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret != LDAP_SUCCESS) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("LDAP: binding failed (dn %s): %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->set.dn == NULL ? "(none)" : conn->set.dn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_get_error(conn));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng while (db_ldap_request_queue_next(conn))
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void db_ldap_default_bind_finished(struct ldap_connection *conn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng LDAPMessage *res)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int ret;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count == 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->default_bind_msgid = -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_result2error(conn->ld, res, FALSE);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (db_ldap_connect_finish(conn, ret) < 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* lost connection, close it */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_conn_close(conn);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void db_ldap_abort_requests(struct ldap_connection *conn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int max_count,
3ade6e843b7f9e2656892a172ecd9e302b0dee09Garrett D'Amore unsigned int timeout_secs)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request *const *requestp, *request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng time_t diff;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng while (queue_count(conn->request_queue) > 0 && max_count > 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng requestp = array_idx(&conn->request_array,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng queue_idx(conn->request_queue, 0));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request = *requestp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng diff = ioloop_time - request->create_time;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (diff < (time_t)timeout_secs)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* timed out, abort */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng queue_delete_tail(conn->request_queue);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->msgid != -1) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count > 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->pending_count--;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->callback(conn, request, NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng max_count--;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void
da14cebe459d3275048785f25bd869cb09b5307fEric Chengdb_ldap_handle_result(struct ldap_connection *conn, LDAPMessage *res)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request *const *requests, *request = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int i, count;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int msgid, ret;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng msgid = ldap_msgid(res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (msgid == conn->default_bind_msgid) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_default_bind_finished(conn, res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng count = queue_count(conn->request_queue);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng requests = count == 0 ? NULL : array_idx(&conn->request_array, 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (i = 0; i < count; i++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request = requests[queue_idx(conn->request_queue, i)];
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->msgid == msgid)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->msgid == -1) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request == NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("LDAP: Reply with unknown msgid %d", msgid);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (request->type == LDAP_REQUEST_TYPE_BIND) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->conn_state == LDAP_CONN_STATE_BINDING);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count == 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state = LDAP_CONN_STATE_BOUND_AUTH;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count > 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->pending_count--;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng queue_delete(conn->request_queue, i);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_result2error(conn->ld, res, 0);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (ret != LDAP_SUCCESS && request->type == LDAP_REQUEST_TYPE_SEARCH) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* handle search failures here */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request_search *srequest =
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (struct ldap_request_search *)request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng auth_request_log_error(request->auth_request, "ldap",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "ldap_search(%s) failed: %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng srequest->filter, ldap_err2string(ret));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng res = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng T_FRAME(
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->callback(conn, request, res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng );
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (i > 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* see if there are timed out requests */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_abort_requests(conn, i,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DB_LDAP_REQUEST_LOST_TIMEOUT_SECS);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
783f25cedcc2d0e6828b895b5f67e9dabca8cd39Michael Speer
783f25cedcc2d0e6828b895b5f67e9dabca8cd39Michael Speerstatic void ldap_input(struct ldap_connection *conn)
783f25cedcc2d0e6828b895b5f67e9dabca8cd39Michael Speer{
783f25cedcc2d0e6828b895b5f67e9dabca8cd39Michael Speer struct timeval timeout;
783f25cedcc2d0e6828b895b5f67e9dabca8cd39Michael Speer LDAPMessage *res;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int ret;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (;;) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->ld == NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng memset(&timeout, 0, sizeof(timeout));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#ifdef OPENLDAP_ASYNC_WORKAROUND
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret == 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* try again, there may be another in buffer */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_result(conn->ld, LDAP_RES_ANY, 1,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng &timeout, &res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret <= 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_handle_result(conn, res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_msgfree(res);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->last_reply_stamp = ioloop_time;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret == 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* send more requests */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng while (db_ldap_request_queue_next(conn))
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou ;
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou } else if (ldap_get_errno(conn) != LDAP_SERVER_DOWN) {
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou i_error("LDAP: ldap_result() failed: %s", ldap_get_error(conn));
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou ldap_conn_reconnect(conn);
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou } else if (queue_count(conn->request_queue) > 0 ||
5d460eafffba936e81c4dd5ebe0f59b238f09121Cathy Zhou ioloop_time - conn->last_reply_stamp <
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DB_LDAP_IDLE_RECONNECT_SECS) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("LDAP: Connection lost to LDAP server, reconnecting");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_conn_reconnect(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* server probably disconnected an idle connection. don't
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng reconnect until the next request comes. */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_conn_close(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#ifdef HAVE_LDAP_SASL
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int
da14cebe459d3275048785f25bd869cb09b5307fEric Chengsasl_interact(LDAP *ld ATTR_UNUSED, unsigned flags ATTR_UNUSED,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng void *defaults, void *interact)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct db_ldap_sasl_bind_context *context = defaults;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng sasl_interact_t *in;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *str;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (in = interact; in->id != SASL_CB_LIST_END; in++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng switch (in->id) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case SASL_CB_GETREALM:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str = context->realm;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case SASL_CB_AUTHNAME:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str = context->authcid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case SASL_CB_USER:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str = context->authzid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng case SASL_CB_PASS:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str = context->passwd;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng default:
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (str != NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng in->len = strlen(str);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng in->result = str;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return LDAP_SUCCESS;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int db_ldap_bind(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int msgid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->conn_state != LDAP_CONN_STATE_BINDING);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->default_bind_msgid == -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count == 0);
9b41bdc4d1e09925acb52ea879d632a2611393dfRobert Mustacchi
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.dnpass,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng LDAP_AUTH_SIMPLE);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (msgid == -1) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(ldap_get_errno(conn) != LDAP_SUCCESS);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (db_ldap_connect_finish(conn, ldap_get_errno(conn)) < 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* lost connection, close it */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_conn_close(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state = LDAP_CONN_STATE_BINDING;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->default_bind_msgid = msgid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void db_ldap_get_fd(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai int ret;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* get the connection's fd */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ret != LDAP_SUCCESS) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_fatal("LDAP: Can't get connection fd: %s",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ldap_err2string(ret));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->fd <= CLIENT_LISTEN_FD) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* Solaris LDAP library seems to be broken */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_fatal("LDAP: Buggy LDAP library returned wrong fd: %d",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->fd);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->fd != -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng net_set_nonblock(conn->fd, TRUE);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengint db_ldap_connect(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int ldap_version;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int ret;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(conn->pending_count == 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->ld == NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->set.uris != NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#ifdef LDAP_HAVE_INITIALIZE
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->ld = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#else
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai i_fatal("LDAP: Your LDAP library doesn't support "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "'uris' setting, use 'hosts' instead.");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (conn->ld == NULL)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai i_fatal("LDAP: ldap_init() failed with hosts: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai conn->set.hosts);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void *)&conn->set.ldap_deref);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (ret != LDAP_SUCCESS) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai i_fatal("LDAP: Can't set deref option: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ldap_err2string(ret));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* If SASL binds are used, the protocol version needs to be
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai at least 3 */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ldap_version = conn->set.sasl_bind &&
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai conn->set.ldap_version < 3 ? 3 :
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai conn->set.ldap_version;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void *)&ldap_version);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (ret != LDAP_OPT_SUCCESS) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai i_fatal("LDAP: Can't set protocol version %u: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ldap_version, ldap_err2string(ret));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (conn->set.tls) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#ifdef LDAP_HAVE_START_TLS_S
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ret = ldap_start_tls_s(conn->ld, NULL, NULL);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (ret != LDAP_SUCCESS) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai i_error("LDAP: ldap_start_tls_s() failed: %s",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ldap_err2string(ret));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai return -1;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#else
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai i_error("LDAP: Your LDAP library doesn't support TLS");
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai return -1;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#endif
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (conn->set.sasl_bind) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai#ifdef HAVE_LDAP_SASL
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai struct db_ldap_sasl_bind_context context;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai memset(&context, 0, sizeof(context));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai context.authcid = conn->set.dn;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai context.passwd = conn->set.dnpass;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai context.realm = conn->set.sasl_realm;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng context.authzid = conn->set.sasl_authz_id;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* There doesn't seem to be a way to do SASL binding
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng asynchronously.. */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->set.sasl_mech,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng NULL, NULL, LDAP_SASL_QUIET,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng sasl_interact, &context);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (db_ldap_connect_finish(conn, ret) < 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#else
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (db_ldap_bind(conn) < 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_get_fd(conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void db_ldap_disconnect_timeout(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng db_ldap_abort_requests(conn, -1U,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (queue_count(conn->request_queue) == 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* no requests left, remove this timeout handler */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng timeout_remove(&conn->to);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void db_ldap_conn_close(struct ldap_connection *conn)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct ldap_request *const *requests, *request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int i;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->default_bind_msgid = -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->pending_count != 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng requests = array_idx(&conn->request_array, 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (i = 0; i < conn->pending_count; i++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request = requests[queue_idx(conn->request_queue, i)];
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_assert(request->msgid != -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng request->msgid = -1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng conn->pending_count = 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (conn->io != NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng io_remove(&conn->io);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (conn->ld != NULL) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer ldap_unbind(conn->ld);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer conn->ld = NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer conn->fd = -1;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (queue_count(conn->request_queue) == 0) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (conn->to != NULL)
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer timeout_remove(&conn->to);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer } else if (conn->to == NULL) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer conn->to = timeout_add(DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS *
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer 1000/2, db_ldap_disconnect_timeout, conn);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer}
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyervoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer char ***attr_names_r, struct hash_table *attr_map,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *skip_attr)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *const *attr, *attr_data, *p;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng string_t *static_data;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng char *name, *value;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int i, j, size;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (*attrlist == '\0')
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng attr = t_strsplit(attrlist, ",");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng static_data = t_str_new(128);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* @UNSAFE */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (size = 0; attr[size] != NULL; size++) ;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *attr_names_r = p_new(conn->pool, char *, size + 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (i = j = 0; i < size; i++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* allow spaces here so "foo=1, bar=2" works */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer attr_data = attr[i];
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng while (*attr_data == ' ') attr_data++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng p = strchr(attr_data, '=');
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (p == NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng name = value = p_strdup(conn->pool, attr_data);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng else if (p != attr_data) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng name = p_strdup_until(conn->pool, attr_data, p);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng value = p_strdup(conn->pool, p + 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* =<static key>=<static value> */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (str_len(static_data) > 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str_append_c(static_data, ',');
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str_append(static_data, p + 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng continue;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (*name != '\0' &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (skip_attr == NULL || strcmp(skip_attr, value) != 0)) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng hash_insert(attr_map, name, value);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (*attr_names_r)[j++] = name;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (str_len(static_data) > 0) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai hash_insert(attr_map, "",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai p_strdup(conn->pool, str_c(static_data)));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai }
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai}
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaistruct var_expand_table *
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaidb_ldap_value_get_var_expand_table(struct auth_request *auth_request)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai{
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai const struct var_expand_table *auth_table;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai struct var_expand_table *table;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai unsigned int count;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai auth_table = auth_request_get_var_expand_table(auth_request, NULL);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (count = 0; auth_table[count].key != '\0'; count++) ;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai count++;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai table = t_new(struct var_expand_table, count + 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng table[0].key = '$';
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng memcpy(table + 1, auth_table, sizeof(*table) * count);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return table;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#define IS_LDAP_ESCAPED_CHAR(c) \
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai
da14cebe459d3275048785f25bd869cb09b5307fEric Chengconst char *ldap_escape(const char *str,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const struct auth_request *auth_request ATTR_UNUSED)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *p;
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore string_t *ret;
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore for (p = str; *p != '\0'; p++) {
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore if (IS_LDAP_ESCAPED_CHAR(*p))
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore break;
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore }
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore if (*p == '\0')
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore return str;
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore ret = t_str_new((size_t) (p - str) + 64);
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore str_append_n(ret, str, (size_t) (p - str));
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore for (; *p != '\0'; p++) {
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore if (IS_LDAP_ESCAPED_CHAR(*p))
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore str_append_c(ret, '\\');
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore str_append_c(ret, *p);
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore }
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore return str_c(ret);
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore}
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amorestruct db_ldap_result_iterate_context *
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amoredb_ldap_result_iterate_init(struct ldap_connection *conn, LDAPMessage *entry,
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore struct auth_request *auth_request,
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore struct hash_table *attr_map)
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore{
61af1958c03f88647637805ecf6bdb99b9eef36bGarrett D'Amore struct db_ldap_result_iterate_context *ctx;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *static_data;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx = t_new(struct db_ldap_result_iterate_context, 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->conn = conn;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->entry = entry;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->auth_request = auth_request;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->attr_map = attr_map;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng static_data = hash_lookup(attr_map, "");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (static_data != NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->static_attrs = t_strsplit(static_data, ",");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (auth_request->auth->verbose_debug)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->debug = t_str_new(256);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
fd0939ef389f48c901faf4bf0b60b82d4bc58b64David Edmondson return ctx;
fd0939ef389f48c901faf4bf0b60b82d4bc58b64David Edmondson}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
fd0939ef389f48c901faf4bf0b60b82d4bc58b64David Edmondsonstatic void
fd0939ef389f48c901faf4bf0b60b82d4bc58b64David Edmondsondb_ldap_result_iterate_finish(struct db_ldap_result_iterate_context *ctx)
fd0939ef389f48c901faf4bf0b60b82d4bc58b64David Edmondson{
fd0939ef389f48c901faf4bf0b60b82d4bc58b64David Edmondson if (ctx->debug != NULL && str_len(ctx->debug) > 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng auth_request_log_debug(ctx->auth_request, "ldap",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "result: %s", str_c(ctx->debug) + 1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ber_free(ctx->ber, 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void
da14cebe459d3275048785f25bd869cb09b5307fEric Chengdb_ldap_result_change_attr(struct db_ldap_result_iterate_context *ctx)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy{
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ctx->name = hash_lookup(ctx->attr_map, ctx->attr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ctx->debug != NULL) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy str_printfa(ctx->debug, " %s(%s)=", ctx->attr,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ctx->name != NULL ? ctx->name : "?unknown?");
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy }
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ctx->name == NULL || *ctx->name == '\0') {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ctx->value = NULL;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy }
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (strchr(ctx->name, '%') != NULL &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (ctx->template = strchr(ctx->name, '=')) != NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* we want to use variables */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->name = t_strdup_until(ctx->name, ctx->template);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->template++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ctx->var_table == NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->var_table = db_ldap_value_get_var_expand_table(
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->auth_request);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->var = t_str_new(256);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->vals = ldap_get_values(ctx->conn->ld, ctx->entry,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->attr);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->value = ctx->vals[0];
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->value_idx = 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void
da14cebe459d3275048785f25bd869cb09b5307fEric Chengdb_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng bool first = ctx->value_idx == 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ctx->template != NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->var_table[0].value = ctx->value;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str_truncate(ctx->var, 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng var_expand(ctx->var, ctx->template, ctx->var_table);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->value = str_c(ctx->var);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ctx->debug != NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (!first)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str_append_c(ctx->debug, '/');
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ctx->auth_request->auth->verbose_debug_passwords ||
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng strcmp(ctx->name, "password") != 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str_append(ctx->debug, ctx->value);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng else
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng str_append(ctx->debug, PASSWORD_HIDDEN_STR);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic bool db_ldap_result_int_next(struct db_ldap_result_iterate_context *ctx)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *p;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark while (ctx->attr != NULL) {
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark if (ctx->vals == NULL) {
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark /* a new attribute */
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark db_ldap_result_change_attr(ctx);
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark } else {
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark /* continuing existing attribute */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ctx->value != NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ctx->value = ctx->vals[++ctx->value_idx];
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (ctx->value != NULL) {
f0f2c3a5cf65a61de34af42edac38b2a7bda3416Girish Moodalbail db_ldap_result_return_value(ctx);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return TRUE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ldap_value_free(ctx->vals); ctx->vals = NULL;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ldap_memfree(ctx->attr);
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->attr = ldap_next_attribute(ctx->conn->ld, ctx->entry,
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->ber);
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark }
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark if (ctx->static_attrs != NULL && *ctx->static_attrs != NULL) {
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark p = strchr(*ctx->static_attrs, '=');
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark if (p == NULL) {
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->name = *ctx->static_attrs;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->value = "";
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark } else {
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->name = t_strdup_until(*ctx->static_attrs, p);
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->value = p + 1;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark }
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark ctx->static_attrs++;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark return TRUE;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark }
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark db_ldap_result_iterate_finish(ctx);
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark return FALSE;
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark}
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmark
1eee170a5f6cf875d905524fea524c7c5c870aa0Erik Nordmarkbool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char **name_r, const char **value_r)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (!db_ldap_result_int_next(ctx))
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return FALSE;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *name_r = ctx->name;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *value_r = ctx->value;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return TRUE;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerbool db_ldap_result_iterate_next_all(struct db_ldap_result_iterate_context *ctx,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const char **name_r,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const char *const **values_r)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!db_ldap_result_int_next(ctx))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return FALSE;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (ctx->template != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* we can use only one value with templates */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ctx->val_1_arr[0] = ctx->value;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *values_r = ctx->val_1_arr;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer } else {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *values_r = (const char *const *)ctx->vals;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ctx->value = NULL;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *name_r = ctx->name;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return TRUE;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic const char *parse_setting(const char *key, const char *value,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer struct ldap_connection *conn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return parse_setting_from_defs(conn->pool, setting_defs,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer &conn->set, key, value);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic struct ldap_connection *ldap_conn_find(const char *config_path)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer struct ldap_connection *conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (conn = ldap_connections; conn != NULL; conn = conn->next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (strcmp(conn->config_path, config_path) == 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return NULL;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstruct ldap_connection *db_ldap_init(const char *config_path)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer struct ldap_connection *conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer pool_t pool;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* see if it already exists */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn = ldap_conn_find(config_path);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (conn != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->refcount++;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (*config_path == '\0')
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal("LDAP: Configuration file path not given");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer pool = pool_alloconly_create("ldap_connection", 1024);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn = p_new(pool, struct ldap_connection, 1);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->pool = pool;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->refcount = 1;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->default_bind_msgid = -1;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->fd = -1;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->config_path = p_strdup(pool, config_path);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->set = default_ldap_settings;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!settings_read(config_path, NULL, parse_setting,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer null_settings_section_callback, conn))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer exit(FATAL_DEFAULT);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (conn->set.base == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal("LDAP: No base given");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (conn->set.uris == NULL && conn->set.hosts == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal("LDAP: No uris or hosts set");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer#ifndef LDAP_HAVE_INITIALIZE
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (conn->set.uris != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer "(ldap_initialize not found)");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer#endif
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->set.ldap_deref = deref2str(conn->set.deref);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->set.ldap_scope = scope2str(conn->set.scope);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_array_init(&conn->request_array, DB_LDAP_MAX_QUEUE_SIZE);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->request_queue = queue_init(&conn->request_array.arr);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer conn->next = ldap_connections;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ldap_connections = conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyervoid db_ldap_unref(struct ldap_connection **_conn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer struct ldap_connection *conn = *_conn;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer struct ldap_connection **p;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *_conn = NULL;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_assert(conn->refcount >= 0);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (--conn->refcount > 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (*p == conn) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *p = conn->next;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer break;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer db_ldap_abort_requests(conn, -1U, 0);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_assert(conn->pending_count == 0);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer db_ldap_conn_close(conn);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_assert(conn->to == NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer array_free(&conn->request_array);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer queue_deinit(&conn->request_queue);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (conn->pass_attr_map != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer hash_destroy(&conn->pass_attr_map);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (conn->user_attr_map != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer hash_destroy(&conn->user_attr_map);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer pool_unref(&conn->pool);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer#ifndef BUILTIN_LDAP
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer/* Building a plugin */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerextern struct passdb_module_interface passdb_ldap;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerextern struct userdb_module_interface userdb_ldap;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyervoid authdb_ldap_init(void);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyervoid authdb_ldap_deinit(void);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyervoid authdb_ldap_init(void)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer passdb_register_module(&passdb_ldap);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer userdb_register_module(&userdb_ldap);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyervoid authdb_ldap_deinit(void)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer{
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer passdb_unregister_module(&passdb_ldap);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer userdb_unregister_module(&userdb_ldap);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#endif
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng