Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[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 (C) 1999-2008 Novell, Inc. (www.novell.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/gi18n-lib.h>
31
32 #include "camel-mime-utils.h"
33 #include "camel-network-settings.h"
34 #include "camel-sasl-cram-md5.h"
35 #include "camel-service.h"
36
37 #define CAMEL_SASL_CRAM_MD5_GET_PRIVATE(obj) \
38         (G_TYPE_INSTANCE_GET_PRIVATE \
39         ((obj), CAMEL_TYPE_SASL_CRAM_MD5, CamelSaslCramMd5Private))
40
41 struct _CamelSaslCramMd5Private {
42         gint placeholder;  /* allow for future expansion */
43 };
44
45 static CamelServiceAuthType sasl_cram_md5_auth_type = {
46         N_("CRAM-MD5"),
47
48         N_("This option will connect to the server using a "
49            "secure CRAM-MD5 password, if the server supports it."),
50
51         "CRAM-MD5",
52         TRUE
53 };
54
55 G_DEFINE_TYPE (CamelSaslCramMd5, camel_sasl_cram_md5, CAMEL_TYPE_SASL)
56
57 /* CRAM-MD5 algorithm:
58  * MD5 ((passwd XOR opad), MD5 ((passwd XOR ipad), timestamp))
59  */
60
61 static GByteArray *
62 sasl_cram_md5_challenge_sync (CamelSasl *sasl,
63                               GByteArray *token,
64                               GCancellable *cancellable,
65                               GError **error)
66 {
67         CamelNetworkSettings *network_settings;
68         CamelSettings *settings;
69         CamelService *service;
70         GChecksum *checksum;
71         guint8 *digest;
72         gsize length;
73         const gchar *hex;
74         const gchar *password;
75         GByteArray *ret = NULL;
76         guchar ipad[64];
77         guchar opad[64];
78         gchar *user;
79         gint i, pw_len;
80
81         /* Need to wait for the server */
82         if (!token)
83                 return NULL;
84
85         service = camel_sasl_get_service (sasl);
86
87         settings = camel_service_ref_settings (service);
88         g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
89
90         network_settings = CAMEL_NETWORK_SETTINGS (settings);
91         user = camel_network_settings_dup_user (network_settings);
92
93         g_object_unref (settings);
94
95         g_return_val_if_fail (user != NULL, NULL);
96
97         password = camel_service_get_password (service);
98         g_return_val_if_fail (password != NULL, NULL);
99
100         length = g_checksum_type_get_length (G_CHECKSUM_MD5);
101         digest = g_alloca (length);
102
103         memset (ipad, 0, sizeof (ipad));
104         memset (opad, 0, sizeof (opad));
105
106         pw_len = strlen (password);
107         if (pw_len <= 64) {
108                 memcpy (ipad, password, pw_len);
109                 memcpy (opad, password, pw_len);
110         } else {
111                 checksum = g_checksum_new (G_CHECKSUM_MD5);
112                 g_checksum_update (checksum, (guchar *) password, pw_len);
113                 g_checksum_get_digest (checksum, digest, &length);
114                 g_checksum_free (checksum);
115
116                 memcpy (ipad, digest, length);
117                 memcpy (opad, digest, length);
118         }
119
120         for (i = 0; i < 64; i++) {
121                 ipad[i] ^= 0x36;
122                 opad[i] ^= 0x5c;
123         }
124
125         checksum = g_checksum_new (G_CHECKSUM_MD5);
126         g_checksum_update (checksum, (guchar *) ipad, sizeof (ipad));
127         g_checksum_update (checksum, (guchar *) token->data, token->len);
128         g_checksum_get_digest (checksum, digest, &length);
129         g_checksum_free (checksum);
130
131         checksum = g_checksum_new (G_CHECKSUM_MD5);
132         g_checksum_update (checksum, (guchar *) opad, sizeof (opad));
133         g_checksum_update (checksum, (guchar *) digest, length);
134
135         /* String is owned by the checksum. */
136         hex = g_checksum_get_string (checksum);
137
138         ret = g_byte_array_new ();
139         g_byte_array_append (ret, (guint8 *) user, strlen (user));
140         g_byte_array_append (ret, (guint8 *) " ", 1);
141         g_byte_array_append (ret, (guint8 *) hex, strlen (hex));
142
143         g_checksum_free (checksum);
144
145         camel_sasl_set_authenticated (sasl, TRUE);
146
147         g_free (user);
148
149         return ret;
150 }
151
152 static void
153 camel_sasl_cram_md5_class_init (CamelSaslCramMd5Class *class)
154 {
155         CamelSaslClass *sasl_class;
156
157         g_type_class_add_private (class, sizeof (CamelSaslCramMd5Private));
158
159         sasl_class = CAMEL_SASL_CLASS (class);
160         sasl_class->auth_type = &sasl_cram_md5_auth_type;
161         sasl_class->challenge_sync = sasl_cram_md5_challenge_sync;
162 }
163
164 static void
165 camel_sasl_cram_md5_init (CamelSaslCramMd5 *sasl)
166 {
167         sasl->priv = CAMEL_SASL_CRAM_MD5_GET_PRIVATE (sasl);
168 }