/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * * This library is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * This library 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * * Authors: Jeffrey Stedfast */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "camel-mime-utils.h" #include "camel-network-settings.h" #include "camel-sasl-cram-md5.h" #include "camel-service.h" #define CAMEL_SASL_CRAM_MD5_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_SASL_CRAM_MD5, CamelSaslCramMd5Private)) struct _CamelSaslCramMd5Private { gint placeholder; /* allow for future expansion */ }; static CamelServiceAuthType sasl_cram_md5_auth_type = { N_("CRAM-MD5"), N_("This option will connect to the server using a " "secure CRAM-MD5 password, if the server supports it."), "CRAM-MD5", TRUE }; G_DEFINE_TYPE (CamelSaslCramMd5, camel_sasl_cram_md5, CAMEL_TYPE_SASL) /* CRAM-MD5 algorithm: * MD5 ((passwd XOR opad), MD5 ((passwd XOR ipad), timestamp)) */ static GByteArray * sasl_cram_md5_challenge_sync (CamelSasl *sasl, GByteArray *token, GCancellable *cancellable, GError **error) { CamelNetworkSettings *network_settings; CamelSettings *settings; CamelService *service; GChecksum *checksum; guint8 *digest; gsize length; const gchar *hex; const gchar *password; GByteArray *ret = NULL; guchar ipad[64]; guchar opad[64]; gchar *user; gint i, pw_len; /* Need to wait for the server */ if (!token) return NULL; service = camel_sasl_get_service (sasl); settings = camel_service_ref_settings (service); g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL); network_settings = CAMEL_NETWORK_SETTINGS (settings); user = camel_network_settings_dup_user (network_settings); g_object_unref (settings); g_return_val_if_fail (user != NULL, NULL); password = camel_service_get_password (service); g_return_val_if_fail (password != NULL, NULL); length = g_checksum_type_get_length (G_CHECKSUM_MD5); digest = g_alloca (length); memset (ipad, 0, sizeof (ipad)); memset (opad, 0, sizeof (opad)); pw_len = strlen (password); if (pw_len <= 64) { memcpy (ipad, password, pw_len); memcpy (opad, password, pw_len); } else { checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (guchar *) password, pw_len); g_checksum_get_digest (checksum, digest, &length); g_checksum_free (checksum); memcpy (ipad, digest, length); memcpy (opad, digest, length); } for (i = 0; i < 64; i++) { ipad[i] ^= 0x36; opad[i] ^= 0x5c; } checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (guchar *) ipad, sizeof (ipad)); g_checksum_update (checksum, (guchar *) token->data, token->len); g_checksum_get_digest (checksum, digest, &length); g_checksum_free (checksum); checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (guchar *) opad, sizeof (opad)); g_checksum_update (checksum, (guchar *) digest, length); /* String is owned by the checksum. */ hex = g_checksum_get_string (checksum); ret = g_byte_array_new (); g_byte_array_append (ret, (guint8 *) user, strlen (user)); g_byte_array_append (ret, (guint8 *) " ", 1); g_byte_array_append (ret, (guint8 *) hex, strlen (hex)); g_checksum_free (checksum); camel_sasl_set_authenticated (sasl, TRUE); g_free (user); return ret; } static void camel_sasl_cram_md5_class_init (CamelSaslCramMd5Class *class) { CamelSaslClass *sasl_class; g_type_class_add_private (class, sizeof (CamelSaslCramMd5Private)); sasl_class = CAMEL_SASL_CLASS (class); sasl_class->auth_type = &sasl_cram_md5_auth_type; sasl_class->challenge_sync = sasl_cram_md5_challenge_sync; } static void camel_sasl_cram_md5_init (CamelSaslCramMd5 *sasl) { sasl->priv = CAMEL_SASL_CRAM_MD5_GET_PRIVATE (sasl); }