db-ldap.c revision 40992309053d51192ae1b36d1dd6c057f2d37257
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (C) 2003 Timo Sirainen */
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "common.h"
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
c252d148fa8ab50aaaa8bbae7beb4d208025171dNikolai Kondrashov
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "network.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "ioloop.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "hash.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "str.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "settings.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "userdb.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "db-ldap.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov
fd5a4eacd56700ffb08a73121aeacdc806cb0132Sumit Bose#include <stddef.h>
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#include <stdlib.h>
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher/* Older versions may require calling ldap_result() twice */
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#if LDAP_VENDOR_VERSION <= 20112
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher# define OPENLDAP_ASYNC_WORKAROUND
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#endif
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
428db8a58c0c149d5efccc6d788f70916c1d34d7Jakub Hrozek/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifndef LDAP_OPT_SUCCESS
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher# define LDAP_OPT_SUCCESS LDAP_SUCCESS
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF(type, name) \
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { type, #name, offsetof(struct ldap_settings, name) }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct setting_def setting_defs[] = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, hosts),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, uris),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, dn),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, dnpass),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_BOOL, auth_bind),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, auth_bind_userdn),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_BOOL, tls),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_BOOL, sasl_bind),
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose DEF(SET_STR, sasl_mech),
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose DEF(SET_STR, sasl_realm),
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose DEF(SET_STR, sasl_authz_id),
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose DEF(SET_STR, sasl_props),
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose DEF(SET_STR, deref),
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose DEF(SET_STR, scope),
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke DEF(SET_STR, base),
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke DEF(SET_INT, ldap_version),
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke DEF(SET_STR, user_attrs),
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose DEF(SET_STR, user_filter),
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose DEF(SET_STR, pass_attrs),
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose DEF(SET_STR, pass_filter),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, default_pass_scheme),
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher DEF(SET_STR, user_global_uid),
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher DEF(SET_STR, user_global_gid),
8214510f125879c3b1d247f2ce981ee20b5375d1Jakub Hrozek
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek { 0, NULL, 0 }
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct ldap_settings default_ldap_settings = {
d921c1eba437662437847279f251a0a5d8f70127Maxim MEMBER(hosts) NULL,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek MEMBER(uris) NULL,
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer MEMBER(dn) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(dnpass) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(auth_bind) FALSE,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(auth_bind_userdn) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(tls) FALSE,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(sasl_bind) FALSE,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce MEMBER(sasl_mech) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(sasl_realm) NULL,
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek MEMBER(sasl_authz_id) NULL,
5377441d7a846461c2d9a7a870cea711360a529aNikolai Kondrashov MEMBER(sasl_props) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(deref) "never",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(scope) "subtree",
32381402a4a9afc003782c9e2301fc59c9bda2a9Yassir Elley MEMBER(base) NULL,
dbfc407eef1d9ba2469687c3ffbe7fd8bb111d94Jakub Hrozek MEMBER(ldap_version) 2,
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher MEMBER(user_attrs) "uid,homeDirectory,,,uidNumber,gidNumber",
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek MEMBER(pass_attrs) "uid,userPassword",
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(default_pass_scheme) "crypt",
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MEMBER(user_global_uid) "",
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MEMBER(user_global_gid) ""
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek};
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozekstatic struct ldap_connection *ldap_connections = NULL;
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozekstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int deref2str(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "never") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_NEVER;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "searching") == 0)
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik return LDAP_DEREF_SEARCHING;
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik if (strcasecmp(str, "finding") == 0)
62bda5f75bda6b77aea30d708c74efaf725d9367Lukas Slebodnik return LDAP_DEREF_FINDING;
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek if (strcasecmp(str, "always") == 0)
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek return LDAP_DEREF_ALWAYS;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown deref option '%s'", str);
4f6931e854c698dcb1c09f99eb330ce2fb97e7c6Lukas Slebodnik}
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int scope2str(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (strcasecmp(str, "base") == 0)
558998ce664055a75595371118f818084d8f2b23Jan Cholasta return LDAP_SCOPE_BASE;
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta if (strcasecmp(str, "onelevel") == 0)
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta return LDAP_SCOPE_ONELEVEL;
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (strcasecmp(str, "subtree") == 0)
558998ce664055a75595371118f818084d8f2b23Jan Cholasta return LDAP_SCOPE_SUBTREE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown scope option '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherconst char *ldap_get_error(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret, err;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
f1828234a850dd28465425248a83a993f262918fPavel Březina if (ret != LDAP_SUCCESS) {
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guay i_error("LDAP: Can't get error number: %s",
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina ldap_err2string(ret));
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina return "??";
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ldap_err2string(err);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_search(struct ldap_connection *conn, struct ldap_request *request,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int scope)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek int msgid;
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek if (!conn->connected) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (!db_ldap_connect(conn)) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina request->callback(conn, request, NULL);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return;
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek }
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek }
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta msgid = ldap_search(conn->ld, request->base, scope,
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta request->filter, request->attributes, 0);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta if (msgid == -1) {
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek i_error("LDAP: ldap_search() failed (filter %s): %s",
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek request->filter, ldap_get_error(conn));
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek request->callback(conn, request, NULL);
19d3aba12c70528708be9440aca66038a291f29eYassir Elley return;
19d3aba12c70528708be9440aca66038a291f29eYassir Elley }
19d3aba12c70528708be9440aca66038a291f29eYassir Elley
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek hash_insert(conn->requests, POINTER_CAST(msgid), request);
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek}
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic void ldap_conn_retry_requests(struct ldap_connection *conn)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose struct hash_table *old_requests;
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek struct hash_iterate_context *iter;
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek void *key, *value;
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose i_assert(conn->connected);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek if (hash_size(conn->requests) == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose old_requests = conn->requests;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose conn->requests = hash_create(default_pool, conn->pool, 0, NULL, NULL);
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter = hash_iterate_init(old_requests);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (hash_iterate(iter, &key, &value)) {
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce struct ldap_request *request = value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->connected);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_search(conn, request, conn->set.ldap_scope);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_iterate_deinit(iter);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_destroy(old_requests);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_reconnect(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_conn_close(conn, FALSE);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!db_ldap_connect(conn)) {
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* failed to reconnect. fail all requests. */
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher ldap_conn_close(conn, TRUE);
fe60346714a73ac3987f786731389320633dd245Pavel Březina }
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose}
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walterstatic void ldap_input(void *context)
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek{
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose struct ldap_connection *conn = context;
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina struct ldap_request *request;
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher struct timeval timeout;
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina LDAPMessage *res;
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina int ret, msgid;
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina while (conn->ld != NULL) {
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina memset(&timeout, 0, sizeof(timeout));
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina#ifdef OPENLDAP_ASYNC_WORKAROUND
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina if (ret == 0) {
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek /* try again, there may be another in buffer */
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek ret = ldap_result(conn->ld, LDAP_RES_ANY, 1,
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek &timeout, &res);
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek }
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek#endif
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek if (ret <= 0) {
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek if (ret < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: ldap_result() failed: %s",
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek ldap_get_error(conn));
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek ldap_conn_reconnect(conn);
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh }
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh return;
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose }
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha msgid = ldap_msgid(res);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek request = hash_lookup(conn->requests, POINTER_CAST(msgid));
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek if (request == NULL) {
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose i_error("LDAP: Reply with unknown msgid %d",
e046ae03d0f55b1c8b0ec2fa6139bf86a3449adfPavel Březina msgid);
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose } else {
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose hash_remove(conn->requests, POINTER_CAST(msgid));
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek request->callback(conn, request, res);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek }
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ldap_msgfree(res);
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek }
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina}
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichlstatic int
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichlsasl_interact(LDAP *ld __attr_unused__, unsigned flags __attr_unused__,
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek void *defaults, void *interact)
a524965fbe0551f1b3a68f1e5c7a5689a652998fSumit Bose{
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek struct sasl_bind_context *context = defaults;
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose sasl_interact_t *in;
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina const char *str;
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose for (in = interact; in->id != SASL_CB_LIST_END; in++) {
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek switch (in->id) {
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina case SASL_CB_GETREALM:
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina str = context->realm;
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek break;
ea422c7061072c125eb53b40d7f3ca444d886913Sumit Bose case SASL_CB_AUTHNAME:
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek str = context->authcid;
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek break;
b590f44c06158485357d69cc5b24d5af05f1bb95Petr Cech case SASL_CB_USER:
01ec08efd0e166ac6f390f8627c6d08dcc63ccc4Jakub Hrozek str = context->authzid;
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose break;
6cb5bad3c8e2f35ca9dce1800a506d626f90c079Lukas Slebodnik case SASL_CB_PASS:
99c5f2f6ba0af6ce52be0d82ec2794bacc215742Jakub Hrozek str = context->passwd;
b407fe0474a674bb42f0f42ab47c7f530a07a367Pavel Březina break;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek default:
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek str = NULL;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek break;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek }
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (str != NULL) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek in->len = strlen(str);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek in->result = str;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek }
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek }
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik return LDAP_SUCCESS;
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik}
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnikbool db_ldap_connect(struct ldap_connection *conn)
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik{
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik int ret, fd;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek struct sasl_bind_context context;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->connected)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek if (conn->ld == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uris != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef LDAP_HAVE_INITIALIZE
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozek conn->ld = NULL;
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek#else
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek i_fatal("LDAP: Your LDAP library doesn't support "
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher "'uris' setting, use 'hosts' instead.");
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher#endif
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik } else
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (conn->ld == NULL)
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik i_fatal("LDAP: ldap_init() failed with hosts: %s",
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik conn->set.hosts);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik (void *) &conn->set.ldap_deref);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (ret != LDAP_SUCCESS) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik i_fatal("LDAP: Can't set deref option: %s",
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher ldap_err2string(ret));
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher }
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher (void *) &conn->set.ldap_version);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek if (ret != LDAP_OPT_SUCCESS) {
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov i_fatal("LDAP: Can't set protocol version %u: %s",
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov conn->set.ldap_version, ldap_err2string(ret));
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.tls) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef LDAP_HAVE_START_TLS_S
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_start_tls_s(conn->ld, NULL, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: ldap_start_tls_s() failed: %s",
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik ldap_err2string(ret));
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik return FALSE;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik }
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik#else
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik i_error("LDAP: Your LDAP library doesn't support TLS");
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* FIXME: we shouldn't use blocking bind */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.sasl_bind) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.authcid = conn->set.dn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.passwd = conn->set.dnpass;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.realm = conn->set.sasl_realm;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose context.authzid = conn->set.sasl_authz_id;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose conn->set.sasl_mech,
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose NULL, NULL, LDAP_SASL_QUIET,
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose sasl_interact, &context);
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose } else {
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose ret = ldap_simple_bind_s(conn->ld, conn->set.dn,
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose conn->set.dnpass);
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose }
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke if (ret == LDAP_SERVER_DOWN) {
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke i_error("LDAP: Can't connect to server: %s",
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke conn->set.hosts);
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke return FALSE;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke }
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher if (ret != LDAP_SUCCESS) {
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher i_error("LDAP: binding failed (dn %s): %s",
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik conn->set.dn == NULL ? "(none)" : conn->set.dn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_get_error(conn));
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return FALSE;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik conn->connected = TRUE;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* register LDAP input to ioloop */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *) &fd);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if (ret != LDAP_SUCCESS) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik i_fatal("LDAP: Can't get connection fd: %s",
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik ldap_err2string(ret));
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik net_set_nonblock(fd, TRUE);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik conn->io = io_add(fd, IO_READ, ldap_input, conn);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* in case there are requests waiting, retry them */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_conn_retry_requests(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests)
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher{
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher struct hash_iterate_context *iter;
15b266d9f14dad26da8678a79019749d0f69532eStephen Gallagher void *key, *value;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (flush_requests) {
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher iter = hash_iterate_init(conn->requests);
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny while (hash_iterate(iter, &key, &value)) {
6a6a821866091e0f722808566c25b951aa346d7cStephen Gallagher struct ldap_request *request = value;
48d7840cae22c5ff4d786149b0d8ecee7efb8306Lukas Slebodnik
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov request->callback(conn, request, NULL);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov }
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov hash_iterate_deinit(iter);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov hash_clear(conn->requests, FALSE);
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose }
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik conn->connected = FALSE;
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (conn->io != NULL)
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik io_remove(&conn->io);
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov if (conn->ld != NULL) {
7bb9ba8688ec1ca930d693eea05e936bc38f6d1bSumit Bose ldap_unbind(conn->ld);
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek conn->ld = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char ***attr_names_r, struct hash_table *attr_map,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *const default_attr_map[])
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
17f08cbd0f909181536b93d6c12c7cd69995f09eSumit Bose const char *const *attr;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov char *name, *value, *p;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov unsigned int i, size;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov if (*attrlist == '\0')
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov return;
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov t_push();
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose attr = t_strsplit(attrlist, ",");
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov /* @UNSAFE */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (size = 0; attr[size] != NULL; size++) ;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *attr_names_r = p_new(conn->pool, char *, size + 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < size; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p = strchr(attr[i], '=');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (p == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = p_strdup(conn->pool, attr[i]);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher value = *default_attr_map == NULL ? name :
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p_strdup(conn->pool, *default_attr_map);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = p_strdup_until(conn->pool, attr[i], p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher value = p_strdup(conn->pool, p + 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (*attr_names_r)[i] = name;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*name != '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_insert(attr_map, name, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*default_attr_map != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher default_attr_map++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher t_pop();
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose}
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek#define IS_LDAP_ESCAPED_CHAR(c) \
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozekconst char *ldap_escape(const char *str,
eaaeaa7e00c3d4bfa792cc4d3c6770dc1e28ef0cSumit Bose const struct auth_request *auth_request __attr_unused__)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *p;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *ret;
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (p = str; *p != '\0'; p++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (IS_LDAP_ESCAPED_CHAR(*p))
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
0ef783e186ef1c9f60e61a4e8e54c44cb366fdfePavel Březina
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (*p == '\0')
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta return str;
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik ret = t_str_new((size_t) (p - str) + 64);
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik str_append_n(ret, str, (size_t) (p - str));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
b3b6189850d50c656d62efbd498789124c033b00Lukas Slebodnik for (; *p != '\0'; p++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (IS_LDAP_ESCAPED_CHAR(*p))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_c(ret, '\\');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_c(ret, *p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return str_c(ret);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny
769347ad4d35d43488eb98f980143495b0db415dStef Walterstatic const char *parse_setting(const char *key, const char *value,
115de6d50f0d0bdd5745a5d8eb0d067be9128528Sumit Bose void *context)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina{
769347ad4d35d43488eb98f980143495b0db415dStef Walter struct ldap_connection *conn = context;
769347ad4d35d43488eb98f980143495b0db415dStef Walter
376eaf187c13c2a1eaea0ffbdd970b6b563ab74cPetr Cech return parse_setting_from_defs(conn->pool, setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher &conn->set, key, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_connection *ldap_conn_find(const char *config_path)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection *conn;
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina for (conn = ldap_connections; conn != NULL; conn = conn->next) {
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina if (strcmp(conn->config_path, config_path) == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return conn;
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek }
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek return NULL;
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek}
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct ldap_connection *db_ldap_init(const char *config_path)
ca261795ce61c41d7e62217ccb2ee913923040ffPavel Březina{
ca261795ce61c41d7e62217ccb2ee913923040ffPavel Březina struct ldap_connection *conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool_t pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* see if it already exists */
77d165f0629966db65753a3aee84a8b4971673afPavel Březina conn = ldap_conn_find(config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->refcount++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*config_path == '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Configuration file path not given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create("ldap_connection", 1024);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn = p_new(pool, struct ldap_connection, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->pool = pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim conn->refcount = 1;
6499d0b915209b670f8e337c4fe76a8be9fa6576Simo Sorce conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->config_path = p_strdup(pool, config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set = default_ldap_settings;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher exit(FATAL_DEFAULT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
4e0404ca1b19830dc0f729e59efd5bbd0a9d6103Lukas Slebodnik if (conn->set.base == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: No base given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnik if (conn->set.uris == NULL && conn->set.hosts == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: No uris or hosts set");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifndef LDAP_HAVE_INITIALIZE
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uris != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "(ldap_initialize not found)");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.ldap_deref = deref2str(conn->set.deref);
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose conn->set.ldap_scope = scope2str(conn->set.scope);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*conn->set.user_global_uid == '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.uid = (uid_t)-1;
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.uid =
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher userdb_parse_uid(NULL, conn->set.user_global_uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uid == (uid_t)-1) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Invalid user_global_uid: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.user_global_uid);
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek }
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
558ec7d717735bb16c210c675c2cc5bee1da4576Lukas Slebodnik if (*conn->set.user_global_gid == '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.gid = (gid_t)-1;
3a4186ae40d0c3b7be46a4c973166f6048fcfe38Lukas Slebodnik else {
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce conn->set.gid =
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter userdb_parse_gid(NULL, conn->set.user_global_gid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.gid == (gid_t)-1) {
46e36286953de4e5af5e4289b90a529929bdd17cPetr Cech i_fatal("LDAP: Invalid user_global_gid: %s",
1658c567191c35beaddffafdb079abe33248037bLukas Slebodnik conn->set.user_global_gid);
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->next = ldap_connections;
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zeleny ldap_connections = conn;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce return conn;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher}
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta
7de6e3534fd61c7619ed34a6b1afe7230b5e6504Ondrej Kosvoid db_ldap_unref(struct ldap_connection **_conn)
701f13b5c8e27bcbfc79e77ce7c76d9f768a448cLukas Slebodnik{
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina struct ldap_connection *conn = *_conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection **p;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *_conn = NULL;
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorce i_assert(conn->refcount >= 0);
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce if (--conn->refcount > 0)
9959c512ac3ba36f7a0db7614f0357ce0bae748fJakub Hrozek return;
7452f1b637276ce582b120f8f5482ae7f3b6bd47Jakub Hrozek
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorce for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
bc052ea17d858c19f9cb9c9e2bc602e754f68831Sumit Bose if (*p == conn) {
2fa8d6655ac37f9bdeb34420000052d921f4a543Michal Zidek *p = conn->next;
a473fb88e6015cf0ccbd2e9005c7e6acca18f452Pavel Březina break;
6499d0b915209b670f8e337c4fe76a8be9fa6576Simo Sorce }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
7ac503a73a26abe49f9f7d175c74df705380898dPavel Březina ldap_conn_close(conn, TRUE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_destroy(conn->requests);
e850be1ff2e13bba9812c94c3d102c0a0b570820Jakub Hrozek if (conn->pass_attr_map != NULL)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina hash_destroy(conn->pass_attr_map);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->user_attr_map != NULL)
d844aab866ae237844360cea70e2dccdc90c783dStephen Gallagher hash_destroy(conn->user_attr_map);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool_unref(conn->pool);
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher}
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher#endif
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce