summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J Stevens <paul@nfg.nl>2010-09-21 13:56:56 +0200
committerPaul J Stevens <paul@nfg.nl>2010-09-21 13:56:56 +0200
commit82e23f355ea43dbcaa23950ef227446dd41d5697 (patch)
tree3b56ca8973b8fb375fa88727710d215eace24836
parentf28e1a098092933ec35b891135320c7bbf5e397d (diff)
fix SSLv3/TLSv1 support
-rw-r--r--src/clientbase.c33
-rw-r--r--src/dbmailtypes.h1
-rw-r--r--src/dm_tls.c26
-rw-r--r--src/dm_tls.h1
-rw-r--r--src/imap4.c3
-rw-r--r--src/imapcommands.c3
-rw-r--r--src/server.c28
-rw-r--r--src/server.h13
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; \