1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
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.
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.
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.
30 #include <glib/gi18n-lib.h>
32 #include "camel-mime-utils.h"
33 #include "camel-network-settings.h"
34 #include "camel-sasl-cram-md5.h"
35 #include "camel-service.h"
37 #define CAMEL_SASL_CRAM_MD5_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE \
39 ((obj), CAMEL_TYPE_SASL_CRAM_MD5, CamelSaslCramMd5Private))
41 struct _CamelSaslCramMd5Private {
42 gint placeholder; /* allow for future expansion */
45 static CamelServiceAuthType sasl_cram_md5_auth_type = {
48 N_("This option will connect to the server using a "
49 "secure CRAM-MD5 password, if the server supports it."),
55 G_DEFINE_TYPE (CamelSaslCramMd5, camel_sasl_cram_md5, CAMEL_TYPE_SASL)
57 /* CRAM-MD5 algorithm:
58 * MD5 ((passwd XOR opad), MD5 ((passwd XOR ipad), timestamp))
62 sasl_cram_md5_challenge_sync (CamelSasl *sasl,
64 GCancellable *cancellable,
67 CamelNetworkSettings *network_settings;
68 CamelSettings *settings;
69 CamelService *service;
74 const gchar *password;
75 GByteArray *ret = NULL;
81 /* Need to wait for the server */
85 service = camel_sasl_get_service (sasl);
87 settings = camel_service_ref_settings (service);
88 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
90 network_settings = CAMEL_NETWORK_SETTINGS (settings);
91 user = camel_network_settings_dup_user (network_settings);
93 g_object_unref (settings);
95 g_return_val_if_fail (user != NULL, NULL);
97 password = camel_service_get_password (service);
98 g_return_val_if_fail (password != NULL, NULL);
100 length = g_checksum_type_get_length (G_CHECKSUM_MD5);
101 digest = g_alloca (length);
103 memset (ipad, 0, sizeof (ipad));
104 memset (opad, 0, sizeof (opad));
106 pw_len = strlen (password);
108 memcpy (ipad, password, pw_len);
109 memcpy (opad, password, pw_len);
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);
116 memcpy (ipad, digest, length);
117 memcpy (opad, digest, length);
120 for (i = 0; i < 64; i++) {
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);
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);
135 /* String is owned by the checksum. */
136 hex = g_checksum_get_string (checksum);
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));
143 g_checksum_free (checksum);
145 camel_sasl_set_authenticated (sasl, TRUE);
153 camel_sasl_cram_md5_class_init (CamelSaslCramMd5Class *class)
155 CamelSaslClass *sasl_class;
157 g_type_class_add_private (class, sizeof (CamelSaslCramMd5Private));
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;
165 camel_sasl_cram_md5_init (CamelSaslCramMd5 *sasl)
167 sasl->priv = CAMEL_SASL_CRAM_MD5_GET_PRIVATE (sasl);