[Evolution-hackers] [PATCH 1/3] Add camel_sasl_try_empty_password_sync() method.
- From: David Woodhouse <dwmw2 infradead org>
- To: evolution-hackers gnome org
- Subject: [Evolution-hackers] [PATCH 1/3] Add camel_sasl_try_empty_password_sync() method.
- Date: Mon, 04 Apr 2011 00:17:33 +0100
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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]