SoupAuthManagerNTLM: allow non-ASCII usernames/passwords
authorDan Winship <danw@gnome.org>
Thu, 20 Oct 2011 21:27:34 +0000 (17:27 -0400)
committerDan Winship <danw@gnome.org>
Sun, 13 Nov 2011 20:11:57 +0000 (15:11 -0500)
Switch to using the Unicode-encoded form of NTLM, so that non-ASCII
usernames/passwords will work.

Also, add a "-n" option to tests/get to make it use NTLM, and make
SoupAuthManagerNTLM allow passwords-in-URLs.

Based on a patch from Joachim Breitner, sponsored by ITOMIG GmbH and
the City of Böblingen.

https://bugzilla.gnome.org/show_bug.cgi?id=576838

libsoup/soup-auth-manager-ntlm.c
tests/get.c
tests/ntlm-test.c

index 7c3f239..a1b76c7 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <ctype.h>
 #include <string.h>
+#include <glib.h>
 
 #ifdef USE_NTLM_AUTH
 #include <stdlib.h>
@@ -387,6 +388,7 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
                SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
        SoupNTLMConnection *conn;
        const char *val;
+       SoupURI *uri;
 
        conn = get_connection_for_msg (priv, msg);
        if (!conn)
@@ -423,8 +425,14 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
        }
 #endif
        conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
-       soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm), msg,
-                                            conn->auth, FALSE);
+
+       uri = soup_message_get_uri (msg);
+       if (uri->password)
+               soup_auth_authenticate (conn->auth, uri->user, uri->password);
+       else {
+               soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm),
+                                                    msg, conn->auth, FALSE);
+       }
 
  done:
        /* Remove the WWW-Authenticate headers so the session won't try
@@ -725,7 +733,7 @@ typedef struct {
 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
 
 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
-#define NTLM_RESPONSE_FLAGS 0x8202
+#define NTLM_RESPONSE_FLAGS 0x8201
 
 typedef struct {
         guchar     header[12];
@@ -751,7 +759,7 @@ ntlm_set_string (NTLMString *string, int *offset, int len)
 static char *
 soup_ntlm_request (void)
 {
-       return g_strdup ("NTLM TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
+       return g_strdup ("NTLM TlRMTVNTUAABAAAABYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
 }
 
 static gboolean
@@ -783,7 +791,9 @@ soup_ntlm_parse_challenge (const char *challenge,
                        return FALSE;
                }
 
-               *default_domain = g_strndup ((char *)chall + domain.offset, domain.length);
+               *default_domain = g_convert ((char *)chall + domain.offset,
+                                            domain.length, "UTF-8", "UCS-2LE",
+                                            NULL, NULL, NULL);
        }
 
        if (nonce) {
@@ -802,8 +812,10 @@ soup_ntlm_response (const char *nonce,
                    const char *host, 
                    const char *domain)
 {
-       int hlen, dlen, ulen, offset;
+       int offset;
+       gsize hlen, dlen, ulen;
        guchar hash[21], lm_resp[24], nt_resp[24];
+       char *user_conv, *host_conv, *domain_conv;
        NTLMResponse resp;
        char *out, *p;
        int state, save;
@@ -819,13 +831,15 @@ soup_ntlm_response (const char *nonce,
 
        offset = sizeof (resp);
 
-       dlen = strlen (domain);
-       ntlm_set_string (&resp.domain, &offset, dlen);
-       ulen = strlen (user);
-       ntlm_set_string (&resp.user, &offset, ulen);
        if (!host)
                host = "UNKNOWN";
-       hlen = strlen (host);
+
+       domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
+       user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
+       host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
+
+       ntlm_set_string (&resp.domain, &offset, dlen);
+       ntlm_set_string (&resp.user, &offset, ulen);
        ntlm_set_string (&resp.host, &offset, hlen);
        ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
        ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
@@ -838,11 +852,11 @@ soup_ntlm_response (const char *nonce,
 
        p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp), 
                                   FALSE, p, &state, &save);
-       p += g_base64_encode_step ((const guchar *) domain, dlen, 
+       p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
                                   FALSE, p, &state, &save);
-       p += g_base64_encode_step ((const guchar *) user, ulen, 
+       p += g_base64_encode_step ((const guchar *) user_conv, ulen,
                                   FALSE, p, &state, &save);
-       p += g_base64_encode_step ((const guchar *) host, hlen, 
+       p += g_base64_encode_step ((const guchar *) host_conv, hlen,
                                   FALSE, p, &state, &save);
        p += g_base64_encode_step (lm_resp, sizeof (lm_resp), 
                                   FALSE, p, &state, &save);
@@ -851,6 +865,10 @@ soup_ntlm_response (const char *nonce,
        p += g_base64_encode_close (FALSE, p, &state, &save);
        *p = '\0';
 
+       g_free (domain_conv);
+       g_free (user_conv);
+       g_free (host_conv);
+
        return out;
 }
 
index a226e31..55dd735 100644 (file)
@@ -105,14 +105,14 @@ main (int argc, char **argv)
 {
        const char *cafile = NULL, *url;
        SoupURI *proxy = NULL, *parsed;
-       gboolean synchronous = FALSE;
+       gboolean synchronous = FALSE, ntlm = FALSE;
        int opt;
 
        g_type_init ();
 
        method = SOUP_METHOD_GET;
 
-       while ((opt = getopt (argc, argv, "c:dhp:qs")) != -1) {
+       while ((opt = getopt (argc, argv, "c:dhnp:qs")) != -1) {
                switch (opt) {
                case 'c':
                        cafile = optarg;
@@ -127,6 +127,10 @@ main (int argc, char **argv)
                        debug = TRUE;
                        break;
 
+               case 'n':
+                       ntlm = TRUE;
+                       break;
+
                case 'p':
                        proxy = soup_uri_new (optarg);
                        if (!proxy) {
@@ -172,6 +176,7 @@ main (int argc, char **argv)
                        SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
                        SOUP_SESSION_USER_AGENT, "get ",
                        SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+                       SOUP_SESSION_USE_NTLM, ntlm,
                        NULL);
        } else {
                session = soup_session_async_new_with_options (
@@ -183,6 +188,7 @@ main (int argc, char **argv)
                        SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
                        SOUP_SESSION_USER_AGENT, "get ",
                        SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+                       SOUP_SESSION_USE_NTLM, ntlm,
                        NULL);
        }
 
index cd74b15..46ac46e 100644 (file)
@@ -41,7 +41,7 @@ typedef enum {
 
 #define NTLM_CHALLENGE "TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMAbwBtAAAAAAA="
 
-#define NTLM_RESPONSE_USER(response) ((response)[87] == 'h' ? NTLM_AUTHENTICATED_ALICE : NTLM_AUTHENTICATED_BOB)
+#define NTLM_RESPONSE_USER(response) ((response)[102] == 'E' ? NTLM_AUTHENTICATED_ALICE : NTLM_AUTHENTICATED_BOB)
 
 static void
 clear_state (gpointer connections, GObject *ex_connection)