db-ldap.c revision 40992309053d51192ae1b36d1dd6c057f2d37257
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (C) 2003 Timo Sirainen */
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher/* Older versions may require calling ldap_result() twice */
428db8a58c0c149d5efccc6d788f70916c1d34d7Jakub Hrozek/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { type, #name, offsetof(struct ldap_settings, name) }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct setting_def setting_defs[] = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct ldap_settings default_ldap_settings = {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher MEMBER(user_attrs) "uid,homeDirectory,,,uidNumber,gidNumber",
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozekstatic struct ldap_connection *ldap_connections = NULL;
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozekstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown deref option '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown scope option '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherconst char *ldap_get_error(struct ldap_connection *conn)
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_search(struct ldap_connection *conn, struct ldap_request *request,
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta msgid = ldap_search(conn->ld, request->base, scope,
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek i_error("LDAP: ldap_search() failed (filter %s): %s",
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek hash_insert(conn->requests, POINTER_CAST(msgid), request);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic void ldap_conn_retry_requests(struct ldap_connection *conn)
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose conn->requests = hash_create(default_pool, conn->pool, 0, NULL, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (hash_iterate(iter, &key, &value)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_search(conn, request, conn->set.ldap_scope);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_reconnect(struct ldap_connection *conn)
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* failed to reconnect. fail all requests. */
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek /* try again, there may be another in buffer */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek request = hash_lookup(conn->requests, POINTER_CAST(msgid));
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose hash_remove(conn->requests, POINTER_CAST(msgid));
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichlsasl_interact(LDAP *ld __attr_unused__, unsigned flags __attr_unused__,
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina const char *str;
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose for (in = interact; in->id != SASL_CB_LIST_END; in++) {
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnikbool db_ldap_connect(struct ldap_connection *conn)
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek i_fatal("LDAP: Your LDAP library doesn't support "
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher "'uris' setting, use 'hosts' instead.");
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik i_fatal("LDAP: ldap_init() failed with hosts: %s",
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov i_fatal("LDAP: Can't set protocol version %u: %s",
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov conn->set.ldap_version, ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_start_tls_s(conn->ld, NULL, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: ldap_start_tls_s() failed: %s",
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik i_error("LDAP: Your LDAP library doesn't support TLS");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* FIXME: we shouldn't use blocking bind */
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke i_error("LDAP: Can't connect to server: %s",
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher i_error("LDAP: binding failed (dn %s): %s",
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik conn->set.dn == NULL ? "(none)" : conn->set.dn,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* register LDAP input to ioloop */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *) &fd);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik i_fatal("LDAP: Can't get connection fd: %s",
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik conn->io = io_add(fd, IO_READ, ldap_input, conn);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* in case there are requests waiting, retry them */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests)
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[])
17f08cbd0f909181536b93d6c12c7cd69995f09eSumit Bose const char *const *attr;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov unsigned int i, size;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (size = 0; attr[size] != NULL; size++) ;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *attr_names_r = p_new(conn->pool, char *, size + 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < size; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher value = *default_attr_map == NULL ? name :
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = p_strdup_until(conn->pool, attr[i], p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
eaaeaa7e00c3d4bfa792cc4d3c6770dc1e28ef0cSumit Bose const struct auth_request *auth_request __attr_unused__)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *p;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (*p == '\0')
b3b6189850d50c656d62efbd498789124c033b00Lukas Slebodnik for (; *p != '\0'; p++) {
769347ad4d35d43488eb98f980143495b0db415dStef Walterstatic const char *parse_setting(const char *key, const char *value,
376eaf187c13c2a1eaea0ffbdd970b6b563ab74cPetr Cech return parse_setting_from_defs(conn->pool, setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_connection *ldap_conn_find(const char *config_path)
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina for (conn = ldap_connections; conn != NULL; conn = conn->next) {
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina if (strcmp(conn->config_path, config_path) == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct ldap_connection *db_ldap_init(const char *config_path)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* see if it already exists */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Configuration file path not given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create("ldap_connection", 1024);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn = p_new(pool, struct ldap_connection, 1);
6499d0b915209b670f8e337c4fe76a8be9fa6576Simo Sorce conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->config_path = p_strdup(pool, config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnik if (conn->set.uris == NULL && conn->set.hosts == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "(ldap_initialize not found)");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.ldap_deref = deref2str(conn->set.deref);
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose conn->set.ldap_scope = scope2str(conn->set.scope);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher userdb_parse_uid(NULL, conn->set.user_global_uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Invalid user_global_uid: %s",
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter userdb_parse_gid(NULL, conn->set.user_global_gid);
7de6e3534fd61c7619ed34a6b1afe7230b5e6504Ondrej Kosvoid db_ldap_unref(struct ldap_connection **_conn)
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorce for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
bc052ea17d858c19f9cb9c9e2bc602e754f68831Sumit Bose if (*p == conn) {