Mercurial > dovecot > core-2.2
changeset 13555:fe89e95867a4
auth: Added passdb imap plugin.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 26 Sep 2011 15:36:21 +0300 |
parents | 743ebecc1224 |
children | 415aa8e92203 |
files | src/auth/Makefile.am src/auth/auth-settings.c src/auth/auth-settings.h src/auth/passdb-imap.c |
diffstat | 4 files changed, 207 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/Makefile.am Mon Sep 26 15:34:58 2011 +0300 +++ b/src/auth/Makefile.am Mon Sep 26 15:36:21 2011 +0300 @@ -14,7 +14,8 @@ auth_module_LTLIBRARIES = \ $(GSSAPI_LIB) \ - $(LDAP_LIB) + $(LDAP_LIB) \ + libpassdb_imap.la pkglibexecdir = $(libexecdir)/dovecot @@ -30,6 +31,7 @@ -I$(top_srcdir)/src/lib-master \ -DAUTH_MODULE_DIR=\""$(auth_moduledir)"\" \ -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \ + -DPKG_RUNDIR=\""$(rundir)"\" \ $(AUTH_CFLAGS) auth_LDFLAGS = -export-dynamic @@ -157,6 +159,16 @@ libauthdb_ldap_la_SOURCES = $(ldap_sources) endif +libpassdb_imap_la_LDFLAGS = -module -avoid-version +libpassdb_imap_la_LIBADD = \ + ../lib-imap-client/libimap_client.la \ + ../lib-ssl-iostream/libssl_iostream.la +libpassdb_imap_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-imap-client +libpassdb_imap_la_SOURCES = passdb-imap.c + pkginc_libdir=$(pkgincludedir) pkginc_lib_HEADERS = $(headers)
--- a/src/auth/auth-settings.c Mon Sep 26 15:34:58 2011 +0300 +++ b/src/auth/auth-settings.c Mon Sep 26 15:36:21 2011 +0300 @@ -215,6 +215,7 @@ DEFLIST(passdbs, "passdb", &auth_passdb_setting_parser_info), DEFLIST(userdbs, "userdb", &auth_userdb_setting_parser_info), + DEF_NOPREFIX(SET_STR, base_dir), DEF_NOPREFIX(SET_BOOL, verbose_proctitle), SETTING_DEFINE_LIST_END @@ -252,6 +253,7 @@ .passdbs = ARRAY_INIT, .userdbs = ARRAY_INIT, + .base_dir = PKG_RUNDIR, .verbose_proctitle = FALSE };
--- a/src/auth/auth-settings.h Mon Sep 26 15:34:58 2011 +0300 +++ b/src/auth/auth-settings.h Mon Sep 26 15:36:21 2011 +0300 @@ -51,6 +51,7 @@ ARRAY_DEFINE(passdbs, struct auth_passdb_settings *); ARRAY_DEFINE(userdbs, struct auth_userdb_settings *); + const char *base_dir; bool verbose_proctitle; /* generated: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/passdb-imap.c Mon Sep 26 15:36:21 2011 +0300 @@ -0,0 +1,191 @@ +/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ + +#include "auth-common.h" +#include "passdb.h" +#include "str.h" +#include "var-expand.h" +#include "imap-resp-code.h" +#include "imapc-client.h" + +#define IMAP_DEFAULT_PORT 143 +#define IMAPS_DEFAULT_PORT 993 +#define DNS_CLIENT_SOCKET_NAME "dns-client" + +struct imap_passdb_module { + struct passdb_module module; + struct imapc_client_settings set; + bool set_have_vars; +}; + +struct imap_auth_request { + struct imapc_client *client; + struct auth_request *auth_request; + verify_plain_callback_t *verify_callback; +}; + +static enum passdb_result +passdb_imap_get_failure_result(const struct imapc_command_reply *reply) +{ + const char *key = reply->resp_text_key; + + if (key == NULL) + return PASSDB_RESULT_PASSWORD_MISMATCH; + + if (strcasecmp(key, IMAP_RESP_CODE_AUTHFAILED) == 0 || + strcasecmp(key, IMAP_RESP_CODE_AUTHZFAILED) == 0) + return PASSDB_RESULT_PASSWORD_MISMATCH; + if (strcasecmp(key, IMAP_RESP_CODE_EXPIRED) == 0) + return PASSDB_RESULT_PASS_EXPIRED; + return PASSDB_RESULT_INTERNAL_FAILURE; +} + +static void +passdb_imap_login_callback(const struct imapc_command_reply *reply, + void *context) +{ + struct imap_auth_request *request = context; + enum passdb_result result = PASSDB_RESULT_INTERNAL_FAILURE; + + switch (reply->state) { + case IMAPC_COMMAND_STATE_OK: + result = PASSDB_RESULT_OK; + break; + case IMAPC_COMMAND_STATE_NO: + result = passdb_imap_get_failure_result(reply); + break; + case IMAPC_COMMAND_STATE_BAD: + case IMAPC_COMMAND_STATE_DISCONNECTED: + break; + } + request->verify_callback(result, request->auth_request); + imapc_client_deinit(&request->client); +} + +static void +passdb_imap_verify_plain(struct auth_request *auth_request, + const char *password, + verify_plain_callback_t *callback) +{ + struct passdb_module *_module = auth_request->passdb->passdb; + struct imap_passdb_module *module = + (struct imap_passdb_module *)_module; + struct imap_auth_request *request; + struct imapc_client_settings set; + const struct var_expand_table *table; + string_t *str; + + set = module->set; + set.debug = auth_request->set->debug; + set.dns_client_socket_path = + t_strconcat(auth_request->set->base_dir, "/", + DNS_CLIENT_SOCKET_NAME, NULL); + set.password = password; + + if (module->set_have_vars) { + str = t_str_new(128); + table = auth_request_get_var_expand_table(auth_request, NULL); + var_expand(str, set.username, table); + set.username = t_strdup(str_c(str)); + + str_truncate(str, 0); + var_expand(str, set.host, table); + set.host = t_strdup(str_c(str)); + } + auth_request_log_debug(auth_request, "imap", "lookup host=%s port=%d", + set.host, set.port); + + request = p_new(auth_request->pool, struct imap_auth_request, 1); + request->client = imapc_client_init(&set); + request->auth_request = auth_request; + request->verify_callback = callback; + + imapc_client_login(request->client, passdb_imap_login_callback, + request); +} + +static struct passdb_module * +passdb_imap_preinit(pool_t pool, const char *args) +{ + struct imap_passdb_module *module; + char **tmp; + const char *key, *value; + bool port_set = FALSE; + + module = p_new(pool, struct imap_passdb_module, 1); + module->module.default_pass_scheme = "PLAIN"; + module->set.port = IMAP_DEFAULT_PORT; + module->set.ssl_mode = IMAPC_CLIENT_SSL_MODE_NONE; + module->set.username = "%u"; + module->set.rawlog_dir = ""; + + for (tmp = p_strsplit(pool, args, " "); *tmp != NULL; tmp++) { + key = *tmp; + value = strchr(key, '='); + if (value == NULL) + value = ""; + else + key = t_strdup_until(key, value++); + if (strcmp(key, "host") == 0) + module->set.host = value; + else if (strcmp(key, "port") == 0) { + if (str_to_uint(value, &module->set.port) < 0 || + module->set.port == 0 || module->set.port > 65535) + i_fatal("passdb imap: Invalid port: %s", value); + port_set = TRUE; + } else if (strcmp(key, "username") == 0) + module->set.username = value; + else if (strcmp(key, "ssl_ca_dir") == 0) + module->set.ssl_ca_dir = value; + else if (strcmp(key, "rawlog_dir") == 0) + module->set.rawlog_dir = value; + else if (strcmp(key, "ssl") == 0) { + if (strcmp(value, "imaps") == 0) { + if (!port_set) + module->set.port = IMAPS_DEFAULT_PORT; + module->set.ssl_mode = + IMAPC_CLIENT_SSL_MODE_IMMEDIATE; + } else if (strcmp(value, "starttls") == 0) { + module->set.ssl_mode = + IMAPC_CLIENT_SSL_MODE_STARTTLS; + } else { + i_fatal("passdb imap: Invalid ssl mode: %s", + value); + } + } else { + i_fatal("passdb imap: Unknown parameter: %s", key); + } + } + + if (module->set.host == NULL) + i_fatal("passdb imap: Missing host parameter"); + + module->set_have_vars = + strchr(module->set.username, '%') != NULL || + strchr(module->set.host, '%') != NULL; + return &module->module; +} + +static struct passdb_module_interface passdb_imap_plugin = { + "imap", + + passdb_imap_preinit, + NULL, + NULL, + + passdb_imap_verify_plain, + NULL, + NULL +}; + +void passdb_imap_init(void); +void passdb_imap_deinit(void); + +void passdb_imap_init(void) +{ + passdb_register_module(&passdb_imap_plugin); + +} +void passdb_imap_deinit(void) +{ + passdb_unregister_module(&passdb_imap_plugin); +}