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_OFFSET 44 #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 = camel_stream_process_connect (CAMEL_STREAM_PROCESS (stream), command, NULL); + g_free (command); + if (ret) { + g_object_unref (stream); + return FALSE; + } + if (camel_stream_printf (stream, "YR\n") < 0) { + g_object_unref (stream); + return FALSE; + } + s = camel_stream_read (stream, buf, sizeof(buf), cancellable, NULL); + if (s < 4) { + g_object_unref (stream); + return FALSE; + } + if (buf[0] != 'Y' || buf[1] != 'R' || buf[2] != ' ' || buf[s-1] != '\n') { + g_object_unref (stream); + return FALSE; + } + + buf[s-1] = 0; + + priv->helper_stream = stream; + priv->type1_msg = g_strdup (buf + 3); + return TRUE; +#else + /* Win32 should be able to use SSPI here. */ + return FALSE; +#endif +} + +static void +sasl_ntlm_finalize (GObject *object) +{ +#ifndef G_OS_WIN32 + CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (object); + CamelSaslNTLMPrivate *priv = ntlm->priv; + + if (priv->type1_msg) + g_free (priv->type1_msg); + if (priv->helper_stream) + g_object_unref (priv->helper_stream); +#endif + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (camel_sasl_ntlm_parent_class)->finalize (object); +} + static void camel_sasl_ntlm_class_init (CamelSaslNTLMClass *class) { + GObjectClass *object_class; CamelSaslClass *sasl_class; g_type_class_add_private (class, sizeof (CamelSaslNTLMPrivate)); + object_class = G_OBJECT_CLASS (class); + object_class->finalize = sasl_ntlm_finalize; + sasl_class = CAMEL_SASL_CLASS (class); sasl_class->challenge_sync = sasl_ntlm_challenge_sync; + sasl_class->try_empty_password_sync = sasl_ntlm_try_empty_password_sync; } static 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