db-ldap.c revision d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76
c636315472e4f87313af7be30b7fbcad4b8ca8a4Stephen Gallagher/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
c636315472e4f87313af7be30b7fbcad4b8ca8a4Stephen Gallagher
fd5a4eacd56700ffb08a73121aeacdc806cb0132Sumit Bose#include "common.h"
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#include "network.h"
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#include "ioloop.h"
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#include "array.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "hash.h"
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#include "aqueue.h"
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#include "str.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "env-util.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "var-expand.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "settings.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "userdb.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "db-ldap.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <stddef.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <stdlib.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <unistd.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define HAVE_LDAP_SASL
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef HAVE_SASL_SASL_H
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher# include <sasl/sasl.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#elif defined (HAVE_SASL_H)
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher# include <sasl.h>
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher#else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher# undef HAVE_LDAP_SASL
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef LDAP_OPT_X_TLS
d921c1eba437662437847279f251a0a5d8f70127Maxim# define OPENLDAP_TLS_OPTIONS
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#if SASL_VERSION_MAJOR < 2
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher# undef HAVE_LDAP_SASL
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifndef LDAP_SASL_QUIET
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Older versions may require calling ldap_result() twice */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#if LDAP_VENDOR_VERSION <= 20112
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher# define OPENLDAP_ASYNC_WORKAROUND
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher#endif
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#ifndef LDAP_OPT_SUCCESS
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher# define LDAP_OPT_SUCCESS LDAP_SUCCESS
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct db_ldap_result_iterate_context {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection *conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher LDAPMessage *entry;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct auth_request *auth_request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
be1ef1c62ad13612be5e1f879476c24452a5d6d0Stephen Gallagher struct hash_table *attr_map;
be1ef1c62ad13612be5e1f879476c24452a5d6d0Stephen Gallagher struct var_expand_table *var_table;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char *attr, **vals;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher const char *name, *value, *template, *val_1_arr[2];
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher const char *const *static_attrs;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher BerElement *ber;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
558998ce664055a75595371118f818084d8f2b23Jan Cholasta string_t *var, *debug;
558998ce664055a75595371118f818084d8f2b23Jan Cholasta unsigned int value_idx;
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta};
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta
558998ce664055a75595371118f818084d8f2b23Jan Cholastastruct db_ldap_sasl_bind_context {
558998ce664055a75595371118f818084d8f2b23Jan Cholasta const char *authcid;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *passwd;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *realm;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *authzid;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF_STR(name) DEF_STRUCT_STR(name, ldap_settings)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF_INT(name) DEF_STRUCT_INT(name, ldap_settings)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, ldap_settings)
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny
f1828234a850dd28465425248a83a993f262918fPavel Březinastatic struct setting_def setting_defs[] = {
f1828234a850dd28465425248a83a993f262918fPavel Březina DEF_STR(hosts),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(uris),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(dn),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(dnpass),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_BOOL(auth_bind),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(auth_bind_userdn),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_BOOL(tls),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_BOOL(sasl_bind),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(sasl_mech),
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina DEF_STR(sasl_realm),
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina DEF_STR(sasl_authz_id),
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina DEF_STR(tls_ca_cert_file),
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek DEF_STR(tls_ca_cert_dir),
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek DEF_STR(tls_cert_file),
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek DEF_STR(tls_key_file),
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta DEF_STR(tls_cipher_suite),
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta DEF_STR(tls_require_cert),
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta DEF_STR(deref),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(scope),
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose DEF_STR(base),
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose DEF_INT(ldap_version),
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose DEF_STR(debug_level),
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose DEF_STR(ldaprc_path),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(user_attrs),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(user_filter),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(pass_attrs),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(pass_filter),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(default_pass_scheme),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { 0, NULL, 0 }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_settings default_ldap_settings = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(hosts) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(uris) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(dn) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(dnpass) NULL,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek MEMBER(auth_bind) FALSE,
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher MEMBER(auth_bind_userdn) NULL,
fe60346714a73ac3987f786731389320633dd245Pavel Březina MEMBER(tls) FALSE,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose MEMBER(sasl_bind) FALSE,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose MEMBER(sasl_mech) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(sasl_realm) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(sasl_authz_id) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(tls_ca_cert_file) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(tls_ca_cert_dir) NULL,
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek MEMBER(tls_cert_file) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(tls_key_file) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(tls_cipher_suite) NULL,
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(tls_require_cert) NULL,
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(deref) "never",
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(scope) "subtree",
667db40da4db362d7ca0a1f7f1c4ba40fb71795aJakub Hrozek MEMBER(base) NULL,
667db40da4db362d7ca0a1f7f1c4ba40fb71795aJakub Hrozek MEMBER(ldap_version) 3,
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(debug_level) "0",
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(ldaprc_path) "",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(user_attrs) "homeDirectory=home,uidNumber=uid,gidNumber=gid",
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(pass_attrs) "uid=user,userPassword=password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(default_pass_scheme) "crypt"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_connection *ldap_connections = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_ldap_bind(struct ldap_connection *conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_conn_close(struct ldap_connection *conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int deref2str(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "never") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_NEVER;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "searching") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_SEARCHING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "finding") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_FINDING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "always") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_ALWAYS;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta i_fatal("LDAP: Unknown deref option '%s'", str);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta}
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozekstatic int scope2str(const char *str)
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "base") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_SCOPE_BASE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "onelevel") == 0)
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta return LDAP_SCOPE_ONELEVEL;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta if (strcasecmp(str, "subtree") == 0)
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta return LDAP_SCOPE_SUBTREE;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown scope option '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef OPENLDAP_TLS_OPTIONS
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int tls_require_cert2str(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "never") == 0)
3b1df539835367cb81cd5ff0f9959947d5642e55Stephen Gallagher return LDAP_OPT_X_TLS_NEVER;
3b1df539835367cb81cd5ff0f9959947d5642e55Stephen Gallagher if (strcasecmp(str, "hard") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_OPT_X_TLS_HARD;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "demand") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_OPT_X_TLS_DEMAND;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "allow") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_OPT_X_TLS_ALLOW;
667db40da4db362d7ca0a1f7f1c4ba40fb71795aJakub Hrozek if (strcasecmp(str, "try") == 0)
667db40da4db362d7ca0a1f7f1c4ba40fb71795aJakub Hrozek return LDAP_OPT_X_TLS_TRY;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown tls_require_cert value '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagherstatic int ldap_get_errno(struct ldap_connection *conn)
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher{
15b266d9f14dad26da8678a79019749d0f69532eStephen Gallagher int ret, err;
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
667db40da4db362d7ca0a1f7f1c4ba40fb71795aJakub Hrozek if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Can't get error number: %s",
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_UNAVAILABLE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return err;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherconst char *ldap_get_error(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ldap_err2string(ldap_get_errno(conn));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_reconnect(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_conn_close(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_connect(conn) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_conn_close(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int ldap_handle_error(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int err = ldap_get_errno(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher switch (err) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_SUCCESS:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_unreached();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_SIZELIMIT_EXCEEDED:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_TIMELIMIT_EXCEEDED:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_NO_SUCH_ATTRIBUTE:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_UNDEFINED_TYPE:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_INAPPROPRIATE_MATCHING:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_CONSTRAINT_VIOLATION:
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose case LDAP_TYPE_OR_VALUE_EXISTS:
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher case LDAP_INVALID_SYNTAX:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_NO_SUCH_OBJECT:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_ALIAS_PROBLEM:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_INVALID_DN_SYNTAX:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_IS_LEAF:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_ALIAS_DEREF_PROBLEM:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_FILTER_ERROR:
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* invalid input */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_SERVER_DOWN:
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose case LDAP_TIMEOUT:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_UNAVAILABLE:
0ef783e186ef1c9f60e61a4e8e54c44cb366fdfePavel Březina case LDAP_BUSY:
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#ifdef LDAP_CONNECT_ERROR
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta case LDAP_CONNECT_ERROR:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_LOCAL_ERROR:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_INVALID_CREDENTIALS:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher default:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* connection problems */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_conn_reconnect(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic int db_ldap_request_bind(struct ldap_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request_bind *brequest =
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (struct ldap_request_bind *)request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(request->type == LDAP_REQUEST_TYPE_BIND);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(request->msgid == -1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_AUTH ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->pending_count == 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->msgid = ldap_bind(conn->ld, brequest->dn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->auth_request->mech_password,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher LDAP_AUTH_SIMPLE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (request->msgid == -1) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "ldap_bind(%s) failed: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher brequest->dn, ldap_get_error(conn));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ldap_handle_error(conn) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken request, remove it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state = LDAP_CONN_STATE_BINDING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_ldap_request_search(struct ldap_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim struct ldap_request_search *srequest =
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher (struct ldap_request_search *)request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(request->msgid == -1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->msgid =
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_search(conn->ld, srequest->base, conn->set.ldap_scope,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher srequest->filter, srequest->attributes, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (request->msgid == -1) {
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek auth_request_log_error(request->auth_request, "ldap",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "ldap_search() failed (filter %s): %s",
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim srequest->filter, ldap_get_error(conn));
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (ldap_handle_error(conn) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken request, remove it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool db_ldap_request_queue_next(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *const *requestp, *request;
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose unsigned int queue_size = aqueue_count(conn->request_queue);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher int ret = -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->pending_count == queue_size) {
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek /* no non-pending requests */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (queue_size > DB_LDAP_MAX_PENDING_REQUESTS) {
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek /* wait until server has replied to some requests */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_connect(conn) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher requestp = array_idx(&conn->request_array,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher aqueue_idx(conn->request_queue,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->pending_count));
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny request = *requestp;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek if (conn->pending_count > 0 &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->type == LDAP_REQUEST_TYPE_BIND) {
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zeleny /* we can't do binds until all existing requests are finished */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return FALSE;
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher switch (conn->conn_state) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_CONN_STATE_DISCONNECTED:
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorce case LDAP_CONN_STATE_BINDING:
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce /* wait until we're in bound state */
9959c512ac3ba36f7a0db7614f0357ce0bae748fJakub Hrozek return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_CONN_STATE_BOUND_AUTH:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (request->type == LDAP_REQUEST_TYPE_BIND)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* bind to default dn first */
d844aab866ae237844360cea70e2dccdc90c783dStephen Gallagher i_assert(conn->pending_count == 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void)db_ldap_bind(conn);
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher return FALSE;
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher case LDAP_CONN_STATE_BOUND_DEFAULT:
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher /* we can do anything in this state */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce break;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina switch (request->type) {
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek case LDAP_REQUEST_TYPE_BIND:
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta ret = db_ldap_request_bind(conn, request);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case LDAP_REQUEST_TYPE_SEARCH:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = db_ldap_request_search(conn, request);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
1f1e6cbc59868f06dee3ab4b3df660fcb77ce1c8Jakub Hrozek
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ret > 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* success */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(request->msgid != -1);
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta conn->pending_count++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (ret < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* disconnected */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken request, remove from queue */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher aqueue_delete_tail(conn->request_queue);
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher request->callback(conn, request, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallaghervoid db_ldap_request(struct ldap_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(request->auth_request != NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->msgid = -1;
4af1d1869d659fec84c518c26844132fa1df8f64Jakub Hrozek request->create_time = ioloop_time;
eb54e05c9658a7274e3238813c54dd0c6577d3ecPavel Březina
e9eeb4302e0e426c6cc1a4e65b95a6f7066e80b9Pavel Březina if (conn->request_queue->full &&
cc84fd46f356c4a36a721ab135a33ec77c93e34dJakub Hrozek aqueue_count(conn->request_queue) >= DB_LDAP_MAX_QUEUE_SIZE) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* Queue is full already, fail this request */
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher struct ldap_request *const *first_requestp;
ae8d047122c7ba8123f72b2eac68944868ac37d4Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher first_requestp = array_idx(&conn->request_array,
213ce2a78b1abe3921d8dc13c949a28130d00aecJan Zeleny aqueue_idx(conn->request_queue, 0));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny "Request queue is full (oldest added %d secs ago)",
ad07ed37b6b51ef134d4524edaf2259e19ac984fJan Zeleny (int)(time(NULL) - (*first_requestp)->create_time));
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny request->callback(conn, request, NULL);
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose aqueue_append(conn->request_queue, &request);
3a62a99faf8e12965100d0b26fc9e07752bd3e2dStephen Gallagher (void)db_ldap_request_queue_next(conn);
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta}
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret == LDAP_SERVER_DOWN) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Can't connect to server: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.uris != NULL ?
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.uris : conn->set.hosts);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5Jan Cholasta }
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose if (ret != LDAP_SUCCESS) {
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose i_error("LDAP: binding failed (dn %s): %s",
347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5Jan Cholasta conn->set.dn == NULL ? "(none)" : conn->set.dn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_get_error(conn));
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek return -1;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek }
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
374bf54785365273b20690bd3792c25a44738041Pavel Březina while (db_ldap_request_queue_next(conn))
374bf54785365273b20690bd3792c25a44738041Pavel Březina ;
374bf54785365273b20690bd3792c25a44738041Pavel Březina return 0;
374bf54785365273b20690bd3792c25a44738041Pavel Březina}
374bf54785365273b20690bd3792c25a44738041Pavel Březina
374bf54785365273b20690bd3792c25a44738041Pavel Březinastatic void db_ldap_default_bind_finished(struct ldap_connection *conn,
374bf54785365273b20690bd3792c25a44738041Pavel Březina LDAPMessage *res)
374bf54785365273b20690bd3792c25a44738041Pavel Březina{
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher int ret;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher i_assert(conn->pending_count == 0);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher conn->default_bind_msgid = -1;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher ret = ldap_result2error(conn->ld, res, FALSE);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (db_ldap_connect_finish(conn, ret) < 0) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* lost connection, close it */
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher db_ldap_conn_close(conn);
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher }
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher}
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherstatic void db_ldap_abort_requests(struct ldap_connection *conn,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher unsigned int max_count,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher unsigned int timeout_secs,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher bool error, const char *reason)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher{
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny struct ldap_request *const *requestp, *request;
c2352a73f52f600d95966ebe0b0819649ba923faStephen Gallagher time_t diff;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
1f1e6cbc59868f06dee3ab4b3df660fcb77ce1c8Jakub Hrozek while (aqueue_count(conn->request_queue) > 0 && max_count > 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny requestp = array_idx(&conn->request_array,
817b1bcafff27cc67630dd0cbd36df708c05fcccStephen Gallagher aqueue_idx(conn->request_queue, 0));
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher request = *requestp;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher diff = ioloop_time - request->create_time;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (diff < (time_t)timeout_secs)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher break;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* timed out, abort */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher aqueue_delete_tail(conn->request_queue);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (request->msgid != -1) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher i_assert(conn->pending_count > 0);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher conn->pending_count--;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (error) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher "%s", reason);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher } else {
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny auth_request_log_info(request->auth_request, "ldap",
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek "%s", reason);
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorce }
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zeleny request->callback(conn, request, NULL);
9959c512ac3ba36f7a0db7614f0357ce0bae748fJakub Hrozek max_count--;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny }
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny}
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherstatic void
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherdb_ldap_handle_result(struct ldap_connection *conn, LDAPMessage *res)
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher{
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher struct ldap_request *const *requests, *request = NULL;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher unsigned int i, count;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek int msgid, ret;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek msgid = ldap_msgid(res);
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta if (msgid == conn->default_bind_msgid) {
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta db_ldap_default_bind_finished(conn, res);
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta return;
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta }
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher count = aqueue_count(conn->request_queue);
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose requests = count == 0 ? NULL : array_idx(&conn->request_array, 0);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher for (i = 0; i < count; i++) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher request = requests[aqueue_idx(conn->request_queue, i)];
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (request->msgid == msgid)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher break;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher if (request->msgid == -1) {
f39b4b2fd57c0ea4cf2f90b511f2cbce37723ef0Sumit Bose request = NULL;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher break;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher }
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose }
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose if (request == NULL) {
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose i_error("LDAP: Reply with unknown msgid %d", msgid);
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose return;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose }
c51a204a40b8f85f7f525edb3e24520916d8b9c7Sumit Bose
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose if (request->type == LDAP_REQUEST_TYPE_BIND) {
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose i_assert(conn->conn_state == LDAP_CONN_STATE_BINDING);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher i_assert(conn->pending_count == 1);
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose conn->conn_state = LDAP_CONN_STATE_BOUND_AUTH;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose }
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher i_assert(conn->pending_count > 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->pending_count--;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher aqueue_delete(conn->request_queue, i);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_result2error(conn->ld, res, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_SUCCESS && request->type == LDAP_REQUEST_TYPE_SEARCH) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* handle search failures here */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher struct ldap_request_search *srequest =
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (struct ldap_request_search *)request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
e369fc08906383e6d5c39832f31bb6600a33f887Simo Sorce "ldap_search(%s) failed: %s",
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher srequest->filter, ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher res = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher T_BEGIN {
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher request->callback(conn, request, res);
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher } T_END;
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (i > 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* see if there are timed out requests */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_abort_requests(conn, i,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher DB_LDAP_REQUEST_LOST_TIMEOUT_SECS,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher TRUE, "Request lost");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_input(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct timeval timeout;
d844aab866ae237844360cea70e2dccdc90c783dStephen Gallagher LDAPMessage *res;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (;;) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (conn->ld == NULL)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina memset(&timeout, 0, sizeof(timeout));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#ifdef OPENLDAP_ASYNC_WORKAROUND
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (ret == 0) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* try again, there may be another in buffer */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ret = ldap_result(conn->ld, LDAP_RES_ANY, 1,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina &timeout, &res);
41ef946f3f74a46b9e26118116e4811e259b30efPavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#endif
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (ret <= 0)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina break;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina db_ldap_handle_result(conn, res);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ldap_msgfree(res);
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek }
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek conn->last_reply_stamp = ioloop_time;
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek if (ret == 0) {
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek /* send more requests */
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek while (db_ldap_request_queue_next(conn))
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek ;
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek } else if (ldap_get_errno(conn) != LDAP_SERVER_DOWN) {
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek i_error("LDAP: ldap_result() failed: %s", ldap_get_error(conn));
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek ldap_conn_reconnect(conn);
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek } else if (aqueue_count(conn->request_queue) > 0 ||
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta ioloop_time - conn->last_reply_stamp <
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta DB_LDAP_IDLE_RECONNECT_SECS) {
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta i_error("LDAP: Connection lost to LDAP server, reconnecting");
b42b5d5aaf4da165582e73ad985fdff6e34e61e4Jakub Hrozek ldap_conn_reconnect(conn);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta } else {
bd03e67c9d2fc4ad0275e7a573385ee5b7b9307aJan Cholasta /* server probably disconnected an idle connection. don't
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta reconnect until the next request comes. */
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta db_ldap_conn_close(conn);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta }
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta}
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose#ifdef HAVE_LDAP_SASL
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bosestatic int
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bosesasl_interact(LDAP *ld ATTR_UNUSED, unsigned flags ATTR_UNUSED,
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose void *defaults, void *interact)
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose{
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose struct db_ldap_sasl_bind_context *context = defaults;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose sasl_interact_t *in;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose const char *str;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose for (in = interact; in->id != SASL_CB_LIST_END; in++) {
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose switch (in->id) {
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose case SASL_CB_GETREALM:
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose str = context->realm;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose break;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose case SASL_CB_AUTHNAME:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str = context->authcid;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case SASL_CB_USER:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str = context->authzid;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher case SASL_CB_PASS:
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher str = context->passwd;
d248b68f90e60a1dd1cca1f694cc51bc3007c8b1Jan Engelhardt break;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher default:
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher str = NULL;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str != NULL) {
4b0309363dbfb9a1409e082b3a84f17b53a751c1Stephen Gallagher in->len = strlen(str);
4b0309363dbfb9a1409e082b3a84f17b53a751c1Stephen Gallagher in->result = str;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek }
52e0894fd65bff4715c88330eb62b28e1635228fStephen Gallagher return LDAP_SUCCESS;
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek}
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek#endif
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekstatic int db_ldap_bind(struct ldap_connection *conn)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int msgid;
8a07521b413a3b5879f824e1872c5770c92ee5c0Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->conn_state != LDAP_CONN_STATE_BINDING);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->default_bind_msgid == -1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->pending_count == 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.dnpass,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher LDAP_AUTH_SIMPLE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (msgid == -1) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(ldap_get_errno(conn) != LDAP_SUCCESS);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_connect_finish(conn, ldap_get_errno(conn)) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* lost connection, close it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_conn_close(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher conn->conn_state = LDAP_CONN_STATE_BINDING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->default_bind_msgid = msgid;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_get_fd(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* get the connection's fd */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Can't get connection fd: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (conn->fd <= STDERR_FILENO) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* Solaris LDAP library seems to be broken */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Buggy LDAP library returned wrong fd: %d",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->fd);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->fd != -1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher net_set_nonblock(conn->fd, TRUE);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_ldap_set_opt(struct ldap_connection *conn, int opt, const void *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *optname, const char *value_str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_set_option(conn == NULL ? NULL : conn->ld, opt, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Can't set option %s to %s: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher optname, value_str, ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_ldap_set_opt_str(struct ldap_connection *conn, int opt, const char *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *optname)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (value != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_opt(conn, opt, value, optname, value);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_set_tls_options(struct ldap_connection *conn)
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny{
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny if (!conn->set.tls)
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny return;
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher#ifdef OPENLDAP_TLS_OPTIONS
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTFILE,
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny conn->set.tls_ca_cert_file, "tls_ca_cert_file");
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTDIR,
f1828234a850dd28465425248a83a993f262918fPavel Březina conn->set.tls_ca_cert_dir, "tls_ca_cert_dir");
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CERTFILE,
f1828234a850dd28465425248a83a993f262918fPavel Březina conn->set.tls_cert_file, "tls_cert_file");
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_KEYFILE,
f1828234a850dd28465425248a83a993f262918fPavel Březina conn->set.tls_key_file, "tls_key_file");
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina conn->set.tls_cipher_suite, "tls_cipher_suite");
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina if (conn->set.tls_require_cert != NULL) {
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina int value = tls_require_cert2str(conn->set.tls_require_cert);
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek db_ldap_set_opt(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &value,
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina "tls_require_cert", conn->set.tls_require_cert);
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek }
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek#else
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina if (conn->set.tls_ca_cert_file != NULL ||
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina conn->set.tls_ca_cert_dir != NULL ||
558998ce664055a75595371118f818084d8f2b23Jan Cholasta conn->set.tls_cert_file != NULL ||
558998ce664055a75595371118f818084d8f2b23Jan Cholasta conn->set.tls_key_file != NULL ||
558998ce664055a75595371118f818084d8f2b23Jan Cholasta conn->set.tls_cipher_suite != NULL)
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta i_warning("LDAP: tls_* settings ignored, "
558998ce664055a75595371118f818084d8f2b23Jan Cholasta "your LDAP library doesn't seem to support them");
558998ce664055a75595371118f818084d8f2b23Jan Cholasta#endif
558998ce664055a75595371118f818084d8f2b23Jan Cholasta}
558998ce664055a75595371118f818084d8f2b23Jan Cholasta
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholastastatic void db_ldap_set_options(struct ldap_connection *conn)
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta{
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta unsigned int ldap_version;
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta int value;
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta db_ldap_set_opt(conn, LDAP_OPT_DEREF, &conn->set.ldap_deref,
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta "deref", conn->set.deref);
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta#ifdef LDAP_OPT_DEBUG_LEVEL
558998ce664055a75595371118f818084d8f2b23Jan Cholasta value = atoi(conn->set.debug_level);
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (value != 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_opt(NULL, LDAP_OPT_DEBUG_LEVEL, &value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "debug_level", conn->set.debug_level);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose#endif
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose if (conn->set.ldap_version < 3) {
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose if (conn->set.sasl_bind)
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose i_fatal("LDAP: sasl_bind=yes requires ldap_version=3");
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose if (conn->set.tls)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: tls=yes requires ldap_version=3");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_version = conn->set.ldap_version;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_opt(conn, LDAP_OPT_PROTOCOL_VERSION, &ldap_version,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "protocol_version", dec2str(ldap_version));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_tls_options(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint db_ldap_connect(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->pending_count == 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->ld == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uris != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef LDAP_HAVE_INITIALIZE
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->ld = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Your LDAP library doesn't support "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "'uris' setting, use 'hosts' instead.");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->ld == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: ldap_init() failed with hosts: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.hosts);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_options(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.tls) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef LDAP_HAVE_START_TLS_S
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_start_tls_s(conn->ld, NULL, NULL);
5843ad321944a028f6dee7e1fd4f9381c4953d07Sumit Bose if (ret != LDAP_SUCCESS) {
fd8595874aa06c8057740001ec465ba76b4af142Jakub Hrozek if (ret == LDAP_OPERATIONS_ERROR &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher strncmp(conn->set.uris, "ldaps:", 6) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Don't use both tls=yes "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "and ldaps URI");
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: ldap_start_tls_s() failed: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Your LDAP library doesn't support TLS");
c8b8901b05da9e31dba320f305ec20301e928cfbSumit Bose return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.sasl_bind) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef HAVE_LDAP_SASL
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_ldap_sasl_bind_context context;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher memset(&context, 0, sizeof(context));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.authcid = conn->set.dn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.passwd = conn->set.dnpass;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.realm = conn->set.sasl_realm;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.authzid = conn->set.sasl_authz_id;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* There doesn't seem to be a way to do SASL binding
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher asynchronously.. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.sasl_mech,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher NULL, NULL, LDAP_SASL_QUIET,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher sasl_interact, &context);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_connect_finish(conn, ret) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_bind(conn) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_get_fd(conn);
9d7d4458d94d0aac0a7edf999368eb18f89cb76aJakub Hrozek conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_disconnect_timeout(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_abort_requests(conn, -1U,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS, FALSE,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Aborting (timeout), we're not connected to LDAP server");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (aqueue_count(conn->request_queue) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* no requests left, remove this timeout handler */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher timeout_remove(&conn->to);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_conn_close(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *const *requests, *request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->default_bind_msgid = -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->pending_count != 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher requests = array_idx(&conn->request_array, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < conn->pending_count; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request = requests[aqueue_idx(conn->request_queue, i)];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher i_assert(request->msgid != -1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->msgid = -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->pending_count = 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->ld != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_unbind(conn->ld);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->ld = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->fd = -1;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->io != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the fd may have already been closed before ldap_unbind(),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher so we'll have to use io_remove_closed(). */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher io_remove_closed(&conn->io);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (aqueue_count(conn->request_queue) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->to != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher timeout_remove(&conn->to);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (conn->to == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->to = timeout_add(DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS *
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher 1000/2, db_ldap_disconnect_timeout, conn);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char ***attr_names_r, struct hash_table *attr_map,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *skip_attr)
9d7d4458d94d0aac0a7edf999368eb18f89cb76aJakub Hrozek{
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher const char *const *attr, *attr_data, *p;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *static_data;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char *name, *value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int i, j, size;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*attrlist == '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher attr = t_strsplit(attrlist, ",");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher static_data = t_str_new(128);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* @UNSAFE */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (size = 0; attr[size] != NULL; size++) ;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *attr_names_r = p_new(conn->pool, char *, size + 1);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = j = 0; i < size; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* allow spaces here so "foo=1, bar=2" works */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher attr_data = attr[i];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (*attr_data == ' ') attr_data++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p = strchr(attr_data, '=');
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (p == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = value = p_strdup(conn->pool, attr_data);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher else if (p != attr_data) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = p_strdup_until(conn->pool, attr_data, p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher value = p_strdup(conn->pool, p + 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* =<static key>=<static value> */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str_len(static_data) > 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_c(static_data, ',');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(static_data, p + 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher continue;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*name != '\0' &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (skip_attr == NULL || strcmp(skip_attr, value) != 0)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_table_insert(attr_map, name, value);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher (*attr_names_r)[j++] = name;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str_len(static_data) > 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_table_insert(attr_map, "",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p_strdup(conn->pool, str_c(static_data)));
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct var_expand_table *
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherdb_ldap_value_get_var_expand_table(struct auth_request *auth_request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct var_expand_table *auth_table;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct var_expand_table *table;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int count;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_table = auth_request_get_var_expand_table(auth_request, NULL);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher for (count = 0; auth_table[count].key != '\0'; count++) ;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher count++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
fe60346714a73ac3987f786731389320633dd245Pavel Březina table = t_new(struct var_expand_table, count + 1);
fe60346714a73ac3987f786731389320633dd245Pavel Březina table[0].key = '$';
fe60346714a73ac3987f786731389320633dd245Pavel Březina memcpy(table + 1, auth_table, sizeof(*table) * count);
fe60346714a73ac3987f786731389320633dd245Pavel Březina return table;
fe60346714a73ac3987f786731389320633dd245Pavel Březina}
fe60346714a73ac3987f786731389320633dd245Pavel Březina
fe60346714a73ac3987f786731389320633dd245Pavel Březina#define IS_LDAP_ESCAPED_CHAR(c) \
fe60346714a73ac3987f786731389320633dd245Pavel Březina ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
fe60346714a73ac3987f786731389320633dd245Pavel Březina
fe60346714a73ac3987f786731389320633dd245Pavel Březinaconst char *ldap_escape(const char *str,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek const struct auth_request *auth_request ATTR_UNUSED)
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek{
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek const char *p;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek string_t *ret;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek for (p = str; *p != '\0'; p++) {
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (IS_LDAP_ESCAPED_CHAR(*p))
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek break;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (*p == '\0')
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek return str;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek ret = t_str_new((size_t) (p - str) + 64);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher str_append_n(ret, str, (size_t) (p - str));
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher for (; *p != '\0'; p++) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher if (IS_LDAP_ESCAPED_CHAR(*p))
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher str_append_c(ret, '\\');
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher str_append_c(ret, *p);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher }
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher return str_c(ret);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher}
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagherstruct db_ldap_result_iterate_context *
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagherdb_ldap_result_iterate_init(struct ldap_connection *conn, LDAPMessage *entry,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose struct auth_request *auth_request,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose struct hash_table *attr_map)
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose{
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose struct db_ldap_result_iterate_context *ctx;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose const char *static_data;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose ctx = t_new(struct db_ldap_result_iterate_context, 1);
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose ctx->conn = conn;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose ctx->entry = entry;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose ctx->auth_request = auth_request;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose ctx->attr_map = attr_map;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher static_data = hash_table_lookup(attr_map, "");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (static_data != NULL) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher const struct var_expand_table *table;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *str;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher table = auth_request_get_var_expand_table(auth_request, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str = t_str_new(256);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher var_expand(str, static_data, table);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ctx->static_attrs = t_strsplit(str_c(str), ",");
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek }
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek if (auth_request->auth->set->debug)
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ctx->debug = t_str_new(256);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
fd8595874aa06c8057740001ec465ba76b4af142Jakub Hrozek return ctx;
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek}
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek
f232789430a080384188d5da89b19d874cf17513Jakub Hrozekstatic void
f232789430a080384188d5da89b19d874cf17513Jakub Hrozekdb_ldap_result_iterate_finish(struct db_ldap_result_iterate_context *ctx)
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek{
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek if (ctx->debug != NULL) {
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek if (str_len(ctx->debug) > 0) {
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek auth_request_log_debug(ctx->auth_request, "ldap",
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek "result: %s", str_c(ctx->debug) + 1);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek } else {
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek auth_request_log_debug(ctx->auth_request, "ldap",
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek "no fields returned by the server");
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek }
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek }
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ber_free(ctx->ber, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březinastatic void
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březinadb_ldap_result_change_attr(struct db_ldap_result_iterate_context *ctx)
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek{
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek ctx->name = hash_table_lookup(ctx->attr_map, ctx->attr);
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek ctx->template = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->debug != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_printfa(ctx->debug, " %s(%s)=", ctx->attr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->name != NULL ? ctx->name : "?unknown?");
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek }
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek if (ctx->name == NULL || *ctx->name == '\0') {
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek ctx->value = NULL;
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek return;
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek }
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek if (strchr(ctx->name, '%') != NULL &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (ctx->template = strchr(ctx->name, '=')) != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we want to use variables */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->name = t_strdup_until(ctx->name, ctx->template);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->template++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->var_table == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->var_table = db_ldap_value_get_var_expand_table(
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->auth_request);
f1ac7d7859b26f0f36f5e8ffacda609f8ece80e5Stephen Gallagher ctx->var = t_str_new(256);
f1ac7d7859b26f0f36f5e8ffacda609f8ece80e5Stephen Gallagher }
f128b7b865062da662127712935dcc58bd022384Stephen Gallagher }
cc7ee57f3adada83ac657e69636ca995d5b6948eStephen Gallagher
f128b7b865062da662127712935dcc58bd022384Stephen Gallagher ctx->vals = ldap_get_values(ctx->conn->ld, ctx->entry,
5f216c753dbd2f2b25a011c5f705ee4f8ad924e6Simo Sorce ctx->attr);
5f216c753dbd2f2b25a011c5f705ee4f8ad924e6Simo Sorce ctx->value = ctx->vals[0];
5f216c753dbd2f2b25a011c5f705ee4f8ad924e6Simo Sorce ctx->value_idx = 0;
1171986bdc3011555c5b62a9d9ee9f7481f48cdcSimo Sorce}
10eae23e2483733d4ca3c21f15b5bdb3f04c9839Simo Sorce
5f216c753dbd2f2b25a011c5f705ee4f8ad924e6Simo Sorcestatic void
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool first = ctx->value_idx == 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->template != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->var_table[0].value = ctx->value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_truncate(ctx->var, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher var_expand(ctx->var, ctx->template, ctx->var_table);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->value = str_c(ctx->var);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
2b7349575770521243a34611e97d73790946a961Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->debug != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!first)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_c(ctx->debug, '/');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->auth_request->auth->set->debug_passwords ||
8d821f0508f495deb376617c165cbcbf396a058aSimo Sorce strcmp(ctx->name, "password") != 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(ctx->debug, ctx->value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(ctx->debug, PASSWORD_HIDDEN_STR);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek}
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozekstatic bool db_ldap_result_int_next(struct db_ldap_result_iterate_context *ctx)
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek{
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek const char *p;
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek while (ctx->attr != NULL) {
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek if (ctx->vals == NULL) {
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek /* a new attribute */
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek db_ldap_result_change_attr(ctx);
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek } else {
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek /* continuing existing attribute */
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek if (ctx->value != NULL)
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek ctx->value = ctx->vals[++ctx->value_idx];
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek }
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek if (ctx->value != NULL) {
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek db_ldap_result_return_value(ctx);
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek return TRUE;
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ldap_value_free(ctx->vals); ctx->vals = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ldap_memfree(ctx->attr);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->attr = ldap_next_attribute(ctx->conn->ld, ctx->entry,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->ber);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (ctx->static_attrs != NULL && *ctx->static_attrs != NULL) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek p = strchr(*ctx->static_attrs, '=');
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (p == NULL) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->name = *ctx->static_attrs;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->value = "";
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek } else {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->name = t_strdup_until(*ctx->static_attrs, p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->value = p + 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* make _next_all() return correct values */
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek ctx->template = "";
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek ctx->val_1_arr[0] = ctx->value;
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek ctx->static_attrs++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek db_ldap_result_iterate_finish(ctx);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherbool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx,
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher const char **name_r, const char **value_r)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher{
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher if (!db_ldap_result_int_next(ctx))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *name_r = ctx->name;
619bd403265ce0880989ba6f8324b010949851bcSumit Bose *value_r = ctx->value;
796463906a54e259bd5b582ce84af4297a58eafcStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherbool db_ldap_result_iterate_next_all(struct db_ldap_result_iterate_context *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char **name_r,
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny const char *const **values_r)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
97ae45d61d921f07e812620e0156aee02b7b83a7Stephen Gallagher if (!db_ldap_result_int_next(ctx))
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny return FALSE;
d42d371c00c83ae44b9d1c3e88ecbe0e01b112e6Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->template != NULL) {
619bd403265ce0880989ba6f8324b010949851bcSumit Bose /* we can use only one value with templates */
796463906a54e259bd5b582ce84af4297a58eafcStephen Gallagher ctx->val_1_arr[0] = ctx->value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *values_r = ctx->val_1_arr;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *values_r = (const char *const *)ctx->vals;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher ctx->value = NULL;
ae8d047122c7ba8123f72b2eac68944868ac37d4Stephen Gallagher *name_r = ctx->name;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher return TRUE;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher}
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherstatic const char *parse_setting(const char *key, const char *value,
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher struct ldap_connection *conn)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher{
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher return parse_setting_from_defs(conn->pool, setting_defs,
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher &conn->set, key, value);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher}
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherstatic struct ldap_connection *ldap_conn_find(const char *config_path)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher{
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher struct ldap_connection *conn;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher for (conn = ldap_connections; conn != NULL; conn = conn->next) {
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher if (strcmp(conn->config_path, config_path) == 0)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher return conn;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher }
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher return NULL;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher}
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherstruct ldap_connection *db_ldap_init(const char *config_path)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher{
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher struct ldap_connection *conn;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher const char *str;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher pool_t pool;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher /* see if it already exists */
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher conn = ldap_conn_find(config_path);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher if (conn != NULL) {
93109c5f1d85c028ce5cf6e31e2249ca90a7f746Jakub Hrozek conn->refcount++;
fd8595874aa06c8057740001ec465ba76b4af142Jakub Hrozek return conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*config_path == '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Configuration file path not given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create("ldap_connection", 1024);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn = p_new(pool, struct ldap_connection, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->pool = pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->refcount = 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
88aeed9a31b734a92630d5e881c960c5f77ba0ceJakub Hrozek conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher conn->default_bind_msgid = -1;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->fd = -1;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->config_path = p_strdup(pool, config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set = default_ldap_settings;
e92ecf948387d1687a5e772ac86e606b1b6af957Stephen Gallagher if (!settings_read(config_path, NULL, parse_setting,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher null_settings_section_callback, conn))
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher exit(FATAL_DEFAULT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.base == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: No base given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uris == NULL && conn->set.hosts == NULL)
04feeade1f6259368a6b23c6b3ecbad261161659Sumit Bose i_fatal("LDAP: No uris or hosts set");
aec5785126354bd8b192f63fe04ea08dae9c0705Stephen Gallagher#ifndef LDAP_HAVE_INITIALIZE
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uris != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "(ldap_initialize not found)");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
c355f8df3eabf3c59af3a506fbffb8b0e4ff9fb7Sumit Bose#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*conn->set.ldaprc_path != '\0') {
e92ecf948387d1687a5e772ac86e606b1b6af957Stephen Gallagher str = getenv("LDAPRC");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str != NULL && strcmp(str, conn->set.ldaprc_path) != 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Multiple different ldaprc_path "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "settings not allowed (%s and %s)",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str, conn->set.ldaprc_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher env_put(t_strconcat("LDAPRC=", conn->set.ldaprc_path, NULL));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher conn->set.ldap_deref = deref2str(conn->set.deref);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.ldap_scope = scope2str(conn->set.scope);
e92ecf948387d1687a5e772ac86e606b1b6af957Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_array_init(&conn->request_array, DB_LDAP_MAX_QUEUE_SIZE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->request_queue = aqueue_init(&conn->request_array.arr);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->next = ldap_connections;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher ldap_connections = conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_unref(struct ldap_connection **_conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection *conn = *_conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection **p;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher *_conn = NULL;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher i_assert(conn->refcount >= 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (--conn->refcount > 0)
e92ecf948387d1687a5e772ac86e606b1b6af957Stephen Gallagher return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*p == conn) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *p = conn->next;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
213ce2a78b1abe3921d8dc13c949a28130d00aecJan Zeleny }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
8b1f2574ce7a964965a18ab047ab09c4694380c4Jan Zeleny
e526b608657f229f7486b3aa8c53b0f2c53b42b1Jan Zeleny db_ldap_abort_requests(conn, -1U, 0, FALSE, "Shutting down");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->pending_count == 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_conn_close(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->to == NULL);
ad07ed37b6b51ef134d4524edaf2259e19ac984fJan Zeleny
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose array_free(&conn->request_array);
881c4ba834b23ae651ac01db667801f314eb0a5dJan Zeleny aqueue_deinit(&conn->request_queue);
36a12aea020a935ffa40505fa02860c3d921ad0cSumit Bose
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (conn->pass_attr_map != NULL)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher hash_table_destroy(&conn->pass_attr_map);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (conn->user_attr_map != NULL)
71ad247500b417836a1a2edec257a4433a7c415fJan Zeleny hash_table_destroy(&conn->user_attr_map);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher pool_unref(&conn->pool);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny#ifndef BUILTIN_LDAP
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny/* Building a plugin */
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zelenyextern struct passdb_module_interface passdb_ldap;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherextern struct userdb_module_interface userdb_ldap;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallaghervoid authdb_ldap_init(void);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallaghervoid authdb_ldap_deinit(void);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid authdb_ldap_init(void)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb_register_module(&passdb_ldap);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher userdb_register_module(&userdb_ldap);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid authdb_ldap_deinit(void)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
88aeed9a31b734a92630d5e881c960c5f77ba0ceJakub Hrozek passdb_unregister_module(&passdb_ldap);
32a5516cc2822cf6ad9950278e3c9701a9389bb4Stephen Gallagher userdb_unregister_module(&userdb_ldap);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher}
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher#endif
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher