Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1426 lines
46 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: inetsp.cpp
//
// Contents: Inet Scheme Provider for Remote Object Retrieval
//
// History: 06-Aug-97 kirtd Created
// 01-Jan-02 philh Moved from wininet to winhttp
//
//----------------------------------------------------------------------------
#include <global.hxx>
#include "cryptver.h"
#include <dbgdef.h>
//+---------------------------------------------------------------------------
//
// Function: InetRetrieveEncodedObject
//
// Synopsis: retrieve encoded object via HTTP, HTTPS protocols
//
//----------------------------------------------------------------------------
BOOL WINAPI InetRetrieveEncodedObject (
IN LPCWSTR pwszUrl,
IN LPCSTR pszObjectOid,
IN DWORD dwRetrievalFlags,
IN DWORD dwTimeout,
OUT PCRYPT_BLOB_ARRAY pObject,
OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
OUT LPVOID* ppvFreeContext,
IN HCRYPTASYNC hAsyncRetrieve,
IN PCRYPT_CREDENTIALS pCredentials,
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
BOOL fResult;
IObjectRetriever* por = NULL;
if ( !( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) )
{
por = new CInetSynchronousRetriever;
}
if ( por == NULL )
{
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
fResult = por->RetrieveObjectByUrl(
pwszUrl,
pszObjectOid,
dwRetrievalFlags,
dwTimeout,
(LPVOID *)pObject,
ppfnFreeObject,
ppvFreeContext,
hAsyncRetrieve,
pCredentials,
NULL,
pAuxInfo
);
por->Release();
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: InetFreeEncodedObject
//
// Synopsis: free encoded object retrieved via InetRetrieveEncodedObject
//
//----------------------------------------------------------------------------
VOID WINAPI InetFreeEncodedObject (
IN LPCSTR pszObjectOid,
IN PCRYPT_BLOB_ARRAY pObject,
IN LPVOID pvFreeContext
)
{
assert( pvFreeContext == NULL );
InetFreeCryptBlobArray( pObject );
}
//+---------------------------------------------------------------------------
//
// Function: InetCancelAsyncRetrieval
//
// Synopsis: cancel asynchronous object retrieval
//
//----------------------------------------------------------------------------
BOOL WINAPI InetCancelAsyncRetrieval (
IN HCRYPTASYNC hAsyncRetrieve
)
{
SetLastError( (DWORD) E_NOTIMPL );
return( FALSE );
}
//+---------------------------------------------------------------------------
//
// Member: CInetSynchronousRetriever::CInetSynchronousRetriever, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CInetSynchronousRetriever::CInetSynchronousRetriever ()
{
m_cRefs = 1;
}
//+---------------------------------------------------------------------------
//
// Member: CInetSynchronousRetriever::~CInetSynchronousRetriever, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CInetSynchronousRetriever::~CInetSynchronousRetriever ()
{
}
//+---------------------------------------------------------------------------
//
// Member: CInetSynchronousRetriever::AddRef, public
//
// Synopsis: IRefCountedObject::AddRef
//
//----------------------------------------------------------------------------
VOID
CInetSynchronousRetriever::AddRef ()
{
InterlockedIncrement( (LONG *)&m_cRefs );
}
//+---------------------------------------------------------------------------
//
// Member: CInetSynchronousRetriever::Release, public
//
// Synopsis: IRefCountedObject::Release
//
//----------------------------------------------------------------------------
VOID
CInetSynchronousRetriever::Release ()
{
if ( InterlockedDecrement( (LONG *)&m_cRefs ) == 0 )
{
delete this;
}
}
//+---------------------------------------------------------------------------
//
// Member: CInetSynchronousRetriever::RetrieveObjectByUrl, public
//
// Synopsis: IObjectRetriever::RetrieveObjectByUrl
//
//----------------------------------------------------------------------------
BOOL
CInetSynchronousRetriever::RetrieveObjectByUrl (
LPCWSTR pwszUrl,
LPCSTR pszObjectOid,
DWORD dwRetrievalFlags,
DWORD dwTimeout,
LPVOID* ppvObject,
PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
LPVOID* ppvFreeContext,
HCRYPTASYNC hAsyncRetrieve,
PCRYPT_CREDENTIALS pCredentials,
LPVOID pvVerify,
PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
BOOL fResult;
DWORD LastError = 0;
HINTERNET hInetSession = NULL;
assert( hAsyncRetrieve == NULL );
if ( ( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL ) )
{
return( SchemeRetrieveCachedCryptBlobArray(
pwszUrl,
dwRetrievalFlags,
(PCRYPT_BLOB_ARRAY)ppvObject,
ppfnFreeObject,
ppvFreeContext,
pAuxInfo
) );
}
fResult = InetGetBindings(
pwszUrl,
dwRetrievalFlags,
dwTimeout,
&hInetSession
);
if ( fResult == TRUE )
{
fResult = InetSendReceiveUrlRequest(
hInetSession,
pwszUrl,
dwRetrievalFlags,
pCredentials,
(PCRYPT_BLOB_ARRAY)ppvObject,
pAuxInfo
);
}
if ( fResult == TRUE )
{
*ppfnFreeObject = InetFreeEncodedObject;
*ppvFreeContext = NULL;
}
else
{
LastError = GetLastError();
}
InetFreeBindings( hInetSession );
SetLastError( LastError );
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Member: CInetSynchronousRetriever::CancelAsyncRetrieval, public
//
// Synopsis: IObjectRetriever::CancelAsyncRetrieval
//
//----------------------------------------------------------------------------
BOOL
CInetSynchronousRetriever::CancelAsyncRetrieval ()
{
SetLastError( (DWORD) E_NOTIMPL );
return( FALSE );
}
//+---------------------------------------------------------------------------
//
// Function: InetGetBindings
//
// Synopsis: get the session bindings
//
//----------------------------------------------------------------------------
BOOL
InetGetBindings (
LPCWSTR pwszUrl,
DWORD dwRetrievalFlags,
DWORD dwTimeout,
HINTERNET* phInetSession
)
{
BOOL fResult = TRUE;
DWORD LastError = 0;
HINTERNET hInetSession;
WCHAR wszUserAgent[64];
const DWORD cchUserAgent = sizeof(wszUserAgent) / sizeof(wszUserAgent[0]);
_snwprintf(wszUserAgent, cchUserAgent - 1,
L"Microsoft-CryptoAPI/%S", VER_PRODUCTVERSION_STR);
wszUserAgent[cchUserAgent - 1] = L'\0';
hInetSession = WinHttpOpen(
wszUserAgent,
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, // dwAccessType
WINHTTP_NO_PROXY_NAME, // pwszProxyName OPTIONAL
WINHTTP_NO_PROXY_BYPASS, // pwszProxyBypass OPTIONAL
0 // dwFlags
);
if ( hInetSession == NULL )
{
return( FALSE );
}
if ( ( fResult == TRUE ) && ( dwTimeout != 0 ) )
{
int iTimeout = (int) dwTimeout;
fResult = WinHttpSetTimeouts(
hInetSession,
iTimeout, // nResolveTimeout
iTimeout, // nConnectTimeout
iTimeout, // nSendTimeout
iTimeout // nReceiveTimeout
);
}
if ( fResult == TRUE )
{
DWORD dwOptionFlag;
dwOptionFlag = WINHTTP_DISABLE_PASSPORT_AUTH;
WinHttpSetOption(
hInetSession,
WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH,
&dwOptionFlag,
sizeof(dwOptionFlag)
);
}
if ( fResult == TRUE )
{
*phInetSession = hInetSession;
}
else
{
LastError = GetLastError();
WinHttpCloseHandle( hInetSession );
}
SetLastError( LastError );
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: InetFreeBindings
//
// Synopsis: free the inet session bindings
//
//----------------------------------------------------------------------------
VOID
InetFreeBindings (
HINTERNET hInetSession
)
{
if ( hInetSession != NULL )
{
WinHttpCloseHandle( hInetSession );
}
}
//+=========================================================================
// WinHttp doesn't support proxy failure rollover to the next proxy in
// the list. When this is fixed, we can revert back to OLD_InetSetProxy.
//-=========================================================================
//+-------------------------------------------------------------------------
// Calls the WinHttp proxy APIs to get the list of one or more proxy
// servers.
//
// The returned *ppProxyInfo must be freed by calling PkiFree()
//
// For no proxy servers, TRUE is returned with *ppProxyInfo set to NULL.
//--------------------------------------------------------------------------
BOOL
InetGetProxy(
IN HINTERNET hInetSession,
IN HINTERNET hInetRequest,
IN LPCWSTR pwszUrl,
IN DWORD dwRetrievalFlags,
OUT WINHTTP_PROXY_INFO **ppProxyInfo
)
{
BOOL fResult = TRUE;
WINHTTP_PROXY_INFO *pProxyInfo = NULL;
//
// Detect IE settings and look up proxy if necessary.
// Boilerplate from Stephen Sulzer.
//
// I copied from CACHED_AUTOPROXY::Generate() at
// \admin\services\drizzle\newjob\downloader.cpp
//
WINHTTP_PROXY_INFO ProxyInfo;
WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyConfig;
BOOL fTryAutoProxy = FALSE;
BOOL fSuccess = FALSE;
ZeroMemory(&ProxyInfo, sizeof(ProxyInfo));
ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions));
ZeroMemory(&IEProxyConfig, sizeof(IEProxyConfig));
if (WinHttpGetIEProxyConfigForCurrentUser(&IEProxyConfig)) {
if (IEProxyConfig.fAutoDetect) {
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
fTryAutoProxy = TRUE;
}
if (IEProxyConfig.lpszAutoConfigUrl) {
AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl;
fTryAutoProxy = TRUE;
}
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
} else {
// WinHttpGetIEProxyForCurrentUser failed, try autodetection anyway...
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
fTryAutoProxy = TRUE;
}
if (fTryAutoProxy) {
if (AutoProxyOptions.dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) {
// First try using the faster DNS_A option
AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A;
fSuccess = WinHttpGetProxyForUrl( hInetSession,
pwszUrl,
&AutoProxyOptions,
&ProxyInfo
);
if (!fSuccess) {
DWORD dwLastErr = GetLastError();
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> WinHttpGetProxyForUrl(DNS) failed: %d (0x%x)\n",
dwLastErr, dwLastErr);
// Try again using the slower DHCP
AutoProxyOptions.dwAutoDetectFlags |=
WINHTTP_AUTO_DETECT_TYPE_DHCP;
}
}
if (!fSuccess)
fSuccess = WinHttpGetProxyForUrl( hInetSession,
pwszUrl,
&AutoProxyOptions,
&ProxyInfo
);
if (fSuccess &&
WINHTTP_ACCESS_TYPE_NO_PROXY == ProxyInfo.dwAccessType &&
!(dwRetrievalFlags & CRYPT_NO_AUTH_RETRIEVAL))
{
// Need to set to low to allow access to such internal sites as:
// http://msw, http://hrweb
DWORD dwOptionFlag = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
if (!WinHttpSetOption(
hInetRequest,
WINHTTP_OPTION_AUTOLOGON_POLICY,
&dwOptionFlag,
sizeof(dwOptionFlag)
))
{
DWORD dwLastErr = GetLastError();
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> WinHttpSetOption(WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW) failed: %d (0x%x)\n",
dwLastErr, dwLastErr);
}
}
}
// If we didn't do autoproxy or if it failed, see
// if there's an explicit proxy server in the IE
// proxy configuration...
//
// This is where the WinHttpGetIEProxyConfigForCurrentUser API
// really comes in handy: in environments in which autoproxy is
// not supported and so the user's IE browser must be
// configured with an explicit proxy server.
//
if (!fTryAutoProxy || !fSuccess) {
if (IEProxyConfig.lpszProxy) {
ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
ProxyInfo.lpszProxy = IEProxyConfig.lpszProxy;
IEProxyConfig.lpszProxy = NULL;
ProxyInfo.lpszProxyBypass = IEProxyConfig.lpszProxyBypass;
IEProxyConfig.lpszProxyBypass = NULL;
}
}
I_CryptNetDebugTracePrintfA(
"CRYPTNET.DLL --> ProxyInfo:: AccessType:%d Proxy:%S ProxyByPass:%S\n",
ProxyInfo.dwAccessType,
ProxyInfo.lpszProxy,
ProxyInfo.lpszProxyBypass
);
if (NULL != ProxyInfo.lpszProxy) {
DWORD cbProxyInfo;
DWORD cchProxy; // including NULL terminator
DWORD cchProxyBypass; // including NULL terminator
cchProxy = wcslen(ProxyInfo.lpszProxy) + 1;
if (NULL != ProxyInfo.lpszProxyBypass) {
cchProxyBypass = wcslen(ProxyInfo.lpszProxyBypass) + 1;
} else {
cchProxyBypass = 0;
}
cbProxyInfo = sizeof(ProxyInfo) +
(cchProxy + cchProxyBypass) * sizeof(WCHAR);
pProxyInfo = (WINHTTP_PROXY_INFO *) PkiNonzeroAlloc(cbProxyInfo);
if (NULL == pProxyInfo) {
fResult = FALSE;
} else {
*pProxyInfo = ProxyInfo;
pProxyInfo->lpszProxy = (LPWSTR) &pProxyInfo[1];
memcpy(pProxyInfo->lpszProxy, ProxyInfo.lpszProxy,
cchProxy * sizeof(WCHAR));
if (0 != cchProxyBypass) {
pProxyInfo->lpszProxyBypass = pProxyInfo->lpszProxy + cchProxy;
memcpy(pProxyInfo->lpszProxyBypass, ProxyInfo.lpszProxyBypass,
cchProxyBypass * sizeof(WCHAR));
} else {
assert(NULL == pProxyInfo->lpszProxyBypass);
}
}
}
if (IEProxyConfig.lpszAutoConfigUrl)
GlobalFree(IEProxyConfig.lpszAutoConfigUrl);
if (IEProxyConfig.lpszProxy)
GlobalFree(IEProxyConfig.lpszProxy);
if (IEProxyConfig.lpszProxyBypass)
GlobalFree(IEProxyConfig.lpszProxyBypass);
if (ProxyInfo.lpszProxy)
GlobalFree(ProxyInfo.lpszProxy);
if (ProxyInfo.lpszProxyBypass)
GlobalFree(ProxyInfo.lpszProxyBypass);
*ppProxyInfo = pProxyInfo;
return fResult;
}
//+-------------------------------------------------------------------------
// Update both the Session and Request handles with proxy list.
// Currently, WinHttp only uses the first proxy server in the list.
//
// Also, for proxies to work using https, it must also be set on the
// session handle.
//--------------------------------------------------------------------------
BOOL
InetSetProxy(
IN HINTERNET hInetSession,
IN HINTERNET hInetRequest,
IN WINHTTP_PROXY_INFO *pProxyInfo
)
{
BOOL fResult;
if (NULL == pProxyInfo || NULL == pProxyInfo->lpszProxy) {
return TRUE;
}
//
// Set the proxy on the session handle
//
fResult = WinHttpSetOption( hInetSession,
WINHTTP_OPTION_PROXY,
pProxyInfo,
sizeof(*pProxyInfo)
);
if (fResult) {
//
// Now set the proxy on the request handle.
//
fResult = WinHttpSetOption( hInetRequest,
WINHTTP_OPTION_PROXY,
pProxyInfo,
sizeof(*pProxyInfo)
);
}
return fResult;
}
//+-------------------------------------------------------------------------
// Since WinHttp doesn't support proxy rollover we will advance to the
// next proxy if WinHttpSendRequest returns one of the following errors.
//--------------------------------------------------------------------------
BOOL
InetIsPossibleBadProxy(
IN DWORD dwErr
)
{
switch (dwErr) {
case ERROR_WINHTTP_NAME_NOT_RESOLVED:
case ERROR_WINHTTP_CANNOT_CONNECT:
case ERROR_WINHTTP_CONNECTION_ERROR:
case ERROR_WINHTTP_TIMEOUT:
return TRUE;
default:
return FALSE;
}
}
//+-------------------------------------------------------------------------
// Advances the lpszProxy to point to the next proxy in the list. Assumes
// that ";" is the delimiter and no proxy server contains this in their
// name.
//
// LastError is preserved. Returns TRUE if successfully found and set the
// next proxy.
//--------------------------------------------------------------------------
BOOL
InetSetNextProxy(
IN HINTERNET hInetSession,
IN HINTERNET hInetRequest,
IN OUT WINHTTP_PROXY_INFO *pProxyInfo
)
{
BOOL fResult = FALSE;
if (NULL != pProxyInfo && NULL != pProxyInfo->lpszProxy) {
DWORD dwLastError = GetLastError();
LPWSTR lpszProxy = pProxyInfo->lpszProxy;
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> Error:: %d (0x%x) Bad Proxy:%S\n",
dwLastError, dwLastError, lpszProxy);
// Assumption:: L';' is used to separater proxy names
while (L'\0' != *lpszProxy && L';' != *lpszProxy) {
lpszProxy++;
}
if (L';' == *lpszProxy) {
lpszProxy++;
// Skip any leading whitespace
while (iswspace(*lpszProxy)) {
lpszProxy++;
}
}
if (L'\0' == *lpszProxy) {
pProxyInfo->lpszProxy = NULL;
} else {
pProxyInfo->lpszProxy = lpszProxy;
fResult = InetSetProxy(
hInetSession,
hInetRequest,
pProxyInfo
);
}
SetLastError(dwLastError);
}
return fResult;
}
#if 0
//+-------------------------------------------------------------------------
// When WinHttp is fixed to support proxy fail rollover, we can revert
// back to this simpler proxy function.
//--------------------------------------------------------------------------
BOOL
OLD_InetSetProxy(
IN HINTERNET hInetSession,
IN HINTERNET hInetRequest,
IN LPCWSTR pwszUrl,
IN DWORD dwRetrievalFlags
)
{
BOOL fResult = TRUE;
//
// Detect IE settings and look up proxy if necessary.
// Boilerplate from Stephen Sulzer.
//
// I copied from CACHED_AUTOPROXY::Generate() at
// \admin\services\drizzle\newjob\downloader.cpp
//
WINHTTP_PROXY_INFO ProxyInfo;
WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyConfig;
BOOL fTryAutoProxy = FALSE;
BOOL fSuccess = FALSE;
ZeroMemory(&ProxyInfo, sizeof(ProxyInfo));
ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions));
ZeroMemory(&IEProxyConfig, sizeof(IEProxyConfig));
if (WinHttpGetIEProxyConfigForCurrentUser(&IEProxyConfig)) {
if (IEProxyConfig.fAutoDetect) {
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
fTryAutoProxy = TRUE;
}
if (IEProxyConfig.lpszAutoConfigUrl) {
AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl;
fTryAutoProxy = TRUE;
}
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
} else {
// WinHttpGetIEProxyForCurrentUser failed, try autodetection anyway...
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
fTryAutoProxy = TRUE;
}
if (fTryAutoProxy) {
if (AutoProxyOptions.dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) {
// First try using the faster DNS_A option
AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DNS_A;
fSuccess = WinHttpGetProxyForUrl( hInetSession,
pwszUrl,
&AutoProxyOptions,
&ProxyInfo
);
if (!fSuccess) {
DWORD dwLastErr = GetLastError();
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> WinHttpGetProxyForUrl(DNS) failed: %d (0x%x)\n",
dwLastErr, dwLastErr);
// Try again using the slower DHCP
AutoProxyOptions.dwAutoDetectFlags |=
WINHTTP_AUTO_DETECT_TYPE_DHCP;
}
}
if (!fSuccess)
fSuccess = WinHttpGetProxyForUrl( hInetSession,
pwszUrl,
&AutoProxyOptions,
&ProxyInfo
);
if (fSuccess &&
WINHTTP_ACCESS_TYPE_NO_PROXY == ProxyInfo.dwAccessType &&
!(dwRetrievalFlags & CRYPT_NO_AUTH_RETRIEVAL))
{
// Need to set to low to allow access to such internal sites as:
// http://msw, http://hrweb
DWORD dwOptionFlag = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
if (!WinHttpSetOption(
hInetRequest,
WINHTTP_OPTION_AUTOLOGON_POLICY,
&dwOptionFlag,
sizeof(dwOptionFlag)
))
{
DWORD dwLastErr = GetLastError();
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> WinHttpSetOption(WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW) failed: %d (0x%x)\n",
dwLastErr, dwLastErr);
}
}
}
// If we didn't do autoproxy or if it failed, see
// if there's an explicit proxy server in the IE
// proxy configuration...
//
// This is where the WinHttpGetIEProxyConfigForCurrentUser API
// really comes in handy: in environments in which autoproxy is
// not supported and so the user's IE browser must be
// configured with an explicit proxy server.
//
if (!fTryAutoProxy || !fSuccess) {
if (IEProxyConfig.lpszProxy) {
ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
ProxyInfo.lpszProxy = IEProxyConfig.lpszProxy;
IEProxyConfig.lpszProxy = NULL;
ProxyInfo.lpszProxyBypass = IEProxyConfig.lpszProxyBypass;
IEProxyConfig.lpszProxyBypass = NULL;
}
}
I_CryptNetDebugTracePrintfA(
"CRYPTNET.DLL --> ProxyInfo:: AccessType:%d Proxy:%S ProxyByPass:%S\n",
ProxyInfo.dwAccessType,
ProxyInfo.lpszProxy,
ProxyInfo.lpszProxyBypass
);
if (NULL != ProxyInfo.lpszProxy) {
//
// Set the proxy on the session handle
//
fResult = WinHttpSetOption( hInetSession,
WINHTTP_OPTION_PROXY,
&ProxyInfo,
sizeof(ProxyInfo)
);
if (fResult)
//
// Now set the proxy on the request handle.
//
fResult = WinHttpSetOption( hInetRequest,
WINHTTP_OPTION_PROXY,
&ProxyInfo,
sizeof(ProxyInfo)
);
}
if (IEProxyConfig.lpszAutoConfigUrl)
GlobalFree(IEProxyConfig.lpszAutoConfigUrl);
if (IEProxyConfig.lpszProxy)
GlobalFree(IEProxyConfig.lpszProxy);
if (IEProxyConfig.lpszProxyBypass)
GlobalFree(IEProxyConfig.lpszProxyBypass);
if (ProxyInfo.lpszProxy)
GlobalFree(ProxyInfo.lpszProxy);
if (ProxyInfo.lpszProxyBypass)
GlobalFree(ProxyInfo.lpszProxyBypass);
return fResult;
}
#endif
//+-------------------------------------------------------------------------
// Handles all of the possible errors that WinHttp can return
// when sending the request.
//--------------------------------------------------------------------------
BOOL
InetSendAuthenticatedRequestAndReceiveResponse(
IN HINTERNET hInetSession,
IN HINTERNET hInetRequest,
IN LPCWSTR pwszUrl,
IN DWORD dwRetrievalFlags,
IN PCRYPT_CREDENTIALS pCredentials
)
{
BOOL fResult;
DWORD dwLastError = 0;
DWORD dwStatus = HTTP_STATUS_BAD_REQUEST;
CRYPT_PASSWORD_CREDENTIALSW PasswordCredentials;
BOOL fFreeCredentials = FALSE;
LPWSTR pwszUserName = NULL; // not allocated
LPWSTR pwszPassword = NULL; // not allocated
#define INET_MAX_RESEND_REQUEST_COUNT 5
DWORD dwResendRequestCount = 0;
#define INET_SET_PROXY_OR_SERVER_CRED_STATE 0
#define INET_SET_ONLY_SERVER_CRED_STATE 1
#define INET_SET_NO_CRED_STATE 2
DWORD dwSetCredState = INET_SET_NO_CRED_STATE;
#define INET_MAX_BAD_PROXY_COUNT 3
DWORD dwBadProxyCount = 0;
WINHTTP_PROXY_INFO *pProxyInfo = NULL;
if (NULL != pCredentials) {
memset( &PasswordCredentials, 0, sizeof( PasswordCredentials ) );
PasswordCredentials.cbSize = sizeof( PasswordCredentials );
if (!SchemeGetPasswordCredentialsW(
pCredentials,
&PasswordCredentials,
&fFreeCredentials
))
goto GetPasswordCredentialsError;
pwszUserName = PasswordCredentials.pszUsername;
pwszPassword = PasswordCredentials.pszPassword;
dwSetCredState = INET_SET_PROXY_OR_SERVER_CRED_STATE;
}
if (!InetGetProxy(
hInetSession,
hInetRequest,
pwszUrl,
dwRetrievalFlags,
&pProxyInfo
))
goto GetProxyError;
if (!InetSetProxy(
hInetSession,
hInetRequest,
pProxyInfo
))
goto SetProxyError;
while (TRUE) {
DWORD dwSizeofStatus;
DWORD dwIndex;
DWORD dwSetCredAuthTarget;
if (!WinHttpSendRequest(
hInetRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, // pwszHeaders
0, // dwHeadersLength
WINHTTP_NO_REQUEST_DATA, // lpOptional
0, // dwOptionalLength
0, // dwTotalLength
0 // dwContext
)) {
dwLastError = GetLastError();
if (ERROR_WINHTTP_RESEND_REQUEST == dwLastError) {
dwResendRequestCount++;
if (INET_MAX_RESEND_REQUEST_COUNT < dwResendRequestCount)
goto ExceededMaxResendRequestCount;
else
continue;
} else if (InetIsPossibleBadProxy(dwLastError)) {
dwBadProxyCount++;
if (INET_MAX_BAD_PROXY_COUNT <= dwBadProxyCount)
goto ExceededMaxBadProxyCount;
if (InetSetNextProxy(
hInetSession,
hInetRequest,
pProxyInfo
))
continue;
}
goto WinHttpSendRequestError;
}
dwResendRequestCount = 0;
if (!WinHttpReceiveResponse(
hInetRequest,
NULL // lpReserved
))
goto WinHttpReceiveResponseError;
if (I_CryptNetIsDebugTracePrintEnabled()) {
for (DWORD i = 0; i < 2; i++) {
BYTE rgbBuf[4096];
DWORD cbBuf;
DWORD dwInfo;
memset(rgbBuf, 0, sizeof(rgbBuf));
cbBuf = sizeof(rgbBuf);
dwInfo = WINHTTP_QUERY_RAW_HEADERS_CRLF;
if (0 == i)
dwInfo |= WINHTTP_QUERY_FLAG_REQUEST_HEADERS;
dwIndex = 0;
if (WinHttpQueryHeaders(
hInetRequest,
dwInfo,
WINHTTP_HEADER_NAME_BY_INDEX, // pwszName OPTIONAL
rgbBuf,
&cbBuf,
&dwIndex
)) {
if (0 == i)
I_CryptNetDebugPrintfA(
"CRYPTNET.DLL --> Request Headers::\n");
else
I_CryptNetDebugPrintfA(
"CRYPTNET.DLL --> Response Headers::\n");
I_CryptNetDebugPrintfA("%S", rgbBuf);
}
}
}
dwSizeofStatus = sizeof( dwStatus );
dwIndex = 0;
if (!WinHttpQueryHeaders(
hInetRequest,
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
WINHTTP_HEADER_NAME_BY_INDEX, // pwszName OPTIONAL
&dwStatus,
&dwSizeofStatus,
&dwIndex
))
goto WinHttpQueryStatusCodeError;
switch (dwStatus) {
case HTTP_STATUS_OK:
goto SuccessReturn;
break;
case HTTP_STATUS_PROXY_AUTH_REQ:
if (INET_SET_PROXY_OR_SERVER_CRED_STATE < dwSetCredState)
goto BadHttpProxyAuthStatus;
dwSetCredState = INET_SET_ONLY_SERVER_CRED_STATE;
dwSetCredAuthTarget = WINHTTP_AUTH_TARGET_PROXY;
break;
case HTTP_STATUS_DENIED:
if (INET_SET_ONLY_SERVER_CRED_STATE < dwSetCredState)
goto BadHttpServerAuthStatus;
dwSetCredState = INET_SET_NO_CRED_STATE;
dwSetCredAuthTarget = WINHTTP_AUTH_TARGET_SERVER;
break;
default:
goto BadHttpStatus;
}
{
DWORD dwSupportedSchemes = 0;
DWORD dwPreferredScheme = 0;
DWORD dwAuthTarget = 0;
DWORD dwSetCredScheme;
assert(HTTP_STATUS_PROXY_AUTH_REQ == dwStatus ||
HTTP_STATUS_DENIED == dwStatus);
if (!WinHttpQueryAuthSchemes(
hInetRequest,
&dwSupportedSchemes,
&dwPreferredScheme,
&dwAuthTarget
))
goto WinHttpQueryAuthSchemesError;
if (dwAuthTarget != dwSetCredAuthTarget)
goto InvalidQueryAuthTarget;
if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE)
dwSetCredScheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM)
dwSetCredScheme = WINHTTP_AUTH_SCHEME_NTLM;
else
goto UnsupportedAuthScheme;
if (!WinHttpSetCredentials(
hInetRequest,
dwSetCredAuthTarget,
dwSetCredScheme,
pwszUserName,
pwszPassword,
NULL // pvAuthParams
))
goto WinHttpSetCredentialsError;
}
}
SuccessReturn:
fResult = TRUE;
CommonReturn:
PkiFree(pProxyInfo);
if (fFreeCredentials)
SchemeFreePasswordCredentialsW(&PasswordCredentials);
SetLastError(dwLastError);
return fResult;
ErrorReturn:
fResult = FALSE;
dwLastError = GetLastError();
goto CommonReturn;
TRACE_ERROR(GetPasswordCredentialsError)
TRACE_ERROR(GetProxyError)
TRACE_ERROR(SetProxyError)
TRACE_ERROR(ExceededMaxResendRequestCount)
TRACE_ERROR(ExceededMaxBadProxyCount)
TRACE_ERROR(WinHttpSendRequestError)
TRACE_ERROR(WinHttpReceiveResponseError)
TRACE_ERROR(WinHttpQueryStatusCodeError)
TRACE_ERROR(WinHttpQueryAuthSchemesError)
TRACE_ERROR(WinHttpSetCredentialsError)
SET_ERROR_VAR(BadHttpStatus, dwStatus)
SET_ERROR_VAR(BadHttpProxyAuthStatus, dwStatus)
SET_ERROR_VAR(BadHttpServerAuthStatus, dwStatus)
SET_ERROR_VAR(InvalidQueryAuthTarget, dwStatus)
SET_ERROR_VAR(UnsupportedAuthScheme, dwStatus)
}
//+---------------------------------------------------------------------------
//
// Function: InetSendReceiveUrlRequest
//
// Synopsis: synchronous processing of an URL via WinInet
//
//----------------------------------------------------------------------------
BOOL
InetSendReceiveUrlRequest (
HINTERNET hInetSession,
LPCWSTR pwszUrl,
DWORD dwRetrievalFlags,
PCRYPT_CREDENTIALS pCredentials,
PCRYPT_BLOB_ARRAY pcba,
PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
BOOL fResult;
DWORD dwLastError = 0;
HINTERNET hInetConnect = NULL;
HINTERNET hInetRequest = NULL;;
URL_COMPONENTS UrlComponents;
PCRYPTNET_CANCEL_BLOCK pCancelBlock=NULL;
LPCWSTR pwszEmpty = L"";
LPWSTR pwszHostName = NULL;
LPWSTR pwszUrlPathPlusExtraInfo = NULL;
LPCWSTR rgpwszAcceptTypes[] = { L"*/*", NULL };
DWORD dwOpenRequestFlags = 0;
LPBYTE pb = NULL;
ULONG cbRead;
ULONG cb;
DWORD dwMaxUrlRetrievalByteCount = 0; // 0 => no max
BOOL fCacheBlob;
if (pAuxInfo &&
offsetof(CRYPT_RETRIEVE_AUX_INFO, dwMaxUrlRetrievalByteCount) <
pAuxInfo->cbSize)
dwMaxUrlRetrievalByteCount = pAuxInfo->dwMaxUrlRetrievalByteCount;
// Extract the HostName and UrlPath from the URL string
memset( &UrlComponents, 0, sizeof( UrlComponents ) );
UrlComponents.dwStructSize = sizeof( UrlComponents );
UrlComponents.dwHostNameLength = (DWORD) -1;
UrlComponents.dwUrlPathLength = (DWORD) -1;
UrlComponents.dwExtraInfoLength = (DWORD) -1;
if (!WinHttpCrackUrl(
pwszUrl,
0, // dwUrlLength, 0 implies null terminated
0, // dwCanonicalizeFlags
&UrlComponents
))
goto WinHttpCrackUrlError;
if (NULL == UrlComponents.lpszHostName) {
UrlComponents.dwHostNameLength = 0;
UrlComponents.lpszHostName = (LPWSTR) pwszEmpty;
}
if (NULL == UrlComponents.lpszUrlPath) {
UrlComponents.dwUrlPathLength = 0;
UrlComponents.lpszUrlPath = (LPWSTR) pwszEmpty;
}
if (NULL == UrlComponents.lpszExtraInfo) {
UrlComponents.dwExtraInfoLength = 0;
UrlComponents.lpszExtraInfo = (LPWSTR) pwszEmpty;
}
pwszHostName = (LPWSTR) PkiNonzeroAlloc(
(UrlComponents.dwHostNameLength + 1) * sizeof(WCHAR));
pwszUrlPathPlusExtraInfo = (LPWSTR) PkiNonzeroAlloc(
(UrlComponents.dwUrlPathLength +
UrlComponents.dwExtraInfoLength + 1) * sizeof(WCHAR));
if (NULL == pwszHostName || NULL == pwszUrlPathPlusExtraInfo)
goto OutOfMemory;
memcpy(pwszHostName, UrlComponents.lpszHostName,
UrlComponents.dwHostNameLength * sizeof(WCHAR));
pwszHostName[UrlComponents.dwHostNameLength] = L'\0';
memcpy(pwszUrlPathPlusExtraInfo, UrlComponents.lpszUrlPath,
UrlComponents.dwUrlPathLength * sizeof(WCHAR));
memcpy(pwszUrlPathPlusExtraInfo + UrlComponents.dwUrlPathLength,
UrlComponents.lpszExtraInfo,
UrlComponents.dwExtraInfoLength * sizeof(WCHAR));
pwszUrlPathPlusExtraInfo[
UrlComponents.dwUrlPathLength +
UrlComponents.dwExtraInfoLength] = L'\0';
hInetConnect = WinHttpConnect(
hInetSession,
pwszHostName,
UrlComponents.nPort,
0 // dwReserved
);
if (NULL == hInetConnect)
goto WinHttpConnectError;
if ( !(dwRetrievalFlags & CRYPT_AIA_RETRIEVAL) ) {
dwOpenRequestFlags |= WINHTTP_FLAG_BYPASS_PROXY_CACHE;
}
hInetRequest = WinHttpOpenRequest(
hInetConnect,
NULL, // pwszVerb, NULL implies GET
pwszUrlPathPlusExtraInfo, // pwszObjectName
NULL, // pwszVersion, NULL implies HTTP/1.1
WINHTTP_NO_REFERER, // pwszReferrer
rgpwszAcceptTypes,
dwOpenRequestFlags
);
if (NULL == hInetRequest)
goto WinHttpOpenRequestError;
if (dwRetrievalFlags & CRYPT_NO_AUTH_RETRIEVAL) {
DWORD dwOptionFlag;
dwOptionFlag = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;
if (!WinHttpSetOption(
hInetRequest,
WINHTTP_OPTION_AUTOLOGON_POLICY,
&dwOptionFlag,
sizeof(dwOptionFlag)
))
goto SetAutoLogonSecurityOptionError;
dwOptionFlag = WINHTTP_DISABLE_AUTHENTICATION;
if (!WinHttpSetOption(
hInetRequest,
WINHTTP_OPTION_DISABLE_FEATURE,
&dwOptionFlag,
sizeof(dwOptionFlag)
))
goto SetDisableAuthenticationOptionError;
}
#if 0
if (!OLD_InetSetProxy(hInetSession, hInetRequest, pwszUrl, dwRetrievalFlags))
goto SetProxyError;
#endif
if (!InetSendAuthenticatedRequestAndReceiveResponse(
hInetSession,
hInetRequest,
pwszUrl,
dwRetrievalFlags,
pCredentials
))
goto InetSendAuthenticatedRequestAndReceiveResponseError;
cbRead = 0;
cb = INET_INITIAL_DATA_BUFFER_SIZE;
pb = CCryptBlobArray::AllocBlob( cb );
if (NULL == pb)
goto OutOfMemory;
pCancelBlock=(PCRYPTNET_CANCEL_BLOCK)I_CryptGetTls(hCryptNetCancelTls);
while (TRUE) {
ULONG cbData;
ULONG cbPerRead;
if (pCancelBlock) {
if (pCancelBlock->pfnCancel(0, pCancelBlock->pvArg))
goto CanceledRead;
}
cbData = 0;
if (!WinHttpQueryDataAvailable(hInetRequest, &cbData) || 0 == cbData)
break;
if (0 != dwMaxUrlRetrievalByteCount &&
(cbRead + cbData) > dwMaxUrlRetrievalByteCount) {
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> Exceeded MaxUrlRetrievalByteCount for: %S\n",
pwszUrl);
goto ExceededMaxUrlRetrievalByteCount;
}
if (cb < (cbRead + cbData)) {
BYTE *pbRealloc;
pbRealloc = CCryptBlobArray::ReallocBlob(
pb,
cb + cbData + INET_GROW_DATA_BUFFER_SIZE
);
if (NULL == pbRealloc)
goto OutOfMemory;
pb = pbRealloc;
cb += cbData + INET_GROW_DATA_BUFFER_SIZE;
}
cbPerRead = 0;
if (!WinHttpReadData(
hInetRequest,
pb+cbRead,
cbData,
&cbPerRead
))
goto WinHttpReadDataError;
cbRead += cbPerRead;
}
{
fResult = TRUE;
CCryptBlobArray cba( 1, 1, fResult );
if (fResult)
fResult = cba.AddBlob( cbRead, pb, FALSE );
if (fResult)
cba.GetArrayInNativeForm(pcba);
else {
cba.FreeArray( FALSE );
goto OutOfMemory;
}
}
fCacheBlob = FALSE;
if ( !( dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT ) ) {
if ( dwRetrievalFlags & CRYPT_AIA_RETRIEVAL ) {
assert(0 < pcba->cBlob);
// Only cache if we are able to decode it.
fCacheBlob = CryptQueryObject(
CERT_QUERY_OBJECT_BLOB,
(const void *) &(pcba->rgBlob[0]),
CERT_QUERY_CONTENT_FLAG_CERT |
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
CERT_QUERY_CONTENT_FLAG_CERT_PAIR,
CERT_QUERY_FORMAT_FLAG_ALL,
0, // dwFlags
NULL, // pdwMsgAndCertEncodingType
NULL, // pdwContentType
NULL, // pdwFormatType
NULL, // phCertStore
NULL, // phMsg
NULL // ppvContext
);
if (!fCacheBlob) {
I_CryptNetDebugErrorPrintfA(
"CRYPTNET.DLL --> Invalid AIA content, no caching: %S\n",
pwszUrl);
}
} else {
fCacheBlob = TRUE;
}
if (fCacheBlob)
fCacheBlob = SchemeCacheCryptBlobArray(
pwszUrl,
dwRetrievalFlags,
pcba,
pAuxInfo
);
}
if (!fCacheBlob) {
if (!SchemeRetrieveUncachedAuxInfo(pAuxInfo))
goto RetrieveUncachedAuxInfoError;
}
fResult = TRUE;
CommonReturn:
WinHttpCloseHandle(hInetRequest);
WinHttpCloseHandle(hInetConnect);
PkiFree(pwszHostName);
PkiFree(pwszUrlPathPlusExtraInfo);
SetLastError(dwLastError);
return fResult;
ErrorReturn:
if (NULL != pb)
CCryptBlobArray::FreeBlob(pb);
dwLastError = GetLastError();
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(WinHttpCrackUrlError)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
TRACE_ERROR(WinHttpConnectError)
TRACE_ERROR(WinHttpOpenRequestError)
TRACE_ERROR(SetAutoLogonSecurityOptionError)
TRACE_ERROR(SetDisableAuthenticationOptionError)
TRACE_ERROR(InetSendAuthenticatedRequestAndReceiveResponseError)
SET_ERROR(CanceledRead, ERROR_CANCELLED)
SET_ERROR(ExceededMaxUrlRetrievalByteCount, ERROR_INVALID_DATA)
TRACE_ERROR(WinHttpReadDataError)
TRACE_ERROR(RetrieveUncachedAuxInfoError)
}
//+---------------------------------------------------------------------------
//
// Function: InetFreeCryptBlobArray
//
// Synopsis: free the crypt blob array
//
//----------------------------------------------------------------------------
VOID
InetFreeCryptBlobArray (
PCRYPT_BLOB_ARRAY pcba
)
{
CCryptBlobArray cba( pcba, 0 );
cba.FreeArray( TRUE );
}
//+---------------------------------------------------------------------------
//
// Function: InetAsyncStatusCallback
//
// Synopsis: status callback for async
//
//----------------------------------------------------------------------------
VOID WINAPI
InetAsyncStatusCallback (
HINTERNET hInet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID pvStatusInfo,
DWORD dwStatusLength
)
{
return;
}