···3636 */
3737#undef NFS_ATTRIBUTE_HACK
38383939+/* Define to `int*' if <unistd.h> doesn't have it. */
4040+#undef socklen_t
4141+3942/* Include code for socket support. Set automatically if you enable pop or
4043 * IMAP */
4144#undef USE_SOCKET
+6-2
configure.in
···558558559559if test "$need_socket" = "yes"
560560then
561561+ AC_MSG_CHECKING([for socklen_t])
562562+ AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_MSG_RESULT([yes]),
563563+ AC_MSG_RESULT([no])
564564+ AC_DEFINE(socklen_t, int*))
561565 AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent))
562566 AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
563567 AC_CHECK_FUNCS(getaddrinfo)
···630634])
631635AM_CONDITIONAL(USE_GSS, test x$need_gss = xyes)
632636633633-AC_ARG_WITH(ssl, [ --with-ssl[=PFX] Compile in SSL socket support for POP/IMAP],
637637+AC_ARG_WITH(ssl, [ --with-ssl[=PFX] Compile in SSL support for POP/IMAP],
634638[ if test "$with_ssl" != "no"
635639 then
636640 if test "$need_socket" != "yes"; then
···664668AM_CONDITIONAL(USE_SSL, test x$need_ssl = xyes)
665669666670dnl SSL support via NSS
667667-AC_ARG_WITH(nss, [ --with-nss[=PFX] Compile in SSL socket support for POP/IMAP via NSS],
671671+AC_ARG_WITH(nss, [ --with-nss[=PFX] Compile in SSL support for POP/IMAP via NSS],
668672[ if test "$with_nss" != no
669673 then
670674 if test "$need_socket" != "yes"; then
+1-1
imap/auth.c
···4848 imap_auth_t* authenticator = imap_authenticators;
4949 int r = -1;
50505151- while (authenticator)
5151+ while (*authenticator)
5252 {
5353 if ((r = (*authenticator)(idata)) != IMAP_AUTH_UNAVAIL)
5454 return r;
+33-1
imap/imap.c
···2929#include "browser.h"
3030#include "message.h"
3131#include "imap_private.h"
3232+#ifdef USE_SSL
3333+# include "mutt_ssl.h"
3434+#endif
32353336#include <unistd.h>
3437#include <ctype.h>
···309312int imap_open_connection (IMAP_DATA* idata)
310313{
311314 char buf[LONG_STRING];
315315+ int rc;
312316313317 if (mutt_socket_open (idata->conn) < 0)
314318 {
···324328325329 if (mutt_strncmp ("* OK", idata->cmd.buf, 4) == 0)
326330 {
327327- if (imap_check_capabilities (idata) || imap_authenticate (idata))
331331+ /* TODO: Parse new tagged CAPABILITY data (* OK [CAPABILITY...]) */
332332+ if (imap_check_capabilities (idata))
333333+ goto bail;
334334+#if defined(USE_SSL) && !defined(USE_NSS)
335335+ /* Attempt STARTTLS if available. TODO: make STARTTLS configurable. */
336336+ if (mutt_bit_isset (idata->capabilities, STARTTLS))
337337+ {
338338+ if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
339339+ goto bail;
340340+ if (rc != -2)
341341+ {
342342+ if (mutt_ssl_starttls (idata->conn))
343343+ {
344344+ dprint (1, (debugfile, "imap_open_connection: STARTTLS failed\n"));
345345+ goto bail;
346346+ }
347347+ else
348348+ {
349349+ /* RFC 2595 demands we recheck CAPABILITY after TLS is negotiated. */
350350+ if (imap_exec (idata, "CAPABILITY", 0))
351351+ goto bail;
352352+ }
353353+ }
354354+ }
355355+#endif
356356+ if (imap_authenticate (idata))
328357 goto bail;
358358+ if (idata->conn->ssf)
359359+ dprint (2, (debugfile, "Communication encrypted at %d bits\n",
360360+ idata->conn->ssf));
329361 }
330362 else if (mutt_strncmp ("* PREAUTH", idata->cmd.buf, 9) == 0)
331363 {
+4-3
imap/message.c
···11/*
22 * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
33- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
33+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
44 *
55 * This program is free software; you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
···89899090 for (msgno = msgbegin; msgno <= msgend ; msgno++)
9191 {
9292- mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1,
9393- msgend + 1);
9292+ if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0)))
9393+ mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1,
9494+ msgend + 1);
94959596 if (msgno + 1 > fetchlast)
9697 {
+9-10
mutt_sasl.c
···11/*
22- * Copyright (C) 2000 Brendan Cully <brendan@kublai.com>
22+ * Copyright (C) 2000-1 Brendan Cully <brendan@kublai.com>
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
···2121#include "mutt.h"
2222#include "account.h"
2323#include "mutt_sasl.h"
2424-#ifdef USE_SSL
2525-# include "mutt_ssl.h"
2626-#endif
2724#include "mutt_socket.h"
28252926#include <sasl.h>
2727+#include <sys/socket.h>
3028#include <netinet/in.h>
3131-#include <netdb.h>
32293330/* arbitrary. SASL will probably use a smaller buffer anyway. OTOH it's
3431 * been a while since I've had access to an SASL server which negotiated
···129126 socklen_t size;
130127131128 size = sizeof (local);
132132- if (getsockname (conn->fd, &local, &size))
129129+ if (getsockname (conn->fd, (struct sockaddr*) &local, &size))
133130 return -1;
134131135132 size = sizeof(remote);
136136- if (getpeername(conn->fd, &remote, &size))
133133+ if (getpeername(conn->fd, (struct sockaddr*) &remote, &size))
137134 return -1;
138135139136#ifdef SASL_IP_LOCAL
···178175 if (conn->account.flags & M_ACCT_SSL)
179176 {
180177 memset (&extprops, 0, sizeof (extprops));
181181- extprops.ssf = mutt_ssl_get_ssf (conn);
178178+ extprops.ssf = conn->ssf;
182179 dprint (2, (debugfile, "External SSF: %d\n", extprops.ssf));
183180 if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &extprops) != SASL_OK)
184181 {
···271268 sasldata->saslconn = saslconn;
272269 /* get ssf so we know whether we have to (en|de)code read/write */
273270 sasl_getprop (saslconn, SASL_SSF, (void**) &sasldata->ssf);
274274- dprint (2, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf));
271271+ dprint (3, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf));
272272+ /* Add SASL SSF to transport SSF */
273273+ conn->ssf += *sasldata->ssf;
275274 sasl_getprop (saslconn, SASL_MAXOUTBUF, (void**) &sasldata->pbufsize);
276276- dprint (2, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize));
275275+ dprint (3, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize));
277276278277 /* clear input buffer */
279278 sasldata->buf = NULL;
+5-2
mutt_socket.h
···11/*
22 * Copyright (C) 1998 Brandon Long <blong@fiction.net>
33- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
33+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
44 *
55 * This program is free software; you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
···3131typedef struct _connection
3232{
3333 ACCOUNT account;
3434+ /* security strength factor, in bits */
3535+ unsigned int ssf;
3636+ void *data;
3737+3438 char inbuf[LONG_STRING];
3539 int bufpos;
36403741 int fd;
3842 int available;
3939- void *data;
40434144 struct _connection *next;
4245
+112-44
mutt_ssl.c
···6868}
6969sslsockdata;
70707171-/* mutt_ssl_get_ssf: Return bit strength of connection encryption. SASL
7272- * uses this to determine how much additional protection to provide,
7373- * if necessary. */
7474-int mutt_ssl_get_ssf (CONNECTION* conn)
7171+/* local prototypes */
7272+int ssl_init (void);
7373+static int add_entropy (const char *file);
7474+static int ssl_check_certificate (sslsockdata * data);
7575+static int ssl_socket_read (CONNECTION * conn);
7676+static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
7777+static int ssl_socket_open (CONNECTION * conn);
7878+static int ssl_socket_close (CONNECTION * conn);
7979+int ssl_negotiate (sslsockdata*);
8080+8181+/* mutt_ssl_starttls: Negotiate TLS over an already opened connection.
8282+ * TODO: Merge this code better with ssl_socket_open. */
8383+int mutt_ssl_starttls (CONNECTION* conn)
7584{
7676- sslsockdata* ssldata = (sslsockdata*) conn->sockdata;
8585+ sslsockdata* ssldata;
7786 int maxbits;
78877979- return SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl), &maxbits);
8080-}
8888+ if (ssl_init())
8989+ goto bail;
9090+9191+ ssldata = (sslsockdata*) safe_calloc (1, sizeof (sslsockdata));
9292+ /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */
9393+ if (! (ssldata->ctx = SSL_CTX_new (TLSv1_client_method ())))
9494+ {
9595+ dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n"));
9696+ goto bail_ssldata;
9797+ }
81989999+ if (! (ssldata->ssl = SSL_new (ssldata->ctx)))
100100+ {
101101+ dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n"));
102102+ goto bail_ctx;
103103+ }
821048383-static int add_entropy (const char *file);
105105+ if (SSL_set_fd (ssldata->ssl, conn->fd) != 1)
106106+ {
107107+ dprint (1, (debugfile, "mutt_ssl_starttls: Error setting fd\n"));
108108+ goto bail_ssl;
109109+ }
110110+111111+ if (ssl_negotiate (ssldata))
112112+ goto bail_ssl;
113113+114114+ /* hmm. watch out if we're starting TLS over any method other than raw. */
115115+ conn->sockdata = ssldata;
116116+ conn->read = ssl_socket_read;
117117+ conn->write = ssl_socket_write;
118118+ conn->close = ssl_socket_close;
119119+120120+ conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl),
121121+ &maxbits);
122122+123123+ return 0;
124124+125125+ bail_ssl:
126126+ FREE (&ssldata->ssl);
127127+ bail_ctx:
128128+ FREE (&ssldata->ctx);
129129+ bail_ssldata:
130130+ FREE (&ssldata);
131131+ bail:
132132+ return -1;
133133+}
134134+84135/*
85136 * OpenSSL library needs to be fed with sufficient entropy. On systems
86137 * with /dev/urandom, this is done transparently by the library itself,
···94145int ssl_init (void)
95146{
96147 char path[_POSIX_PATH_MAX];
148148+ static unsigned char init_complete = 0;
971499898- if (HAVE_ENTROPY()) return 0;
9999-100100- /* load entropy from files */
101101- add_entropy (SslEntropyFile);
102102- add_entropy (RAND_file_name (path, sizeof (path)));
150150+ if (init_complete)
151151+ return 0;
152152+153153+ if (! HAVE_ENTROPY())
154154+ {
155155+ /* load entropy from files */
156156+ add_entropy (SslEntropyFile);
157157+ add_entropy (RAND_file_name (path, sizeof (path)));
103158104104- /* load entropy from egd sockets */
159159+ /* load entropy from egd sockets */
105160#ifdef HAVE_RAND_EGD
106106- add_entropy (getenv ("EGDSOCKET"));
107107- snprintf (path, sizeof(path), "%s/.entropy", NONULL(Homedir));
108108- add_entropy (path);
109109- add_entropy ("/tmp/entropy");
161161+ add_entropy (getenv ("EGDSOCKET"));
162162+ snprintf (path, sizeof(path), "%s/.entropy", NONULL(Homedir));
163163+ add_entropy (path);
164164+ add_entropy ("/tmp/entropy");
110165#endif
111166112112- /* shuffle $RANDFILE (or ~/.rnd if unset) */
113113- RAND_write_file (RAND_file_name (path, sizeof (path)));
114114- mutt_clear_error ();
115115- if (HAVE_ENTROPY()) return 0;
167167+ /* shuffle $RANDFILE (or ~/.rnd if unset) */
168168+ RAND_write_file (RAND_file_name (path, sizeof (path)));
169169+ mutt_clear_error ();
170170+ if (! HAVE_ENTROPY())
171171+ {
172172+ mutt_error (_("Failed to find enough entropy on your system"));
173173+ sleep (2);
174174+ return -1;
175175+ }
176176+ }
116177117117- mutt_error (_("Failed to find enough entropy on your system"));
118118- sleep (2);
119119- return -1;
178178+ /* I don't think you can do this just before reading the error. The call
179179+ * itself might clobber the last SSL error. */
180180+ SSL_load_error_strings();
181181+ SSL_library_init();
182182+ init_complete = 1;
183183+ return 0;
120184}
121185122186static int add_entropy (const char *file)
···161225 return -1;
162226}
163227164164-static int ssl_check_certificate (sslsockdata * data);
165165-166166-static int ssl_socket_read (CONNECTION * conn);
167167-static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
168168-static int ssl_socket_open (CONNECTION * conn);
169169-static int ssl_socket_close (CONNECTION * conn);
170228171229int ssl_socket_setup (CONNECTION * conn)
172230{
···199257int ssl_socket_open (CONNECTION * conn)
200258{
201259 sslsockdata *data;
202202- int err;
260260+ int maxbits;
203261204262 if (raw_socket_open (conn) < 0)
205263 return -1;
···207265 data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata));
208266 conn->sockdata = data;
209267210210- SSL_library_init();
211268 data->ctx = SSL_CTX_new (SSLv23_client_method ());
212269213270 /* disable SSL protocols as needed */
···227284 data->ssl = SSL_new (data->ctx);
228285 SSL_set_fd (data->ssl, conn->fd);
229286230230- if ((err = SSL_connect (data->ssl)) != 1)
287287+ if (ssl_negotiate(data))
288288+ {
289289+ ssl_socket_close (conn);
290290+ return -1;
291291+ }
292292+293293+ conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (data->ssl),
294294+ &maxbits);
295295+296296+ return 0;
297297+}
298298+299299+/* ssl_negotiate: After SSL state has been initialised, attempt to negotiate
300300+ * SSL over the wire, including certificate checks. */
301301+int ssl_negotiate (sslsockdata* ssldata)
302302+{
303303+ if (SSL_connect (ssldata->ssl) != 1)
231304 {
232305 unsigned long e;
233233- SSL_load_error_strings();
234306 while ((e = ERR_get_error()) != 0)
235307 {
236236- mutt_error ("%s", ERR_reason_error_string(e));
308308+ mutt_error ("SSL failed: %s", ERR_reason_error_string(e));
237309 sleep (1);
238310 }
239239- ssl_socket_close (conn);
240311 return -1;
241312 }
242313243243- data->cert = SSL_get_peer_certificate (data->ssl);
244244- if (!data->cert)
314314+ ssldata->cert = SSL_get_peer_certificate (ssldata->ssl);
315315+ if (!ssldata->cert)
245316 {
246317 mutt_error (_("Unable to get certificate from peer"));
247318 sleep (1);
248319 return -1;
249320 }
250321251251- if (!ssl_check_certificate (data))
252252- {
253253- ssl_socket_close (conn);
322322+ if (!ssl_check_certificate (ssldata))
254323 return -1;
255255- }
256324257325 mutt_message (_("SSL connection using %s (%s)"),
258258- SSL_get_cipher_version (data->ssl), SSL_get_cipher_name (data->ssl));
326326+ SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl));
259327 sleep (1);
260328261329 return 0;