]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Added initial support for SSL.
authorTimo Sirainen <tss@iki.fi>
Mon, 31 Jan 2011 16:41:04 +0000 (18:41 +0200)
committerTimo Sirainen <tss@iki.fi>
Mon, 31 Jan 2011 16:41:04 +0000 (18:41 +0200)
configure.in
src/lib-storage/index/imapc/Makefile.am
src/lib-storage/index/imapc/imapc-client-private.h
src/lib-storage/index/imapc/imapc-client.c
src/lib-storage/index/imapc/imapc-client.h
src/lib-storage/index/imapc/imapc-connection.c
src/lib-storage/index/imapc/imapc-storage.c

index e1e1b1ae204fd2f74d2ca0bc8e8c1970ecb23819..021ce5e8982a9caf8b3c9d9497cacf49e463e4ba 100644 (file)
@@ -2429,7 +2429,7 @@ dbox_common_libs='$(top_builddir)/src/lib-storage/index/dbox-common/libstorage_d
 sdbox_libs='$(top_builddir)/src/lib-storage/index/dbox-single/libstorage_dbox_single.la'
 mdbox_libs='$(top_builddir)/src/lib-storage/index/dbox-multi/libstorage_dbox_multi.la'
 cydir_libs='$(top_builddir)/src/lib-storage/index/cydir/libstorage_cydir.la'
-imapc_libs='$(top_builddir)/src/lib-storage/index/imapc/libstorage_imapc.la'
+imapc_libs='$(top_builddir)/src/lib-storage/index/imapc/libstorage_imapc.la $(top_builddir)/src/lib-ssl-iostream/libssl_iostream.la'
 raw_libs='$(top_builddir)/src/lib-storage/index/raw/libstorage_raw.la'
 shared_libs='$(top_builddir)/src/lib-storage/index/shared/libstorage_shared.la'
 
index 4f47d890d0afe9300e17dd7724c87d931492a7e0..5f9e375992e909be75a477d52452eac20f0a97b3 100644 (file)
@@ -4,6 +4,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-test \
        -I$(top_srcdir)/src/lib-dns \
