This indicates that a SASL method with the need_password flag can be tried
without providing a password, for single-sign-on using system credentials.

This will be used by NTLM.
---
 camel/camel-sasl.c                          |   25 ++++++++++
 camel/camel-sasl.h                          |    6 +++
 camel/providers/imap/camel-imap-store.c     |   51 +++++++++++++++------
 camel/providers/imapx/camel-imapx-server.c  |   31 +++++++++++--
 camel/providers/smtp/camel-smtp-transport.c |   65 ++++++++++++++-------------
 5 files changed, 128 insertions(+), 50 deletions(-)

diff --git a/camel/camel-sasl.c b/camel/camel-sasl.c
index 02006c6..58a4a2b 100644
--- a/camel/camel-sasl.c
+++ b/camel/camel-sasl.c
@@ -419,6 +419,31 @@ camel_sasl_get_authenticated (CamelSasl *sasl)
 }
 
 /**
+ * camel_sasl_try_empty_password_sync:
+ * @sasl: a #CamelSasl object
+ *
+ * Returns: whether or not @sasl can attempt to authenticate without a
+ * password being provided by the caller. This will be %TRUE for an
+ * authentication method which can attempt to use single-sign-on
+ * credentials, but which can fall back to using a provided password
+ * so it still has the @need_password flag set in its description.
+ **/
+gboolean
+camel_sasl_try_empty_password_sync (CamelSasl *sasl, GCancellable *cancellable)
+{
+       CamelSaslClass *class;
+
+       g_return_val_if_fail (CAMEL_IS_SASL (sasl), FALSE);
+
+       class = CAMEL_SASL_GET_CLASS (sasl);
+
+       if (class->try_empty_password_sync == NULL)
+               return FALSE;
+
+       return class->try_empty_password_sync (sasl, cancellable);
+}
+
+/**
  * camel_sasl_set_authenticated:
  * @sasl: a #CamelSasl
  * @authenticated: whether we have successfully authenticated
diff --git a/camel/camel-sasl.h b/camel/camel-sasl.h
index 3bb3a84..eede608 100644
--- a/camel/camel-sasl.h
+++ b/camel/camel-sasl.h
@@ -64,6 +64,9 @@ struct _CamelSaslClass {
        CamelObjectClass parent_class;
 
        /* Synchronous I/O Methods */
