commit b3eb5661eb70979f12deb88c5f732014a5f933e8
parent 074298d482b7d5cf99db00b84a9afd87bd69abfb
Author: Michael Elkins <me@mutt.org>
Date: Sat, 23 Dec 2000 00:02:42 +0000
added CRAM-MD5 authentication support.
parse server capability string to determine if STARTTLS is available
Diffstat:
M | Makefile.am | | | 2 | +- |
M | README | | | 3 | ++- |
A | cram.c | | | 85 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | imap.c | | | 74 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
M | isync.h | | | 7 | +++++++ |
5 files changed, 161 insertions(+), 10 deletions(-)
diff --git a/Makefile.am b/Makefile.am
@@ -1,5 +1,5 @@
bin_PROGRAMS=isync
-isync_SOURCES=main.c imap.c sync.c maildir.c isync.h list.c
+isync_SOURCES=main.c imap.c sync.c maildir.c isync.h list.c cram.c
man_MANS=isync.1
EXTRA_DIST=sample.isyncrc $(man_MANS)
CPPFLAGS=$(RPM_OPT_FLAGS)
diff --git a/README b/README
@@ -18,8 +18,9 @@ maintained, and all flags are synchronized.
* Fast mode for fetching new mail only
* Supports imaps: (port 993) TLS/SSL connections
- * Supports STARTTLS (RFC2595)
+ * Supports STARTTLS (RFC2595) for confidentiality
* Supports NAMESPACE (RFC2342)
+ * Supports CRAM-MD5 (RFC2095) for authentication
* Compatibility
diff --git a/cram.c b/cram.c
@@ -0,0 +1,85 @@
+/* $Id$
+ *
+ * isync - IMAP4 to maildir mailbox synchronizer
+ * Copyright (C) 2000 Michael R. Elkins <me@mutt.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include "isync.h"
+
+#if HAVE_LIBSSL
+
+#include <openssl/hmac.h>
+
+#define ENCODED_SIZE(n) (4*((n+2)/3))
+
+static char
+hexchar (unsigned int b)
+{
+ if (b < 10)
+ return '0' + b;
+ return 'a' + (b - 10);
+}
+
+char *
+cram (const char *challenge, const char *user, const char *pass)
+{
+ HMAC_CTX hmac;
+ char hash[16];
+ char hex[33];
+ int i;
+ unsigned int hashlen = sizeof (hash);
+ char buf[256];
+ int len = strlen (challenge);
+ char *response = calloc (1, 1 + len);
+ char *final;
+
+ /* response will always be smaller than challenge because we are
+ * decoding.
+ */
+ len = EVP_DecodeBlock ((unsigned char *) response, (unsigned char *) challenge, strlen (challenge));
+// printf ("CRAM-MD5 challege is %s\n", response);
+
+ HMAC_Init (&hmac, (unsigned char *) pass, strlen (pass), EVP_md5 ());
+ HMAC_Update (&hmac, (unsigned char *) response, strlen(response));
+ HMAC_Final (&hmac, (unsigned char *) hash, &hashlen);
+
+ assert (hashlen == sizeof (hash));
+
+ free (response);
+
+ hex[32] = 0;
+ for (i = 0; i < 16; i++)
+ {
+ hex[2 * i] = hexchar ((hash[i] >> 4) & 0xf);
+ hex[2 * i + 1] = hexchar (hash[i] & 0xf);
+ }
+
+ snprintf (buf, sizeof (buf), "%s %s", user, hex);
+// printf ("Response: %s\n", buf);
+
+ len = strlen (buf);
+ len = ENCODED_SIZE (len) + 1;
+ final = malloc (len);
+ final[len - 1] = 0;
+
+ assert (EVP_EncodeBlock ((unsigned char *) final, (unsigned char *) buf, strlen (buf)) == len - 1);
+
+ return final;
+}
+
+#endif
diff --git a/imap.c b/imap.c
@@ -401,6 +401,18 @@ imap_exec (imap_t * imap, const char *fmt, ...)
{
parse_response_code (imap, cmd);
}
+ else if (!strcmp ("CAPABILITY", arg))
+ {
+#if HAVE_LIBSSL
+ while ((arg = next_arg (&cmd)))
+ {
+ if (!strcmp ("STARTTLS", arg))
+ imap->have_starttls = 1;
+ else if (!strcmp ("AUTH=CRAM-MD5", arg))
+ imap->have_cram = 1;
+ }
+#endif
+ }
else if ((arg1 = next_arg (&cmd)))
{
if (!strcmp ("EXISTS", arg1))
@@ -428,6 +440,26 @@ imap_exec (imap_t * imap, const char *fmt, ...)
return -1;
}
}
+#if HAVE_LIBSSL
+ else if (*arg == '+')
+ {
+ char *resp;
+
+ if (!imap->cram)
+ {
+ puts ("Error, not doing CRAM-MD5 authentication");
+ return -1;
+ }
+ resp = cram (cmd, imap->box->user, imap->box->pass);
+
+ socket_write (imap->sock, resp, strlen (resp));
+ if (Verbose)
+ puts (resp);
+ socket_write (imap->sock, "\r\n", 2);
+ free (resp);
+ imap->cram = 0;
+ }
+#endif
else if ((size_t) atol (arg) != Tag)
{
puts ("wrong tag");
@@ -510,17 +542,23 @@ imap_open (config_t * box, unsigned int minuid)
#if HAVE_LIBSSL
if (!box->use_imaps)
{
+ /* let's see what this puppy can do... */
+ ret = imap_exec (imap, "CAPABILITY");
+
/* always try to select SSL support if available */
- ret = imap_exec (imap, "STARTTLS");
- if (!ret)
+ if (imap->have_starttls && !imap_exec (imap, "STARTTLS"))
use_ssl = 1;
- else if (box->require_ssl)
+
+ if (!use_ssl)
{
- puts ("Error, SSL support not available");
- return 0;
+ if (box->require_ssl)
+ {
+ puts ("Error, SSL support not available");
+ return 0;
+ }
+ else
+ puts ("Warning, SSL support not available");
}
- else
- puts ("Warning, SSL support not available");
}
else
use_ssl = 1;
@@ -543,11 +581,31 @@ imap_open (config_t * box, unsigned int minuid)
imap->sock->use_ssl = 1;
puts ("SSL support enabled");
+
+ if (box->use_imaps)
+ ret = imap_exec (imap, "CAPABILITY");
}
+#else
+ ret = imap_exec (imap, "CAPABILITY");
#endif
puts ("Logging in...");
- ret = imap_exec (imap, "LOGIN \"%s\" \"%s\"", box->user, box->pass);
+#if HAVE_LIBSSL
+ if (imap->have_cram)
+ {
+ puts ("Authenticating with CRAM-MD5");
+ imap->cram = 1;
+ ret = imap_exec (imap, "AUTHENTICATE CRAM-MD5");
+ }
+ else
+#endif
+ {
+#if HAVE_LIBSSL
+ if (!use_ssl)
+#endif
+ puts ("*** Warning *** Password is being sent in the clear");
+ ret = imap_exec (imap, "LOGIN \"%s\" \"%s\"", box->user, box->pass);
+ }
if (!ret)
{
diff --git a/isync.h b/isync.h
@@ -130,6 +130,11 @@ typedef struct
list_t *ns_personal;
list_t *ns_other;
list_t *ns_shared;
+#if HAVE_LIBSSL
+ unsigned int have_cram:1;
+ unsigned int have_starttls:1;
+ unsigned int cram:1;
+#endif
}
imap_t;
@@ -144,6 +149,8 @@ extern int Verbose;
#if HAVE_LIBSSL
extern SSL_CTX *SSLContext;
+
+char *cram (const char *, const char *, const char *);
#endif
char *next_arg (char **);