+       -I$(top_srcdir)/src/lib-ssl-iostream \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-index \
index ff8e27ef85b376f476d04aadfb50d7ff39f2fe3f..d8442ab0580bab39bf78515c2830594a16857338 100644 (file)
@@ -11,6 +11,7 @@ struct imapc_client_connection {
 struct imapc_client {
        pool_t pool;
        struct imapc_client_settings set;
+       struct ssl_iostream_context *ssl_ctx;
 
        imapc_untagged_callback_t *untagged_callback;
        void *untagged_context;
index 325fd440f0aec775c121e593215f029880ce1dfe..4939560cb018ae09159af2ed4ba3fd7fbbe33455 100644 (file)
@@ -5,6 +5,7 @@
 #include "str.h"
 #include "ioloop.h"
 #include "safe-mkstemp.h"
+#include "iostream-ssl.h"
 #include "imapc-seqmap.h"
 #include "imapc-connection.h"
 #include "imapc-client-private.h"
@@ -33,6 +34,8 @@ struct imapc_client *
 imapc_client_init(const struct imapc_client_settings *set)
 {
        struct imapc_client *client;
+       struct ssl_iostream_settings ssl_set;
+       const char *source;
        pool_t pool;
 
        pool = pool_alloconly_create("imapc client", 1024);
@@ -48,6 +51,23 @@ imapc_client_init(const struct imapc_client_settings *set)
                p_strdup(pool, set->dns_client_socket_path);
        client->set.temp_path_prefix =
                p_strdup(pool, set->temp_path_prefix);
+
+       if (set->ssl_mode != IMAPC_CLIENT_SSL_MODE_NONE) {
+               client->set.ssl_mode = set->ssl_mode;
+               client->set.ssl_ca_dir = p_strdup(pool, set->ssl_ca_dir);
+
+               memset(&ssl_set, 0, sizeof(ssl_set));
+               ssl_set.ca_dir = set->ssl_ca_dir;
+               ssl_set.verify_remote_cert = TRUE;
+
+               source = t_strdup_printf("%s:%u", set->host, set->port);
+               if (ssl_iostream_context_init_client(source, &ssl_set,
+                                                    &client->ssl_ctx) < 0) {
+                       i_error("imapc(%s): Couldn't initialize SSL context",
+                               source);
+               }
+       }
+
        p_array_init(&client->conns, pool, 8);
        return client;
 }
@@ -59,6 +79,8 @@ void imapc_client_deinit(struct imapc_client **_client)
 
        *_client = NULL;
 
+       if (client->ssl_ctx != NULL)
+               ssl_iostream_context_deinit(&client->ssl_ctx);
        array_foreach_modifiable(&client->conns, connp)
                imapc_connection_deinit(&(*connp)->conn);
        pool_unref(&client->pool);
index 072a4895d7cbbf12aeeb29d8f4e1432b4adcbc7a..79026011c5b58f758fad35ff02b46fbd03454138 100644 (file)
@@ -23,6 +23,12 @@ struct imapc_capability_name {
 };
 extern const struct imapc_capability_name imapc_capability_names[];
 
+enum imapc_client_ssl_mode {
+       IMAPC_CLIENT_SSL_MODE_NONE,
+       IMAPC_CLIENT_SSL_MODE_IMMEDIATE,
+       IMAPC_CLIENT_SSL_MODE_STARTTLS
+};
+
 struct imapc_client_settings {
        const char *host;
        unsigned int port;
@@ -33,6 +39,9 @@ struct imapc_client_settings {
 
        const char *dns_client_socket_path;
        const char *temp_path_prefix;
+
+       enum imapc_client_ssl_mode ssl_mode;
+       const char *ssl_ca_dir;
 };
 
 struct imapc_command_reply {
index a5f6e7f362147f3ea270f4200d1406a8fe8b271f..9f9bb1c7c9bf9a64050eaed4b1e5b52afc4cea5e 100644 (file)
@@ -9,6 +9,7 @@
 #include "write-full.h"
 #include "str.h"
 #include "dns-lookup.h"
+#include "iostream-ssl.h"
 #include "imap-quote.h"
 #include "imap-util.h"
 #include "imap-parser.h"
@@ -68,6 +69,8 @@ struct imapc_connection {
        struct imap_parser *parser;
        struct timeout *to;
 
+       struct ssl_iostream *ssl_iostream;
+
        int (*input_callback)(struct imapc_connection *conn);
        enum imapc_input_state input_state;
        unsigned int cur_tag;
@@ -123,7 +126,8 @@ void imapc_connection_deinit(struct imapc_connection **_conn)
        *_conn = NULL;
 
        imapc_connection_disconnect(conn);
-       p_strsplit_free(default_pool, conn->capabilities_list);
+       if (conn->capabilities_list != NULL)
+               p_strsplit_free(default_pool, conn->capabilities_list);
        array_free(&conn->cmd_send_queue);
        array_free(&conn->cmd_wait_list);
        array_free(&conn->literal_files);
@@ -215,6 +219,8 @@ static void imapc_connection_disconnect(struct imapc_connection *conn)
                timeout_remove(&conn->to);
        imap_parser_destroy(&conn->parser);
        io_remove(&conn->io);
+       if (conn->ssl_iostream != NULL)
+               ssl_iostream_unref(&conn->ssl_iostream);
        i_stream_destroy(&conn->input);
        o_stream_destroy(&conn->output);
        net_disconnect(conn->fd);
@@ -835,15 +841,73 @@ static int imapc_connection_input_one(struct imapc_connection *conn)
 
 static void imapc_connection_input(struct imapc_connection *conn)
 {
-       if (i_stream_read(conn->input) == -1) {
+       ssize_t ret;
+
+       if ((ret = i_stream_read(conn->input)) > 0)
+               imapc_connection_input_pending(conn);
+       else if (ret < 0) {
                /* disconnected */
-               i_error("imapc(%s): Server disconnected unexpectedly",
-                       conn->name);
+               if (conn->ssl_iostream == NULL) {
+                       i_error("imapc(%s): Server disconnected unexpectedly",
+                               conn->name);
+               } else {
+                       i_error("imapc(%s): Server disconnected: %s", conn->name,
+                               ssl_iostream_get_last_error(conn->ssl_iostream));
+               }
                imapc_connection_disconnect(conn);
                return;
        }
+}
 
-       imapc_connection_input_pending(conn);
+static int imapc_connection_ssl_handshaked(void *context)
+{
+       struct imapc_connection *conn = context;
+
+       if (ssl_iostream_has_valid_client_cert(conn->ssl_iostream))
+               return 0;
+
+       if (!ssl_iostream_has_broken_client_cert(conn->ssl_iostream)) {
+               i_error("imapc(%s): SSL certificate not received", conn->name);
+       } else {
+               i_error("imapc(%s): Received invalid SSL certificate",
+                       conn->name);
+       }
+       i_stream_close(conn->input);
+       return -1;
+}
+
+static int imapc_connection_ssl_init(struct imapc_connection *conn)
+{
+       struct ssl_iostream_settings ssl_set;
+       const char *source;
+
+       if (conn->client->ssl_ctx == NULL) {
+               i_error("imapc(%s): No SSL context", conn->name);
+               return -1;
+       }
+
+       memset(&ssl_set, 0, sizeof(ssl_set));
+       ssl_set.verbose_invalid_cert = TRUE;
+       ssl_set.verify_remote_cert = TRUE;
+       ssl_set.require_valid_cert = TRUE;
+
+       source = t_strdup_printf("imapc(%s): ", conn->name);
+       if (io_stream_create_ssl(conn->client->ssl_ctx, source, &ssl_set,
+                                &conn->input, &conn->output,
+                                &conn->ssl_iostream) < 0) {
+               i_error("imapc(%s): Couldn't initialize SSL client",
+                       conn->name);
+               return -1;
+       }
+       ssl_iostream_set_handshake_callback(conn->ssl_iostream,
+                                           imapc_connection_ssl_handshaked,
+                                           conn);
+       if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
+               i_error("imapc(%s): SSL handshake failed", conn->name);
+               return -1;
+       }
+       imap_parser_set_streams(conn->parser, conn->input, NULL);
+       return 0;
 }
 
 static void imapc_connection_connected(struct imapc_connection *conn)
@@ -861,6 +925,11 @@ static void imapc_connection_connected(struct imapc_connection *conn)
        }
        io_remove(&conn->io);
        conn->io = io_add(conn->fd, IO_READ, imapc_connection_input, conn);
+
+       if (conn->client->set.ssl_mode == IMAPC_CLIENT_SSL_MODE_IMMEDIATE) {
+               if (imapc_connection_ssl_init(conn) < 0)
+                       imapc_connection_disconnect(conn);
+       }
 }
 
 static void imapc_connection_timeout(struct imapc_connection *conn)
@@ -956,7 +1025,7 @@ void imapc_connection_input_pending(struct imapc_connection *conn)
                return;
 
        o_stream_cork(conn->output);
-       while (ret > 0 && !conn->client->stop_now) {
+       while (ret > 0 && !conn->client->stop_now && conn->input != NULL) {
                T_BEGIN {
                        ret = imapc_connection_input_one(conn);
                } T_END;
index 9177c222800e66f8d80997fefdd10c6af540c46d..184c7ab1cb616f9b6ba3139139f19413814a348e 100644 (file)
@@ -163,7 +163,7 @@ imapc_storage_create(struct mail_storage *_storage,
 {
        struct imapc_storage *storage = (struct imapc_storage *)_storage;
        struct imapc_client_settings set;
-       const char *port;
+       const char *port, *value;
        string_t *str;
 
        memset(&set, 0, sizeof(set));
@@ -196,6 +196,16 @@ imapc_storage_create(struct mail_storage *_storage,
        mail_user_set_get_temp_prefix(str, _storage->user->set);
        set.temp_path_prefix = str_c(str);
 
+       set.ssl_ca_dir = mail_user_plugin_getenv(_storage->user,
+                                                "imapc_ssl_ca_dir");
+       if (set.ssl_ca_dir != NULL) {
+               value = mail_user_plugin_getenv(_storage->user,
+                                               "imapc_ssl_starttls");
+               set.ssl_mode = value != NULL ?
+                       IMAPC_CLIENT_SSL_MODE_STARTTLS :
+                       IMAPC_CLIENT_SSL_MODE_IMMEDIATE;
+       }
+
        storage->list = (struct imapc_mailbox_list *)ns->list;
        storage->list->storage = storage;
        storage->client = imapc_client_init(&set);