[Evolution-hackers] [PATCH 2/3] Add asynchronous camel_sasl_try_empty_password()
--- camel/camel-sasl.c | 49 + camel/camel-sasl.h |8 2 files changed, 57 insertions(+), 0 deletions(-) diff --git a/camel/camel-sasl.c b/camel/camel-sasl.c index 58a4a2b..90b64d6 100644 --- a/camel/camel-sasl.c +++ b/camel/camel-sasl.c @@ -288,6 +288,53 @@ sasl_challenge_finish (CamelSasl *sasl, } static void +sasl_try_empty_password_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + gboolean res; + + res = camel_sasl_try_empty_password_sync (CAMEL_SASL (object), cancellable); + + g_simple_async_result_set_op_res_gboolean (simple, res); +} + +static void +sasl_try_empty_password (CamelSasl *sasl, +gint io_priority, +GCancellable *cancellable, +GAsyncReadyCallback callback, +gpointer user_data) +{ + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new ( + G_OBJECT (sasl), callback, user_data, sasl_try_empty_password); + + g_simple_async_result_run_in_thread ( + simple, sasl_try_empty_password_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +sasl_try_empty_password_finish (CamelSasl *sasl, + GAsyncResult *result) +{ + GSimpleAsyncResult *simple; + gboolean res; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (sasl), sasl_try_empty_password), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + res = g_simple_async_result_get_op_res_gboolean (simple); + + return res; +} + +static void camel_sasl_class_init (CamelSaslClass *class) { GObjectClass *object_class; @@ -302,6 +349,8 @@ camel_sasl_class_init (CamelSaslClass *class) class-challenge = sasl_challenge; class-challenge_finish = sasl_challenge_finish; + class-try_empty_password = sasl_try_empty_password; + class-try_empty_password_finish = sasl_try_empty_password_finish; g_object_class_install_property ( object_class, diff --git a/camel/camel-sasl.h b/camel/camel-sasl.h index eede608..4ef9b41 100644 --- a/camel/camel-sasl.h +++ b/camel/camel-sasl.h @@ -82,6 +82,14 @@ struct _CamelSaslClass { GByteArray *(*challenge_finish) (CamelSasl *sasl, GAsyncResult *result, GError **error); + void(*try_empty_password) (CamelSasl *sasl, +gint io_priority, +GCancellable *cancellable, +GAsyncReadyCallback callback, +gpointer user_data); + gboolean(*try_empty_password_finish) + (CamelSasl *sasl, +GAsyncResult *result); }; GType camel_sasl_get_type (void); -- 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
[Evolution-hackers] [PATCH 1/3] Add camel_sasl_try_empty_password_sync() method.
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, -
[Evolution-hackers] [PATCH 3/3] Add support for NTLM single-sign-on using /usr/bin/ntlm_auth
There's a simple test version of ntlm_auth at http://david.woodhou.se/ntlm_auth_v2.c --- camel/camel-sasl-ntlm.c | 134 +++ 1 files changed, 134 insertions(+), 0 deletions(-) diff --git a/camel/camel-sasl-ntlm.c b/camel/camel-sasl-ntlm.c index a24c837..61b9cc3 100644 --- a/camel/camel-sasl-ntlm.c +++ b/camel/camel-sasl-ntlm.c @@ -28,9 +28,14 @@ #include glib/gi18n-lib.h #include camel-sasl-ntlm.h +#include camel-stream-process.h struct _CamelSaslNTLMPrivate { gint placeholder; /* allow for future expansion */ +#ifndef G_OS_WIN32 + CamelStream *helper_stream; + gchar *type1_msg; +#endif }; CamelServiceAuthType camel_sasl_ntlm_authtype = { @@ -61,6 +66,8 @@ G_DEFINE_TYPE (CamelSaslNTLM, camel_sasl_ntlm, CAMEL_TYPE_SASL) #define NTLM_RESPONSE_HOST_OFFSET44 #define NTLM_RESPONSE_FLAGS_OFFSET 60 +#define NTLM_AUTH_HELPER /usr/bin/ntlm_auth + static void ntlm_calc_response (const guchar key[21], const guchar plaintext[8], guchar results[24]); @@ -661,6 +668,10 @@ sasl_ntlm_challenge_sync (CamelSasl *sasl, GCancellable *cancellable, GError **error) { +#ifndef G_OS_WIN32 + CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (sasl); + CamelSaslNTLMPrivate *priv = ntlm-priv; +#endif CamelService *service; GByteArray *ret; gchar *user; @@ -671,6 +682,49 @@ sasl_ntlm_challenge_sync (CamelSasl *sasl, ret = g_byte_array_new (); +#ifndef G_OS_WIN32 + if (priv-helper_stream !service-url-passwd) { + guchar *data; + gsize length = 0; + char buf[1024]; + gsize s = 0; + buf [0] = 0; + + if (!token || !token-len) { + if (priv-type1_msg) { + data = g_base64_decode (priv-type1_msg, length); + g_byte_array_append (ret, data, length); + g_free (data); + g_free (priv-type1_msg); + priv-type1_msg = NULL; + } + return ret; + } else { + gchar *type2 = g_base64_encode (token-data, token-len); + if (camel_stream_printf (priv-helper_stream, TT %s\n, +type2) = 0 + (s = camel_stream_read (priv-helper_stream, buf, + sizeof(buf), cancellable, NULL)) 4 + buf[0] == 'K' buf[1] == 'K' buf[2] == ' ' + buf[s-1] == '\n') { + data = g_base64_decode (buf + 3, length); + g_byte_array_append (ret, data, length); + g_free (data); + } else + g_warning (Didn't get valid response from ntlm_auth helper); + + g_free (type2); + } + /* On failure, we just return an empty string. Setting the + GError would cause the providers to abort the whole + connection, and we want them to ask the user for a password + and continue. */ + g_object_unref (priv-helper_stream); + priv-helper_stream = NULL; + return ret; + } +#endif + if (!token || token-len NTLM_CHALLENGE_NONCE_OFFSET + 8) goto fail; @@ -768,15 +822,95 @@ exit: return ret; } +static gboolean sasl_ntlm_try_empty_password_sync (CamelSasl *sasl, GCancellable *cancellable) +{ +#ifndef G_OS_WIN32 + CamelStream *stream = camel_stream_process_new (); + CamelService *service = camel_sasl_get_service (sasl); + CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (sasl); + CamelSaslNTLMPrivate *priv = ntlm-priv; + gchar *user; + gchar buf[1024]; + gsize s; + gchar *command; + int ret; + + if (access (NTLM_AUTH_HELPER, X_OK)) + return FALSE; + + user = strchr (service-url-user, '\\'); + if (user) { + command = g_strdup_printf (%s --helper-protocol ntlmssp-client-1 + --use-cached-creds --username '%s' + --domain '%.*s', NTLM_AUTH_HELPER, + user + 1, (int)(user - service-url-user), + service-url-user); + } else { + command = g_strdup_printf (%s --helper-protocol ntlmssp-client-1 + --use-cached-creds --username '%s', + NTLM_AUTH_HELPER, service-url-user); + } + ret =