[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