db-ldap.c revision 0d7d27765267594a5870892268ab345148306d49
c636315472e4f87313af7be30b7fbcad4b8ca8a4Stephen Gallagher/* Copyright (C) 2003 Timo Sirainen */
c636315472e4f87313af7be30b7fbcad4b8ca8a4Stephen Gallagher
fd5a4eacd56700ffb08a73121aeacdc806cb0132Sumit Bose#include "config.h"
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#undef HAVE_CONFIG_H
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#include "common.h"
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#include "network.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "ioloop.h"
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#include "hash.h"
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#include "str.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "settings.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "db-ldap.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <stddef.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <stdlib.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Older versions may require calling ldap_result() twice */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#if LDAP_VENDOR_VERSION <= 20112
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher# define OPENLDAP_ASYNC_WORKAROUND
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifndef LDAP_OPT_SUCCESS
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose# define LDAP_OPT_SUCCESS LDAP_SUCCESS
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose#endif
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF(type, name) \
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher { type, #name, offsetof(struct ldap_settings, name) }
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct setting_def setting_defs[] = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, hosts),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, uris),
d921c1eba437662437847279f251a0a5d8f70127Maxim DEF(SET_STR, dn),
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek DEF(SET_STR, dnpass),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, deref),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, scope),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, base),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_INT, ldap_version),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, user_attrs),
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce DEF(SET_STR, user_filter),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, pass_attrs),
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek DEF(SET_STR, pass_filter),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_STR, default_pass_scheme),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF(SET_INT, user_global_uid),
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher DEF(SET_INT, user_global_gid)
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher};
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct ldap_settings default_ldap_settings = {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MEMBER(hosts) NULL,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MEMBER(uris) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(dn) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(dnpass) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(deref) "never",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(scope) "subtree",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(base) NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(ldap_version) 2,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(user_attrs) "uid,homeDirectory,,,uidNumber,gidNumber",
be1ef1c62ad13612be5e1f879476c24452a5d6d0Stephen Gallagher MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek MEMBER(pass_attrs) "uid,userPassword",
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(default_pass_scheme) "crypt",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(user_global_uid) (uid_t)-1,
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher MEMBER(user_global_gid) (gid_t)-1
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_connection *ldap_connections = NULL;
558998ce664055a75595371118f818084d8f2b23Jan Cholasta
558998ce664055a75595371118f818084d8f2b23Jan Cholastastatic void ldap_conn_close(struct ldap_connection *conn);
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholastastatic int deref2str(const char *str)
558998ce664055a75595371118f818084d8f2b23Jan Cholasta{
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (strcasecmp(str, "never") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_NEVER;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "searching") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_SEARCHING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "finding") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_FINDING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "always") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_DEREF_ALWAYS;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny i_fatal("LDAP: Unknown deref option '%s'", str);
f1828234a850dd28465425248a83a993f262918fPavel Březina}
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guay
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guaystatic int scope2str(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "base") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_SCOPE_BASE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "onelevel") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_SCOPE_ONELEVEL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcasecmp(str, "subtree") == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return LDAP_SCOPE_SUBTREE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_fatal("LDAP: Unknown scope option '%s'", str);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozekconst char *ldap_get_error(struct ldap_connection *conn)
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek{
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek int ret, err;
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Can't get error number: %s",
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose ldap_err2string(ret));
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose return "??";
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose }
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ldap_err2string(err);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_search(struct ldap_connection *conn, const char *base, int scope,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *filter, char **attributes,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int msgid;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!conn->connected) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!db_ldap_connect(conn)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->callback(conn, request, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher msgid = ldap_search(conn->ld, base, scope, filter, attributes, 0);
fe60346714a73ac3987f786731389320633dd245Pavel Březina if (msgid == -1) {
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose i_error("LDAP: ldap_search() failed (filter %s): %s",
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose filter, ldap_get_error(conn));
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose request->callback(conn, request, NULL);
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose return;
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose }
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose hash_insert(conn->requests, POINTER_CAST(msgid), request);
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose}
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagherstatic void ldap_input(void *context)
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina{
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina struct ldap_connection *conn = context;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct timeval timeout;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek LDAPMessage *res;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek int ret, msgid;
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek while (conn->ld != NULL) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek memset(&timeout, 0, sizeof(timeout));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#ifdef OPENLDAP_ASYNC_WORKAROUND
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek if (ret == 0) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* try again, there may be another in buffer */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_result(conn->ld, LDAP_RES_ANY, 1,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher &timeout, &res);
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher }
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher#endif
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher if (ret <= 0) {
fa551077410019fb34460dc730950e93b62b2963Jakub Hrozek if (ret < 0) {
fa551077410019fb34460dc730950e93b62b2963Jakub Hrozek i_error("LDAP: ldap_result() failed: %s",
fa551077410019fb34460dc730950e93b62b2963Jakub Hrozek ldap_get_error(conn));
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher /* reconnect */
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher ldap_conn_close(conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher return;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher msgid = ldap_msgid(res);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request = hash_lookup(conn->requests, POINTER_CAST(msgid));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (request == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Reply with unknown msgid %d",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher msgid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher hash_remove(conn->requests, POINTER_CAST(msgid));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->callback(conn, request, res);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_msgfree(res);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint db_ldap_connect(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret, fd;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose if (conn->connected)
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose return TRUE;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose if (conn->ld == NULL) {
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher if (conn->set.uris != NULL) {
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher#ifdef LDAP_HAVE_INITIALIZE
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->ld = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Your LDAP library doesn't support "
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta "'uris' setting, use 'hosts' instead.");
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta#endif
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta } else
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->ld == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: ldap_init() failed with hosts: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.hosts);
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta (void *) &conn->set.ldap_deref);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Can't set deref option: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void *) &conn->set.ldap_version);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_OPT_SUCCESS) {
3b1df539835367cb81cd5ff0f9959947d5642e55Stephen Gallagher i_fatal("LDAP: Can't set protocol version %u: %s",
3b1df539835367cb81cd5ff0f9959947d5642e55Stephen Gallagher conn->set.ldap_version, ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher /* NOTE: we use blocking connect, we couldn't do anything anyway
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher until it's done. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_simple_bind_s(conn->ld, conn->set.dn, conn->set.dnpass);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret == LDAP_SERVER_DOWN) {
667db40da4db362d7ca0a1f7f1c4ba40fb71795aJakub Hrozek i_error("LDAP: Can't connect to server: %s", conn->set.hosts);
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose return FALSE;
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_SUCCESS) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: ldap_simple_bind_s() failed (dn %s): %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.dn == NULL ? "(none)" : conn->set.dn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_get_error(conn));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher }
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher
15b266d9f14dad26da8678a79019749d0f69532eStephen Gallagher conn->connected = TRUE;
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny /* register LDAP input to ioloop */
6a6a821866091e0f722808566c25b951aa346d7cStephen Gallagher ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *) &fd);
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose if (ret != LDAP_SUCCESS) {
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose i_fatal("LDAP: Can't get connection fd: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_err2string(ret));
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher net_set_nonblock(fd, TRUE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->io = io_add(fd, IO_READ, ldap_input, conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_close(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct hash_iterate_context *iter;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher void *key, *value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter = hash_iterate_init(conn->requests);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (hash_iterate(iter, &key, &value)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *request = value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->callback(conn, request, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_iterate_deinit(iter);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_clear(conn->requests, FALSE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->connected = FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->io != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher io_remove(conn->io);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->io = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->ld != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_unbind(conn->ld);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->ld = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose}
b32159300fea63222d8dd9200ed634087704ea74Stephen 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{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *const *attr;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char *name, *value, *p;
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce unsigned int i, size;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*attrlist == '\0')
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
0ef783e186ef1c9f60e61a4e8e54c44cb366fdfePavel Březina t_push();
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek attr = t_strsplit(attrlist, ",");
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* @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 :
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny p_strdup(conn->pool, *default_attr_map);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny } 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
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek if (*default_attr_map != NULL)
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek default_attr_map++;
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek }
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek t_pop();
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define IS_LDAP_ESCAPED_CHAR(c) \
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherconst char *ldap_escape(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *p;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (p = str; *p != '\0'; p++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (IS_LDAP_ESCAPED_CHAR(*p))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*p == '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return str;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = t_str_new((size_t) (p - str) + 64);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_n(ret, str, (size_t) (p - str));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (; *p != '\0'; p++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (IS_LDAP_ESCAPED_CHAR(*p))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_c(ret, '\\');
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim str_append_c(ret, *p);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return str_c(ret);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic const char *parse_setting(const char *key, const char *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher void *context)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection *conn = context;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek return parse_setting_from_defs(conn->pool, setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher &conn->set, key, value);
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim}
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_connection *ldap_conn_find(const char *config_path)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection *conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (conn = ldap_connections; conn != NULL; conn = conn->next) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcmp(conn->config_path, config_path) == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherstruct ldap_connection *db_ldap_init(const char *config_path)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_connection *conn;
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek pool_t pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* see if it already exists */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn = ldap_conn_find(config_path);
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek if (conn != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->refcount++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create("ldap_connection", 1024);
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek conn = p_new(pool, struct ldap_connection, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->pool = pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
3a4186ae40d0c3b7be46a4c973166f6048fcfe38Lukas Slebodnik conn->refcount = 1;
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny conn->config_path = p_strdup(pool, config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set = default_ldap_settings;
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher exit(FATAL_DEFAULT);
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zeleny
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (conn->set.base == NULL)
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta i_fatal("LDAP: No base given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.ldap_deref = deref2str(conn->set.deref);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.ldap_scope = scope2str(conn->set.scope);
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorce
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce conn->next = ldap_connections;
9959c512ac3ba36f7a0db7614f0357ce0bae748fJakub Hrozek ldap_connections = conn;
7452f1b637276ce582b120f8f5482ae7f3b6bd47Jakub Hrozek return conn;
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorce}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_unref(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (--conn->refcount > 0)
e850be1ff2e13bba9812c94c3d102c0a0b570820Jakub Hrozek return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->refcount == 0);
d844aab866ae237844360cea70e2dccdc90c783dStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_conn_close(conn);
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher hash_destroy(conn->requests);
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher if (conn->pass_attr_map != NULL)
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce hash_destroy(conn->pass_attr_map);
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose if (conn->user_attr_map != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hash_destroy(conn->user_attr_map);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina pool_unref(conn->pool);
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek}
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher