[Goodies-commits] r4040 - in xfce4-mailwatch-plugin/trunk: . libmailwatch-core

Brian Tarricone kelnos at xfce.org
Fri Mar 14 06:02:37 CET 2008


Author: kelnos
Date: 2008-03-14 05:02:37 +0000 (Fri, 14 Mar 2008)
New Revision: 4040

Modified:
   xfce4-mailwatch-plugin/trunk/NEWS
   xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c
   xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-pop3.c
   xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.c
   xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.h
Log:
add CRAM-MD5 authentication support for imap and pop3 (bug 3420)


Modified: xfce4-mailwatch-plugin/trunk/NEWS
===================================================================
--- xfce4-mailwatch-plugin/trunk/NEWS	2008-03-13 12:34:27 UTC (rev 4039)
+++ xfce4-mailwatch-plugin/trunk/NEWS	2008-03-14 05:02:37 UTC (rev 4040)
@@ -9,6 +9,7 @@
     * Fix incorrect getaddrinfo() usage breaking use on NetBSD (bug 3767).
     * Fix possible hang when reading IMAP responses when a selected folder
       is later deleted or unsubscribed.
+    * Fix buffer size issues when reading IMAP folder contents (bug 2009).
 
   Features:
     * Update the new message counts for all mailboxes on startup, rather than
@@ -16,6 +17,8 @@
     * Document the behavior of forcing a new messsage count update when the
       user double-clicks the icon (patch from Maximilian Schleiss).
     * Add experimental IPv6 support.
+    * Add an 'Update Now' menu item (bug 3908).
+    * Add CRAM-MD5 authentication support for POP3 and IMAP (bug 3420).
 
 Version 1.0.1 (20 Apr 2006):
 

Modified: xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c
===================================================================
--- xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c	2008-03-13 12:34:27 UTC (rev 4039)
+++ xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c	2008-03-14 05:02:37 UTC (rev 4040)
@@ -253,9 +253,61 @@
         goto cleanuperr;
     }
     
+#ifdef HAVE_SSL_SUPPORT
+    if(strstr(buf, "AUTH=CRAM-MD5")) {
+        /* the server supports CRAM-MD5; prefer that over LOGIN */
+        g_snprintf(buf, BUFSIZE, "%05d AUTHENTICATE CRAM-MD5\r\n",
+                   ++imailbox->imap_tag);
+        bout = imap_send(imailbox, buf);
+        if(bout != strlen(buf))
+            goto cleanuperr;
+        
+        bin = imap_recv(imailbox, buf, BUFSIZE);
+        DBG("response from AUTHENTICATE CRAM-MD5 (%d): %s\n", bin, bin>0?buf:"(nada)");
+        if(bin <= 0)
+            goto cleanuperr;
+
+        if(*buf == '+' && *(buf+1) == ' ' && *(buf+2)) {
+            gchar *p, *response_base64;
+
+            /* we got a challenge */
+            p = strstr(buf, "\r\n");
+            if(!p)
+                p = strstr(buf, "\n");
+            if(!p) {
+                DBG("cram-md5 challenge wasn't a full line?");
+                goto cleanuperr;
+            }
+            *p = 0;
+
+            response_base64 = xfce_mailwatch_cram_md5(username, password,
+                                                      buf + 2);
+            if(!response_base64)
+                goto cleanuperr;
+            g_snprintf(buf, BUFSIZE, "%s\r\n", response_base64);
+            g_free(response_base64);
+            bout = imap_send(imailbox, buf);
+            DBG("sent CRAM-MD5 response: %s\n", buf);
+            if(bout != strlen(buf))
+                goto cleanuperr;
+
+            bin = imap_recv(imailbox, buf, BUFSIZE);
+            DBG("reponse from cram-md5 resp (%d): %s\n", bin, bin>0?buf:"(nada)");
+            if(bin <= 0)
+                goto cleanuperr;
+            if(!strstr(buf, "OK"))
+                goto cleanuperr;
+
+            /* auth successful */
+            TRACE("leaving (success)");
+            return TRUE;
+        }
+    }
+#endif
+
     /* send the creds */
     g_snprintf(buf, BUFSIZE, "%05d LOGIN \"%s\" \"%s\"\r\n",
-            ++imailbox->imap_tag, username, password);
+               ++imailbox->imap_tag, username, password);
     bout = imap_send(imailbox, buf);
     DBG("sent login (%d)", bout);
     if(bout != strlen(buf))

Modified: xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-pop3.c
===================================================================
--- xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-pop3.c	2008-03-13 12:34:27 UTC (rev 4039)
+++ xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-pop3.c	2008-03-14 05:02:37 UTC (rev 4040)
@@ -202,8 +202,76 @@
     gint bin, bout;
     gchar buf[BUFSIZE+1];
     
