[Evolution-hackers] [PATCH 2/3] Add asynchronous camel_sasl_try_empty_password()

2011-04-03 Thread David Woodhouse
---
 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.

2011-04-03 Thread David Woodhouse
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

2011-04-03 Thread David Woodhouse
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 =