[2/5] winhttp: Add support for basic authentication.

Hans Leidekker hans at codeweavers.com
Thu Apr 22 09:35:11 CDT 2010


---
 dlls/winhttp/request.c |  520 +++++++++++++++++++++++++++---------------------
 1 files changed, 290 insertions(+), 230 deletions(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index f2c48a8..7c1205c 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -1158,6 +1158,282 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD heade
     return ret;
 }
 
+#define ARRAYSIZE(array) (sizeof(array) / sizeof((array)[0]))
+
+static DWORD auth_scheme_from_header( WCHAR *header )
+{
+    static const WCHAR basic[]     = {'B','a','s','i','c'};
+    static const WCHAR ntlm[]      = {'N','T','L','M'};
+    static const WCHAR passport[]  = {'P','a','s','s','p','o','r','t'};
+    static const WCHAR digest[]    = {'D','i','g','e','s','t'};
+    static const WCHAR negotiate[] = {'N','e','g','o','t','i','a','t','e'};
+
+    if (!strncmpiW( header, basic, ARRAYSIZE(basic) ) &&
+        (header[ARRAYSIZE(basic)] == ' ' || !header[ARRAYSIZE(basic)])) return WINHTTP_AUTH_SCHEME_BASIC;
+
+    if (!strncmpiW( header, ntlm, ARRAYSIZE(ntlm) ) &&
+        (header[ARRAYSIZE(ntlm)] == ' ' || !header[ARRAYSIZE(ntlm)])) return WINHTTP_AUTH_SCHEME_NTLM;
+
+    if (!strncmpiW( header, passport, ARRAYSIZE(passport) ) &&
+        (header[ARRAYSIZE(passport)] == ' ' || !header[ARRAYSIZE(passport)])) return WINHTTP_AUTH_SCHEME_PASSPORT;
+
+    if (!strncmpiW( header, digest, ARRAYSIZE(digest) ) &&
+        (header[ARRAYSIZE(digest)] == ' ' || !header[ARRAYSIZE(digest)])) return WINHTTP_AUTH_SCHEME_DIGEST;
+
+    if (!strncmpiW( header, negotiate, ARRAYSIZE(negotiate) ) &&
+        (header[ARRAYSIZE(negotiate)] == ' ' || !header[ARRAYSIZE(negotiate)])) return WINHTTP_AUTH_SCHEME_NEGOTIATE;
+
+    return 0;
+}
+
+static BOOL query_auth_schemes( request_t *request, DWORD level, LPDWORD supported, LPDWORD first )
+{
+    DWORD index = 0;
+    BOOL ret = FALSE;
+
+    for (;;)
+    {
+        WCHAR *buffer;
+        DWORD size, scheme;
+
+        size = 0;
+        query_headers( request, level, NULL, NULL, &size, &index );
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
+
+        index--;
+        if (!(buffer = heap_alloc( size ))) return FALSE;
+        if (!query_headers( request, level, NULL, buffer, &size, &index ))
+        {
+            heap_free( buffer );
+            return FALSE;
+        }
+        scheme = auth_scheme_from_header( buffer );
+        if (first && index == 1) *first = scheme;
+        *supported |= scheme;
+
+        heap_free( buffer );
+        ret = TRUE;
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *          WinHttpQueryAuthSchemes (winhttp.@)
+ */
+BOOL WINAPI WinHttpQueryAuthSchemes( HINTERNET hrequest, LPDWORD supported, LPDWORD first, LPDWORD target )
+{
+    BOOL ret = FALSE;
+    request_t *request;
+
+    TRACE("%p, %p, %p, %p\n", hrequest, supported, first, target);
+
+    if (!(request = (request_t *)grab_object( hrequest )))
+    {
+        set_last_error( ERROR_INVALID_HANDLE );
+        return FALSE;
+    }
+    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
+    {
+        release_object( &request->hdr );
+        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
+        return FALSE;
+    }
+
+    if (query_auth_schemes( request, WINHTTP_QUERY_WWW_AUTHENTICATE, supported, first ))
+    {
+        *target = WINHTTP_AUTH_TARGET_SERVER;
+        ret = TRUE;
+    }
+    else if (query_auth_schemes( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, supported, first ))
+    {
+        *target = WINHTTP_AUTH_TARGET_PROXY;
+        ret = TRUE;
+    }
+
+    release_object( &request->hdr );
+    return ret;
+}
+
+static UINT encode_base64( const char *bin, unsigned int len, WCHAR *base64 )
+{
+    UINT n = 0, x;
+    static const char base64enc[] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+    while (len > 0)
+    {
+        /* first 6 bits, all from bin[0] */
+        base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
+        x = (bin[0] & 3) << 4;
+
+        /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
+        if (len == 1)
+        {
+            base64[n++] = base64enc[x];
+            base64[n++] = '=';
+            base64[n++] = '=';
+            break;
+        }
+        base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
+        x = (bin[1] & 0x0f) << 2;
+
+        /* next 6 bits 4 from bin[1] and 2 from bin[2] */
+        if (len == 2)
+        {
+            base64[n++] = base64enc[x];
+            base64[n++] = '=';
+            break;
+        }
+        base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
+
+        /* last 6 bits, all from bin [2] */
+        base64[n++] = base64enc[bin[2] & 0x3f];
+        bin += 3;
+        len -= 3;
+    }
+    base64[n] = 0;
+    return n;
+}
+
+static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme, LPCWSTR username, LPCWSTR password )
+{
+    static const WCHAR basic[] = {'B','a','s','i','c',' ',0};
+    const WCHAR *auth_scheme, *auth_target;
+    WCHAR *auth_header;
+    DWORD len, auth_data_len;
+    char *auth_data;
+    BOOL ret;
+
+    if (!username || !password)
+    {
+        set_last_error( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+
+    switch (target)
+    {
+    case WINHTTP_AUTH_TARGET_SERVER: auth_target = attr_authorization; break;
+    case WINHTTP_AUTH_TARGET_PROXY:  auth_target = attr_proxy_authorization; break;
+    default:
+        WARN("unknown target %x\n", target);
+        return FALSE;
+    }
+    switch (scheme)
+    {
+    case WINHTTP_AUTH_SCHEME_BASIC:
+    {
+        int userlen = WideCharToMultiByte( CP_UTF8, 0, username, strlenW( username ), NULL, 0, NULL, NULL );
+        int passlen = WideCharToMultiByte( CP_UTF8, 0, password, strlenW( password ), NULL, 0, NULL, NULL );
+
+        TRACE("basic authentication\n");
+
+        auth_scheme = basic;
+        auth_data_len = userlen + 1 + passlen;
+        if (!(auth_data = heap_alloc( auth_data_len ))) return FALSE;
+
+        WideCharToMultiByte( CP_UTF8, 0, username, -1, auth_data, userlen, NULL, NULL );
+        auth_data[userlen] = ':';
+        WideCharToMultiByte( CP_UTF8, 0, password, -1, auth_data + userlen + 1, passlen, NULL, NULL );
+        break;
+    }
+    case WINHTTP_AUTH_SCHEME_NTLM:
+    case WINHTTP_AUTH_SCHEME_PASSPORT:
+    case WINHTTP_AUTH_SCHEME_DIGEST:
+    case WINHTTP_AUTH_SCHEME_NEGOTIATE:
+        FIXME("unimplemented authentication scheme %x\n", scheme);
+        return FALSE;
+    default:
+        WARN("unknown authentication scheme %x\n", scheme);
+        return FALSE;
+    }
+
+    len = strlenW( auth_scheme ) + ((auth_data_len + 2) * 4) / 3;
+    if (!(auth_header = heap_alloc( (len + 1) * sizeof(WCHAR) )))
+    {
+        heap_free( auth_data );
+        return FALSE;
+    }
+    strcpyW( auth_header, auth_scheme );
+    encode_base64( auth_data, auth_data_len, auth_header + strlenW( auth_header ) );
+
+    ret = process_header( request, auth_target, auth_header, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, TRUE );
+
+    heap_free( auth_data );
+    heap_free( auth_header );
+    return ret;
+}
+
+/***********************************************************************
+ *          WinHttpSetCredentials (winhttp.@)
+ */
+BOOL WINAPI WinHttpSetCredentials( HINTERNET hrequest, DWORD target, DWORD scheme, LPCWSTR username,
+                                   LPCWSTR password, LPVOID params )
+{
+    BOOL ret;
+    request_t *request;
+
+    TRACE("%p, %x, 0x%08x, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params);
+
+    if (!(request = (request_t *)grab_object( hrequest )))
+    {
+        set_last_error( ERROR_INVALID_HANDLE );
+        return FALSE;
+    }
+    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
+    {
+        release_object( &request->hdr );
+        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
+        return FALSE;
+    }
+
+    ret = set_credentials( request, target, scheme, username, password );
+
+    release_object( &request->hdr );
+    return ret;
+}
+
+static BOOL handle_authorization( request_t *request, DWORD status )
+{
+    DWORD schemes, level, target;
+    const WCHAR *username, *password;
+
+    switch (status)
+    {
+    case 401:
+        target = WINHTTP_AUTH_TARGET_SERVER;
+        level  = WINHTTP_QUERY_WWW_AUTHENTICATE;
+        break;
+
+    case 407:
+        target = WINHTTP_AUTH_TARGET_PROXY;
+        level  = WINHTTP_QUERY_PROXY_AUTHENTICATE;
+        break;
+
+    default:
+        WARN("unhandled status %u\n", status);
+        return FALSE;
+    }
+
+    if (!query_auth_schemes( request, level, &schemes, NULL )) return FALSE;
+
+    if (target == WINHTTP_AUTH_TARGET_SERVER)
+    {
+        username = request->connect->username;
+        password = request->connect->password;
+    }
+    else
+    {
+        username = request->connect->session->proxy_username;
+        password = request->connect->session->proxy_password;
+    }
+
+    if (schemes & WINHTTP_AUTH_SCHEME_BASIC)
+        return set_credentials( request, target, WINHTTP_AUTH_SCHEME_BASIC, username, password );
+
+    FIXME("unsupported authentication scheme\n");
+    return FALSE;
+}
+
 static void clear_response_headers( request_t *request )
 {
     unsigned int i;
@@ -1577,7 +1853,20 @@ static BOOL receive_response( request_t *request, BOOL async )
             ret = send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE ); /* recurse synchronously */
             continue;
         }
-        if (status == 401) FIXME("authentication not supported\n");
+        else if (status == 401 || status == 407)
+        {
+            if (request->hdr.disable_flags & WINHTTP_DISABLE_AUTHENTICATION) break;
+
+            drain_content( request );
+            if (!handle_authorization( request, status ))
+            {
+                ret = TRUE;
+                break;
+            }
+            clear_response_headers( request );
+            ret = send_request( request, NULL, 0, NULL, 0, 0, 0, FALSE );
+            continue;
+        }
         break;
     }
 
@@ -1848,232 +2137,3 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write
     release_object( &request->hdr );
     return ret;
 }
-
-#define ARRAYSIZE(array) (sizeof(array) / sizeof((array)[0]))
-
-static DWORD auth_scheme_from_header( WCHAR *header )
-{
-    static const WCHAR basic[]     = {'B','a','s','i','c'};
-    static const WCHAR ntlm[]      = {'N','T','L','M'};
-    static const WCHAR passport[]  = {'P','a','s','s','p','o','r','t'};
-    static const WCHAR digest[]    = {'D','i','g','e','s','t'};
-    static const WCHAR negotiate[] = {'N','e','g','o','t','i','a','t','e'};
-
-    if (!strncmpiW( header, basic, ARRAYSIZE(basic) ) &&
-        (header[ARRAYSIZE(basic)] == ' ' || !header[ARRAYSIZE(basic)])) return WINHTTP_AUTH_SCHEME_BASIC;
-
-    if (!strncmpiW( header, ntlm, ARRAYSIZE(ntlm) ) &&
-        (header[ARRAYSIZE(ntlm)] == ' ' || !header[ARRAYSIZE(ntlm)])) return WINHTTP_AUTH_SCHEME_NTLM;
-
-    if (!strncmpiW( header, passport, ARRAYSIZE(passport) ) &&
-        (header[ARRAYSIZE(passport)] == ' ' || !header[ARRAYSIZE(passport)])) return WINHTTP_AUTH_SCHEME_PASSPORT;
-
-    if (!strncmpiW( header, digest, ARRAYSIZE(digest) ) &&
-        (header[ARRAYSIZE(digest)] == ' ' || !header[ARRAYSIZE(digest)])) return WINHTTP_AUTH_SCHEME_DIGEST;
-
-    if (!strncmpiW( header, negotiate, ARRAYSIZE(negotiate) ) &&
-        (header[ARRAYSIZE(negotiate)] == ' ' || !header[ARRAYSIZE(negotiate)])) return WINHTTP_AUTH_SCHEME_NEGOTIATE;
-
-    return 0;
-}
-
-static BOOL query_auth_schemes( request_t *request, DWORD level, LPDWORD supported, LPDWORD first )
-{
-    DWORD index = 0;
-    BOOL ret = FALSE;
-
-    for (;;)
-    {
-        WCHAR *buffer;
-        DWORD size, scheme;
-
-        size = 0;
-        query_headers( request, level, NULL, NULL, &size, &index );
-        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
-
-        index--;
-        if (!(buffer = heap_alloc( size ))) return FALSE;
-        if (!query_headers( request, level, NULL, buffer, &size, &index ))
-        {
-            heap_free( buffer );
-            return FALSE;
-        }
-        scheme = auth_scheme_from_header( buffer );
-        if (index == 1) *first = scheme;
-        *supported |= scheme;
-
-        heap_free( buffer );
-        ret = TRUE;
-    }
-    return ret;
-}
-
-/***********************************************************************
- *          WinHttpQueryAuthSchemes (winhttp.@)
- */
-BOOL WINAPI WinHttpQueryAuthSchemes( HINTERNET hrequest, LPDWORD supported, LPDWORD first, LPDWORD target )
-{
-    BOOL ret = FALSE;
-    request_t *request;
-
-    TRACE("%p, %p, %p, %p\n", hrequest, supported, first, target);
-
-    if (!(request = (request_t *)grab_object( hrequest )))
-    {
-        set_last_error( ERROR_INVALID_HANDLE );
-        return FALSE;
-    }
-    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
-    {
-        release_object( &request->hdr );
-        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
-        return FALSE;
-    }
-
-    if (query_auth_schemes( request, WINHTTP_QUERY_WWW_AUTHENTICATE, supported, first ))
-    {
-        *target = WINHTTP_AUTH_TARGET_SERVER;
-        ret = TRUE;
-    }
-    else if (query_auth_schemes( request, WINHTTP_QUERY_PROXY_AUTHENTICATE, supported, first ))
-    {
-        *target = WINHTTP_AUTH_TARGET_PROXY;
-        ret = TRUE;
-    }
-
-    release_object( &request->hdr );
-    return ret;
-}
-
-static UINT encode_base64( const char *bin, unsigned int len, WCHAR *base64 )
-{
-    UINT n = 0, x;
-    static const char base64enc[] =
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-    while (len > 0)
-    {
-        /* first 6 bits, all from bin[0] */
-        base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
-        x = (bin[0] & 3) << 4;
-
-        /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
-        if (len == 1)
-        {
-            base64[n++] = base64enc[x];
-            base64[n++] = '=';
-            base64[n++] = '=';
-            break;
-        }
-        base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
-        x = (bin[1] & 0x0f) << 2;
-
-        /* next 6 bits 4 from bin[1] and 2 from bin[2] */
-        if (len == 2)
-        {
-            base64[n++] = base64enc[x];
-            base64[n++] = '=';
-            break;
-        }
-        base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
-
-        /* last 6 bits, all from bin [2] */
-        base64[n++] = base64enc[bin[2] & 0x3f];
-        bin += 3;
-        len -= 3;
-    }
-    base64[n] = 0;
-    return n;
-}
-
-static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme, LPCWSTR username, LPCWSTR password )
-{
-    static const WCHAR basic[] = {'B','a','s','i','c',' ',0};
-
-    const WCHAR *auth_scheme, *auth_target;
-    WCHAR *auth_header;
-    DWORD len, auth_data_len;
-    char *auth_data;
-    BOOL ret;
-
-    switch (target)
-    {
-    case WINHTTP_AUTH_TARGET_SERVER: auth_target = attr_authorization; break;
-    case WINHTTP_AUTH_TARGET_PROXY:  auth_target = attr_proxy_authorization; break;
-    default:
-        WARN("unknown target %x\n", target);
-        return FALSE;
-    }
-    switch (scheme)
-    {
-    case WINHTTP_AUTH_SCHEME_BASIC:
-    {
-        int userlen = WideCharToMultiByte( CP_UTF8, 0, username, strlenW( username ), NULL, 0, NULL, NULL );
-        int passlen = WideCharToMultiByte( CP_UTF8, 0, password, strlenW( password ), NULL, 0, NULL, NULL );
-
-        TRACE("basic authentication\n");
-
-        auth_scheme = basic;
-        auth_data_len = userlen + 1 + passlen;
-        if (!(auth_data = heap_alloc( auth_data_len ))) return FALSE;
-
-        WideCharToMultiByte( CP_UTF8, 0, username, -1, auth_data, userlen, NULL, NULL );
-        auth_data[userlen] = ':';
-        WideCharToMultiByte( CP_UTF8, 0, password, -1, auth_data + userlen + 1, passlen, NULL, NULL );
-        break;
-    }
-    case WINHTTP_AUTH_SCHEME_NTLM:
-    case WINHTTP_AUTH_SCHEME_PASSPORT:
-    case WINHTTP_AUTH_SCHEME_DIGEST:
-    case WINHTTP_AUTH_SCHEME_NEGOTIATE:
-        FIXME("unimplemented authentication scheme %x\n", scheme);
-        return FALSE;
-    default:
-        WARN("unknown authentication scheme %x\n", scheme);
-        return FALSE;
-    }
-
-    len = strlenW( auth_scheme ) + ((auth_data_len + 2) * 4) / 3;
-    if (!(auth_header = heap_alloc( (len + 1) * sizeof(WCHAR) )))
-    {
-        heap_free( auth_data );
-        return FALSE;
-    }
-    strcpyW( auth_header, auth_scheme );
-    encode_base64( auth_data, auth_data_len, auth_header + strlenW( auth_header ) );
-
-    ret = process_header( request, auth_target, auth_header, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, TRUE );
-
-    heap_free( auth_data );
-    heap_free( auth_header );
-    return ret;
-}
-
-/***********************************************************************
- *          WinHttpSetCredentials (winhttp.@)
- */
-BOOL WINAPI WinHttpSetCredentials( HINTERNET hrequest, DWORD target, DWORD scheme, LPCWSTR username,
-                                   LPCWSTR password, LPVOID params )
-{
-    BOOL ret;
-    request_t *request;
-
-    TRACE("%p, %x, 0x%08x, %s, %p, %p\n", hrequest, target, scheme, debugstr_w(username), password, params);
-
-    if (!(request = (request_t *)grab_object( hrequest )))
-    {
-        set_last_error( ERROR_INVALID_HANDLE );
-        return FALSE;
-    }
-    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
-    {
-        release_object( &request->hdr );
-        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
-        return FALSE;
-    }
-
-    ret = set_credentials( request, target, scheme, username, password );
-
-    release_object( &request->hdr );
-    return ret;
-}
-- 
1.7.0.4







More information about the wine-patches mailing list