*
*/
+/* If building without Kerberos support, this class is an empty shell. */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
-#ifdef HAVE_KRB5
-#include <netdb.h>
#include <string.h>
-#include <sys/socket.h>
#include <sys/types.h>
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <sys/socket.h>
+#endif
+
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+
+#include "camel-net-utils.h"
+#include "camel-network-settings.h"
+#include "camel-sasl-gssapi.h"
+#include "camel-session.h"
+
+#ifdef HAVE_KRB5
+
#ifdef HAVE_HEIMDAL_KRB5
#include <krb5.h>
#else
#include <krb5/krb5.h>
-#endif
+#endif /* HAVE_HEIMDAL_KRB5 */
+
#ifdef HAVE_ET_COM_ERR_H
#include <et/com_err.h>
#else
#ifdef HAVE_COM_ERR_H
#include <com_err.h>
-#endif
-#endif
+#endif /* HAVE_COM_ERR_H */
+#endif /* HAVE_ET_COM_ERR_H */
+
#ifdef HAVE_MIT_KRB5
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_generic.h>
-#endif
+#endif /* HAVE_MIT_KRB5 */
+
#ifdef HAVE_HEIMDAL_KRB5
#include <gssapi.h>
#else
-#ifdef HAVE_SUN_KRB5
+#ifdef HAVE_SUN_KRB5
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_ext.h>
extern gss_OID gss_nt_service_name;
-#endif
-#endif
+#endif /* HAVE_SUN_KRB5 */
+#endif /* HAVE_HEIMDAL_KRB5 */
+
+#define CAMEL_SASL_GSSAPI_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), CAMEL_TYPE_SASL_GSSAPI, CamelSaslGssapiPrivate))
#ifndef GSS_C_OID_KRBV5_DES
#define GSS_C_OID_KRBV5_DES GSS_C_NO_OID
#endif
-#include <glib/gi18n-lib.h>
-#include <gio/gio.h>
-
-#include "camel-net-utils.h"
-#include "camel-sasl-gssapi.h"
-#include "camel-session.h"
-
#define DBUS_PATH "/org/gnome/KrbAuthDialog"
#define DBUS_INTERFACE "org.gnome.KrbAuthDialog"
#define DBUS_METHOD "org.gnome.KrbAuthDialog.acquireTgt"
-#define CAMEL_SASL_GSSAPI_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), CAMEL_TYPE_SASL_GSSAPI, CamelSaslGssapiPrivate))
-
-CamelServiceAuthType camel_sasl_gssapi_authtype = {
+static CamelServiceAuthType sasl_gssapi_auth_type = {
N_("GSSAPI"),
N_("This option will connect to the server using "
gss_name_t target;
};
+#endif /* HAVE_KRB5 */
+
G_DEFINE_TYPE (CamelSaslGssapi, camel_sasl_gssapi, CAMEL_TYPE_SASL)
+#ifdef HAVE_KRB5
+
static void
gssapi_set_exception (OM_uint32 major,
OM_uint32 minor,
/* DBUS Specific code */
static gboolean
-send_dbus_message (gchar *name)
+send_dbus_message (const gchar *name)
{
gint success = FALSE;
GError *error = NULL;
/* Sends the message: Have a 300 sec wait timeout */
reply = g_dbus_connection_send_message_with_reply_sync (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 300 * 1000, NULL, NULL, &error);
+ if (!error && reply) {
+ if (g_dbus_message_to_gerror (reply, &error)) {
+ g_object_unref (reply);
+ reply = NULL;
+ }
+ }
+
if (error) {
+ g_dbus_error_strip_remote_error (error);
g_warning ("%s: %s\n", G_STRFUNC, error->message);
g_error_free (error);
}
- if (reply) {
+ if (reply) {
GVariant *body = g_dbus_message_get_body (reply);
- success = body && g_variant_get_boolean (body);
+ if (body)
+ g_variant_get (body, "(b)", &success);
- g_object_unref (reply);
- }
+ g_object_unref (reply);
+ }
/* Free the message */
g_object_unref (message);
/* END DBus stuff */
static GByteArray *
-sasl_gssapi_challenge (CamelSasl *sasl,
- GByteArray *token,
- GError **error)
+sasl_gssapi_challenge_sync (CamelSasl *sasl,
+ GByteArray *token,
+ GCancellable *cancellable,
+ GError **error)
{
CamelSaslGssapiPrivate *priv;
+ CamelNetworkSettings *network_settings;
+ CamelSettings *settings;
CamelService *service;
OM_uint32 major, minor, flags, time;
gss_buffer_desc inbuf, outbuf;
gchar *str;
struct addrinfo *ai, hints;
const gchar *service_name;
+ gchar *host;
+ gchar *user;
priv = CAMEL_SASL_GSSAPI_GET_PRIVATE (sasl);
service = camel_sasl_get_service (sasl);
service_name = camel_sasl_get_service_name (sasl);
+ settings = camel_service_ref_settings (service);
+ g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ host = camel_network_settings_dup_host (network_settings);
+ user = camel_network_settings_dup_user (network_settings);
+
+ g_object_unref (settings);
+
+ g_return_val_if_fail (user != NULL, NULL);
+
+ if (host == NULL)
+ host = g_strdup ("localhost");
+
switch (priv->state) {
case GSSAPI_STATE_INIT:
- memset(&hints, 0, sizeof(hints));
+ memset (&hints, 0, sizeof (hints));
hints.ai_flags = AI_CANONNAME;
- ai = camel_getaddrinfo(service->url->host?service->url->host:"localhost", NULL, &hints, error);
+ ai = camel_getaddrinfo (
+ host, NULL, &hints, cancellable, error);
if (ai == NULL)
- return NULL;
+ goto exit;
str = g_strdup_printf("%s@%s", service_name, ai->ai_canonname);
- camel_freeaddrinfo(ai);
+ camel_freeaddrinfo (ai);
inbuf.value = str;
inbuf.length = strlen (str);
if (major != GSS_S_COMPLETE) {
gssapi_set_exception (major, minor, error);
- return NULL;
+ goto exit;
}
input_token = GSS_C_NO_BUFFER;
error, CAMEL_SERVICE_ERROR,
CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
_("Bad authentication response from server."));
- return NULL;
+ goto exit;
}
inbuf.value = token->data;
priv->state = GSSAPI_STATE_CONTINUE_NEEDED;
break;
default:
- if (major == (OM_uint32)GSS_S_FAILURE &&
- (minor == (OM_uint32)KRB5KRB_AP_ERR_TKT_EXPIRED ||
- minor == (OM_uint32)KRB5KDC_ERR_NEVER_VALID) &&
- send_dbus_message (service->url->user))
+ if (major == (OM_uint32) GSS_S_FAILURE &&
+ (minor == (OM_uint32) KRB5KRB_AP_ERR_TKT_EXPIRED ||
+ minor == (OM_uint32) KRB5KDC_ERR_NEVER_VALID) &&
+ send_dbus_message (user))
goto challenge;
gssapi_set_exception (major, minor, error);
- return NULL;
+ goto exit;
}
challenge = g_byte_array_new ();
error, CAMEL_SERVICE_ERROR,
CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
_("Bad authentication response from server."));
- return NULL;
+ goto exit;
}
inbuf.value = token->data;
major = gss_unwrap (&minor, priv->ctx, &inbuf, &outbuf, &conf_state, &qop);
if (major != GSS_S_COMPLETE) {
gssapi_set_exception (major, minor, error);
- return NULL;
+ goto exit;
}
if (outbuf.length < 4) {
#ifndef HAVE_HEIMDAL_KRB5
gss_release_buffer (&minor, &outbuf);
#endif
- return NULL;
+ goto exit;
}
/* check that our desired security layer is supported */
#ifndef HAVE_HEIMDAL_KRB5
gss_release_buffer (&minor, &outbuf);
#endif
- return NULL;
+ goto exit;
}
- inbuf.length = 4 + strlen (service->url->user);
+ inbuf.length = 4 + strlen (user);
inbuf.value = str = g_malloc (inbuf.length);
memcpy (inbuf.value, outbuf.value, 4);
str[0] = DESIRED_SECURITY_LAYER;
- memcpy (str + 4, service->url->user, inbuf.length - 4);
+ memcpy (str + 4, user, inbuf.length - 4);
#ifndef HAVE_HEIMDAL_KRB5
gss_release_buffer (&minor, &outbuf);
if (major != GSS_S_COMPLETE) {
gssapi_set_exception (major, minor, error);
g_free (str);
- return NULL;
+ goto exit;
}
g_free (str);
camel_sasl_set_authenticated (sasl, TRUE);
break;
default:
- return NULL;
+ break;
}
+exit:
+ g_free (host);
+ g_free (user);
+
return challenge;
}
+#endif /* HAVE_KRB5 */
+
static void
camel_sasl_gssapi_class_init (CamelSaslGssapiClass *class)
{
+#ifdef HAVE_KRB5
GObjectClass *object_class;
CamelSaslClass *sasl_class;
object_class->finalize = sasl_gssapi_finalize;
sasl_class = CAMEL_SASL_CLASS (class);
- sasl_class->challenge = sasl_gssapi_challenge;
+ sasl_class->auth_type = &sasl_gssapi_auth_type;
+ sasl_class->challenge_sync = sasl_gssapi_challenge_sync;
+#endif /* HAVE_KRB5 */
}
static void
camel_sasl_gssapi_init (CamelSaslGssapi *sasl)
{
+#ifdef HAVE_KRB5
sasl->priv = CAMEL_SASL_GSSAPI_GET_PRIVATE (sasl);
-
sasl->priv->state = GSSAPI_STATE_INIT;
sasl->priv->ctx = GSS_C_NO_CONTEXT;
sasl->priv->target = GSS_C_NO_NAME;
-}
-
#endif /* HAVE_KRB5 */
+}