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
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;
|
|
}
|