summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--acconfig.h3
-rw-r--r--configure.in8
-rw-r--r--imap/auth.c2
-rw-r--r--imap/imap.c34
-rw-r--r--imap/message.c7
-rw-r--r--mutt_sasl.c19
-rw-r--r--mutt_socket.h7
-rw-r--r--mutt_ssl.c156
-rw-r--r--mutt_ssl.h2
9 files changed, 174 insertions, 64 deletions
diff --git a/acconfig.h b/acconfig.h
index 3dad2c55..42b6c934 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -36,6 +36,9 @@
*/
#undef NFS_ATTRIBUTE_HACK
+/* Define to `int*' if <unistd.h> doesn't have it. */
+#undef socklen_t
+
/* Include code for socket support. Set automatically if you enable pop or
* IMAP */
#undef USE_SOCKET
diff --git a/configure.in b/configure.in
index 82e01d1c..238cb7c3 100644
--- a/configure.in
+++ b/configure.in
@@ -558,6 +558,10 @@ dnl -- end socket dependencies --
if test "$need_socket" = "yes"
then
+ AC_MSG_CHECKING([for socklen_t])
+ AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no])
+ AC_DEFINE(socklen_t, int*))
AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent))
AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
AC_CHECK_FUNCS(getaddrinfo)
@@ -630,7 +634,7 @@ AC_ARG_WITH(gss, [ --with-gss[=DIR] Compile in GSSAPI authenticati
])
AM_CONDITIONAL(USE_GSS, test x$need_gss = xyes)
-AC_ARG_WITH(ssl, [ --with-ssl[=PFX] Compile in SSL socket support for POP/IMAP],
+AC_ARG_WITH(ssl, [ --with-ssl[=PFX] Compile in SSL support for POP/IMAP],
[ if test "$with_ssl" != "no"
then
if test "$need_socket" != "yes"; then
@@ -664,7 +668,7 @@ AC_ARG_WITH(ssl, [ --with-ssl[=PFX] Compile in SSL socket support for
AM_CONDITIONAL(USE_SSL, test x$need_ssl = xyes)
dnl SSL support via NSS
-AC_ARG_WITH(nss, [ --with-nss[=PFX] Compile in SSL socket support for POP/IMAP via NSS],
+AC_ARG_WITH(nss, [ --with-nss[=PFX] Compile in SSL support for POP/IMAP via NSS],
[ if test "$with_nss" != no
then
if test "$need_socket" != "yes"; then
diff --git a/imap/auth.c b/imap/auth.c
index fa485bfe..97ac5d12 100644
--- a/imap/auth.c
+++ b/imap/auth.c
@@ -48,7 +48,7 @@ int imap_authenticate (IMAP_DATA* idata)
imap_auth_t* authenticator = imap_authenticators;
int r = -1;
- while (authenticator)
+ while (*authenticator)
{
if ((r = (*authenticator)(idata)) != IMAP_AUTH_UNAVAIL)
return r;
diff --git a/imap/imap.c b/imap/imap.c
index ba96e782..2b479601 100644
--- a/imap/imap.c
+++ b/imap/imap.c
@@ -29,6 +29,9 @@
#include "browser.h"
#include "message.h"
#include "imap_private.h"
+#ifdef USE_SSL
+# include "mutt_ssl.h"
+#endif
#include <unistd.h>
#include <ctype.h>
@@ -309,6 +312,7 @@ IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags)
int imap_open_connection (IMAP_DATA* idata)
{
char buf[LONG_STRING];
+ int rc;
if (mutt_socket_open (idata->conn) < 0)
{
@@ -324,8 +328,36 @@ int imap_open_connection (IMAP_DATA* idata)
if (mutt_strncmp ("* OK", idata->cmd.buf, 4) == 0)
{
- if (imap_check_capabilities (idata) || imap_authenticate (idata))
+ /* TODO: Parse new tagged CAPABILITY data (* OK [CAPABILITY...]) */
+ if (imap_check_capabilities (idata))
+ goto bail;
+#if defined(USE_SSL) && !defined(USE_NSS)
+ /* Attempt STARTTLS if available. TODO: make STARTTLS configurable. */
+ if (mutt_bit_isset (idata->capabilities, STARTTLS))
+ {
+ if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
+ goto bail;
+ if (rc != -2)
+ {
+ if (mutt_ssl_starttls (idata->conn))
+ {
+ dprint (1, (debugfile, "imap_open_connection: STARTTLS failed\n"));
+ goto bail;
+ }
+ else
+ {
+ /* RFC 2595 demands we recheck CAPABILITY after TLS is negotiated. */
+ if (imap_exec (idata, "CAPABILITY", 0))
+ goto bail;
+ }
+ }
+ }
+#endif
+ if (imap_authenticate (idata))
goto bail;
+ if (idata->conn->ssf)
+ dprint (2, (debugfile, "Communication encrypted at %d bits\n",
+ idata->conn->ssf));
}
else if (mutt_strncmp ("* PREAUTH", idata->cmd.buf, 9) == 0)
{
diff --git a/imap/message.c b/imap/message.c
index adaf142b..b3a14e83 100644
--- a/imap/message.c
+++ b/imap/message.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -89,8 +89,9 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
for (msgno = msgbegin; msgno <= msgend ; msgno++)
{
- mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1,
- msgend + 1);
+ if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0)))
+ mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1,
+ msgend + 1);
if (msgno + 1 > fetchlast)
{
diff --git a/mutt_sasl.c b/mutt_sasl.c
index 581d1c2e..eb3e2ce4 100644
--- a/mutt_sasl.c
+++ b/mutt_sasl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 2000-1 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,14 +21,11 @@
#include "mutt.h"
#include "account.h"
#include "mutt_sasl.h"
-#ifdef USE_SSL
-# include "mutt_ssl.h"
-#endif
#include "mutt_socket.h"
#include <sasl.h>
+#include <sys/socket.h>
#include <netinet/in.h>
-#include <netdb.h>
/* arbitrary. SASL will probably use a smaller buffer anyway. OTOH it's
* been a while since I've had access to an SASL server which negotiated
@@ -129,11 +126,11 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn)
socklen_t size;
size = sizeof (local);
- if (getsockname (conn->fd, &local, &size))
+ if (getsockname (conn->fd, (struct sockaddr*) &local, &size))
return -1;
size = sizeof(remote);
- if (getpeername(conn->fd, &remote, &size))
+ if (getpeername(conn->fd, (struct sockaddr*) &remote, &size))
return -1;
#ifdef SASL_IP_LOCAL
@@ -178,7 +175,7 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn)
if (conn->account.flags & M_ACCT_SSL)
{
memset (&extprops, 0, sizeof (extprops));
- extprops.ssf = mutt_ssl_get_ssf (conn);
+ extprops.ssf = conn->ssf;
dprint (2, (debugfile, "External SSF: %d\n", extprops.ssf));
if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &extprops) != SASL_OK)
{
@@ -271,9 +268,11 @@ void mutt_sasl_setup_conn (CONNECTION* conn, sasl_conn_t* saslconn)
sasldata->saslconn = saslconn;
/* get ssf so we know whether we have to (en|de)code read/write */
sasl_getprop (saslconn, SASL_SSF, (void**) &sasldata->ssf);
- dprint (2, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf));
+ dprint (3, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf));
+ /* Add SASL SSF to transport SSF */
+ conn->ssf += *sasldata->ssf;
sasl_getprop (saslconn, SASL_MAXOUTBUF, (void**) &sasldata->pbufsize);
- dprint (2, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize));
+ dprint (3, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize));
/* clear input buffer */
sasldata->buf = NULL;
diff --git a/mutt_socket.h b/mutt_socket.h
index fd776d2d..b20767da 100644
--- a/mutt_socket.h
+++ b/mutt_socket.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1998 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,12 +31,15 @@
typedef struct _connection
{
ACCOUNT account;
+ /* security strength factor, in bits */
+ unsigned int ssf;
+ void *data;
+
char inbuf[LONG_STRING];
int bufpos;
int fd;
int available;
- void *data;
struct _connection *next;
diff --git a/mutt_ssl.c b/mutt_ssl.c
index efd1b643..ac52e1f1 100644
--- a/mutt_ssl.c
+++ b/mutt_ssl.c
@@ -68,19 +68,70 @@ typedef struct _sslsockdata
}
sslsockdata;
-/* mutt_ssl_get_ssf: Return bit strength of connection encryption. SASL
- * uses this to determine how much additional protection to provide,
- * if necessary. */
-int mutt_ssl_get_ssf (CONNECTION* conn)
+/* local prototypes */
+int ssl_init (void);
+static int add_entropy (const char *file);
+static int ssl_check_certificate (sslsockdata * data);
+static int ssl_socket_read (CONNECTION * conn);
+static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
+static int ssl_socket_open (CONNECTION * conn);
+static int ssl_socket_close (CONNECTION * conn);
+int ssl_negotiate (sslsockdata*);
+
+/* mutt_ssl_starttls: Negotiate TLS over an already opened connection.
+ * TODO: Merge this code better with ssl_socket_open. */
+int mutt_ssl_starttls (CONNECTION* conn)
{
- sslsockdata* ssldata = (sslsockdata*) conn->sockdata;
+ sslsockdata* ssldata;
int maxbits;
- return SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl), &maxbits);
-}
+ if (ssl_init())
+ goto bail;
+ ssldata = (sslsockdata*) safe_calloc (1, sizeof (sslsockdata));
+ /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */
+ if (! (ssldata->ctx = SSL_CTX_new (TLSv1_client_method ())))
+ {
+ dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n"));
+ goto bail_ssldata;
+ }
+
+ if (! (ssldata->ssl = SSL_new (ssldata->ctx)))
+ {
+ dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n"));
+ goto bail_ctx;
+ }
+
+ if (SSL_set_fd (ssldata->ssl, conn->fd) != 1)
+ {
+ dprint (1, (debugfile, "mutt_ssl_starttls: Error setting fd\n"));
+ goto bail_ssl;
+ }
+
+ if (ssl_negotiate (ssldata))
+ goto bail_ssl;
+
+ /* hmm. watch out if we're starting TLS over any method other than raw. */
+ conn->sockdata = ssldata;
+ conn->read = ssl_socket_read;
+ conn->write = ssl_socket_write;
+ conn->close = ssl_socket_close;
+
+ conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl),
+ &maxbits);
+
+ return 0;
+
+ bail_ssl:
+ FREE (&ssldata->ssl);
+ bail_ctx:
+ FREE (&ssldata->ctx);
+ bail_ssldata:
+ FREE (&ssldata);
+ bail:
+ return -1;
+}
-static int add_entropy (const char *file);
/*
* OpenSSL library needs to be fed with sufficient entropy. On systems
* with /dev/urandom, this is done transparently by the library itself,
@@ -94,29 +145,42 @@ static int add_entropy (const char *file);
int ssl_init (void)
{
char path[_POSIX_PATH_MAX];
+ static unsigned char init_complete = 0;
- if (HAVE_ENTROPY()) return 0;
-
- /* load entropy from files */
- add_entropy (SslEntropyFile);
- add_entropy (RAND_file_name (path, sizeof (path)));
+ if (init_complete)
+ return 0;
+
+ if (! HAVE_ENTROPY())
+ {
+ /* load entropy from files */
+ add_entropy (SslEntropyFile);
+ add_entropy (RAND_file_name (path, sizeof (path)));
- /* load entropy from egd sockets */
+ /* load entropy from egd sockets */
#ifdef HAVE_RAND_EGD
- add_entropy (getenv ("EGDSOCKET"));
- snprintf (path, sizeof(path), "%s/.entropy", NONULL(Homedir));
- add_entropy (path);
- add_entropy ("/tmp/entropy");
+ add_entropy (getenv ("EGDSOCKET"));
+ snprintf (path, sizeof(path), "%s/.entropy", NONULL(Homedir));
+ add_entropy (path);
+ add_entropy ("/tmp/entropy");
#endif
- /* shuffle $RANDFILE (or ~/.rnd if unset) */
- RAND_write_file (RAND_file_name (path, sizeof (path)));
- mutt_clear_error ();
- if (HAVE_ENTROPY()) return 0;
+ /* shuffle $RANDFILE (or ~/.rnd if unset) */
+ RAND_write_file (RAND_file_name (path, sizeof (path)));
+ mutt_clear_error ();
+ if (! HAVE_ENTROPY())
+ {
+ mutt_error (_("Failed to find enough entropy on your system"));
+ sleep (2);
+ return -1;
+ }
+ }
- mutt_error (_("Failed to find enough entropy on your system"));
- sleep (2);
- return -1;
+ /* I don't think you can do this just before reading the error. The call
+ * itself might clobber the last SSL error. */
+ SSL_load_error_strings();
+ SSL_library_init();
+ init_complete = 1;
+ return 0;
}
static int add_entropy (const char *file)
@@ -161,12 +225,6 @@ static int ssl_socket_open_err (CONNECTION *conn)
return -1;
}
-static int ssl_check_certificate (sslsockdata * data);
-
-static int ssl_socket_read (CONNECTION * conn);
-static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
-static int ssl_socket_open (CONNECTION * conn);
-static int ssl_socket_close (CONNECTION * conn);
int ssl_socket_setup (CONNECTION * conn)
{
@@ -199,7 +257,7 @@ int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len)
int ssl_socket_open (CONNECTION * conn)
{
sslsockdata *data;
- int err;
+ int maxbits;
if (raw_socket_open (conn) < 0)
return -1;
@@ -207,7 +265,6 @@ int ssl_socket_open (CONNECTION * conn)
data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata));
conn->sockdata = data;
- SSL_library_init();
data->ctx = SSL_CTX_new (SSLv23_client_method ());
/* disable SSL protocols as needed */
@@ -227,35 +284,46 @@ int ssl_socket_open (CONNECTION * conn)
data->ssl = SSL_new (data->ctx);
SSL_set_fd (data->ssl, conn->fd);
- if ((err = SSL_connect (data->ssl)) != 1)
+ if (ssl_negotiate(data))
+ {
+ ssl_socket_close (conn);
+ return -1;
+ }
+
+ conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (data->ssl),
+ &maxbits);
+
+ return 0;
+}
+
+/* ssl_negotiate: After SSL state has been initialised, attempt to negotiate
+ * SSL over the wire, including certificate checks. */
+int ssl_negotiate (sslsockdata* ssldata)
+{
+ if (SSL_connect (ssldata->ssl) != 1)
{
unsigned long e;
- SSL_load_error_strings();
while ((e = ERR_get_error()) != 0)
{
- mutt_error ("%s", ERR_reason_error_string(e));
+ mutt_error ("SSL failed: %s", ERR_reason_error_string(e));
sleep (1);
}
- ssl_socket_close (conn);
return -1;
}
- data->cert = SSL_get_peer_certificate (data->ssl);
- if (!data->cert)
+ ssldata->cert = SSL_get_peer_certificate (ssldata->ssl);
+ if (!ssldata->cert)
{
mutt_error (_("Unable to get certificate from peer"));
sleep (1);
return -1;
}
- if (!ssl_check_certificate (data))
- {
- ssl_socket_close (conn);
+ if (!ssl_check_certificate (ssldata))
return -1;
- }
mutt_message (_("SSL connection using %s (%s)"),
- SSL_get_cipher_version (data->ssl), SSL_get_cipher_name (data->ssl));
+ SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl));
sleep (1);
return 0;
diff --git a/mutt_ssl.h b/mutt_ssl.h
index 73ece1a1..67917035 100644
--- a/mutt_ssl.h
+++ b/mutt_ssl.h
@@ -24,7 +24,7 @@
extern char *SslCertFile;
extern char *SslEntropyFile;
-int mutt_ssl_get_ssf (CONNECTION* conn);
+int mutt_ssl_starttls (CONNECTION* conn);
extern int ssl_socket_setup (CONNECTION *conn);