db-ldap.c revision efb7a523ea2f7670ca07acaaa5aeb30692ad6cd3
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen/* Copyright (C) 2003-2006 Timo Sirainen */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen/* Older versions may require calling ldap_result() twice */
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen { type, #name, offsetof(struct ldap_settings, name) }
5a8b0ce25f7838652b4a0cb9dab0ad19ec0fab25Timo Sirainen MEMBER(user_attrs) "uid,homeDirectory,,,uidNumber,gidNumber",
5a8b0ce25f7838652b4a0cb9dab0ad19ec0fab25Timo Sirainen MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
5a8b0ce25f7838652b4a0cb9dab0ad19ec0fab25Timo Sirainen MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_connections = NULL;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainenstatic int db_ldap_bind(struct ldap_connection *conn);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: Unknown deref option '%s'", str);
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen i_fatal("LDAP: Unknown scope option '%s'", str);
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainenconst char *ldap_get_error(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainenvoid db_ldap_search(struct ldap_connection *conn, struct ldap_request *request,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* switch back to the default dn before doing the search
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen msgid = ldap_search(conn->ld, request->base, scope,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: ldap_search() failed (filter %s): %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen hash_insert(conn->requests, POINTER_CAST(msgid), request);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainenstatic void ldap_conn_retry_requests(struct ldap_connection *conn)
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen conn->requests = hash_create(default_pool, conn->pool, 0, NULL, NULL);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* first retry all the search requests */
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* bind request */
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen db_ldap_search(conn, request, conn->set.ldap_scope);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* next retry all the bind requests. without auth binds the
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen only bind request can be the initial connection binding,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen which we don't care to retry. */
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainenstatic void ldap_conn_reconnect(struct ldap_connection *conn)
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen /* failed to reconnect. fail all requests. */
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen /* try again, there may be another in buffer */
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen request = hash_lookup(conn->requests, POINTER_CAST(msgid));
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen hash_remove(conn->requests, POINTER_CAST(msgid));
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainensasl_interact(LDAP *ld __attr_unused__, unsigned flags __attr_unused__,
dd2d3ef41dc407afb8afc49e18ff53640e4b4e02Timo Sirainen struct ldap_sasl_bind_context *context = defaults;
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen const char *str;
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen for (in = interact; in->id != SASL_CB_LIST_END; in++) {
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainenstatic int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen conn->set.dn == NULL ? "(none)" : conn->set.dn,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* in case there are requests waiting, retry them */
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainenstatic void db_ldap_bind_callback(struct ldap_connection *conn,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* aborted */
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen ret = ldap_parse_sasl_bind_result(conn->ld, res, NULL, FALSE);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen i_error("LDAP: ldap_parse_sasl_bind_result() failed: %s",
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen ret = ldap_result2error(conn->ld, res, FALSE);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainenstatic int db_ldap_bind(struct ldap_connection *conn)
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen ldap_request->callback = db_ldap_bind_callback;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen hash_insert(conn->requests, POINTER_CAST(msgid), ldap_request);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* we're binding back to the original DN, not doing an
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen authentication bind */
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainenstatic void db_ldap_get_fd(struct ldap_connection *conn)
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen /* get the connection's fd */
b270b29d458f3cbd6e63320bb17e23f809da0045Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainenint db_ldap_connect(struct ldap_connection *conn)
e65cc79f80577e83c706f0678c78e2c0bd91434fTimo Sirainen if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen i_fatal("LDAP: Your LDAP library doesn't support "
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen "'uris' setting, use 'hosts' instead.");
e65cc79f80577e83c706f0678c78e2c0bd91434fTimo Sirainen conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: ldap_init() failed with hosts: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen /* If SASL binds are used, the protocol version needs to be
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen at least 3 */
b567e0172c73dcf7642462e86962060358dd5f28Timo Sirainen ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
b567e0172c73dcf7642462e86962060358dd5f28Timo Sirainen i_fatal("LDAP: Can't set protocol version %u: %s",
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen i_error("LDAP: ldap_start_tls_s() failed: %s",
40992309053d51192ae1b36d1dd6c057f2d37257Timo Sirainen i_error("LDAP: Your LDAP library doesn't support TLS");
efb7a523ea2f7670ca07acaaa5aeb30692ad6cd3Timo Sirainen /* There doesn't seem to be a way to do SASL binding
efb7a523ea2f7670ca07acaaa5aeb30692ad6cd3Timo Sirainen asynchronously.. */
23f8c5356cacdbd1cc09a39a08ef37a39125bb74Timo Sirainen ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
efb7a523ea2f7670ca07acaaa5aeb30692ad6cd3Timo Sirainen i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests)
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainenvoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
0d7d27765267594a5870892268ab345148306d49Timo Sirainen char ***attr_names_r, struct hash_table *attr_map,
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen const char *const default_attr_map[],
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen const char *const *attr;
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen unsigned int i, j, size;
0e90e1b11b699166a4a4c5e01d132a28c3e26affTimo Sirainen /* @UNSAFE */
0d7d27765267594a5870892268ab345148306d49Timo Sirainen *attr_names_r = p_new(conn->pool, char *, size + 1);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen for (i = j = 0; i < size; i++) {
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen name = p_strdup_until(conn->pool, attr[i], p);
16133a719ce8b6a5b8cedd721340cc1607c43433Timo Sirainen if (skip_attr != NULL && strcmp(skip_attr, value) == 0)
1c38a95332f1945c9806d7d83175a0d948f51291Timo Sirainen ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
3c9783956dea385b322cd7fa6bf8c98c17a907a0Timo Sirainen const struct auth_request *auth_request __attr_unused__)
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen const char *p;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen if (*p == '\0')
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen for (; *p != '\0'; p++) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic const char *parse_setting(const char *key, const char *value,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return parse_setting_from_defs(conn->pool, setting_defs,
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_conn_find(const char *config_path)
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen for (conn = ldap_connections; conn != NULL; conn = conn->next) {
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen if (strcmp(conn->config_path, config_path) == 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstruct ldap_connection *db_ldap_init(const char *config_path)
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen /* see if it already exists */
2e1e493b248dec0127b1eabeea5a8bc330378fcdTimo Sirainen i_fatal("LDAP: Configuration file path not given");
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen pool = pool_alloconly_create("ldap_connection", 1024);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn = p_new(pool, struct ldap_connection, 1);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->config_path = p_strdup(pool, config_path);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen if (conn->set.uris == NULL && conn->set.hosts == NULL)
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
b1504ccfa93e77d906e39e6aa31a592d69f6b5b4Timo Sirainen "(ldap_initialize not found)");
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->set.ldap_deref = deref2str(conn->set.deref);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen conn->set.ldap_scope = scope2str(conn->set.scope);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen userdb_parse_uid(NULL, conn->set.user_global_uid);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen userdb_parse_gid(NULL, conn->set.user_global_gid);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid db_ldap_unref(struct ldap_connection **_conn)
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {