Mercurial > dovecot > core-2.2
diff src/lib-storage/index/imapc/imapc-connection.c @ 12617:7b7434fef6ff
imapc: Added initial support for SSL.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 31 Jan 2011 18:41:04 +0200 |
parents | 3dde816d945d |
children | 4244c828b59d |
line wrap: on
line diff
--- a/src/lib-storage/index/imapc/imapc-connection.c Mon Jan 31 18:40:27 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-connection.c Mon Jan 31 18:41:04 2011 +0200 @@ -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 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 @@ *_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 @@ 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 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 @@ } 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 @@ 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;