-    TRACE("entering");
+#ifdef HAVE_SSL_SUPPORT
+    gint off;
+    gchar *p, *q;
     
+    /* see if CRAM-MD5 is supported */
+    g_strlcpy(buf, "CAPA\r\n", BUFSIZE);
+    bout = pop3_send(pmailbox, buf);
+    if(bout != strlen(buf))
+        goto cleanuperr;
+
+    off = 0;
+    do {
+        bin = pop3_recv(pmailbox, buf + off, BUFSIZE - off);
+        if(bin > 0)
+            off += bin;
+    } while(bin > 0 && !strstr(buf, ".\r\n"));
+    if(bin < 0)
+        goto cleanuperr;
+
+    if((p = strstr(buf, "SASL ")) && (q = strstr(p, "\r\n"))
+       && (p = strstr(p, "CRAM-MD5")) && p < q)
+    {
+        /* server supports CRAM-MD5 */
+        g_strlcpy(buf, "AUTH CRAM-MD5\r\n", BUFSIZE);
+        bout = pop3_send(pmailbox, buf);
+        if(bout != strlen(buf))
+            goto cleanuperr;
+
+        bin = pop3_recv(pmailbox, buf, BUFSIZE);
+        if(bin <= 0)
+            goto cleanuperr;
+        DBG("got cram-md5 challenge: %s\n", buf);
+
+        if(*buf == '+' && *(buf+1) == ' ' && *(buf+2)) {
+            gchar *response_base64;
+
+            p = strstr(buf, "\r\n");
+            if(!p)
+                p = strstr(buf, "\n");
+            if(!p) {
+                DBG("cram-md5 challenge wasn't a full line?");
+                goto cleanuperr;
+            }
+            *p = 0;
+
+            response_base64 = xfce_mailwatch_cram_md5(username, password,
+                                                      buf + 2);
+            if(!response_base64)
+                goto cleanuperr;
+            g_strlcpy(buf, response_base64, BUFSIZE);
+            g_strlcat(buf, "\r\n", BUFSIZE);
+            g_free(response_base64);
+            bout = pop3_send(pmailbox, buf);
+            if(bout != strlen(buf))
+                goto cleanuperr;
+
+            bin = pop3_recv(pmailbox, buf, BUFSIZE);
+            if(bin <= 0)
+                goto cleanuperr;
+            DBG("got response to cram-md5 auth: %s", buf);
+            if(strncmp(buf, "+OK", 3))
+                goto cleanuperr;
+
+            TRACE("leaving (success)");
+
+            return TRUE;
+        }
+    }
+#endif
+
     /* send the username */
     g_snprintf(buf, BUFSIZE, "USER %s\r\n", username);
     bout = pop3_send(pmailbox, buf);
@@ -240,7 +308,7 @@
     
     return TRUE;
     
-    cleanuperr:
+cleanuperr:
     
     shutdown(pmailbox->sockfd, SHUT_RDWR);
     close(pmailbox->sockfd);

Modified: xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.c
===================================================================
--- xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.c	2008-03-13 12:34:27 UTC (rev 4039)
+++ xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.c	2008-03-14 05:02:37 UTC (rev 4040)
@@ -498,7 +498,79 @@
 #endif
 }
 
+#ifdef HAVE_SSL_SUPPORT
 
+/* assumes |dest| is allocated 2x |src_len| */
+static void
+bin2hex(gchar *dest,
+        const guchar *src,
+        gsize src_len)
+{
+    static const gchar hexdigits[] = "0123456789abcdef";
+
+    if(!src_len)
+        return;
+
+    while(src_len-- > 0) {
+        *dest++ = hexdigits[(*src >> 4) & 0xf];
+        *dest++ = hexdigits[*src & 0xf];
+        src++;
+    }
+}
+
+gchar *
+xfce_mailwatch_cram_md5(const gchar *username,
+                        const gchar *password,
+                        const gchar *challenge_base64)
+{
+    gchar challenge[2048];
+    gsize len, username_len;
+    gcry_md_hd_t hmac_md5;
+    gchar *response, *response_base64 = NULL;
+    
+    g_return_val_if_fail(username && *username && password && *password
+                         && challenge_base64 && *challenge_base64, NULL);
+
+    len = xfce_mailwatch_base64_decode(challenge_base64, (guchar *)challenge,
+                                       sizeof(challenge) - 1);
+    if(len <= 0)
+        return NULL;
+    challenge[len] = 0;
+    DBG("challenge is \"%s\"\n", challenge);
+
+    if(gcry_md_open(&hmac_md5, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
+        return NULL;
+    gcry_md_setkey(hmac_md5, password, strlen(password));
+    gcry_md_write(hmac_md5, challenge, len);
+    gcry_md_final(hmac_md5);
+
+    username_len = strlen(username);
+    /* username + a space + MD5 in hex + null */
+    response = g_malloc0(username_len + 1
+                         + gcry_md_get_algo_dlen(GCRY_MD_MD5)*2 + 1);
+    strcpy(response, username);
+    response[username_len] = ' ';
+    bin2hex(response + username_len + 1, gcry_md_read(hmac_md5, GCRY_MD_MD5),
+            gcry_md_get_algo_dlen(GCRY_MD_MD5));
+
+    gcry_md_close(hmac_md5);
+
+    DBG("response before base64: %s\n", response);
+    if(xfce_mailwatch_base64_encode((guchar *)response, strlen(response),
+                                    &response_base64) <= 0)
+    {
+        g_free(response_base64);
+        response_base64 = NULL;
+    }
+
+    g_free(response);
+
+    return response_base64;
+}
+
+#endif
+
+
 /*
  * The following Base64 code is provided under the following license:
  *
@@ -534,13 +606,15 @@
  * SUCH DAMAGE.
  *
  * Modified slightly by Brian Tarricone <bjt23 at cornell.edu> to use g_malloc()
- * and glib primitive types.
+ * and glib primitive types, and to add buffer overrun checking.
  */
 
 static const gchar base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 gint
-xfce_mailwatch_base64_encode(const guint8 *data, gint size, gchar **str)
+xfce_mailwatch_base64_encode(const guint8 *data,
+                             gsize size,
+                             gchar **str)
 {
   gchar *s, *p;
   gint i;
@@ -548,8 +622,6 @@
   const guchar *q;
 
   p = s = (gchar *)g_malloc(size*4/3+4);
-  if (p == NULL)
-      return -1;
   q = (const guchar *)data;
   i=0;
   for(i = 0; i < size;){
@@ -577,6 +649,91 @@
   return strlen(s);
 }
 
+static
+int pos(gchar c)
+{
+  gchar *p;
+  for(p = (gchar *)base64; *p; p++)
+    if(*p == c)
+      return p - base64;
+  return -1;
+}
+
+gint
+xfce_mailwatch_base64_decode(const gchar *str,
+                             guint8 *data,
+                             gsize size)
+{
+  const char *p;
+  unsigned char *q;
+  int c;
+  int x;
+  int done = 0;
+  
+  q=(unsigned char*)data;
+  for(p=str; *p && !done; p+=4){
+    x = pos(p[0]);
+    if(x >= 0)
+      c = x;
+    else{
+      done = 3;
+      break;
+    }
+    c*=64;
+    
+    x = pos(p[1]);
+    if(x >= 0)
+      c += x;
+    else
+      return -1;
+    c*=64;
+    
+    if(p[2] == '=')
+      done++;
+    else{
+      x = pos(p[2]);
+      if(x >= 0)
+	c += x;
+      else
+	return -1;
+    }
+    c*=64;
+    
+    if(p[3] == '=')
+      done++;
+    else{
+      if(done)
+	return -1;
+      x = pos(p[3]);
+      if(x >= 0)
+	c += x;
+      else
+	return -1;
+    }
+    if(done < 3) {
+      if(!size)
+        return -1;
+      *q++=(c&0x00ff0000)>>16;
+      --size;
+    }
+      
+    if(done < 2) {
+      if(!size)
+        return -1;
+      *q++=(c&0x0000ff00)>>8;
+      --size;
+    }
+
+    if(done < 1) {
+      if(!size)
+          return -1;
+      *q++=(c&0x000000ff)>>0;
+      --size;
+    }
+  }
+  return q - (unsigned char*)data;
+}
+
 /*****
  * End Base64 code.  Don't put other stuff under here.
  *****/

Modified: xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.h
===================================================================
--- xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.h	2008-03-13 12:34:27 UTC (rev 4039)
+++ xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-utils.h	2008-03-14 05:02:37 UTC (rev 4040)
@@ -88,10 +88,16 @@
 GtkWidget *xfce_mailwatch_create_framebox(const gchar *title,
                                           GtkWidget **frame_bin);
 
+gchar *xfce_mailwatch_cram_md5(const gchar *username,
+                               const gchar *password,
+                               const gchar *challenge_base64);
+
 gint xfce_mailwatch_base64_encode(const guint8 *data,
-                                  gint size,
+                                  gsize size,
                                   gchar **str);
-
+gint xfce_mailwatch_base64_decode(const gchar *str,
+                                  guint8 *data,
+                                  gsize size);
 G_END_DECLS
 
 #endif




More information about the Goodies-commits mailing list