Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-sasl-cram-md5.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2001 Ximian, Inc. (www.ximian.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <glib/gi18n-lib.h>
32
33 #include <libedataserver/md5-utils.h>
34
35 #include "camel-mime-utils.h"
36 #include "camel-sasl-cram-md5.h"
37 #include "camel-service.h"
38
39 CamelServiceAuthType camel_sasl_cram_md5_authtype = {
40         N_("CRAM-MD5"),
41
42         N_("This option will connect to the server using a "
43            "secure CRAM-MD5 password, if the server supports it."),
44
45         "CRAM-MD5",
46         TRUE
47 };
48
49 static CamelSaslClass *parent_class = NULL;
50
51 /* Returns the class for a CamelSaslCramMd5 */
52 #define CSCM_CLASS(so) CAMEL_SASL_CRAM_MD5_CLASS (CAMEL_OBJECT_GET_CLASS (so))
53
54 static GByteArray *cram_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
55
56 static void
57 camel_sasl_cram_md5_class_init (CamelSaslCramMd5Class *camel_sasl_cram_md5_class)
58 {
59         CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_cram_md5_class);
60         
61         parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
62         
63         /* virtual method overload */
64         camel_sasl_class->challenge = cram_md5_challenge;
65 }
66
67 CamelType
68 camel_sasl_cram_md5_get_type (void)
69 {
70         static CamelType type = CAMEL_INVALID_TYPE;
71         
72         if (type == CAMEL_INVALID_TYPE) {
73                 type = camel_type_register (camel_sasl_get_type (),
74                                             "CamelSaslCramMd5",
75                                             sizeof (CamelSaslCramMd5),
76                                             sizeof (CamelSaslCramMd5Class),
77                                             (CamelObjectClassInitFunc) camel_sasl_cram_md5_class_init,
78                                             NULL,
79                                             NULL,
80                                             NULL);
81         }
82         
83         return type;
84 }
85
86 /* CRAM-MD5 algorithm:
87  * MD5 ((passwd XOR opad), MD5 ((passwd XOR ipad), timestamp))
88  */
89
90 static GByteArray *
91 cram_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
92 {
93         char *passwd;
94         guchar digest[16], md5asc[33], *s, *p;
95         GByteArray *ret = NULL;
96         guchar ipad[64];
97         guchar opad[64];
98         MD5Context ctx;
99         int i, pw_len;
100         
101         /* Need to wait for the server */
102         if (!token)
103                 return NULL;
104         
105         g_return_val_if_fail (sasl->service->url->passwd != NULL, NULL);
106         
107         memset (ipad, 0, sizeof (ipad));
108         memset (opad, 0, sizeof (opad));
109         
110         passwd = sasl->service->url->passwd;
111         pw_len = strlen (passwd);
112         if (pw_len <= 64) {
113                 memcpy (ipad, passwd, pw_len);
114                 memcpy (opad, passwd, pw_len);
115         } else {
116                 md5_get_digest (passwd, pw_len, ipad);
117                 memcpy (opad, ipad, 16);
118         }
119         
120         for (i = 0; i < 64; i++) {
121                 ipad[i] ^= 0x36;
122                 opad[i] ^= 0x5c;
123         }
124         
125         md5_init (&ctx);
126         md5_update (&ctx, ipad, 64);
127         md5_update (&ctx, token->data, token->len);
128         md5_final (&ctx, digest);
129         
130         md5_init (&ctx);
131         md5_update (&ctx, opad, 64);
132         md5_update (&ctx, digest, 16);
133         md5_final (&ctx, digest);
134         
135         /* lowercase hexify that bad-boy... */
136         for (s = digest, p = md5asc; p < md5asc + 32; s++, p += 2)
137                 sprintf (p, "%.2x", *s);
138         
139         ret = g_byte_array_new ();
140         g_byte_array_append (ret, sasl->service->url->user, strlen (sasl->service->url->user));
141         g_byte_array_append (ret, " ", 1);
142         g_byte_array_append (ret, md5asc, 32);
143         
144         sasl->authenticated = TRUE;
145         
146         return ret;
147 }