Эх сурвалжийг харах

added CRAM-MD5 authentication support.

parse server capability string to determine if STARTTLS is available
Michael Elkins 24 жил өмнө
parent
commit
b3eb5661eb
5 өөрчлөгдсөн 161 нэмэгдсэн , 10 устгасан
  1. 1 1
      Makefile.am
  2. 2 1
      README
  3. 85 0
      cram.c
  4. 66 8
      imap.c
  5. 7 0
      isync.h

+ 1 - 1
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)

+ 2 - 1
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
 

+ 85 - 0
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

+ 66 - 8
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)
     {

+ 7 - 0
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 **);