]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: Added passdb imap plugin.
authorTimo Sirainen <tss@iki.fi>
Mon, 26 Sep 2011 12:36:21 +0000 (15:36 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 26 Sep 2011 12:36:21 +0000 (15:36 +0300)
src/auth/Makefile.am
src/auth/auth-settings.c
src/auth/auth-settings.h
src/auth/passdb-imap.c [new file with mode: 0644]

index 915929d645ff617d1fde80afca3aa782beaf3ca0..acba3969ed3f2310eaf089aa79c84e73c9b5f4cd 100644 (file)
@@ -14,7 +14,8 @@ endif
 
 auth_module_LTLIBRARIES = \
        $(GSSAPI_LIB) \
-       $(LDAP_LIB)
+       $(LDAP_LIB) \
+       libpassdb_imap.la
 
 pkglibexecdir = $(libexecdir)/dovecot
 
@@ -30,6 +31,7 @@ AM_CPPFLAGS = \
        -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_CPPFLAGS = $(AM_CPPFLAGS) -DPLUGIN_BUILD
 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)
 
index 8e57f5435c68b245d8039e0374fc47437fbc93ed..f71c52b923b0a5fd1ca1f5ccff1bc3a6a1379a69 100644 (file)
@@ -215,6 +215,7 @@ static const struct setting_define auth_setting_defines[] = {
        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 @@ static const struct auth_settings auth_default_settings = {
        .passdbs = ARRAY_INIT,
        .userdbs = ARRAY_INIT,
 
+       .base_dir = PKG_RUNDIR,
        .verbose_proctitle = FALSE
 };
 
index cec94a83d94f0d28876e5dcfb4848a2e81be44bf..63d054b3ab6f1906929d7312291a41b0792dc562 100644 (file)
@@ -51,6 +51,7 @@ struct auth_settings {
        ARRAY_DEFINE(passdbs, struct auth_passdb_settings *);
        ARRAY_DEFINE(userdbs, struct auth_userdb_settings *);
 
+       const char *base_dir;
        bool verbose_proctitle;
 
        /* generated: */
diff --git a/src/auth/passdb-imap.c b/src/auth/passdb-imap.c
new file mode 100644 (file)
index 0000000..9ef378c
--- /dev/null
@@ -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);
+}