From cb28969c2aef28be6e6aa750a5efa5d3530c2da5 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Tue, 5 Jun 2007 19:49:58 +0100 Subject: [PATCH] wininet: Implement NTLM support for proxy authentication. --- dlls/wininet/http.c | 172 +++++++++++++++++----------------------- dlls/wininet/internet.h | 1 + 2 files changed, 75 insertions(+), 98 deletions(-) diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 97cc54bb07b..71f78008703 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -113,8 +113,6 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, INT index, BOOL Request); static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index); static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); -static BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr, - LPCWSTR username, LPCWSTR password ); static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); @@ -399,19 +397,6 @@ static void HTTP_ProcessHeaders( LPWININETHTTPREQW lpwhr ) } } -static void HTTP_AddProxyInfo( LPWININETHTTPREQW lpwhr ) -{ - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; - LPWININETAPPINFOW hIC = lpwhs->lpAppInfo; - - assert(lpwhs->hdr.htype == WH_HHTTPSESSION); - assert(hIC->hdr.htype == WH_HINIT); - - if (hIC && (hIC->lpszProxyUsername || hIC->lpszProxyPassword )) - HTTP_InsertProxyAuthorization(lpwhr, hIC->lpszProxyUsername, - hIC->lpszProxyPassword); -} - static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue ) { static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ @@ -419,12 +404,12 @@ static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue ) ((pszAuthValue[ARRAYSIZE(szBasic)] != ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); } -static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue ) +static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, + struct HttpAuthInfo **ppAuthInfo, + LPWSTR domain_and_username, LPWSTR password ) { SECURITY_STATUS sec_status; - struct HttpAuthInfo *pAuthInfo = lpwhr->pAuthInfo; - LPWSTR password = lpwhr->lpHttpSession->lpszPassword; - LPWSTR domain_and_username = lpwhr->lpHttpSession->lpszUserName; + struct HttpAuthInfo *pAuthInfo = *ppAuthInfo; BOOL first = FALSE; TRACE("%s\n", debugstr_w(pszAuthValue)); @@ -501,7 +486,7 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue return FALSE; } } - lpwhr->pAuthInfo = pAuthInfo; + *ppAuthInfo = pAuthInfo; } else if (pAuthInfo->finished) return FALSE; @@ -1190,99 +1175,41 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin ) } /*********************************************************************** - * HTTP_EncodeBasicAuth - * - * Encode the basic authentication string for HTTP 1.1 - */ -static LPWSTR HTTP_EncodeBasicAuth( LPCWSTR username, LPCWSTR password) -{ - UINT len; - char *in; - LPWSTR out; - static const WCHAR szBasic[] = {'B','a','s','i','c',' '}; /* Note: not nul-terminated */ - int userlen = WideCharToMultiByte(CP_UTF8, 0, username, lstrlenW(username), NULL, 0, NULL, NULL); - int passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); - - in = HeapAlloc( GetProcessHeap(), 0, userlen + 1 + passlen ); - if( !in ) - return NULL; - - len = ARRAYSIZE(szBasic) + - (lstrlenW( username ) + 1 + lstrlenW ( password ))*2 + 1 + 1; - out = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); - if( out ) - { - WideCharToMultiByte(CP_UTF8, 0, username, -1, in, userlen, NULL, NULL); - in[userlen] = ':'; - WideCharToMultiByte(CP_UTF8, 0, password, -1, &in[userlen+1], passlen, NULL, NULL); - memcpy( out, szBasic, sizeof(szBasic) ); - HTTP_EncodeBase64( in, userlen + 1 + passlen, &out[strlenW(out)] ); - } - HeapFree( GetProcessHeap(), 0, in ); - - return out; -} - -/*********************************************************************** - * HTTP_InsertProxyAuthorization - * - * Insert the basic authorization field in the request header - */ -static BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr, - LPCWSTR username, LPCWSTR password ) -{ - WCHAR *authorization = HTTP_EncodeBasicAuth( username, password ); - BOOL ret = TRUE; - - if (!authorization) - return FALSE; - - TRACE( "Inserting authorization: %s\n", debugstr_w( authorization ) ); - - HTTP_ProcessHeader(lpwhr, szProxy_Authorization, authorization, - HTTP_ADDHDR_FLAG_REPLACE|HTTP_ADDHDR_FLAG_REQ); - - HeapFree( GetProcessHeap(), 0, authorization ); - - return ret; -} - -/*********************************************************************** - * HTTP_InsertAuthorization + * HTTP_InsertAuthorizationForHeader * * Insert or delete the authorization field in the request header. */ -static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr ) +static BOOL HTTP_InsertAuthorizationForHeader( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) { WCHAR *authorization = NULL; - if (lpwhr->pAuthInfo && lpwhr->pAuthInfo->auth_data_len) + if (pAuthInfo && pAuthInfo->auth_data_len) { static const WCHAR wszSpace[] = {' ',0}; unsigned int len; /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */ - len = strlenW(lpwhr->pAuthInfo->scheme)+1+((lpwhr->pAuthInfo->auth_data_len+2)*4)/3; + len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3; authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); if (!authorization) return FALSE; - strcpyW(authorization, lpwhr->pAuthInfo->scheme); + strcpyW(authorization, pAuthInfo->scheme); strcatW(authorization, wszSpace); - HTTP_EncodeBase64(lpwhr->pAuthInfo->auth_data, - lpwhr->pAuthInfo->auth_data_len, + HTTP_EncodeBase64(pAuthInfo->auth_data, + pAuthInfo->auth_data_len, authorization+strlenW(authorization)); /* clear the data as it isn't valid now that it has been sent to the * server */ - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data); - lpwhr->pAuthInfo->auth_data = NULL; - lpwhr->pAuthInfo->auth_data_len = 0; + HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data); + pAuthInfo->auth_data = NULL; + pAuthInfo->auth_data_len = 0; } TRACE("Inserting authorization: %s\n", debugstr_w(authorization)); - HTTP_ProcessHeader(lpwhr, szAuthorization, authorization, + HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); HeapFree(GetProcessHeap(), 0, authorization); @@ -1290,6 +1217,26 @@ static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr ) return TRUE; } +/*********************************************************************** + * HTTP_InsertAuthorization + * + * Insert the authorization field in the request header + */ +static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr ) +{ + return HTTP_InsertAuthorizationForHeader(lpwhr, lpwhr->pAuthInfo, szAuthorization); +} + +/*********************************************************************** + * HTTP_InsertProxyAuthorization + * + * Insert the proxy authorization field in the request header + */ +static BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr ) +{ + return HTTP_InsertAuthorizationForHeader(lpwhr, lpwhr->pProxyAuthInfo, szProxy_Authorization); +} + /*********************************************************************** * HTTP_DealWithProxy */ @@ -2659,8 +2606,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE); HTTP_InsertAuthorization(lpwhr); - /* if there's a proxy username and password, add it to the headers */ - HTTP_AddProxyInfo(lpwhr); + HTTP_InsertProxyAuthorization(lpwhr); requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, FALSE); @@ -2697,6 +2643,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (bEndRequest) { DWORD dwBufferSize; + DWORD dwStatusCode; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); @@ -2722,13 +2669,16 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (lpwhr->dwContentLength == 0) HTTP_FinishedReading(lpwhr); + dwBufferSize = sizeof(dwStatusCode); + if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, + &dwStatusCode,&dwBufferSize,NULL)) + dwStatusCode = 0; + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess) { - DWORD dwCode,dwCodeLength=sizeof(DWORD); WCHAR szNewLocation[2048]; dwBufferSize=sizeof(szNewLocation); - if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) && - (dwCode==HTTP_STATUS_REDIRECT || dwCode==HTTP_STATUS_MOVED) && + if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) && HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) { HTTP_DrainContent(lpwhr); @@ -2745,16 +2695,32 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, } if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess) { - DWORD dwCode,dwCodeLength=sizeof(DWORD); WCHAR szAuthValue[2048]; dwBufferSize=2048; - if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) && - (dwCode == HTTP_STATUS_DENIED)) + if (dwStatusCode == HTTP_STATUS_DENIED) { DWORD dwIndex = 0; while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) { - if (HTTP_DoAuthorization(lpwhr, szAuthValue)) + if (HTTP_DoAuthorization(lpwhr, szAuthValue, + &lpwhr->pAuthInfo, + lpwhr->lpHttpSession->lpszUserName, + lpwhr->lpHttpSession->lpszPassword)) + { + loop_next = TRUE; + break; + } + } + } + if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) + { + DWORD dwIndex = 0; + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + { + if (HTTP_DoAuthorization(lpwhr, szAuthValue, + &lpwhr->pProxyAuthInfo, + lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername, + lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword)) { loop_next = TRUE; break; @@ -3349,6 +3315,16 @@ static VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr) HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo); lpwhr->pAuthInfo = NULL; } + if (lpwhr->pProxyAuthInfo) + { + DeleteSecurityContext(&lpwhr->pProxyAuthInfo->ctx); + FreeCredentialsHandle(&lpwhr->pProxyAuthInfo->cred); + + HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->auth_data); + HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->scheme); + HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo); + lpwhr->pProxyAuthInfo = NULL; + } lpwhs = lpwhr->lpHttpSession; hIC = lpwhs->lpAppInfo; diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 4bb7a883bb1..76d98f184dd 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -202,6 +202,7 @@ typedef struct HTTPHEADERW *pCustHeaders; DWORD nCustHeaders; struct HttpAuthInfo *pAuthInfo; + struct HttpAuthInfo *pProxyAuthInfo; } WININETHTTPREQW, *LPWININETHTTPREQW;