+       gboolean        (*try_empty_password_sync)
+                                               (CamelSasl *sasl,
+                                                GCancellable *cancellable);
        GByteArray *    (*challenge_sync)       (CamelSasl *sasl,
                                                 GByteArray *token,
                                                 GCancellable *cancellable,
@@ -85,6 +88,9 @@ GType         camel_sasl_get_type             (void);
 CamelSasl *    camel_sasl_new                  (const gchar *service_name,
                                                 const gchar *mechanism,
                                                 CamelService *service);
+gboolean       camel_sasl_try_empty_password_sync
+                                               (CamelSasl *sasl,
+                                                GCancellable *cancellable);
 gboolean       camel_sasl_get_authenticated    (CamelSasl *sasl);
 void           camel_sasl_set_authenticated    (CamelSasl *sasl,
                                                 gboolean authenticated);
diff --git a/camel/providers/imap/camel-imap-store.c 
b/camel/providers/imap/camel-imap-store.c
index 521a185..9fa53ee 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -653,20 +653,23 @@ connect_to_server_wrapper (CamelService *service,
 
 static gboolean
 try_auth (CamelImapStore *store,
-          const gchar *mech,
+          CamelSasl *sasl,
           GCancellable *cancellable,
           GError **error)
 {
-       CamelSasl *sasl;
+       CamelService *service = CAMEL_SERVICE (store);
        CamelImapResponse *response;
        gchar *resp;
        gchar *sasl_resp;
 
-       response = camel_imap_command (store, NULL, cancellable, error, 
"AUTHENTICATE %s", mech);
-       if (!response)
+       response = camel_imap_command (store, NULL, cancellable, error,
+                                      "AUTHENTICATE %s",
+                                      service->url->authmech);
+       if (!response) {
+               g_object_unref (sasl);
                return FALSE;
+       }
 
-       sasl = camel_sasl_new ("imap", mech, CAMEL_SERVICE (store));
        while (!camel_sasl_get_authenticated (sasl)) {
                resp = camel_imap_response_extract_continuation (store, 
response, error);
                if (!resp)
@@ -718,6 +721,7 @@ imap_auth_loop (CamelService *service,
        CamelSession *session = camel_service_get_session (service);
        CamelServiceAuthType *authtype = NULL;
        CamelImapResponse *response;
+       CamelSasl *sasl = NULL;
        gchar *errbuf = NULL;
        gboolean authenticated = FALSE;
        const gchar *auth_domain;
@@ -754,12 +758,22 @@ imap_auth_loop (CamelService *service,
                        return FALSE;
                }
 
-               if (!authtype->need_password) {
-                       authenticated = try_auth (
-                               store, authtype->authproto,
-                               cancellable, error);
-                       if (!authenticated)
+               sasl = camel_sasl_new ("imap", service->url->authmech,
+                                      CAMEL_SERVICE (store));
+               if (!sasl) {
+               nosasl:
+                       g_set_error (
+                                    error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                                    _("Error creating SASL authentication 
object."));
+                       return FALSE;
+               }
+
+               if (!authtype->need_password ||
+                   camel_sasl_try_empty_password_sync (sasl, cancellable)) {
+                       authenticated = try_auth (store, sasl, cancellable, 
error);
+                       if (!authenticated && !authtype->need_password)
                                return FALSE;
+                       sasl = NULL;
                }
        }
 
@@ -799,6 +813,8 @@ imap_auth_loop (CamelService *service,
                                        error, G_IO_ERROR,
                                        G_IO_ERROR_CANCELLED,
                                        _("You did not enter a password."));
+                               if (sasl)
+                                       g_object_unref (sasl);
                                return FALSE;
                        }
                }
@@ -811,11 +827,16 @@ imap_auth_loop (CamelService *service,
                                return FALSE;
                }
 
-               if (authtype)
-                       authenticated = try_auth (
-                               store, authtype->authproto,
-                               cancellable, &local_error);
-               else {
+               if (authtype) {
+                       if (!sasl)
+                               sasl = camel_sasl_new ("imap", 
service->url->authmech,
+                                                      CAMEL_SERVICE (store));
+                       if (!sasl)
+                               goto nosasl;
+                       authenticated = try_auth (store, sasl, cancellable,
+                                                 &local_error);
+                       sasl = NULL;
+               } else {
                        response = camel_imap_command (store, NULL, 
cancellable, &local_error,
                                                       "LOGIN %S %S",
                                                       service->url->user,
diff --git a/camel/providers/imapx/camel-imapx-server.c 
b/camel/providers/imapx/camel-imapx-server.c
index 2c73fb9..08a6e4d 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -3010,7 +3010,6 @@ imapx_reconnect (CamelIMAPXServer *is,
                  GCancellable *cancellable,
                  GError **error)
 {
-       CamelSasl *sasl;
        CamelIMAPXCommand *ic;
        gchar *errbuf = NULL;
        CamelService *service = (CamelService *) is->store;
@@ -3018,9 +3017,17 @@ imapx_reconnect (CamelIMAPXServer *is,
        gboolean authenticated = FALSE;
        CamelServiceAuthType *authtype = NULL;
        guint32 prompt_flags = CAMEL_SESSION_PASSWORD_SECRET;
+       gboolean need_password = FALSE;
 
        while (!authenticated) {
-               if (errbuf) {
+               CamelSasl *sasl = NULL;
+
+               if (authtype && authtype->need_password && !need_password) {
+                       /* We tried an empty password, but it didn't work */
+                       need_password = TRUE;
+                       g_free (errbuf);
+                       errbuf = NULL;
+               } else if (errbuf) {
                        /* We need to un-cache the password before prompting 
again */
                        prompt_flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
                        g_free (service->url->passwd);
@@ -3047,6 +3054,7 @@ imapx_reconnect (CamelIMAPXServer *is,
 
                        authtype = camel_sasl_authtype (service->url->authmech);
                        if (!authtype) {
+                       noauth:
                                g_set_error (
                                        error, CAMEL_SERVICE_ERROR,
                                        CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
@@ -3056,7 +3064,20 @@ imapx_reconnect (CamelIMAPXServer *is,
                        }
                }
 
-               if (service->url->passwd == NULL && (!authtype || 
authtype->need_password)) {
+               if (authtype) {
+                       sasl = camel_sasl_new ("imap", authtype->authproto, 
service);
+                       if (!sasl)
+                               goto noauth;
+
+                       /* If this is the *first* attempt, set 'need_password'
+                          as appropriate. */
+                       if (!need_password)
+                               need_password = authtype->need_password &&
+                                       !camel_sasl_try_empty_password_sync 
(sasl, cancellable);
+               } else
+                       need_password = TRUE;
+
+               if (need_password && service->url->passwd == NULL) {
                        gchar *base_prompt;
                        gchar *full_prompt;
 
@@ -3083,10 +3104,12 @@ imapx_reconnect (CamelIMAPXServer *is,
                                        error, G_IO_ERROR,
                                        G_IO_ERROR_CANCELLED,
                                        _("You did not enter a password."));
+                               if (sasl)
+                                       g_object_unref (sasl);
                                goto exception;
                        }
                }
-               if (authtype && (sasl = camel_sasl_new ("imap", 
authtype->authproto, service))) {
+               if (sasl) {
                        ic = camel_imapx_command_new (
                                is, "AUTHENTICATE", NULL, cancellable,
                                "AUTHENTICATE %A", sasl);
diff --git a/camel/providers/smtp/camel-smtp-transport.c 
b/camel/providers/smtp/camel-smtp-transport.c
index 27a04e2..fe05241 100644
--- a/camel/providers/smtp/camel-smtp-transport.c
+++ b/camel/providers/smtp/camel-smtp-transport.c
@@ -60,7 +60,7 @@ static gboolean               smtp_helo               
(CamelSmtpTransport *transport,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean                smtp_auth               (CamelSmtpTransport 
*transport,
-                                                const gchar *mech,
+                                                CamelSasl *sasl,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean                smtp_mail               (CamelSmtpTransport 
*transport,
@@ -368,6 +368,7 @@ smtp_connect_sync (CamelService *service,
                    GError **error)
 {
        CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
+       CamelSasl *sasl = NULL;
        gboolean has_authtypes;
 
        /* We (probably) need to check popb4smtp before we connect ... */
@@ -423,13 +424,23 @@ smtp_connect_sync (CamelService *service,
                        return FALSE;
                }
 
-               if (!authtype->need_password) {
-                       /* authentication mechanism doesn't need a password,
-                          so if it fails there's nothing we can do */
-                       authenticated = smtp_auth (
-                               transport, authtype->authproto,
-                               cancellable, error);
-                       if (!authenticated) {
+               sasl = camel_sasl_new ("smtp", service->url->authmech,
+                                      CAMEL_SERVICE (transport));
+
+               if (!sasl) {
+               nosasl:
+                       g_set_error (
+                                    error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                                    _("Error creating SASL authentication 
object."));
+                       camel_service_disconnect_sync (service, TRUE, NULL);
+                       return FALSE;
+               }
+               if (!authtype->need_password ||
+                   camel_sasl_try_empty_password_sync (sasl, cancellable)) {
+                       authenticated = smtp_auth (transport, sasl, 
cancellable, error);
+                       if (!authenticated && !authtype->need_password) {
+                               /* authentication mechanism doesn't need a 
password,
+                                  so if it fails there's nothing we can do */
                                camel_service_disconnect_sync (
                                        service, TRUE, NULL);
                                return FALSE;
@@ -444,6 +455,7 @@ smtp_connect_sync (CamelService *service,
 
                        if (errbuf) {
                                /* We need to un-cache the password before 
prompting again */
+                               password_flags |= 
CAMEL_SESSION_PASSWORD_REPROMPT;
                                g_free (service->url->passwd);
                                service->url->passwd = NULL;
                        }
@@ -475,10 +487,14 @@ smtp_connect_sync (CamelService *service,
                                        return FALSE;
                                }
                        }
-
-                       authenticated = smtp_auth (
-                               transport, authtype->authproto,
-                               cancellable, &local_error);
+                       if (!sasl)
+                               sasl = camel_sasl_new ("smtp", 
service->url->authmech,
+                                                      CAMEL_SERVICE 
(transport));
+                       if (!sasl)
+                               goto nosasl;
+
+                       authenticated = smtp_auth (transport, sasl, 
cancellable, &local_error);
+                       sasl = NULL;
                        if (!authenticated) {
                                if (g_cancellable_is_cancelled (cancellable) ||
                                    g_error_matches (local_error, 
CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE)) {
@@ -501,11 +517,6 @@ smtp_connect_sync (CamelService *service,
                                service->url->passwd = NULL;
                        }
 
-                       /* Force a password prompt on the next pass, in
-                        * case we have an invalid password cached.  This
-                        * avoids repeated authentication attempts using
-                        * the same invalid password. */
-                       password_flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
                }
        }
 
@@ -1136,36 +1147,28 @@ smtp_helo (CamelSmtpTransport *transport,
 
 static gboolean
 smtp_auth (CamelSmtpTransport *transport,
-           const gchar *mech,
+           CamelSasl *sasl,
            GCancellable *cancellable,
            GError **error)
 {
        CamelService *service;
        gchar *cmdbuf, *respbuf = NULL, *challenge;
        gboolean auth_challenge = FALSE;
-       CamelSasl *sasl = NULL;
 
        service = CAMEL_SERVICE (transport);
 
        camel_operation_push_message (cancellable, _("SMTP Authentication"));
 
-       sasl = camel_sasl_new ("smtp", mech, service);
-       if (!sasl) {
-               camel_operation_pop_message (cancellable);
-               g_set_error (
-                       error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-                       _("Error creating SASL authentication object."));
-               return FALSE;
-       }
-
        challenge = camel_sasl_challenge_base64_sync (
                sasl, NULL, cancellable, error);
        if (challenge) {
                auth_challenge = TRUE;
-               cmdbuf = g_strdup_printf ("AUTH %s %s\r\n", mech, challenge);
+               cmdbuf = g_strdup_printf ("AUTH %s %s\r\n",
+                                         service->url->authmech, challenge);
                g_free (challenge);
        } else {
-               cmdbuf = g_strdup_printf ("AUTH %s\r\n", mech);
+               cmdbuf = g_strdup_printf ("AUTH %s\r\n",
+                                         service->url->authmech);
        }
 
        d(fprintf (stderr, "sending : %s", cmdbuf));
@@ -1203,7 +1206,7 @@ smtp_auth (CamelSmtpTransport *transport,
                                   "authentication mechanism is broken. Please 
report this to the\n"
                                   "appropriate vendor and suggest that they 
re-read rfc2554 again\n"
                                   "for the first time (specifically Section 
4).\n",
-                                  mech));
+                                  service->url->authmech));
                }
 
                /* eat whtspc */
-- 
1.7.4



_______________________________________________
evolution-hackers mailing list
evolution-hackers@gnome.org
To change your list options or unsubscribe, visit ...
http://mail.gnome.org/mailman/listinfo/evolution-hackers

Reply via email to