passdb-ldap.c revision 368fc39f2712bd2ff4db0219d85e63225132511f
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2003 Timo Sirainen */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "config.h"
345648b341f228bd7f0b89f8aa3ecb9c470d817eTimo Sirainen#undef HAVE_CONFIG_H
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#ifdef PASSDB_LDAP
5a2cb3d097a2d9a9e930af997e7bf3400a8d840dTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "common.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "hash.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "str.h"
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen#include "var-expand.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "password-scheme.h"
16f46efe0e090fe6975acf012a61a160f4787985Andrey Panin#include "auth-cache.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "db-ldap.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "passdb.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include <ldap.h>
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include <stdlib.h>
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenextern struct passdb_module passdb_ldap;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstatic const char *default_attr_map[] = {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen "user", "password", NULL
16f46efe0e090fe6975acf012a61a160f4787985Andrey Panin};
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstruct passdb_ldap_request {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct ldap_request request;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen enum passdb_credentials credentials;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen union {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen verify_plain_callback_t *verify_plain;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen lookup_credentials_callback_t *lookup_credentials;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen } callback;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen char password[1]; /* variable width */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen};
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
7242e1ce7803b83bc82e239ef111b47c1c72dd4bAndrey Paninstatic struct ldap_connection *passdb_ldap_conn;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic char *passdb_ldap_cache_key;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic void
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenldap_query_save_result(struct ldap_connection *conn, LDAPMessage *entry,
c57776c06ec99ba9b0dafdbf9475ea72ea8ca134Timo Sirainen struct auth_request *auth_request)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen{
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen BerElement *ber;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const char *name;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen char *attr, **vals;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen unsigned int i;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen attr = ldap_first_attribute(conn->ld, entry, &ber);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen while (attr != NULL) {
4051fa1f367553cac34f74c2e332a678390bcee5Timo Sirainen name = hash_lookup(passdb_ldap_conn->attr_map, attr);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen vals = ldap_get_values(conn->ld, entry, attr);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen if (name != NULL && vals != NULL) {
4051fa1f367553cac34f74c2e332a678390bcee5Timo Sirainen for (i = 0; vals[i] != NULL; i++) {
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen auth_request_set_field(auth_request,
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen name, vals[i],
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen conn->set.default_pass_scheme);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen }
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen }
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen ldap_value_free(vals);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen ldap_memfree(attr);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen attr = ldap_next_attribute(conn->ld, entry, ber);
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen }
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen}
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainenstatic void handle_request(struct ldap_connection *conn,
59beb411159176b39e48a52d60dd3239732e67b4Timo Sirainen struct ldap_request *request, LDAPMessage *res)
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen{
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen struct passdb_ldap_request *ldap_request =
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen (struct passdb_ldap_request *) request;
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen struct auth_request *auth_request = request->context;
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen enum passdb_result passdb_result;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen LDAPMessage *entry;
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen const char *password, *scheme;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen int ret;
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen password = NULL;
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen if (res != NULL) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ret = ldap_result2error(conn->ld, res, 0);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (ret != LDAP_SUCCESS) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_log_error(auth_request, "ldap",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen "ldap_search() failed: %s",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ldap_err2string(ret));
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen res = NULL;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen entry = res == NULL ? NULL : ldap_first_entry(conn->ld, res);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (entry == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (res != NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_log_info(auth_request, "ldap",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen "unknown user");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen passdb_result = PASSDB_RESULT_USER_UNKNOWN;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen } else {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ldap_query_save_result(conn, entry, auth_request);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (auth_request->passdb_password == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_log_error(auth_request, "ldap",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen "No password in reply");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen } else if (ldap_next_entry(conn->ld, entry) != NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_log_error(auth_request, "ldap",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen "Multiple password replies");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen } else {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen password = auth_request->passdb_password;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen passdb_result = PASSDB_RESULT_OK;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen /* LDAP result is freed now. we can check if auth_request is
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen even needed anymore */
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (!auth_request_unref(auth_request))
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen return;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen scheme = password_get_scheme(&password);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen /* auth_request_set_field() sets scheme */
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen i_assert(password == NULL || scheme != NULL);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (ldap_request->credentials != -1) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen passdb_handle_credentials(passdb_result,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ldap_request->credentials, password, scheme,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ldap_request->callback.lookup_credentials,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen return;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen /* verify plain */
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (password == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ldap_request->callback.verify_plain(passdb_result,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen return;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ret = password_verify(ldap_request->password, password, scheme,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request->user);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (ret < 0) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_log_error(auth_request, "ldap",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen "Unknown password scheme %s", scheme);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen } else if (ret == 0) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_log_info(auth_request, "ldap",
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen "password mismatch");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen ldap_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen PASSDB_RESULT_PASSWORD_MISMATCH,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen}
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainenstatic void ldap_lookup_pass(struct auth_request *auth_request,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen struct ldap_request *ldap_request)
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct ldap_connection *conn = passdb_ldap_conn;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen const struct var_expand_table *vars;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen const char **attr_names = (const char **)conn->attr_names;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen const char *filter, *base;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen string_t *str;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen vars = auth_request_get_var_expand_table(auth_request, ldap_escape);
59beb411159176b39e48a52d60dd3239732e67b4Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen str = t_str_new(512);
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen var_expand(str, conn->set.base, vars);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen base = t_strdup(str_c(str));
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen str_truncate(str, 0);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen var_expand(str, conn->set.pass_filter, vars);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen filter = str_c(str);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen auth_request_ref(auth_request);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ldap_request->callback = handle_request;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ldap_request->context = auth_request;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen auth_request_log_debug(auth_request, "ldap",
f97cf1c086715db87094bc3d0a4fefdd80bd869cTimo Sirainen "base=%s scope=%s filter=%s fields=%s",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen base, conn->set.scope, filter,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen t_strarray_join(attr_names, ","));
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen db_ldap_search(conn, base, conn->set.ldap_scope,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen filter, passdb_ldap_conn->attr_names,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ldap_request);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen}
33c6d5807b449463e9b81db5ec99fe027cc1b984Timo Sirainen
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainenstatic void
94a78eb438622fa53abef1e1726714dacad4b61cTimo Sirainenldap_verify_plain(struct auth_request *request,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen const char *password __attr_unused__,
59beb411159176b39e48a52d60dd3239732e67b4Timo Sirainen verify_plain_callback_t *callback)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen struct passdb_ldap_request *ldap_request;
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen ldap_request->credentials = -1;
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen ldap_request->callback.verify_plain = callback;
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen ldap_lookup_pass(request, &ldap_request->request);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstatic void ldap_lookup_credentials(struct auth_request *request,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen enum passdb_credentials credentials,
b7c2065b3f10f9ae27787a9db5aaefbfc70d4502Timo Sirainen lookup_credentials_callback_t *callback)
f97cf1c086715db87094bc3d0a4fefdd80bd869cTimo Sirainen{
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen struct passdb_ldap_request *ldap_request;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
ldap_request->credentials = credentials;
ldap_request->callback.lookup_credentials = callback;
ldap_lookup_pass(request, &ldap_request->request);
}
static void passdb_ldap_preinit(const char *args)
{
passdb_ldap_conn = db_ldap_init(args);
db_ldap_set_attrs(passdb_ldap_conn, passdb_ldap_conn->set.pass_attrs,
default_attr_map);
passdb_ldap.cache_key = passdb_ldap_cache_key =
auth_cache_parse_key(passdb_ldap_conn->set.pass_filter);
passdb_ldap.default_pass_scheme =
passdb_ldap_conn->set.default_pass_scheme;
}
static void passdb_ldap_init(const char *args __attr_unused__)
{
(void)db_ldap_connect(passdb_ldap_conn);
}
static void passdb_ldap_deinit(void)
{
db_ldap_unref(passdb_ldap_conn);
i_free(passdb_ldap_cache_key);
}
struct passdb_module passdb_ldap = {
"ldap",
NULL, NULL, FALSE,
passdb_ldap_preinit,
passdb_ldap_init,
passdb_ldap_deinit,
ldap_verify_plain,
ldap_lookup_credentials
};
#endif