bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-common.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
44fc0a34c39f1ddb3a776918630010867a5dd04eTimo Sirainen#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "ioloop.h"
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen#include "array.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "hash.h"
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen#include "aqueue.h"
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen#include "str.h"
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen#include "time-util.h"
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen#include "env-util.h"
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen#include "var-expand.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "settings.h"
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen#include "userdb.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "db-ldap.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include <stddef.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen#define HAVE_LDAP_SASL
d8c2d988a913d1aae9abf2dd50c611c87d81d72aTimo Sirainen#ifdef HAVE_SASL_SASL_H
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen# include <sasl/sasl.h>
d8c2d988a913d1aae9abf2dd50c611c87d81d72aTimo Sirainen#elif defined (HAVE_SASL_H)
d8c2d988a913d1aae9abf2dd50c611c87d81d72aTimo Sirainen# include <sasl.h>
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen#else
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen# undef HAVE_LDAP_SASL
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen#endif
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen#ifdef LDAP_OPT_X_TLS
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen# define OPENLDAP_TLS_OPTIONS
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen#endif
0a8db75f72270a4d5964fd9ec082b618dd8d138dMartti Rannanjärvi#if !defined(SASL_VERSION_MAJOR) || SASL_VERSION_MAJOR < 2
d8c2d988a913d1aae9abf2dd50c611c87d81d72aTimo Sirainen# undef HAVE_LDAP_SASL
d8c2d988a913d1aae9abf2dd50c611c87d81d72aTimo Sirainen#endif
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen
594d203bdcbd160688bce5d5a6d65783b919ad49Timo Sirainen#ifndef LDAP_SASL_QUIET
594d203bdcbd160688bce5d5a6d65783b919ad49Timo Sirainen# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
594d203bdcbd160688bce5d5a6d65783b919ad49Timo Sirainen#endif
594d203bdcbd160688bce5d5a6d65783b919ad49Timo Sirainen
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen/* Older versions may require calling ldap_result() twice */
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen#if LDAP_VENDOR_VERSION <= 20112
3e1ded79bbc9166aa221bcf62d8eb2bee179c557Timo Sirainen# define OPENLDAP_ASYNC_WORKAROUND
3e1ded79bbc9166aa221bcf62d8eb2bee179c557Timo Sirainen#endif
3e1ded79bbc9166aa221bcf62d8eb2bee179c557Timo Sirainen
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen#ifndef LDAP_OPT_SUCCESS
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen# define LDAP_OPT_SUCCESS LDAP_SUCCESS
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen#endif
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomistatic const char *LDAP_ESCAPE_CHARS = "*,\\#+<>;\"()= ";
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainenstruct db_ldap_result {
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen int refcount;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen LDAPMessage *msg;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen};
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenstruct db_ldap_value {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const char **values;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen bool used;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen};
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainenstruct db_ldap_result_iterate_context {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen pool_t pool;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi struct ldap_request *ldap_request;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const ARRAY_TYPE(ldap_field) *attr_map;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen unsigned int attr_idx;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen /* attribute name => value */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE(char *, struct db_ldap_value *) ldap_attrs;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const char *val_1_arr[2];
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen string_t *var, *debug;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen bool skip_null_values;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen bool iter_dn_values;
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov LDAPMessage *ldap_msg;
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov LDAP *ld;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen};
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstruct db_ldap_sasl_bind_context {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen const char *authcid;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen const char *passwd;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen const char *realm;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen const char *authzid;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen};
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen#define DEF_STR(name) DEF_STRUCT_STR(name, ldap_settings)
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen#define DEF_INT(name) DEF_STRUCT_INT(name, ldap_settings)
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, ldap_settings)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic struct setting_def setting_defs[] = {
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(hosts),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(uris),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(dn),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(dnpass),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_BOOL(auth_bind),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(auth_bind_userdn),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_BOOL(tls),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_BOOL(sasl_bind),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(sasl_mech),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(sasl_realm),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(sasl_authz_id),
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen DEF_STR(tls_ca_cert_file),
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen DEF_STR(tls_ca_cert_dir),
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen DEF_STR(tls_cert_file),
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen DEF_STR(tls_key_file),
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen DEF_STR(tls_cipher_suite),
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen DEF_STR(tls_require_cert),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(deref),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(scope),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(base),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_INT(ldap_version),
f4a19b0cf11cdff437571708d9d788d02a906a00Timo Sirainen DEF_STR(debug_level),
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen DEF_STR(ldaprc_path),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(user_attrs),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(user_filter),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(pass_attrs),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(pass_filter),
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen DEF_STR(iterate_attrs),
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen DEF_STR(iterate_filter),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(default_pass_scheme),
964c86de7158ccafdfe665853579d71232e2634eTimo Sirainen DEF_BOOL(userdb_warning_disable),
e153e1205bc686fac815ce7bb534adcb36dfb722Timo Sirainen DEF_BOOL(blocking),
e25885d4c7c4b392c66bbf26a9b892362d90f001Timo Sirainen
e25885d4c7c4b392c66bbf26a9b892362d90f001Timo Sirainen { 0, NULL, 0 }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen};
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainenstatic struct ldap_settings default_ldap_settings = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .hosts = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .uris = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .dn = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .dnpass = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .auth_bind = FALSE,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .auth_bind_userdn = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls = FALSE,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .sasl_bind = FALSE,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .sasl_mech = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .sasl_realm = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .sasl_authz_id = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls_ca_cert_file = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls_ca_cert_dir = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls_cert_file = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls_key_file = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls_cipher_suite = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .tls_require_cert = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .deref = "never",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .scope = "subtree",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .base = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .ldap_version = 3,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .debug_level = "0",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .ldaprc_path = "",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .user_attrs = "homeDirectory=home,uidNumber=uid,gidNumber=gid",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .user_filter = "(&(objectClass=posixAccount)(uid=%u))",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .pass_attrs = "uid=user,userPassword=password",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .pass_filter = "(&(objectClass=posixAccount)(uid=%u))",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .iterate_attrs = "uid=user",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .iterate_filter = "(objectClass=posixAccount)",
964c86de7158ccafdfe665853579d71232e2634eTimo Sirainen .default_pass_scheme = "crypt",
e153e1205bc686fac815ce7bb534adcb36dfb722Timo Sirainen .userdb_warning_disable = FALSE,
e153e1205bc686fac815ce7bb534adcb36dfb722Timo Sirainen .blocking = FALSE
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen};
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_connections = NULL;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainenstatic int db_ldap_bind(struct ldap_connection *conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic void db_ldap_conn_close(struct ldap_connection *conn);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstruct db_ldap_result_iterate_context *
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainendb_ldap_result_iterate_init_full(struct ldap_connection *conn,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_search *ldap_request,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen LDAPMessage *res, bool skip_null_values,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen bool iter_dn_values);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainenstatic int deref2str(const char *str, int *ref_r)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (strcasecmp(str, "never") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *ref_r = LDAP_DEREF_NEVER;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "searching") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *ref_r = LDAP_DEREF_SEARCHING;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "finding") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *ref_r = LDAP_DEREF_FINDING;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "always") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *ref_r = LDAP_DEREF_ALWAYS;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen return -1;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen return 0;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainenstatic int scope2str(const char *str, int *scope_r)
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen{
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen if (strcasecmp(str, "base") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *scope_r = LDAP_SCOPE_BASE;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "onelevel") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *scope_r = LDAP_SCOPE_ONELEVEL;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "subtree") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *scope_r = LDAP_SCOPE_SUBTREE;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen return -1;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen return 0;
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen}
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen#ifdef OPENLDAP_TLS_OPTIONS
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainenstatic int tls_require_cert2str(const char *str, int *value_r)
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen{
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen if (strcasecmp(str, "never") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *value_r = LDAP_OPT_X_TLS_NEVER;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "hard") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *value_r = LDAP_OPT_X_TLS_HARD;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "demand") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *value_r = LDAP_OPT_X_TLS_DEMAND;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "allow") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *value_r = LDAP_OPT_X_TLS_ALLOW;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else if (strcasecmp(str, "try") == 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen *value_r = LDAP_OPT_X_TLS_TRY;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen else
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen return -1;
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen return 0;
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen}
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen#endif
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
78361883c67c58e339697c167ca285731f50287bTimo Sirainenstatic int ldap_get_errno(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen int ret, err;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret != LDAP_SUCCESS) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: Can't get error number: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_err2string(ret));
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen return LDAP_UNAVAILABLE;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
78361883c67c58e339697c167ca285731f50287bTimo Sirainen return err;
78361883c67c58e339697c167ca285731f50287bTimo Sirainen}
78361883c67c58e339697c167ca285731f50287bTimo Sirainen
78361883c67c58e339697c167ca285731f50287bTimo Sirainenconst char *ldap_get_error(struct ldap_connection *conn)
78361883c67c58e339697c167ca285731f50287bTimo Sirainen{
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen const char *ret;
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen char *str = NULL;
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen ret = ldap_err2string(ldap_get_errno(conn));
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, (void *)&str);
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen if (str != NULL) {
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen ret = t_strconcat(ret, ", ", str, NULL);
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen ldap_memfree(str);
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen }
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen ldap_set_option(conn->ld, LDAP_OPT_ERROR_STRING, NULL);
c184857e1fc86878761f6e47896c9cc1fad2d666Timo Sirainen return ret;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainenstatic void ldap_conn_reconnect(struct ldap_connection *conn)
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_conn_close(conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (db_ldap_connect(conn) < 0)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_conn_close(conn);
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen}
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic int ldap_handle_error(struct ldap_connection *conn)
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen{
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen int err = ldap_get_errno(conn);
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen switch (err) {
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_SUCCESS:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen i_unreached();
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_SIZELIMIT_EXCEEDED:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_TIMELIMIT_EXCEEDED:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_NO_SUCH_ATTRIBUTE:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_UNDEFINED_TYPE:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_INAPPROPRIATE_MATCHING:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_CONSTRAINT_VIOLATION:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_TYPE_OR_VALUE_EXISTS:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_INVALID_SYNTAX:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_NO_SUCH_OBJECT:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_ALIAS_PROBLEM:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_INVALID_DN_SYNTAX:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_IS_LEAF:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_ALIAS_DEREF_PROBLEM:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_FILTER_ERROR:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen /* invalid input */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return -1;
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_SERVER_DOWN:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_TIMEOUT:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_UNAVAILABLE:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_BUSY:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen#ifdef LDAP_CONNECT_ERROR
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_CONNECT_ERROR:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen#endif
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_LOCAL_ERROR:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen case LDAP_INVALID_CREDENTIALS:
4f93b5ab69b9a6420827f540742883efbb35f063Timo Sirainen case LDAP_OPERATIONS_ERROR:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen default:
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen /* connection problems */
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen ldap_conn_reconnect(conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return 0;
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen }
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen}
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic int db_ldap_request_bind(struct ldap_connection *conn,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *request)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request_bind *brequest =
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen (struct ldap_request_bind *)request;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(request->type == LDAP_REQUEST_TYPE_BIND);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(request->msgid == -1);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_AUTH ||
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->msgid = ldap_bind(conn->ld, brequest->dn,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->auth_request->mech_password,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen LDAP_AUTH_SIMPLE);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (request->msgid == -1) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen "ldap_bind(%s) failed: %s",
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen brequest->dn, ldap_get_error(conn));
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (ldap_handle_error(conn) < 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* broken request, remove it */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return 0;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return -1;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state = LDAP_CONN_STATE_BINDING;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return 1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic int db_ldap_request_search(struct ldap_connection *conn,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *request)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request_search *srequest =
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen (struct ldap_request_search *)request;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(request->msgid == -1);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->msgid =
2219b375f50f9af1f3e69b7b38aab733ea174c24Timo Sirainen ldap_search(conn->ld, *srequest->base == '\0' ? NULL :
2219b375f50f9af1f3e69b7b38aab733ea174c24Timo Sirainen srequest->base, conn->set.ldap_scope,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen srequest->filter, srequest->attributes, 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (request->msgid == -1) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen "ldap_search(%s) parsing failed: %s",
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen srequest->filter, ldap_get_error(conn));
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (ldap_handle_error(conn) < 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* broken request, remove it */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return 0;
1a59321a1116f9819e7b2899379a44de339ce802Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return 1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic bool db_ldap_request_queue_next(struct ldap_connection *conn)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *const *requestp, *request;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen int ret = -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
89676692402d8a58415b2c11256652322091ebabTimo Sirainen /* connecting may call db_ldap_connect_finish(), which gets us back
89676692402d8a58415b2c11256652322091ebabTimo Sirainen here. so do the connection before checking the request queue. */
89676692402d8a58415b2c11256652322091ebabTimo Sirainen if (db_ldap_connect(conn) < 0)
89676692402d8a58415b2c11256652322091ebabTimo Sirainen return FALSE;
d779da03fd24e13b0c6fbfa9a93ad0e4132c9f47Timo Sirainen
42ec694fb0f2e1fb1d8afcfb441382daea487bd9Timo Sirainen if (conn->pending_count == aqueue_count(conn->request_queue)) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* no non-pending requests */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
42ec694fb0f2e1fb1d8afcfb441382daea487bd9Timo Sirainen if (conn->pending_count > DB_LDAP_MAX_PENDING_REQUESTS) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* wait until server has replied to some requests */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
1a59321a1116f9819e7b2899379a44de339ce802Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen requestp = array_idx(&conn->request_array,
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen aqueue_idx(conn->request_queue,
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen conn->pending_count));
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request = *requestp;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (conn->pending_count > 0 &&
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->type == LDAP_REQUEST_TYPE_BIND) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* we can't do binds until all existing requests are finished */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen switch (conn->conn_state) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen case LDAP_CONN_STATE_DISCONNECTED:
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen case LDAP_CONN_STATE_BINDING:
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* wait until we're in bound state */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen case LDAP_CONN_STATE_BOUND_AUTH:
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (request->type == LDAP_REQUEST_TYPE_BIND)
0c822051bb9a910ee588fd97f7ec6f9df3d1b3c6Timo Sirainen break;
0c822051bb9a910ee588fd97f7ec6f9df3d1b3c6Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* bind to default dn first */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen (void)db_ldap_bind(conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen case LDAP_CONN_STATE_BOUND_DEFAULT:
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* we can do anything in this state */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen break;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen switch (request->type) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen case LDAP_REQUEST_TYPE_BIND:
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen ret = db_ldap_request_bind(conn, request);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen break;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen case LDAP_REQUEST_TYPE_SEARCH:
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen ret = db_ldap_request_search(conn, request);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen break;
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen }
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (ret > 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* success */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(request->msgid != -1);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->pending_count++;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return TRUE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen } else if (ret < 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* disconnected */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen } else {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* broken request, remove from queue */
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen aqueue_delete_tail(conn->request_queue);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->callback(conn, request, NULL);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return TRUE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
52c3bd140aefa777c1421137e033615ae0a58e72Timo Sirainenstatic void
52c3bd140aefa777c1421137e033615ae0a58e72Timo Sirainendb_ldap_check_hanging(struct ldap_connection *conn, struct ldap_request *request)
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen{
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen struct ldap_request *const *first_requestp;
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen unsigned int count;
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen time_t secs_diff;
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen count = aqueue_count(conn->request_queue);
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen if (count == 0)
52c3bd140aefa777c1421137e033615ae0a58e72Timo Sirainen return;
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen first_requestp = array_idx(&conn->request_array,
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen aqueue_idx(conn->request_queue, 0));
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen secs_diff = ioloop_time - (*first_requestp)->create_time;
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen if (secs_diff > DB_LDAP_REQUEST_LOST_TIMEOUT_SECS) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen "Connection appears to be hanging, reconnecting");
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen ldap_conn_reconnect(conn);
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen }
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen}
584a5375b70caa8bf7b202248aea84092bcb9c22Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenvoid db_ldap_request(struct ldap_connection *conn,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *request)
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen{
d95ef05d0c6ea5fdc8bc877dcf8f3b8fff6d8fb4Timo Sirainen i_assert(request->auth_request != NULL);
d95ef05d0c6ea5fdc8bc877dcf8f3b8fff6d8fb4Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->msgid = -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->create_time = ioloop_time;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
52c3bd140aefa777c1421137e033615ae0a58e72Timo Sirainen db_ldap_check_hanging(conn, request);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen aqueue_append(conn->request_queue, &request);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen (void)db_ldap_request_queue_next(conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (ret == LDAP_SERVER_DOWN) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_error("LDAP: Can't connect to server: %s",
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->set.uris != NULL ?
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->set.uris : conn->set.hosts);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (ret != LDAP_SUCCESS) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_error("LDAP: binding failed (dn %s): %s",
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->set.dn == NULL ? "(none)" : conn->set.dn,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen ldap_get_error(conn));
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen while (db_ldap_request_queue_next(conn))
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen ;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen return 0;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic void db_ldap_default_bind_finished(struct ldap_connection *conn,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen int ret;
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->default_bind_msgid = -1;
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen ret = ldap_result2error(conn->ld, res->msg, FALSE);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (db_ldap_connect_finish(conn, ret) < 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* lost connection, close it */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_conn_close(conn);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic void db_ldap_abort_requests(struct ldap_connection *conn,
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen unsigned int max_count,
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen unsigned int timeout_secs,
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen bool error, const char *reason)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *const *requestp, *request;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen time_t diff;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen while (aqueue_count(conn->request_queue) > 0 && max_count > 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen requestp = array_idx(&conn->request_array,
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen aqueue_idx(conn->request_queue, 0));
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request = *requestp;
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen diff = ioloop_time - request->create_time;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (diff < (time_t)timeout_secs)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen break;
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* timed out, abort */
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen aqueue_delete_tail(conn->request_queue);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (request->msgid != -1) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count > 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->pending_count--;
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen }
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen if (error) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen "%s", reason);
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen } else {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_info(request->auth_request, AUTH_SUBSYS_DB,
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen "%s", reason);
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->callback(conn, request, NULL);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen max_count--;
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic struct ldap_request *
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainendb_ldap_find_request(struct ldap_connection *conn, int msgid,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned int *idx_r)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *const *requests, *request = NULL;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen unsigned int i, count;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen count = aqueue_count(conn->request_queue);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (count == 0)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return NULL;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen requests = array_idx(&conn->request_array, 0);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen for (i = 0; i < count; i++) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen request = requests[aqueue_idx(conn->request_queue, i)];
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (request->msgid == msgid) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *idx_r = i;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return request;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (request->msgid == -1)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen break;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return NULL;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstatic int db_ldap_fields_get_dn(struct ldap_connection *conn,
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen struct ldap_request_search *request,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct auth_request *auth_request = request->request.auth_request;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_named_result *named_res;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct db_ldap_result_iterate_context *ldap_iter;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const char *name, *const *values;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen ldap_iter = db_ldap_result_iterate_init_full(conn, request, res->msg,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen TRUE, TRUE);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (values[1] != NULL) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_warning(auth_request, AUTH_SUBSYS_DB,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen "Multiple values found for '%s', "
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen "using value '%s'", name, values[0]);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_foreach_modifiable(&request->named_results, named_res) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (strcmp(named_res->field->name, name) != 0)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen continue;
6264b5ea568948885d269419ac4b4e3b00045042Timo Sirainen /* In future we could also support LDAP URLs here */
6264b5ea568948885d269419ac4b4e3b00045042Timo Sirainen named_res->dn = p_strdup(auth_request->pool,
6264b5ea568948885d269419ac4b4e3b00045042Timo Sirainen values[0]);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen db_ldap_result_iterate_deinit(&ldap_iter);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return 0;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstruct ldap_field_find_subquery_context {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ARRAY_TYPE(string) attr_names;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const char *name;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen};
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenstatic int
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainendb_ldap_field_subquery_find(const char *data, void *context,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **value_r,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **error_r ATTR_UNUSED)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_field_find_subquery_context *ctx = context;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen char *ldap_attr;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const char *p;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (*data != '\0') {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen data = t_strcut(data, ':');
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen p = strchr(data, '@');
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (p != NULL && strcmp(p+1, ctx->name) == 0) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ldap_attr = p_strdup_until(unsafe_data_stack_pool,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen data, p);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_append(&ctx->attr_names, &ldap_attr, 1);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = NULL;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstatic int
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenldap_request_send_subquery(struct ldap_connection *conn,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_search *request,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_named_result *named_res)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const struct ldap_field *field;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *p, *error;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen char *name;
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi struct auth_request *auth_request = request->request.auth_request;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_field_find_subquery_context ctx;
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi const struct var_expand_table *table =
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi auth_request_get_var_expand_table(auth_request, NULL);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi const struct var_expand_func_table *ptr;
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi struct var_expand_func_table *ftable;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen string_t *tmp_str = t_str_new(64);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ARRAY(struct var_expand_func_table) var_funcs_table;
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi t_array_init(&var_funcs_table, 8);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi for(ptr = auth_request_var_funcs_table; ptr->key != NULL; ptr++) {
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi array_append(&var_funcs_table, ptr, 1);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi }
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ftable = array_append_space(&var_funcs_table);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ftable->key = "ldap";
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ftable->func = db_ldap_field_subquery_find;
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ftable = array_append_space(&var_funcs_table);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ftable->key = "ldap_ptr";
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi ftable->func = db_ldap_field_subquery_find;
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi array_append_zero(&var_funcs_table);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen t_array_init(&ctx.attr_names, 8);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ctx.name = named_res->field->name;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* get the attributes names into array (ldapAttr@name -> ldapAttr) */
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_foreach(request->attr_map, field) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (field->ldap_attr_name[0] == '\0') {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen str_truncate(tmp_str, 0);
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi if (var_expand_with_funcs(tmp_str, field->value, table,
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi array_idx(&var_funcs_table, 0), &ctx, &error) <= 0) {
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi auth_request_log_error(auth_request,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen AUTH_SUBSYS_DB,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen "Failed to expand subquery %s: %s",
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen field->value, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return -1;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen } else {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen p = strchr(field->ldap_attr_name, '@');
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (p != NULL &&
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen strcmp(p+1, named_res->field->name) == 0) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen name = p_strdup_until(unsafe_data_stack_pool,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen field->ldap_attr_name, p);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_append(&ctx.attr_names, &name, 1);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_append_zero(&ctx.attr_names);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen request->request.msgid =
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ldap_search(conn->ld, named_res->dn, LDAP_SCOPE_BASE,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen NULL, array_idx_modifiable(&ctx.attr_names, 0), 0);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (request->request.msgid == -1) {
c8177e49ca88e9df9ae5b24861c9ce913fba103eAki Tuomi auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen "ldap_search(dn=%s) failed: %s",
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen named_res->dn, ldap_get_error(conn));
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return 0;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainenstatic int db_ldap_search_save_result(struct ldap_request_search *request,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res)
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen{
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen struct ldap_request_named_result *named_res;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (!array_is_created(&request->named_results)) {
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (request->result != NULL)
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen return -1;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen request->result = res;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen } else {
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen named_res = array_idx_modifiable(&request->named_results,
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen request->name_idx);
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (named_res->result != NULL)
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen return -1;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen named_res->result = res;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen }
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen res->refcount++;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen return 0;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen}
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstatic int db_ldap_search_next_subsearch(struct ldap_connection *conn,
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen struct ldap_request_search *request,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_named_result *named_res;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const struct ldap_field *field;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
8d8dc14bf9df8b809582e5b76d80f45a45c70eb4Timo Sirainen if (request->result != NULL)
8d8dc14bf9df8b809582e5b76d80f45a45c70eb4Timo Sirainen res = request->result;
8d8dc14bf9df8b809582e5b76d80f45a45c70eb4Timo Sirainen
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (!array_is_created(&request->named_results)) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* see if we need to do more LDAP queries */
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen p_array_init(&request->named_results,
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen request->request.auth_request->pool, 2);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_foreach(request->attr_map, field) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (!field->value_is_dn)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen continue;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen named_res = array_append_space(&request->named_results);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen named_res->field = field;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen if (db_ldap_fields_get_dn(conn, request, res) < 0)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return -1;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen } else {
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen request->name_idx++;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen while (request->name_idx < array_count(&request->named_results)) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* send the next LDAP query */
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen named_res = array_idx_modifiable(&request->named_results,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen request->name_idx);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (named_res->dn != NULL) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (ldap_request_send_subquery(conn, request,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen named_res) < 0)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return -1;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return 1;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* dn field wasn't returned, skip this */
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen request->name_idx++;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return 0;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstatic bool
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainendb_ldap_handle_request_result(struct ldap_connection *conn,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request *request, unsigned int idx,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen struct ldap_request_search *srequest = NULL;
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen const struct ldap_request_named_result *named_res;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen int ret;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen bool final_result;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_assert(conn->pending_count > 0);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (request->type == LDAP_REQUEST_TYPE_BIND) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_BINDING);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 1);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state = LDAP_CONN_STATE_BOUND_AUTH;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } else {
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen srequest = (struct ldap_request_search *)request;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen switch (ldap_msgtype(res->msg)) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen case LDAP_RES_SEARCH_ENTRY:
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen case LDAP_RES_SEARCH_RESULT:
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen break;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen case LDAP_RES_SEARCH_REFERENCE:
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* we're going to ignore this */
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return FALSE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen default:
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_error("LDAP: Reply with unexpected type %d",
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen ldap_msgtype(res->msg));
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return TRUE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen if (ldap_msgtype(res->msg) == LDAP_RES_SEARCH_ENTRY) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ret = LDAP_SUCCESS;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen final_result = FALSE;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen } else {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen final_result = TRUE;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen ret = ldap_result2error(conn->ld, res->msg, 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
749f6acd6790067c3103e8f9e793692fdb5ae30aTimo Sirainen /* LDAP_NO_SUCH_OBJECT is returned for nonexistent base */
749f6acd6790067c3103e8f9e793692fdb5ae30aTimo Sirainen if (ret != LDAP_SUCCESS && ret != LDAP_NO_SUCH_OBJECT &&
749f6acd6790067c3103e8f9e793692fdb5ae30aTimo Sirainen request->type == LDAP_REQUEST_TYPE_SEARCH) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* handle search failures here */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request_search *srequest =
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen (struct ldap_request_search *)request;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
872521e5ee7480b1002a9789a86874bd92e6aad8Timo Sirainen if (!array_is_created(&srequest->named_results)) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen "ldap_search(base=%s filter=%s) failed: %s",
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen srequest->base, srequest->filter,
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen ldap_err2string(ret));
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen } else {
872521e5ee7480b1002a9789a86874bd92e6aad8Timo Sirainen named_res = array_idx(&srequest->named_results,
872521e5ee7480b1002a9789a86874bd92e6aad8Timo Sirainen srequest->name_idx);
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen "ldap_search(base=%s) failed: %s",
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen named_res->dn, ldap_err2string(ret));
f30ab1a83f91b92c6576d34c033332af6b2898b1Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen res = NULL;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
f2f40b6ca4ce986d80ae0fe59efb542b3b837bfaTimo Sirainen if (ret == LDAP_SUCCESS && srequest != NULL && !srequest->multi_entry) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* expand any @results */
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (!final_result) {
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (db_ldap_search_save_result(srequest, res) < 0) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(request->auth_request, AUTH_SUBSYS_DB,
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen "LDAP search returned multiple entries");
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen res = NULL;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen } else {
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen /* wait for finish */
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen return FALSE;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen }
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen } else {
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen ret = db_ldap_search_next_subsearch(conn, srequest, res);
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (ret > 0) {
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen /* more LDAP queries left */
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen return FALSE;
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen }
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen if (ret < 0)
c2bae70e86bab833f1f51a6d8333c8996275ff08Timo Sirainen res = NULL;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen if (res == NULL && !final_result) {
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen /* wait for the final reply */
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen request->failed = TRUE;
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen return TRUE;
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen }
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen if (request->failed)
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen res = NULL;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (final_result) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen conn->pending_count--;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen aqueue_delete(conn->request_queue, idx);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen T_BEGIN {
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen if (res != NULL && srequest != NULL && srequest->result != NULL)
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen request->callback(conn, request, srequest->result->msg);
f2f40b6ca4ce986d80ae0fe59efb542b3b837bfaTimo Sirainen
55bfe6c008cb8872ff6a917daaabc4f2e81c0fe2Timo Sirainen request->callback(conn, request, res == NULL ? NULL : res->msg);
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen } T_END;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (idx > 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* see if there are timed out requests */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen db_ldap_abort_requests(conn, idx,
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen DB_LDAP_REQUEST_LOST_TIMEOUT_SECS,
3cff7935d606a75357472a3e4269e0b06ac1bef2Timo Sirainen TRUE, "Request lost");
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return TRUE;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainenstatic void db_ldap_result_unref(struct db_ldap_result **_res)
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen{
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res = *_res;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen *_res = NULL;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen i_assert(res->refcount > 0);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen if (--res->refcount == 0) {
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen ldap_msgfree(res->msg);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen i_free(res);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen }
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen}
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainenstatic void
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainendb_ldap_request_free(struct ldap_request *request)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (request->type == LDAP_REQUEST_TYPE_SEARCH) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_search *srequest =
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen (struct ldap_request_search *)request;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct ldap_request_named_result *named_res;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen if (srequest->result != NULL)
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen db_ldap_result_unref(&srequest->result);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen if (array_is_created(&srequest->named_results)) {
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen array_foreach_modifiable(&srequest->named_results, named_res) {
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen if (named_res->result != NULL)
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen db_ldap_result_unref(&named_res->result);
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen }
80ef919fa14d4196bcbf1e486d2d549154fa62e8Timo Sirainen array_clear(&srequest->named_results);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstatic void
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainendb_ldap_handle_result(struct ldap_connection *conn, struct db_ldap_result *res)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen struct auth_request *auth_request;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request *request;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen unsigned int idx;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen int msgid;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen msgid = ldap_msgid(res->msg);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (msgid == conn->default_bind_msgid) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen db_ldap_default_bind_finished(conn, res);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen request = db_ldap_find_request(conn, msgid, &idx);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (request == NULL) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen i_error("LDAP: Reply with unknown msgid %d", msgid);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen /* request is allocated from auth_request's pool */
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen auth_request = request->auth_request;
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen auth_request_ref(auth_request);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (db_ldap_handle_request_result(conn, request, idx, res))
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen db_ldap_request_free(request);
5acace56d99e0bef77b35e9b55113afde837680aTimo Sirainen auth_request_unref(&auth_request);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen}
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void ldap_input(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct timeval timeout;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen struct db_ldap_result *res;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen LDAPMessage *msg;
c51fe409810cbb2432b72d6819bd183469fcaebcTimo Sirainen time_t prev_reply_diff;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen int ret;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen do {
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen if (conn->ld == NULL)
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen return;
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&timeout);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen ret = ldap_result(conn->ld, LDAP_RES_ANY, 0, &timeout, &msg);
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen#ifdef OPENLDAP_ASYNC_WORKAROUND
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen if (ret == 0) {
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen /* try again, there may be another in buffer */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ret = ldap_result(conn->ld, LDAP_RES_ANY, 0,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen &timeout, &msg);
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen }
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen#endif
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen if (ret <= 0)
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen break;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen res = i_new(struct db_ldap_result, 1);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen res->refcount = 1;
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen res->msg = msg;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_handle_result(conn, res);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen db_ldap_result_unref(&res);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } while (conn->io != NULL);
c51fe409810cbb2432b72d6819bd183469fcaebcTimo Sirainen
c51fe409810cbb2432b72d6819bd183469fcaebcTimo Sirainen prev_reply_diff = ioloop_time - conn->last_reply_stamp;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->last_reply_stamp = ioloop_time;
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (ret > 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* input disabled, continue once it's enabled */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_assert(conn->io == NULL);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } else if (ret == 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* send more requests */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen while (db_ldap_request_queue_next(conn))
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen ;
d39e77e1f7f58e1e21042a673b718541fa3f63c7Timo Sirainen } else if (ldap_get_errno(conn) != LDAP_SERVER_DOWN) {
613daa324c2b61ec69291519a57186be7cc23286Timo Sirainen i_error("LDAP: ldap_result() failed: %s", ldap_get_error(conn));
0d68d1da0825e01be3f207042b9132ae8dfc9c06Timo Sirainen ldap_conn_reconnect(conn);
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen } else if (aqueue_count(conn->request_queue) > 0 ||
c51fe409810cbb2432b72d6819bd183469fcaebcTimo Sirainen prev_reply_diff < DB_LDAP_IDLE_RECONNECT_SECS) {
d39e77e1f7f58e1e21042a673b718541fa3f63c7Timo Sirainen i_error("LDAP: Connection lost to LDAP server, reconnecting");
d39e77e1f7f58e1e21042a673b718541fa3f63c7Timo Sirainen ldap_conn_reconnect(conn);
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen } else {
d39e77e1f7f58e1e21042a673b718541fa3f63c7Timo Sirainen /* server probably disconnected an idle connection. don't
d39e77e1f7f58e1e21042a673b718541fa3f63c7Timo Sirainen reconnect until the next request comes. */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_conn_close(conn);
54cc31729775282a6f3e0c02adcd1ab4cadc1cdfTimo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen#ifdef HAVE_LDAP_SASL
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainenstatic int
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainensasl_interact(LDAP *ld ATTR_UNUSED, unsigned flags ATTR_UNUSED,
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen void *defaults, void *interact)
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct db_ldap_sasl_bind_context *context = defaults;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen sasl_interact_t *in;
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen const char *str;
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen for (in = interact; in->id != SASL_CB_LIST_END; in++) {
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen switch (in->id) {
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen case SASL_CB_GETREALM:
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen str = context->realm;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen break;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen case SASL_CB_AUTHNAME:
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen str = context->authcid;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen break;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen case SASL_CB_USER:
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen str = context->authzid;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen break;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen case SASL_CB_PASS:
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen str = context->passwd;
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen break;
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen default:
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen str = NULL;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen break;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen }
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen if (str != NULL) {
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen in->len = strlen(str);
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen in->result = str;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen }
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen }
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen return LDAP_SUCCESS;
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen}
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen#endif
a399486f2d8d5bed51bc6344baba61a7f2b0dcdbTimo Sirainen
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainenstatic void ldap_connection_timeout(struct ldap_connection *conn)
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen{
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_BINDING);
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_error("LDAP %s: Initial binding to LDAP server timed out",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path);
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen db_ldap_conn_close(conn);
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen}
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov#ifdef HAVE_LDAP_SASL
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilovstatic int db_ldap_bind_sasl(struct ldap_connection *conn)
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov{
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov struct db_ldap_sasl_bind_context context;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov int ret;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&context);
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov context.authcid = conn->set.dn;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov context.passwd = conn->set.dnpass;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov context.realm = conn->set.sasl_realm;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov context.authzid = conn->set.sasl_authz_id;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov /* There doesn't seem to be a way to do SASL binding
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov asynchronously.. */
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov conn->set.sasl_mech,
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov NULL, NULL, LDAP_SASL_QUIET,
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov sasl_interact, &context);
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov if (db_ldap_connect_finish(conn, ret) < 0)
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov return -1;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov return 0;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov}
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov#else
144e0b545e5e1dac1fd825b4140b65bbf44ccb31Timo Sirainenstatic int db_ldap_bind_sasl(struct ldap_connection *conn ATTR_UNUSED)
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov{
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov i_unreached(); /* already checked at init */
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov return -1;
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov}
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov#endif
372b7c40bf035413dd3b9677f8f50f692b3602f0Matwey V. Kornilov
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilovstatic int db_ldap_bind_simple(struct ldap_connection *conn)
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen{
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen int msgid;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->conn_state != LDAP_CONN_STATE_BINDING);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->default_bind_msgid == -1);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 0);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
763fd2ac217023c0940415379abcd5eb7a0f7ba7Timo Sirainen msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.dnpass,
763fd2ac217023c0940415379abcd5eb7a0f7ba7Timo Sirainen LDAP_AUTH_SIMPLE);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen if (msgid == -1) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(ldap_get_errno(conn) != LDAP_SUCCESS);
7cf0a6613fca9983b8a3443f9f6ef15df5a22162Timo Sirainen if (db_ldap_connect_finish(conn, ldap_get_errno(conn)) < 0) {
7cf0a6613fca9983b8a3443f9f6ef15df5a22162Timo Sirainen /* lost connection, close it */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_conn_close(conn);
7cf0a6613fca9983b8a3443f9f6ef15df5a22162Timo Sirainen }
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen return -1;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen }
1a59321a1116f9819e7b2899379a44de339ce802Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state = LDAP_CONN_STATE_BINDING;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->default_bind_msgid = msgid;
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to);
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen conn->to = timeout_add(DB_LDAP_REQUEST_LOST_TIMEOUT_SECS*1000,
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen ldap_connection_timeout, conn);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen return 0;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen}
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilovstatic int db_ldap_bind(struct ldap_connection *conn)
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov{
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov if (conn->set.sasl_bind) {
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov if (db_ldap_bind_sasl(conn) < 0)
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov return -1;
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov } else {
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov if (db_ldap_bind_simple(conn) < 0)
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov return -1;
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov }
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov return 0;
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov}
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainenstatic void db_ldap_get_fd(struct ldap_connection *conn)
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen{
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen int ret;
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen /* get the connection's fd */
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen if (ret != LDAP_SUCCESS) {
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: Can't get connection fd: %s",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path, ldap_err2string(ret));
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (conn->fd <= STDERR_FILENO) {
d2ded6e1da2d07ac070888873ddc10999a6d87baTimo Sirainen /* Solaris LDAP library seems to be broken */
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: Buggy LDAP library returned wrong fd: %d",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path, conn->fd);
d2ded6e1da2d07ac070888873ddc10999a6d87baTimo Sirainen }
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen i_assert(conn->fd != -1);
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen net_set_nonblock(conn->fd, TRUE);
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen}
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(1)
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainendb_ldap_set_opt(struct ldap_connection *conn, LDAP *ld, int opt,
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen const void *value, const char *optname, const char *value_str)
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen{
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen int ret;
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen ret = ldap_set_option(ld, opt, value);
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen if (ret != LDAP_SUCCESS) {
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: Can't set option %s to %s: %s",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path, optname, value_str, ldap_err2string(ret));
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen }
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen}
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(1)
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainendb_ldap_set_opt_str(struct ldap_connection *conn, LDAP *ld, int opt,
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen const char *value, const char *optname)
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen{
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen if (value != NULL)
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt(conn, ld, opt, value, optname, value);
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen}
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainenstatic void db_ldap_set_tls_options(struct ldap_connection *conn)
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen{
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen#ifdef OPENLDAP_TLS_OPTIONS
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt_str(conn, NULL, LDAP_OPT_X_TLS_CACERTFILE,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen conn->set.tls_ca_cert_file, "tls_ca_cert_file");
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt_str(conn, NULL, LDAP_OPT_X_TLS_CACERTDIR,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen conn->set.tls_ca_cert_dir, "tls_ca_cert_dir");
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt_str(conn, NULL, LDAP_OPT_X_TLS_CERTFILE,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen conn->set.tls_cert_file, "tls_cert_file");
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt_str(conn, NULL, LDAP_OPT_X_TLS_KEYFILE,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen conn->set.tls_key_file, "tls_key_file");
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt_str(conn, NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen conn->set.tls_cipher_suite, "tls_cipher_suite");
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen if (conn->set.tls_require_cert != NULL) {
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt(conn, NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &conn->set.ldap_tls_require_cert_parsed,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen "tls_require_cert", conn->set.tls_require_cert);
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen }
f023d5a1665cc388131159914898ceecc526eda5Timo Sirainen#else
f023d5a1665cc388131159914898ceecc526eda5Timo Sirainen if (conn->set.tls_ca_cert_file != NULL ||
f023d5a1665cc388131159914898ceecc526eda5Timo Sirainen conn->set.tls_ca_cert_dir != NULL ||
f023d5a1665cc388131159914898ceecc526eda5Timo Sirainen conn->set.tls_cert_file != NULL ||
f023d5a1665cc388131159914898ceecc526eda5Timo Sirainen conn->set.tls_key_file != NULL ||
d492e2f0d022289c8068abfbfda86b73a66f1a50Timo Sirainen conn->set.tls_cipher_suite != NULL) {
d492e2f0d022289c8068abfbfda86b73a66f1a50Timo Sirainen i_fatal("LDAP %s: tls_* settings aren't supported by your LDAP library - they must not be set",
d492e2f0d022289c8068abfbfda86b73a66f1a50Timo Sirainen conn->config_path);
d492e2f0d022289c8068abfbfda86b73a66f1a50Timo Sirainen }
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen#endif
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen}
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainenstatic void db_ldap_set_options(struct ldap_connection *conn)
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen{
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen unsigned int ldap_version;
f4a19b0cf11cdff437571708d9d788d02a906a00Timo Sirainen int value;
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen#ifdef LDAP_OPT_NETWORK_TIMEOUT
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen struct timeval tv;
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen int ret;
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen tv.tv_sec = DB_LDAP_CONNECT_TIMEOUT_SECS; tv.tv_usec = 0;
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen ret = ldap_set_option(conn->ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen if (ret != LDAP_SUCCESS) {
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen i_fatal("LDAP %s: Can't set network-timeout: %s",
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen conn->config_path, ldap_err2string(ret));
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen }
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen#endif
fb3178a1924dae52151d88c4d4ded879df43dd3fTimo Sirainen
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt(conn, conn->ld, LDAP_OPT_DEREF, &conn->set.ldap_deref,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen "deref", conn->set.deref);
f4a19b0cf11cdff437571708d9d788d02a906a00Timo Sirainen#ifdef LDAP_OPT_DEBUG_LEVEL
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_int(conn->set.debug_level, &value) >= 0 && value != 0) {
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt(conn, NULL, LDAP_OPT_DEBUG_LEVEL, &value,
f4a19b0cf11cdff437571708d9d788d02a906a00Timo Sirainen "debug_level", conn->set.debug_level);
f4a19b0cf11cdff437571708d9d788d02a906a00Timo Sirainen }
f4a19b0cf11cdff437571708d9d788d02a906a00Timo Sirainen#endif
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
4756ae94c4db02e694c3425d9d949678117b66a3Timo Sirainen ldap_version = conn->set.ldap_version;
cc3cbeae65642023018d7e38eb325fea509c3e66Timo Sirainen db_ldap_set_opt(conn, conn->ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version,
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen "protocol_version", dec2str(ldap_version));
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen db_ldap_set_tls_options(conn);
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen}
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainenstatic void db_ldap_init_ld(struct ldap_connection *conn)
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen{
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen int ret;
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen if (conn->set.uris != NULL) {
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen#ifdef LDAP_HAVE_INITIALIZE
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen ret = ldap_initialize(&conn->ld, conn->set.uris);
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen if (ret != LDAP_SUCCESS) {
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: ldap_initialize() failed with uris %s: %s",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path, conn->set.uris,
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen ldap_err2string(ret));
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen }
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen#else
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen i_unreached(); /* already checked at init */
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen#endif
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen } else {
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen if (conn->ld == NULL) {
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: ldap_init() failed with hosts: %s",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path, conn->set.hosts);
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen }
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen }
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen db_ldap_set_options(conn);
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen}
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainenint db_ldap_connect(struct ldap_connection *conn)
b96dcd982888d89e6f2508258d6d9588d79c7a26Timo Sirainen{
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch int debug_level;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch bool debug;
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen struct timeval start, end;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen int ret;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch debug = FALSE;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_int(conn->set.debug_level, &debug_level) >= 0)
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch debug = debug_level > 0;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED)
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen return 0;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen if (debug) {
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen if (gettimeofday(&start, NULL) < 0)
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&start);
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 0);
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen if (conn->delayed_connect) {
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen conn->delayed_connect = FALSE;
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen timeout_remove(&conn->to);
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen }
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen if (conn->ld == NULL)
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen db_ldap_init_ld(conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen if (conn->set.tls) {
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen#ifdef LDAP_HAVE_START_TLS_S
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen ret = ldap_start_tls_s(conn->ld, NULL, NULL);
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen if (ret != LDAP_SUCCESS) {
8f0a5540a21d235f4f830517c6211f6f92948f2cTimo Sirainen if (ret == LDAP_OPERATIONS_ERROR &&
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen conn->set.uris != NULL &&
8f0a5540a21d235f4f830517c6211f6f92948f2cTimo Sirainen strncmp(conn->set.uris, "ldaps:", 6) == 0) {
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: Don't use both tls=yes "
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen "and ldaps URI", conn->config_path);
8f0a5540a21d235f4f830517c6211f6f92948f2cTimo Sirainen }
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_error("LDAP %s: ldap_start_tls_s() failed: %s",
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen conn->config_path, ldap_err2string(ret));
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen return -1;
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen }
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen#else
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen i_unreached(); /* already checked at init */
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen#endif
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen }
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov if (db_ldap_bind(conn) < 0)
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov return -1;
adb497977f0719bb75df2afcf4932125d107de4bMatwey V. Kornilov
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen if (debug) {
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen if (gettimeofday(&end, NULL) == 0) {
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen int msecs = timeval_diff_msecs(&end, &start);
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen i_debug("LDAP initialization took %d msecs", msecs);
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen }
eaa9884158bc0cf98379939f72061e31c359cf39Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_get_fd(conn);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen return 0;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainenstatic void db_ldap_connect_callback(struct ldap_connection *conn)
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen{
cd58b6bbd3bf060beb34cb5b56ef8781b36f4f05Timo Sirainen i_assert(conn->conn_state == LDAP_CONN_STATE_DISCONNECTED);
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen (void)db_ldap_connect(conn);
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen}
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainenvoid db_ldap_connect_delayed(struct ldap_connection *conn)
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen{
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen if (conn->delayed_connect)
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen return;
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen conn->delayed_connect = TRUE;
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen
e3c410263ee86079b575cb5084e773b2601ae576Timo Sirainen i_assert(conn->to == NULL);
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen conn->to = timeout_add_short(0, db_ldap_connect_callback, conn);
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen}
99363aeac519d37553b7776b322e60b8a23cd2b9Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenvoid db_ldap_enable_input(struct ldap_connection *conn, bool enable)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (!enable) {
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&conn->io);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } else {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (conn->io == NULL && conn->fd != -1) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ldap_input(conn);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic void db_ldap_disconnect_timeout(struct ldap_connection *conn)
095034a7699bfc464a07883f633551b5c313c4e7Timo Sirainen{
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen db_ldap_abort_requests(conn, UINT_MAX,
1512eb3e1f8d7366122089a03e3c8688986a5a26Timo Sirainen DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS, FALSE,
1512eb3e1f8d7366122089a03e3c8688986a5a26Timo Sirainen "Aborting (timeout), we're not connected to LDAP server");
095034a7699bfc464a07883f633551b5c313c4e7Timo Sirainen
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen if (aqueue_count(conn->request_queue) == 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen /* no requests left, remove this timeout handler */
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen timeout_remove(&conn->to);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen}
095034a7699bfc464a07883f633551b5c313c4e7Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainenstatic void db_ldap_conn_close(struct ldap_connection *conn)
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen{
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen struct ldap_request *const *requests, *request;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen unsigned int i;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
cd58b6bbd3bf060beb34cb5b56ef8781b36f4f05Timo Sirainen conn->delayed_connect = FALSE;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->default_bind_msgid = -1;
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to);
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen if (conn->pending_count != 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen requests = array_idx(&conn->request_array, 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen for (i = 0; i < conn->pending_count; i++) {
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen request = requests[aqueue_idx(conn->request_queue, i)];
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(request->msgid != -1);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen request->msgid = -1;
e023e3c2677ab66d7a7445eae9caf3d739e199cbTimo Sirainen }
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->pending_count = 0;
9e7182d6fa1940ec14cc2938699820b68ee1dc0dTimo Sirainen }
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->ld != NULL) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_unbind(conn->ld);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->ld = NULL;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen conn->fd = -1;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek /* the fd may have already been closed before ldap_unbind(),
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek so we'll have to use io_remove_closed(). */
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove_closed(&conn->io);
baf992882696ce085fa9122a559dbba8e627e19fTimo Sirainen
2d0a002723dac5c58c250f6566efb1f5e474c169Timo Sirainen if (aqueue_count(conn->request_queue) > 0) {
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->to = timeout_add(DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS *
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen 1000/2, db_ldap_disconnect_timeout, conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainenstruct ldap_field_find_context {
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen ARRAY_TYPE(string) attr_names;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen pool_t pool;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen};
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenstatic int
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainendb_ldap_field_find(const char *data, void *context,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **value_r,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **error_r ATTR_UNUSED)
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen{
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen struct ldap_field_find_context *ctx = context;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen char *ldap_attr;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen if (*data != '\0') {
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen ldap_attr = p_strdup(ctx->pool, t_strcut(data, ':'));
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (strchr(ldap_attr, '@') == NULL)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen array_append(&ctx->attr_names, &ldap_attr, 1);
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen }
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = NULL;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen}
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainenvoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen char ***attr_names_r, ARRAY_TYPE(ldap_field) *attr_map,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen const char *skip_attr)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen static struct var_expand_func_table var_funcs_table[] = {
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen { "ldap", db_ldap_field_find },
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen { "ldap_ptr", db_ldap_field_find },
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen { NULL, NULL }
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen };
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen struct ldap_field_find_context ctx;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct ldap_field *field;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen string_t *tmp_str;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *const *attr, *attr_data, *p, *error;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen char *ldap_attr, *name, *templ;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen unsigned int i;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen if (*attrlist == '\0')
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen return;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen attr = t_strsplit_spaces(attrlist, ",");
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen tmp_str = t_str_new(128);
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen ctx.pool = conn->pool;
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen p_array_init(&ctx.attr_names, conn->pool, 16);
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen for (i = 0; attr[i] != NULL; i++) {
99ee694f4099ea3dcc3b6b8331b093a8f1a2c604Timo Sirainen /* allow spaces here so "foo=1, bar=2" works */
99ee694f4099ea3dcc3b6b8331b093a8f1a2c604Timo Sirainen attr_data = attr[i];
99ee694f4099ea3dcc3b6b8331b093a8f1a2c604Timo Sirainen while (*attr_data == ' ') attr_data++;
99ee694f4099ea3dcc3b6b8331b093a8f1a2c604Timo Sirainen
99ee694f4099ea3dcc3b6b8331b093a8f1a2c604Timo Sirainen p = strchr(attr_data, '=');
acbf19bc103b663fbc311a3b2b88d586ea60c20dTimo Sirainen if (p == NULL)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_attr = name = p_strdup(conn->pool, attr_data);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen else if (attr_data[0] == '@') {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ldap_attr = "";
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen name = p_strdup(conn->pool, attr_data);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen } else {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_attr = p_strdup_until(conn->pool, attr_data, p);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen name = p_strdup(conn->pool, p + 1);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen templ = strchr(name, '=');
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen if (templ == NULL) {
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen if (*ldap_attr == '\0') {
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen /* =foo static value */
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen templ = "";
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen }
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen } else {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen *templ++ = '\0';
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen str_truncate(tmp_str, 0);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand_with_funcs(tmp_str, templ, NULL,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen var_funcs_table, &ctx, &error) <= 0) {
ec8e55a73623e40dfce9bfb5a60abf047788b222Martti Rannanjärvi /* This var_expand_with_funcs call fills the
ec8e55a73623e40dfce9bfb5a60abf047788b222Martti Rannanjärvi * ldap_field_find_context in ctx, but the
ec8e55a73623e40dfce9bfb5a60abf047788b222Martti Rannanjärvi * resulting string_t is not used, and the
ec8e55a73623e40dfce9bfb5a60abf047788b222Martti Rannanjärvi * return value or error_r is not checked since
ec8e55a73623e40dfce9bfb5a60abf047788b222Martti Rannanjärvi * it gives errors for non-ldap variable
ec8e55a73623e40dfce9bfb5a60abf047788b222Martti Rannanjärvi * expansions. */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen if (strchr(templ, '%') == NULL) {
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen /* backwards compatibility:
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen attr=name=prefix means same as
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen attr=name=prefix%$ when %vars are missing */
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen templ = p_strconcat(conn->pool, templ,
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen "%$", NULL);
9a8727ac119e429f8318262d9a2ba54aa4299306Timo Sirainen }
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (*name == '\0')
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_error("LDAP %s: Invalid attrs entry: %s", conn->config_path, attr_data);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen else if (skip_attr == NULL || strcmp(skip_attr, name) != 0) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen field = array_append_space(attr_map);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (name[0] == '@') {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* @name=ldapField */
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen name++;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen field->value_is_dn = TRUE;
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen } else if (name[0] == '!' && name == ldap_attr) {
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen /* !ldapAttr */
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen name = "";
adea69875046ece77dc36abd3f88a241a3f17ad9Timo Sirainen i_assert(ldap_attr[0] == '!');
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen ldap_attr++;
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen field->skip = TRUE;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen field->name = name;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen field->value = templ;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen field->ldap_attr_name = ldap_attr;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (*ldap_attr != '\0' &&
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen strchr(ldap_attr, '@') == NULL) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen /* root request's attribute */
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen array_append(&ctx.attr_names, &ldap_attr, 1);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&ctx.attr_names);
63cf2e557bdd9dd8bb4e2ecb84763ef884231f18Timo Sirainen *attr_names_r = array_idx_modifiable(&ctx.attr_names, 0);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainenstatic const struct var_expand_table *
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainendb_ldap_value_get_var_expand_table(struct auth_request *auth_request,
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen const char *ldap_value)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen struct var_expand_table *table;
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen unsigned int count = 1;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen table = auth_request_get_var_expand_table_full(auth_request, NULL,
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen &count);
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen table[0].key = '$';
be83284aff645d005e22817ab144fc598486619aTimo Sirainen table[0].value = ldap_value;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen return table;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
1c38a95332f1945c9806d7d83175a0d948f51291Timo Sirainen#define IS_LDAP_ESCAPED_CHAR(c) \
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi ((((unsigned char)(c)) & 0x80) != 0 || strchr(LDAP_ESCAPE_CHARS, (c)) != NULL)
1c38a95332f1945c9806d7d83175a0d948f51291Timo Sirainen
3c9783956dea385b322cd7fa6bf8c98c17a907a0Timo Sirainenconst char *ldap_escape(const char *str,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const struct auth_request *auth_request ATTR_UNUSED)
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen{
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi string_t *ret = NULL;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi for (const char *p = str; *p != '\0'; p++) {
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi if (IS_LDAP_ESCAPED_CHAR(*p)) {
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi if (ret == NULL) {
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi ret = t_str_new((size_t) (p - str) + 64);
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi str_append_n(ret, str, (size_t) (p - str));
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi }
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi str_printfa(ret, "\\%02X", (unsigned char)*p);
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi } else if (ret != NULL)
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi str_append_c(ret, *p);
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen }
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
917cac3e0f87f1c60e6569dcb6efba97ac0aa8c2Aki Tuomi return ret == NULL ? str : str_c(ret);
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen}
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenstatic bool
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenldap_field_hide_password(struct db_ldap_result_iterate_context *ctx,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const char *attr)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const struct ldap_field *field;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi if (ctx->ldap_request->auth_request->set->debug_passwords)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return FALSE;
db966fce2a30ac996d90ad31daffe47734ef4ad9Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen array_foreach(ctx->attr_map, field) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (strcmp(field->ldap_attr_name, attr) == 0) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (strcmp(field->name, "password") == 0 ||
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen strcmp(field->name, "password_noscheme") == 0)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return TRUE;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
db966fce2a30ac996d90ad31daffe47734ef4ad9Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return FALSE;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainenstatic void
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenget_ldap_fields(struct db_ldap_result_iterate_context *ctx,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_connection *conn, LDAPMessage *entry,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const char *suffix)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct db_ldap_value *ldap_value;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen char *attr, **vals;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen unsigned int i, count;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen BerElement *ber;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen attr = ldap_first_attribute(conn->ld, entry, &ber);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen while (attr != NULL) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen vals = ldap_get_values(conn->ld, entry, attr);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value = p_new(ctx->pool, struct db_ldap_value, 1);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (vals == NULL) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value->values = p_new(ctx->pool, const char *, 1);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen count = 0;
337db2d47544b384b06cda46931560f9f54530b2Timo Sirainen } else {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen for (count = 0; vals[count] != NULL; count++) ;
337db2d47544b384b06cda46931560f9f54530b2Timo Sirainen }
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value->values = p_new(ctx->pool, const char *, count + 1);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen for (i = 0; i < count; i++)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value->values[i] = p_strdup(ctx->pool, vals[i]);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (ctx->debug != NULL) {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen str_printfa(ctx->debug, " %s%s=", attr, suffix);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (count == 0)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_append(ctx->debug, "<no values>");
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen else if (ldap_field_hide_password(ctx, attr))
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_append(ctx->debug, PASSWORD_HIDDEN_STR);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen else {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_append(ctx->debug, ldap_value->values[0]);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen for (i = 1; i < count; i++) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_printfa(ctx->debug, ",%s",
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value->values[0]);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen hash_table_insert(ctx->ldap_attrs,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen p_strconcat(ctx->pool, attr, suffix, NULL),
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ldap_value);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value_free(vals);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_memfree(attr);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen attr = ldap_next_attribute(conn->ld, entry, ber);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ber_free(ber, 0);
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenstruct db_ldap_result_iterate_context *
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainendb_ldap_result_iterate_init_full(struct ldap_connection *conn,
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen struct ldap_request_search *ldap_request,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen LDAPMessage *res, bool skip_null_values,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen bool iter_dn_values)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct db_ldap_result_iterate_context *ctx;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const struct ldap_request_named_result *named_res;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen const char *suffix;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen pool_t pool;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
1b81b28b2e7856748cffd7d01052a944b6c80b23Timo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"ldap result iter", 1024);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ctx = p_new(pool, struct db_ldap_result_iterate_context, 1);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ctx->pool = pool;
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi ctx->ldap_request = &ldap_request->request;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ctx->attr_map = ldap_request->attr_map;
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen ctx->skip_null_values = skip_null_values;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen ctx->iter_dn_values = iter_dn_values;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&ctx->ldap_attrs, pool, 0, strcase_hash, strcasecmp);
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen ctx->var = str_new(ctx->pool, 256);
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi if (ctx->ldap_request->auth_request->debug)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ctx->debug = t_str_new(256);
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov ctx->ldap_msg = res;
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov ctx->ld = conn->ld;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen get_ldap_fields(ctx, conn, res, "");
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen if (array_is_created(&ldap_request->named_results)) {
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen array_foreach(&ldap_request->named_results, named_res) {
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen suffix = t_strdup_printf("@%s", named_res->field->name);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen if (named_res->result != NULL) {
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen get_ldap_fields(ctx, conn,
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen named_res->result->msg, suffix);
14b495a09db7aea6b68146fd6427229e75d2bb39Timo Sirainen }
068afb0ee323c59fd4830d49a40a59be11ea0212Timo Sirainen }
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return ctx;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainenstruct db_ldap_result_iterate_context *
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainendb_ldap_result_iterate_init(struct ldap_connection *conn,
b6df44e31bf9d54669b5903dfb5dd3fbbe896accTimo Sirainen struct ldap_request_search *ldap_request,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen LDAPMessage *res, bool skip_null_values)
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen{
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen return db_ldap_result_iterate_init_full(conn, ldap_request, res,
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen skip_null_values, FALSE);
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen}
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainenstatic const char *db_ldap_field_get_default(const char *data)
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen{
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen const char *p;
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen p = i_strchr_to_next(data, ':');
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen if (p == NULL)
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen return "";
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen else {
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen /* default value given */
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen return p;
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen }
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen}
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenstatic int
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainendb_ldap_field_expand(const char *data, void *context,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **value_r, const char **error_r ATTR_UNUSED)
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen{
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen struct db_ldap_result_iterate_context *ctx = context;
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen struct db_ldap_value *ldap_value;
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen const char *field_name = t_strcut(data, ':');
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen ldap_value = hash_table_lookup(ctx->ldap_attrs, field_name);
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen if (ldap_value == NULL) {
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen /* requested ldap attribute wasn't returned at all */
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if (ctx->debug != NULL)
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen str_printfa(ctx->debug, "; %s missing", field_name);
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = db_ldap_field_get_default(data);
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen }
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen ldap_value->used = TRUE;
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen if (ldap_value->values[0] == NULL) {
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen /* no value for ldap attribute */
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = db_ldap_field_get_default(data);
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen }
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen if (ldap_value->values[1] != NULL) {
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi auth_request_log_warning(ctx->ldap_request->auth_request,
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi AUTH_SUBSYS_DB,
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen "Multiple values found for '%s', using value '%s'",
74d5f3c4e3fd49d966a87f317f439a71954b3c70Timo Sirainen field_name, ldap_value->values[0]);
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen }
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = ldap_value->values[0];
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen}
c349375340580e4ef10b427323c6e67c14ae4996Timo Sirainen
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenstatic int
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainendb_ldap_field_ptr_expand(const char *data, void *context,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **value_r, const char **error_r)
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen{
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen struct db_ldap_result_iterate_context *ctx = context;
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen const char *field_name, *suffix;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen int ret;
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen suffix = strchr(t_strcut(data, ':'), '@');
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen if ((ret = db_ldap_field_expand(data, ctx, &field_name, error_r)) <= 0)
12c57531519d66e237e865c6ee3f7eadfe148550Timo Sirainen i_unreached();
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen if (field_name[0] == '\0') {
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = "";
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen }
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen field_name = t_strconcat(field_name, suffix, NULL);
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return db_ldap_field_expand(field_name, ctx, value_r, error_r);
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen}
a9b698e78ff0b4c71b1966c5a5d568c77632474cTimo Sirainen
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitovstatic int
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitovdb_ldap_field_dn_expand(const char *data ATTR_UNUSED, void *context ATTR_UNUSED,
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov const char **value_r, const char **error_r ATTR_UNUSED)
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov{
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov struct db_ldap_result_iterate_context *ctx = context;
a8adad33c80f82beb3c3529065a3d2b936cfd2fcTimo Sirainen char *dn = ldap_get_dn(ctx->ld, ctx->ldap_msg);
a8adad33c80f82beb3c3529065a3d2b936cfd2fcTimo Sirainen *value_r = t_strdup(dn);
a8adad33c80f82beb3c3529065a3d2b936cfd2fcTimo Sirainen ldap_memfree(dn);
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov return 1;
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov}
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainenstatic struct var_expand_func_table ldap_var_funcs_table[] = {
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen { "ldap", db_ldap_field_expand },
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen { "ldap_ptr", db_ldap_field_ptr_expand },
aec3f901e5895a6be413b8e7cf34de89d856ad21Sergey Kitov { "ldap_dn", db_ldap_field_dn_expand },
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen { NULL, NULL }
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen};
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenstatic const char *const *
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainendb_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const struct ldap_field *field,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct db_ldap_value *ldap_value)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen{
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen const struct var_expand_table *var_table;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *const *values, *error;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen if (ldap_value != NULL)
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen values = ldap_value->values;
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen else {
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen /* LDAP attribute doesn't exist */
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen ctx->val_1_arr[0] = NULL;
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen values = ctx->val_1_arr;
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen }
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen
914d477534d4d502d3c3432e7910f9332366064fTimo Sirainen if (field->value == NULL) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen /* use the LDAP attribute's value */
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen } else {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen /* template */
7783bfe16d9f2c3076e519c5bf190c37a3aa7774Timo Sirainen if (values[0] == NULL && *field->ldap_attr_name != '\0') {
7783bfe16d9f2c3076e519c5bf190c37a3aa7774Timo Sirainen /* ldapAttr=key=template%$, but ldapAttr doesn't
7783bfe16d9f2c3076e519c5bf190c37a3aa7774Timo Sirainen exist. */
7783bfe16d9f2c3076e519c5bf190c37a3aa7774Timo Sirainen return values;
7783bfe16d9f2c3076e519c5bf190c37a3aa7774Timo Sirainen }
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen if (values[0] != NULL && values[1] != NULL) {
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi auth_request_log_warning(ctx->ldap_request->auth_request,
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi AUTH_SUBSYS_DB,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen "Multiple values found for '%s', "
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen "using value '%s'",
7c85bb54c14c0ca3e7171431f99a594615792086Timo Sirainen field->name, values[0]);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen /* do this lookup separately for each expansion, because:
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen 1) the values are allocated from data stack
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen 2) if "user" field is updated, we want %u/%n/%d updated
4bbc8a478be20d0be16e92179fc32327004ebf86Timo Sirainen (and less importantly the same for other variables) */
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi var_table = db_ldap_value_get_var_expand_table(
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi ctx->ldap_request->auth_request, values[0]);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand_with_funcs(ctx->var, field->value, var_table,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen ldap_var_funcs_table, ctx, &error) <= 0) {
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi auth_request_log_warning(ctx->ldap_request->auth_request,
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi AUTH_SUBSYS_DB,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen "Failed to expand template %s: %s",
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen field->value, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ctx->val_1_arr[0] = str_c(ctx->var);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen values = ctx->val_1_arr;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return values;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenbool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const char **name_r,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const char *const **values_r)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const struct var_expand_table *tab;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen const struct ldap_field *field;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct db_ldap_value *ldap_value;
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen unsigned int pos;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *error;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen do {
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen if (ctx->attr_idx == array_count(ctx->attr_map))
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen return FALSE;
3fb1531681f9cbe49928f8e32357a692bf901c83Timo Sirainen field = array_idx(ctx->attr_map, ctx->attr_idx++);
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen } while (field->value_is_dn != ctx->iter_dn_values ||
626a206050bbe60b1f758c8918d09dad8accf225Timo Sirainen field->skip);
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value = *field->ldap_attr_name == '\0' ? NULL :
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen hash_table_lookup(ctx->ldap_attrs, field->ldap_attr_name);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (ldap_value != NULL)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen ldap_value->used = TRUE;
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen else if (ctx->debug != NULL && *field->ldap_attr_name != '\0')
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_printfa(ctx->debug, "; %s missing", field->ldap_attr_name);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen str_truncate(ctx->var, 0);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen *values_r = db_ldap_result_return_value(ctx, field, ldap_value);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen if (strchr(field->name, '%') == NULL)
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen *name_r = field->name;
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen else {
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen /* expand %variables also for LDAP name fields. we'll use the
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen same ctx->var, which may already contain the value. */
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen str_append_c(ctx->var, '\0');
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen pos = str_len(ctx->var);
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi tab = auth_request_get_var_expand_table(
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi ctx->ldap_request->auth_request, NULL);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand_with_funcs(ctx->var, field->name, tab,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen ldap_var_funcs_table, ctx, &error) <= 0) {
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi auth_request_log_warning(ctx->ldap_request->auth_request,
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi AUTH_SUBSYS_DB,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen "Failed to expand %s: %s", field->name, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen *name_r = str_c(ctx->var) + pos;
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen }
86c4dc0121015e403f9dd94ff7816b2baa5bd692Timo Sirainen
190ba2ebc899bd114e1e4ab9ee119be10f0cc0ecTimo Sirainen if (ctx->skip_null_values && (*values_r)[0] == NULL) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen /* no values. don't confuse the caller with this reply. */
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return db_ldap_result_iterate_next(ctx, name_r, values_r);
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return TRUE;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenstatic void
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainendb_ldap_result_finish_debug(struct db_ldap_result_iterate_context *ctx)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct hash_iterate_context *iter;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen char *name;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen struct db_ldap_value *value;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int unused_count = 0;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t orig_len;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
53e4a0d5cb048ea2bdf598ca56120b626b8615f5Martti Rannanjärvi if (ctx->ldap_request->result_logged)
53e4a0d5cb048ea2bdf598ca56120b626b8615f5Martti Rannanjärvi return;
53e4a0d5cb048ea2bdf598ca56120b626b8615f5Martti Rannanjärvi
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen orig_len = str_len(ctx->debug);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (orig_len == 0) {
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi auth_request_log_debug(ctx->ldap_request->auth_request,
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi AUTH_SUBSYS_DB,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen "no fields returned by the server");
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen return;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
1cb29929a19dea32779606cd54a1e63aefead88dTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_append(ctx->debug, "; ");
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen iter = hash_table_iterate_init(ctx->ldap_attrs);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, ctx->ldap_attrs, &name, &value)) {
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen if (!value->used) {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_printfa(ctx->debug, "%s,", name);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen unused_count++;
1cb29929a19dea32779606cd54a1e63aefead88dTimo Sirainen }
1cb29929a19dea32779606cd54a1e63aefead88dTimo Sirainen }
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen hash_table_iterate_deinit(&iter);
1cb29929a19dea32779606cd54a1e63aefead88dTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (unused_count == 0)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_truncate(ctx->debug, orig_len);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen else {
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_truncate(ctx->debug, str_len(ctx->debug)-1);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen str_append(ctx->debug, " unused");
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen }
5ced9eb9ef70b745462ff3ac238fb7af94581cb2Martti Rannanjärvi auth_request_log_debug(ctx->ldap_request->auth_request, AUTH_SUBSYS_DB,
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen "result: %s", str_c(ctx->debug) + 1);
53e4a0d5cb048ea2bdf598ca56120b626b8615f5Martti Rannanjärvi
53e4a0d5cb048ea2bdf598ca56120b626b8615f5Martti Rannanjärvi ctx->ldap_request->result_logged = TRUE;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainenvoid db_ldap_result_iterate_deinit(struct db_ldap_result_iterate_context **_ctx)
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen{
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen struct db_ldap_result_iterate_context *ctx = *_ctx;
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen *_ctx = NULL;
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen if (ctx->debug != NULL)
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen db_ldap_result_finish_debug(ctx);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen hash_table_destroy(&ctx->ldap_attrs);
0a8926b91a84abf462afdc1ed95def229377d7ffTimo Sirainen pool_unref(&ctx->pool);
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen}
4261a8b43792dc4db4b39e6910319835b7450e84Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic const char *parse_setting(const char *key, const char *value,
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return parse_setting_from_defs(conn->pool, setting_defs,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen &conn->set, key, value);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_conn_find(const char *config_path)
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen{
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen struct ldap_connection *conn;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen for (conn = ldap_connections; conn != NULL; conn = conn->next) {
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen if (strcmp(conn->config_path, config_path) == 0)
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen return conn;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen }
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen return NULL;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen}
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
964c86de7158ccafdfe665853579d71232e2634eTimo Sirainenstruct ldap_connection *db_ldap_init(const char *config_path, bool userdb)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct ldap_connection *conn;
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen const char *str, *error;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen pool_t pool;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen /* see if it already exists */
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn = ldap_conn_find(config_path);
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen if (conn != NULL) {
964c86de7158ccafdfe665853579d71232e2634eTimo Sirainen if (userdb)
964c86de7158ccafdfe665853579d71232e2634eTimo Sirainen conn->userdb_used = TRUE;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->refcount++;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen return conn;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen }
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
2e1e493b248dec0127b1eabeea5a8bc330378fcdTimo Sirainen if (*config_path == '\0')
2e1e493b248dec0127b1eabeea5a8bc330378fcdTimo Sirainen i_fatal("LDAP: Configuration file path not given");
2e1e493b248dec0127b1eabeea5a8bc330378fcdTimo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen pool = pool_alloconly_create("ldap_connection", 1024);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn = p_new(pool, struct ldap_connection, 1);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->pool = pool;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->refcount = 1;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
964c86de7158ccafdfe665853579d71232e2634eTimo Sirainen conn->userdb_used = userdb;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen conn->default_bind_msgid = -1;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen conn->fd = -1;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->config_path = p_strdup(pool, config_path);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->set = default_ldap_settings;
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen if (!settings_read_nosection(config_path, parse_setting, conn, &error))
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen i_fatal("ldap %s: %s", config_path, error);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->set.base == NULL)
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen i_fatal("LDAP %s: No base given", config_path);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen if (conn->set.uris == NULL && conn->set.hosts == NULL)
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen i_fatal("LDAP %s: No uris or hosts set", config_path);
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen#ifndef LDAP_HAVE_INITIALIZE
3c9e09fa412f62259e3a10bfe9ac6afb1becc2f0Timo Sirainen if (conn->set.uris != NULL) {
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen i_fatal("LDAP %s: uris set, but Dovecot compiled without support for LDAP uris "
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen "(ldap_initialize() not supported by LDAP library)", config_path);
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen }
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen#endif
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen#ifndef LDAP_HAVE_START_TLS_S
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen if (conn->set.tls)
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen i_fatal("LDAP %s: tls=yes, but your LDAP library doesn't support TLS", config_path);
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen#endif
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen#ifndef HAVE_LDAP_SASL
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen if (conn->set.sasl_bind)
67d650c5a18d0a03271bcb299e34ef7660835ac6Timo Sirainen i_fatal("LDAP %s: sasl_bind=yes but no SASL support compiled in", conn->config_path);
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen#endif
41e360a76aa9cf0d69aded3e0d5b0d5b5e91b50fTimo Sirainen if (conn->set.ldap_version < 3) {
41e360a76aa9cf0d69aded3e0d5b0d5b5e91b50fTimo Sirainen if (conn->set.sasl_bind)
41e360a76aa9cf0d69aded3e0d5b0d5b5e91b50fTimo Sirainen i_fatal("LDAP %s: sasl_bind=yes requires ldap_version=3", config_path);
41e360a76aa9cf0d69aded3e0d5b0d5b5e91b50fTimo Sirainen if (conn->set.tls)
41e360a76aa9cf0d69aded3e0d5b0d5b5e91b50fTimo Sirainen i_fatal("LDAP %s: tls=yes requires ldap_version=3", config_path);
41e360a76aa9cf0d69aded3e0d5b0d5b5e91b50fTimo Sirainen }
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen#ifdef OPENLDAP_TLS_OPTIONS
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen if (conn->set.tls_require_cert != NULL) {
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen if (tls_require_cert2str(conn->set.tls_require_cert,
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen &conn->set.ldap_tls_require_cert_parsed) < 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen i_fatal("LDAP %s: Unknown tls_require_cert value '%s'",
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen config_path, conn->set.tls_require_cert);
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen }
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen#endif
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen if (*conn->set.ldaprc_path != '\0') {
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen str = getenv("LDAPRC");
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen if (str != NULL && strcmp(str, conn->set.ldaprc_path) != 0) {
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen i_fatal("LDAP %s: Multiple different ldaprc_path "
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen "settings not allowed (%s and %s)",
f2dda28eb05337cabcd66b909a66affe79de1b4aTimo Sirainen config_path, str, conn->set.ldaprc_path);
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen }
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen env_put(t_strconcat("LDAPRC=", conn->set.ldaprc_path, NULL));
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen }
f8464772990b52cb8de4553bc1135adcf72813b8Timo Sirainen
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen if (deref2str(conn->set.deref, &conn->set.ldap_deref) < 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen i_fatal("LDAP %s: Unknown deref option '%s'", config_path, conn->set.deref);
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen if (scope2str(conn->set.scope, &conn->set.ldap_scope) < 0)
6332ef7522d7a77a18c1bec4fc80d92ee597336cTimo Sirainen i_fatal("LDAP %s: Unknown scope option '%s'", config_path, conn->set.scope);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen
31088625f59b7359d70845d81ea9e3dd8a24eb63Timo Sirainen i_array_init(&conn->request_array, 512);
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen conn->request_queue = aqueue_init(&conn->request_array.arr);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->next = ldap_connections;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen ldap_connections = conn;
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen
e885bb21d4f65f0239a8d05f5a8f17b56d5e9954Timo Sirainen db_ldap_init_ld(conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return conn;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid db_ldap_unref(struct ldap_connection **_conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct ldap_connection *conn = *_conn;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen struct ldap_connection **p;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_conn = NULL;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen i_assert(conn->refcount >= 0);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (--conn->refcount > 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen if (*p == conn) {
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen *p = conn->next;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen break;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen }
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen db_ldap_abort_requests(conn, UINT_MAX, 0, FALSE, "Shutting down");
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->pending_count == 0);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen db_ldap_conn_close(conn);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen i_assert(conn->to == NULL);
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen
fc4ff2356fee6389d4cf2b3f12f4098a436f0502Timo Sirainen array_free(&conn->request_array);
63cde222abaaa2a9bdaa9a143698dbc8b23bd742Timo Sirainen aqueue_deinit(&conn->request_queue);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&conn->pool);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen#ifndef BUILTIN_LDAP
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen/* Building a plugin */
cc03958ccda8258252c512412f8d5600ce383b14Timo Sirainenextern struct passdb_module_interface passdb_ldap_plugin;
cc03958ccda8258252c512412f8d5600ce383b14Timo Sirainenextern struct userdb_module_interface userdb_ldap_plugin;
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainenvoid authdb_ldap_init(void);
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainenvoid authdb_ldap_deinit(void);
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainenvoid authdb_ldap_init(void)
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen{
cc03958ccda8258252c512412f8d5600ce383b14Timo Sirainen passdb_register_module(&passdb_ldap_plugin);
cc03958ccda8258252c512412f8d5600ce383b14Timo Sirainen userdb_register_module(&userdb_ldap_plugin);
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen}
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainenvoid authdb_ldap_deinit(void)
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen{
cc03958ccda8258252c512412f8d5600ce383b14Timo Sirainen passdb_unregister_module(&passdb_ldap_plugin);
cc03958ccda8258252c512412f8d5600ce383b14Timo Sirainen userdb_unregister_module(&userdb_ldap_plugin);
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen}
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen#endif
be20a7ddf87cb56ee63016dd0029f0c523be09b6Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#endif