diff options
author | Paul J Stevens <paul@nfg.nl> | 2010-09-21 13:56:56 +0200 |
---|---|---|
committer | Paul J Stevens <paul@nfg.nl> | 2010-09-21 13:56:56 +0200 |
commit | 82e23f355ea43dbcaa23950ef227446dd41d5697 (patch) | |
tree | 3b56ca8973b8fb375fa88727710d215eace24836 | |
parent | f28e1a098092933ec35b891135320c7bbf5e397d (diff) |
fix SSLv3/TLSv1 support
-rw-r--r-- | src/clientbase.c | 33 | ||||
-rw-r--r-- | src/dbmailtypes.h | 1 | ||||
-rw-r--r-- | src/dm_tls.c | 26 | ||||
-rw-r--r-- | src/dm_tls.h | 1 | ||||
-rw-r--r-- | src/imap4.c | 3 | ||||
-rw-r--r-- | src/imapcommands.c | 3 | ||||
-rw-r--r-- | src/server.c | 28 | ||||
-rw-r--r-- | src/server.h | 13 |
8 files changed, 63 insertions, 45 deletions
diff --git a/src/clientbase.c b/src/clientbase.c index cbf99d5a..f2833ef4 100644 --- a/src/clientbase.c +++ b/src/clientbase.c @@ -180,10 +180,9 @@ clientbase_t * client_init(client_sock *c) /* make streams */ client->rx = client->tx = c->sock; - client->ssl = c->ssl; - - if (c->ssl) - client->ssl_state = TRUE; + if (c->ssl_state == -1) { + ci_starttls(client); + } } client->read_buffer = g_string_new(""); @@ -212,21 +211,14 @@ int ci_starttls(clientbase_t *self) { int e; TRACE(TRACE_DEBUG,"[%p] ssl_state [%d]", self, self->ssl_state); - if (self->ssl && self->ssl_state) { + if (self->ssl && self->ssl_state > 0) { TRACE(TRACE_ERR, "ssl already initialized"); return DM_EGENERAL; } if (! self->ssl) { self->ssl_state = FALSE; - if (! (self->ssl = SSL_new(tls_context))) { - TRACE(TRACE_ERR, "Error creating TLS connection: %s", tls_get_error()); - return DM_EGENERAL; - } - if ( !SSL_set_fd(self->ssl, self->tx)) { - TRACE(TRACE_ERR, "Error linking SSL structure to file descriptor: %s", tls_get_error()); - SSL_free(self->ssl); - self->ssl = NULL; + if (! (self->ssl = tls_setup(self->tx))) { return DM_EGENERAL; } } @@ -234,6 +226,7 @@ int ci_starttls(clientbase_t *self) if ((e = SSL_accept(self->ssl)) != 1) { int e2; if ((e2 = self->cb_error(self->rx, e, (void *)self))) { + SSL_shutdown(self->ssl); SSL_free(self->ssl); self->ssl = NULL; return DM_EGENERAL; @@ -242,10 +235,10 @@ int ci_starttls(clientbase_t *self) return e; } } + TRACE(TRACE_INFO,"[%p] SSL handshake successful using %s", self->ssl, SSL_get_cipher(self->ssl)); self->ssl_state = TRUE; } - TRACE(TRACE_DEBUG,"[%p] ssl initialized", self); return DM_SUCCESS; } @@ -347,10 +340,12 @@ void ci_read_cb(clientbase_t *self) while (TRUE) { memset(ibuf, 0, sizeof(ibuf)); - if (self->ssl) - t = SSL_read(self->ssl, (void *)ibuf, IBUFLEN); - else - t = read(self->rx, (void *)ibuf, IBUFLEN); + if (self->ssl) { + t = SSL_read(self->ssl, ibuf, sizeof(ibuf)-1); + TRACE(TRACE_DEBUG, "[%p] [%ld]", self, t); + } else { + t = read(self->rx, ibuf, sizeof(ibuf)-1); + } if (t < 0) { int e; @@ -361,6 +356,8 @@ void ci_read_cb(clientbase_t *self) break; } else if (t == 0) { + if (self->ssl) + self->cb_error(self->rx, errno, (void *)self); self->client_state |= CLIENT_EOF; break; diff --git a/src/dbmailtypes.h b/src/dbmailtypes.h index 3e14aa5f..f91a46be 100644 --- a/src/dbmailtypes.h +++ b/src/dbmailtypes.h @@ -298,6 +298,7 @@ enum BODY_FETCH_ITEM_TYPES { typedef struct { int sock; SSL *ssl; /* SSL/TLS context for this client */ + gboolean ssl_state; /* SSL_accept done or not */ struct sockaddr *caddr; socklen_t caddr_len; struct sockaddr *saddr; diff --git a/src/dm_tls.c b/src/dm_tls.c index 23626bf0..9f4441a2 100644 --- a/src/dm_tls.c +++ b/src/dm_tls.c @@ -35,11 +35,14 @@ SSL_CTX *tls_context; /* Create the initial SSL context structure */ SSL_CTX *tls_init(void) { + SSL_CTX *ctx; SSL_library_init(); SSL_load_error_strings(); /* FIXME: We need to allow for the allowed SSL/TLS versions to be */ /* configurable. */ - return SSL_CTX_new(SSLv23_method()); + + ctx = SSL_CTX_new(SSLv23_server_method()); + return ctx; } /* load the certificates into the context */ @@ -96,7 +99,26 @@ void tls_load_ciphers(serverConfig_t *conf) { /* Grab the top error off of the error stack and then return a string * corresponding to that error */ -char *tls_get_error(void) { +char *tls_get_error(void) +{ return ERR_error_string(ERR_get_error(), NULL); } +SSL *tls_setup(int fd) +{ + SSL *ssl; + + if (! (ssl = SSL_new(tls_context))) { + TRACE(TRACE_ERR, "Error creating TLS connection: %s", tls_get_error()); + return NULL; + } + if ( !SSL_set_fd(ssl, fd)) { + TRACE(TRACE_ERR, "Error linking SSL structure to file descriptor: %s", tls_get_error()); + SSL_shutdown(ssl); + SSL_free(ssl); + return NULL; + } + + return ssl; +} + diff --git a/src/dm_tls.h b/src/dm_tls.h index 108e44a3..ef27134b 100644 --- a/src/dm_tls.h +++ b/src/dm_tls.h @@ -23,6 +23,7 @@ #include "dbmail.h" SSL_CTX *tls_init(void); +SSL *tls_setup(int); void tls_load_certs(serverConfig_t *); void tls_load_ciphers(serverConfig_t *); char *tls_get_error(void); diff --git a/src/imap4.c b/src/imap4.c index 6a5d4bb2..f844cbbc 100644 --- a/src/imap4.c +++ b/src/imap4.c @@ -435,7 +435,8 @@ int imap_handle_connection(client_sock *c) session->ci = ci; - if (! server_conf->ssl) Capa_remove(session->capa, "STARTTLS"); + if ((! server_conf->ssl) || (ci->ssl_state == TRUE)) + Capa_remove(session->capa, "STARTTLS"); reset_callbacks(session); diff --git a/src/imapcommands.c b/src/imapcommands.c index 54b66a4d..f6c0f6a8 100644 --- a/src/imapcommands.c +++ b/src/imapcommands.c @@ -134,6 +134,9 @@ int _ic_starttls(ImapSession *self) } ci_write(self->ci, "%s OK Begin TLS now\r\n", self->tag); i = ci_starttls(self->ci); + + Capa_remove(self->capa, "STARTTLS"); + if (i < 0) i = 0; if (i == 0) return 3; /* done */ diff --git a/src/server.c b/src/server.c index 05f541bb..807f197a 100644 --- a/src/server.c +++ b/src/server.c @@ -502,27 +502,7 @@ static void _sock_cb(int sock, short event, void *arg, gboolean ssl) c->saddr = saddr; c->saddr_len = len; - if (ssl) { - if (! (c->ssl = SSL_new(tls_context))) { - TRACE(TRACE_ERR, "Error creating TLS connection: %s", tls_get_error()); - event_add(ev, NULL); - return; - } - if ( !SSL_set_fd(c->ssl, c->sock)) { - TRACE(TRACE_ERR, "Error linking SSL structure to file descriptor: %s", tls_get_error()); - SSL_free(c->ssl); - c->ssl = NULL; - event_add(ev, NULL); - return; - } - if (SSL_accept(c->ssl) <= 0) { - TRACE(TRACE_ERR, "Error in TLS handshake: %s", tls_get_error()); - SSL_free(c->ssl); - c->ssl = NULL; - event_add(ev, NULL); - return; - } - } + if (ssl) c->ssl_state = -1; // defer tls setup TRACE(TRACE_INFO, "connection accepted"); @@ -532,8 +512,10 @@ static void _sock_cb(int sock, short event, void *arg, gboolean ssl) g_free(caddr); g_free(saddr); - if (c->ssl) + if (c->ssl) { + SSL_shutdown(c->ssl); SSL_free(c->ssl); + } g_free(c); @@ -691,7 +673,7 @@ int server_run(serverConfig_t *conf) k = i+1; for (k = i, i = 0; i < conf->ssl_socketcount; i++, k++) { TRACE(TRACE_DEBUG, "Adding event for ssl socket [%d] [%d/%d]", conf->ssl_listenSockets[i], k+1, total); - event_set(&evsock[k], conf->ssl_listenSockets[k], EV_READ, server_sock_ssl_cb, &evsock[k]); + event_set(&evsock[k], conf->ssl_listenSockets[i], EV_READ, server_sock_ssl_cb, &evsock[k]); event_add(&evsock[k], NULL); } } diff --git a/src/server.h b/src/server.h index b4bd089a..7510a3c4 100644 --- a/src/server.h +++ b/src/server.h @@ -28,7 +28,18 @@ #define _SERVER_H #include "dbmail.h" - + +#define BLOCK(a) \ + { \ + int flags; \ + if ( (flags = fcntl(a, F_GETFL, 0)) < 0) \ + perror("F_GETFL"); \ + flags &= ~O_NONBLOCK; \ + if (fcntl(a, F_SETFL, flags) < 0) \ + perror("F_SETFL"); \ + } + + #define UNBLOCK(a) \ { \ int flags; \ |