db-ldap.c revision 473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "config.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#undef HAVE_CONFIG_H
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "common.h"
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen#include "network.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "ioloop.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "hash.h"
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen#include "str.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "settings.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include "db-ldap.h"
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#include <stddef.h>
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo 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
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#define DEF(type, name) \
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen { type, #name, offsetof(struct ldap_settings, name) }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic struct setting_def setting_defs[] = {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen DEF(SET_STR, hosts),
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen DEF(SET_STR, dn),
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen DEF(SET_STR, dnpass),
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen DEF(SET_STR, deref),
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen DEF(SET_STR, scope),
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen DEF(SET_STR, base),
10c5fd417af4ee30b68c967f5e7d5a49f4f149b5Timo Sirainen DEF(SET_STR, user_attrs),
10c5fd417af4ee30b68c967f5e7d5a49f4f149b5Timo Sirainen DEF(SET_STR, user_filter),
10c5fd417af4ee30b68c967f5e7d5a49f4f149b5Timo Sirainen DEF(SET_STR, pass_attrs),
1f18053d463f0294387b5e4dd11f9010bda9a24eTimo Sirainen DEF(SET_STR, pass_filter),
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen DEF(SET_STR, default_pass_scheme),
1f18053d463f0294387b5e4dd11f9010bda9a24eTimo Sirainen DEF(SET_STR, user_global_uid),
1f18053d463f0294387b5e4dd11f9010bda9a24eTimo Sirainen DEF(SET_STR, user_global_gid)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen};
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstruct ldap_settings default_ldap_settings = {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen MEMBER(hosts) "localhost",
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen MEMBER(dn) NULL,
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen MEMBER(dnpass) NULL,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen MEMBER(deref) "never",
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen MEMBER(scope) "subtree",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen MEMBER(base) NULL,
10c5fd417af4ee30b68c967f5e7d5a49f4f149b5Timo Sirainen MEMBER(user_attrs) NULL,
10c5fd417af4ee30b68c967f5e7d5a49f4f149b5Timo Sirainen MEMBER(user_filter) NULL,
10c5fd417af4ee30b68c967f5e7d5a49f4f149b5Timo Sirainen MEMBER(pass_attrs) NULL,
1f18053d463f0294387b5e4dd11f9010bda9a24eTimo Sirainen MEMBER(pass_filter) NULL,
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen MEMBER(default_pass_scheme) "crypt",
1f18053d463f0294387b5e4dd11f9010bda9a24eTimo Sirainen MEMBER(user_global_uid) 0,
1f18053d463f0294387b5e4dd11f9010bda9a24eTimo Sirainen MEMBER(user_global_gid) 0
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen};
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_connections = NULL;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic int ldap_conn_open(struct ldap_connection *conn);
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainenstatic void ldap_conn_close(struct ldap_connection *conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic int deref2str(const char *str)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (strcasecmp(str, "never") == 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return LDAP_DEREF_NEVER;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (strcasecmp(str, "searching") == 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return LDAP_DEREF_SEARCHING;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (strcasecmp(str, "finding") == 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return LDAP_DEREF_FINDING;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (strcasecmp(str, "always") == 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return LDAP_DEREF_ALWAYS;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: Unknown deref option '%s'", str);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainenstatic int scope2str(const char *str)
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen{
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen if (strcasecmp(str, "base") == 0)
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen return LDAP_SCOPE_BASE;
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen if (strcasecmp(str, "onelevel") == 0)
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen return LDAP_SCOPE_ONELEVEL;
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen if (strcasecmp(str, "subtree") == 0)
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen return LDAP_SCOPE_SUBTREE;
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen i_fatal("LDAP: Unknown scope option '%s'", str);
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen}
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic const char *get_ldap_error(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));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return "??";
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return ldap_err2string(err);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenvoid db_ldap_search(struct ldap_connection *conn, const char *base, int scope,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen const char *filter, char **attributes,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct ldap_request *request)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen int msgid;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (!conn->connected) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (!ldap_conn_open(conn)) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen request->callback(conn, request, NULL);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen msgid = ldap_search(conn->ld, base, scope, filter, attributes, 0);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (msgid == -1) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: ldap_search() failed (filter %s): %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen filter, get_ldap_error(conn));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen request->callback(conn, request, NULL);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen hash_insert(conn->requests, POINTER_CAST(msgid), request);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic void ldap_input(void *context)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct ldap_connection *conn = context;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct ldap_request *request;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct timeval timeout;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen LDAPMessage *res;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen int ret, msgid;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen for (;;) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen memset(&timeout, 0, sizeof(timeout));
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen#ifdef OPENLDAP_ASYNC_WORKAROUND
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen if (ret == 0) {
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen /* try again, there may be another in buffer */
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen ret = ldap_result(conn->ld, LDAP_RES_ANY, 1,
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen &timeout, &res);
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen }
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen#endif
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret <= 0) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret < 0) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: ldap_result() failed: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen get_ldap_error(conn));
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen /* reconnect */
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen ldap_conn_close(conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_result2error(conn->ld, res, 0);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret != LDAP_SUCCESS) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: ldap_result() failed: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_err2string(ret));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen } else {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen msgid = ldap_msgid(res);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen request = hash_lookup(conn->requests,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen POINTER_CAST(msgid));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (request != NULL) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen request->callback(conn, request, res);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen hash_remove(conn->requests,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen POINTER_CAST(msgid));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_free(request);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen } else {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: Reply with unknown msgid %d",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen msgid);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_msgfree(res);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic int ldap_conn_open(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen int ret, fd;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->connected)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return TRUE;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->ld == NULL) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->ld == NULL)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: ldap_init() failed with hosts: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->set.hosts);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen (void *) &conn->set.ldap_deref);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret != LDAP_SUCCESS) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: Can't set deref option: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_err2string(ret));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen /* NOTE: we use blocking connect, we couldn't do anything anyway
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen until it's done. */
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen ret = ldap_simple_bind_s(conn->ld, conn->set.dn, conn->set.dnpass);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret != LDAP_SUCCESS) {
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen if (ret == LDAP_SERVER_DOWN) {
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen i_error("LDAP: Can't connect to server: %s",
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen conn->set.hosts);
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen } else {
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen i_error("LDAP: ldap_simple_bind_s() failed: %s",
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen ldap_err2string(ret));
985375eafa124c948eee326eb6bfbe2b268514b5Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return FALSE;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->connected = TRUE;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen /* register LDAP input to ioloop */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *) &fd);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (ret != LDAP_SUCCESS) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: Can't get connection fd: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_err2string(ret));
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen net_set_nonblock(fd, TRUE);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->io = io_add(fd, IO_READ, ldap_input, conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return TRUE;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic void ldap_conn_close(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->connected) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen io_remove(conn->io);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->io = NULL;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->connected = FALSE;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->ld != NULL) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_unbind(conn->ld);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->ld = NULL;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenvoid db_ldap_set_attrs(struct ldap_connection *conn, const char *value,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen unsigned int **attrs, char ***attr_names)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen const char *const *attr;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen unsigned int i, dest, size;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen attr = t_strsplit(value, ",");
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (*attr == NULL || **attr == '\0')
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("Missing uid field in attrs");
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen for (size = 0; attr[size] != NULL; size++) ;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen /* +1 for terminating NULL */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen *attrs = p_new(conn->pool, unsigned int, size);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen *attr_names = p_new(conn->pool, char *, size + 1);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen for (i = 0, dest = 0; *attr != NULL; i++, attr++) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (**attr != '\0') {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen (*attrs)[dest] = i;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen (*attr_names)[dest] = p_strdup(conn->pool, *attr);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen dest++;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainenconst char *ldap_escape(const char *str)
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen{
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen string_t *s;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen const char *p;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen for (p = str; *p != '\0'; p++) {
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen if (strchr("*()\\", *p) != NULL)
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen break;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen }
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen if (*p == '\0')
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen return str;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen s = t_str_new(64);
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen str_append_n(s, str, (size_t) (p-str));
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen for (; *p != '\0'; p++) {
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen if (strchr("*()\\", *p) != NULL)
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen str_append_c(s, '\\');
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen str_append_c(s, *p);
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen }
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen return str_c(s);
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen}
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic const char *parse_setting(const char *key, const char *value,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen void *context)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct ldap_connection *conn = context;
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
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstruct ldap_connection *db_ldap_init(const char *config_path)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct ldap_connection *conn;
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) {
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->refcount++;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen return conn;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen }
c4457e497e01b57565d24da624968699b166e02aTimo 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
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->refcount = 1;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->config_path = p_strdup(pool, config_path);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->set = default_ldap_settings;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen settings_read(config_path, parse_setting, conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (conn->set.base == NULL)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: No base given");
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->set.ldap_deref = deref2str(conn->set.deref);
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen conn->set.ldap_scope = scope2str(conn->set.scope);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen (void)ldap_conn_open(conn);
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->next = ldap_connections;
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen ldap_connections = conn;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return conn;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenvoid db_ldap_unref(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen if (--conn->refcount > 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ldap_conn_close(conn);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen hash_destroy(conn->requests);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen pool_unref(conn->pool);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen}
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#endif