Rename camel_service_get_settings().
[platform/upstream/evolution-data-server.git] / camel / camel-sasl-gssapi.c
index 554e8e8..75745e2 100644 (file)
  *
  */
 
+/* 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 "
@@ -105,8 +116,12 @@ struct _CamelSaslGssapiPrivate {
        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,
@@ -186,7 +201,7 @@ sasl_gssapi_finalize (GObject *object)
 /* DBUS Specific code */
 
 static gboolean
-send_dbus_message (gchar *name)
+send_dbus_message (const gchar *name)
 {
        gint success = FALSE;
        GError *error = NULL;
@@ -218,18 +233,27 @@ send_dbus_message (gchar *name)
        /* 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);
@@ -241,11 +265,14 @@ send_dbus_message (gchar *name)
 /* 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;
@@ -257,22 +284,39 @@ sasl_gssapi_challenge (CamelSasl *sasl,
        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);
@@ -281,7 +325,7 @@ sasl_gssapi_challenge (CamelSasl *sasl,
 
                if (major != GSS_S_COMPLETE) {
                        gssapi_set_exception (major, minor, error);
-                       return NULL;
+                       goto exit;
                }
 
                input_token = GSS_C_NO_BUFFER;
@@ -294,7 +338,7 @@ sasl_gssapi_challenge (CamelSasl *sasl,
                                error, CAMEL_SERVICE_ERROR,
                                CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
                                _("Bad authentication response from server."));
-                       return NULL;
+                       goto exit;
                }
 
                inbuf.value = token->data;
@@ -316,14 +360,14 @@ sasl_gssapi_challenge (CamelSasl *sasl,
                        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 ();
@@ -338,7 +382,7 @@ sasl_gssapi_challenge (CamelSasl *sasl,
                                error, CAMEL_SERVICE_ERROR,
                                CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
                                _("Bad authentication response from server."));
-                       return NULL;
+                       goto exit;
                }
 
                inbuf.value = token->data;
@@ -347,7 +391,7 @@ sasl_gssapi_challenge (CamelSasl *sasl,
                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) {
@@ -358,7 +402,7 @@ sasl_gssapi_challenge (CamelSasl *sasl,
 #ifndef HAVE_HEIMDAL_KRB5
                        gss_release_buffer (&minor, &outbuf);
 #endif
-                       return NULL;
+                       goto exit;
                }
 
                /* check that our desired security layer is supported */
@@ -370,14 +414,14 @@ sasl_gssapi_challenge (CamelSasl *sasl,
 #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);
@@ -387,7 +431,7 @@ sasl_gssapi_challenge (CamelSasl *sasl,
                if (major != GSS_S_COMPLETE) {
                        gssapi_set_exception (major, minor, error);
                        g_free (str);
-                       return NULL;
+                       goto exit;
                }
 
                g_free (str);
@@ -403,15 +447,22 @@ sasl_gssapi_challenge (CamelSasl *sasl,
                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;
 
@@ -421,17 +472,18 @@ camel_sasl_gssapi_class_init (CamelSaslGssapiClass *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 */
+}