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.
1327 lines
28 KiB
1327 lines
28 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: ds.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <wininet.h>
|
|
#include <winineti.h> // for MAX_CACHE_ENTRY_INFO_SIZE
|
|
|
|
#include "cryptnet.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTUTIL_CACHE_CPP__
|
|
|
|
|
|
typedef struct _QUERY_INFO
|
|
{
|
|
WCHAR const *pwszInfo;
|
|
DWORD dwInfo;
|
|
} QUERY_INFO;
|
|
|
|
|
|
QUERY_INFO g_rgQueryInfo[] = {
|
|
#if 0
|
|
L"HTTP_QUERY_MIME_VERSION-Req",
|
|
HTTP_QUERY_MIME_VERSION | HTTP_QUERY_FLAG_REQUEST_HEADERS,
|
|
L"HTTP_QUERY_CONTENT_TYPE-Req",
|
|
HTTP_QUERY_CONTENT_TYPE | HTTP_QUERY_FLAG_REQUEST_HEADERS,
|
|
L"HTTP_QUERY_CONTENT_TRANSFER_ENCODING-Req",
|
|
HTTP_QUERY_CONTENT_TRANSFER_ENCODING | HTTP_QUERY_FLAG_REQUEST_HEADERS,
|
|
L"HTTP_QUERY_CONTENT_LENGTH-Req",
|
|
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_REQUEST_HEADERS,
|
|
#endif
|
|
|
|
L"HTTP_QUERY_MIME_VERSION", HTTP_QUERY_MIME_VERSION,
|
|
L"HTTP_QUERY_CONTENT_TYPE", HTTP_QUERY_CONTENT_TYPE,
|
|
L"HTTP_QUERY_CONTENT_TRANSFER_ENCODING",
|
|
HTTP_QUERY_CONTENT_TRANSFER_ENCODING,
|
|
|
|
L"HTTP_QUERY_CONTENT_LENGTH",
|
|
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
|
|
|
|
L"HTTP_QUERY_VERSION", HTTP_QUERY_VERSION,
|
|
L"HTTP_QUERY_STATUS_CODE", HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
|
|
L"HTTP_QUERY_STATUS_TEXT", HTTP_QUERY_STATUS_TEXT,
|
|
L"HTTP_QUERY_RAW_HEADERS", HTTP_QUERY_RAW_HEADERS,
|
|
L"HTTP_QUERY_RAW_HEADERS_CRLF", HTTP_QUERY_RAW_HEADERS_CRLF,
|
|
L"HTTP_QUERY_CONTENT_ENCODING", HTTP_QUERY_CONTENT_ENCODING,
|
|
L"HTTP_QUERY_LOCATION", HTTP_QUERY_LOCATION,
|
|
L"HTTP_QUERY_ORIG_URI", HTTP_QUERY_ORIG_URI,
|
|
L"HTTP_QUERY_REQUEST_METHOD", HTTP_QUERY_REQUEST_METHOD,
|
|
L"HTTP_QUERY_DATE", HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME,
|
|
L"HTTP_QUERY_EXPIRES", HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME,
|
|
L"HTTP_QUERY_LAST_MODIFIED",
|
|
HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME,
|
|
};
|
|
|
|
|
|
HRESULT
|
|
DisplayQueryInfo(
|
|
IN HINTERNET hInternetFile)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(g_rgQueryInfo); i++)
|
|
{
|
|
QUERY_INFO *pQuery = &g_rgQueryInfo[i];
|
|
DWORD dwIndex;
|
|
BOOL fFirst;
|
|
|
|
fFirst = TRUE;
|
|
dwIndex = 0;
|
|
while (TRUE)
|
|
{
|
|
BYTE rgbBuf[MAX_CACHE_ENTRY_INFO_SIZE];
|
|
DWORD cbBuf;
|
|
DWORD dwThisIndex = dwIndex;
|
|
BOOL fResult;
|
|
DWORD dwValue;
|
|
SYSTEMTIME st;
|
|
|
|
if (HTTP_QUERY_FLAG_NUMBER & pQuery->dwInfo)
|
|
{
|
|
cbBuf = sizeof(dwValue);
|
|
fResult = HttpQueryInfo(
|
|
hInternetFile,
|
|
pQuery->dwInfo,
|
|
&dwValue,
|
|
&cbBuf,
|
|
&dwIndex);
|
|
}
|
|
else
|
|
if (HTTP_QUERY_FLAG_SYSTEMTIME & pQuery->dwInfo)
|
|
{
|
|
cbBuf = sizeof(st);
|
|
fResult = HttpQueryInfo(
|
|
hInternetFile,
|
|
pQuery->dwInfo,
|
|
&st,
|
|
&cbBuf,
|
|
&dwIndex);
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(rgbBuf, sizeof(rgbBuf));
|
|
cbBuf = sizeof(rgbBuf);
|
|
|
|
fResult = HttpQueryInfo(
|
|
hInternetFile,
|
|
pQuery->dwInfo,
|
|
rgbBuf,
|
|
&cbBuf,
|
|
&dwIndex);
|
|
}
|
|
if (!fResult)
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr3(
|
|
hr,
|
|
"HttpQueryInfo",
|
|
pQuery->pwszInfo,
|
|
HRESULT_FROM_WIN32(ERROR_HTTP_HEADER_NOT_FOUND),
|
|
HRESULT_FROM_WIN32(ERROR_HTTP_INVALID_QUERY_REQUEST));
|
|
break;
|
|
}
|
|
|
|
if (HTTP_QUERY_FLAG_NUMBER & pQuery->dwInfo)
|
|
{
|
|
wprintf(
|
|
L"%ws[%d] = %x (%d)\n",
|
|
pQuery->pwszInfo,
|
|
dwThisIndex,
|
|
dwValue,
|
|
dwValue);
|
|
}
|
|
else
|
|
if (HTTP_QUERY_FLAG_SYSTEMTIME & pQuery->dwInfo)
|
|
{
|
|
FILETIME ft;
|
|
|
|
if (!SystemTimeToFileTime(&st, &ft))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(
|
|
hr,
|
|
error,
|
|
"SystemTimeToFileTime",
|
|
pQuery->pwszInfo);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"%ws[%d] =", pQuery->pwszInfo, dwThisIndex);
|
|
hr = cuDumpFileTime(0, NULL, &ft);
|
|
wprintf(wszNewLine);
|
|
_PrintIfError(hr, "cuDumpFileTime");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(
|
|
L"%ws[%d] = \"%.*ws\"\n",
|
|
pQuery->pwszInfo,
|
|
dwThisIndex,
|
|
cbBuf / sizeof(WCHAR),
|
|
rgbBuf);
|
|
if (1 < g_fVerbose)
|
|
{
|
|
DumpHex(0, (BYTE const *) rgbBuf, cbBuf);
|
|
}
|
|
}
|
|
fFirst = FALSE;
|
|
if (dwThisIndex == dwIndex)
|
|
{
|
|
#if 0
|
|
wprintf(
|
|
L"HttpQueryInfo(%ws) dwIndex not advanced\n",
|
|
pQuery->pwszInfo);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayCacheEntryInfo(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbCachEntryInfo;
|
|
BYTE rgbCachEntryInfo[MAX_CACHE_ENTRY_INFO_SIZE];
|
|
INTERNET_CACHE_ENTRY_INFO *pCacheEntryInfo =
|
|
(INTERNET_CACHE_ENTRY_INFO *) &rgbCachEntryInfo[0];
|
|
|
|
cbCachEntryInfo = sizeof(rgbCachEntryInfo);
|
|
if (!GetUrlCacheEntryInfo(pwszURL, pCacheEntryInfo, &cbCachEntryInfo))
|
|
{
|
|
hr = myHLastError();
|
|
wprintf(L"%ws\n", pwszURL);
|
|
_JumpError(hr, error, "GetUrlCacheEntryInfo");
|
|
}
|
|
wprintf(
|
|
L"%ws %d %ws\n",
|
|
myLoadResourceString(IDS_WININET_CACHE_ENTRY_COLON),
|
|
cbCachEntryInfo,
|
|
myLoadResourceString(IDS_BYTES));
|
|
|
|
if (0 != cbCachEntryInfo)
|
|
{
|
|
wprintf(
|
|
L" %ws \"%ws\"\n",
|
|
myLoadResourceString(IDS_FORMAT_SOURCE_URL),
|
|
pCacheEntryInfo->lpszSourceUrlName);
|
|
|
|
wprintf(
|
|
L" %ws \"%ws\"\n",
|
|
myLoadResourceString(IDS_FORMAT_LOCAL_FILENAME),
|
|
pCacheEntryInfo->lpszLocalFileName);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_USE_COUNT), pCacheEntryInfo->dwUseCount);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_HIT_RATE), pCacheEntryInfo->dwHitRate);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_FILE_SIZE), pCacheEntryInfo->dwSizeLow);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_LAST_MOD_TIME_COLON));
|
|
cuDumpFileTime(0, NULL, &pCacheEntryInfo->LastModifiedTime);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_EXPIRE_TIME_COLON));
|
|
cuDumpFileTime(0, NULL, &pCacheEntryInfo->ExpireTime);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_LAST_ACCESS_TIME_COLON));
|
|
cuDumpFileTime(0, NULL, &pCacheEntryInfo->LastAccessTime);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_LAST_SYNC_TIME_COLON));
|
|
cuDumpFileTime(0, NULL, &pCacheEntryInfo->LastSyncTime);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
typedef struct _DATABLOCK {
|
|
struct _DATABLOCK *pNext;
|
|
DWORD cbData;
|
|
BYTE abData[1];
|
|
} DATABLOCK;
|
|
|
|
|
|
HRESULT
|
|
AddDataBlock(
|
|
IN BYTE *pb,
|
|
IN DWORD cb,
|
|
IN OUT DATABLOCK **ppData)
|
|
{
|
|
HRESULT hr;
|
|
DATABLOCK *pData = NULL;
|
|
|
|
pData = (DATABLOCK *) LocalAlloc(LMEM_FIXED, sizeof(*pData) + cb);
|
|
if (NULL == pData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
pData->pNext = *ppData;
|
|
pData->cbData = cb;
|
|
CopyMemory(pData->abData, pb, cb);
|
|
*ppData = pData;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ReadURL(
|
|
OPTIONAL IN HINTERNET hInternetFile,
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hStore = NULL;
|
|
BYTE *pb = NULL;
|
|
BYTE *pb2;
|
|
DWORD cb;
|
|
DWORD cbRead;
|
|
DATABLOCK *pData = NULL;
|
|
DATABLOCK *pData2;
|
|
|
|
if (NULL == hInternetFile)
|
|
{
|
|
if (!CryptRetrieveObjectByUrl(
|
|
pwszURL,
|
|
CONTEXT_OID_CAPI2_ANY,
|
|
CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
|
|
(g_fForce?
|
|
CRYPT_WIRE_ONLY_RETRIEVAL :
|
|
CRYPT_CACHE_ONLY_RETRIEVAL),
|
|
0,
|
|
(VOID **) &hStore,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr2(hr, error, "CryptRetrieveObjectByUrl", pwszURL, hr);
|
|
}
|
|
hr = cuDumpAndVerifyStore(
|
|
hStore,
|
|
DVNS_DUMP,
|
|
NULL, // pwszCertName
|
|
MAXDWORD, // iCertSave
|
|
MAXDWORD, // iCRLSave
|
|
MAXDWORD, // iCTLSave
|
|
NULL, // pwszfnOut
|
|
NULL); // pwszPassword
|
|
_JumpIfError(hr, error, "cuDumpAndVerifyStore");
|
|
}
|
|
else
|
|
{
|
|
cb = 0;
|
|
if (!InternetQueryDataAvailable(
|
|
hInternetFile,
|
|
&cb,
|
|
0, // dwFlags
|
|
0)) // dwContext
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "InternetQueryDataAvailable");
|
|
}
|
|
|
|
cb = 0;
|
|
while (TRUE)
|
|
{
|
|
BYTE ab[4096];
|
|
|
|
if (!InternetReadFile(hInternetFile, ab, sizeof(ab), &cbRead))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "InternetReadFile");
|
|
}
|
|
if (0 == cbRead)
|
|
{
|
|
break;
|
|
}
|
|
hr = AddDataBlock(ab, cbRead, &pData);
|
|
_JumpIfError(hr, error, "AddDataBlock");
|
|
|
|
cb += cbRead;
|
|
}
|
|
|
|
pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pb)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
pb2 = &pb[cb];
|
|
for (pData2 = pData; NULL != pData2; pData2 = pData2->pNext)
|
|
{
|
|
pb2 -= pData2->cbData;
|
|
CSASSERT(pb2 >= pb);
|
|
CopyMemory(pb2, pData2->abData, pData2->cbData);
|
|
}
|
|
CSASSERT(pb2 == pb);
|
|
|
|
hr = cuDumpAsnBinary(pb, cb, MAXDWORD);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "cuDumpAsnBinary");
|
|
DumpHex(0, pb, cb);
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hStore)
|
|
{
|
|
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
while (NULL != pData)
|
|
{
|
|
pData2 = pData;
|
|
pData = pData->pNext;
|
|
LocalFree(pData2);
|
|
}
|
|
if (NULL != pb)
|
|
{
|
|
LocalFree(pb);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DeleteCacheGroups()
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
HANDLE hFind = NULL;
|
|
GROUPID GroupId;
|
|
DWORD cDelete = 0;
|
|
|
|
hFind = FindFirstUrlCacheGroup(
|
|
0, // dwFlags
|
|
CACHEGROUP_SEARCH_ALL, // dwFilter
|
|
NULL, // lpSearchCondition
|
|
0, // dwSearchCondition
|
|
&GroupId,
|
|
NULL); // lpReserved
|
|
if (NULL == hFind)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "FindFirstUrlCacheGroup");
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
//wprintf(L"GROUPID: %I64u (0x%I64x)\n", GroupId, GroupId);
|
|
if (!DeleteUrlCacheGroup(
|
|
GroupId,
|
|
CACHEGROUP_FLAG_FLUSHURL_ONDELETE, // dwFlags
|
|
NULL)) // lpReserved
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "DeleteUrlCacheGroup");
|
|
}
|
|
else
|
|
{
|
|
cDelete++;
|
|
}
|
|
|
|
if (!FindNextUrlCacheGroup(hFind, &GroupId, NULL))
|
|
{
|
|
hr = myHLastError();
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpError(hr, error, "FindNextUrlCacheGroup");
|
|
}
|
|
}
|
|
//wprintf(L"Deleted %u groups\n", cDelete);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hFind)
|
|
{
|
|
if (!FindCloseUrlCache(hFind))
|
|
{
|
|
hr2 = myHLastError();
|
|
_PrintError(hr2, "FindCloseUrlCache");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HANDLE
|
|
myFindFirstUrlCacheEntry(
|
|
OPTIONAL IN WCHAR const *pwszPattern,
|
|
OUT INTERNET_CACHE_ENTRY_INFO **ppcei,
|
|
OUT DWORD *pcb)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hFind = NULL;
|
|
INTERNET_CACHE_ENTRY_INFO *pcei = NULL;
|
|
DWORD cb;
|
|
BOOL fRetried;
|
|
|
|
*ppcei = NULL;
|
|
cb = MAX_CACHE_ENTRY_INFO_SIZE;
|
|
fRetried = FALSE;
|
|
while (TRUE)
|
|
{
|
|
pcei = (INTERNET_CACHE_ENTRY_INFO *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pcei)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
hFind = FindFirstUrlCacheEntry(pwszPattern, pcei, &cb);
|
|
if (NULL != hFind)
|
|
{
|
|
break;
|
|
}
|
|
hr = myHLastError();
|
|
if (!fRetried || HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
|
|
{
|
|
_JumpError(hr, error, "FindFirstUrlCacheEntry");
|
|
}
|
|
LocalFree(pcei);
|
|
pcei = NULL;
|
|
fRetried = TRUE;
|
|
}
|
|
*pcb = cb;
|
|
*ppcei = pcei;
|
|
pcei = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pcei)
|
|
{
|
|
LocalFree(pcei);
|
|
}
|
|
if (NULL == hFind)
|
|
{
|
|
CSASSERT(FAILED(hr));
|
|
SetLastError(hr);
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(S_OK == hr);
|
|
}
|
|
return(hFind);
|
|
}
|
|
|
|
|
|
BOOL
|
|
myFindNextUrlCacheEntry(
|
|
HANDLE hFind,
|
|
OUT INTERNET_CACHE_ENTRY_INFO **ppcei,
|
|
OUT DWORD *pcb)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fRet;
|
|
INTERNET_CACHE_ENTRY_INFO *pcei = NULL;
|
|
DWORD cb;
|
|
BOOL fRetried;
|
|
|
|
*ppcei = NULL;
|
|
cb = MAX_CACHE_ENTRY_INFO_SIZE;
|
|
fRet = FALSE;
|
|
fRetried = FALSE;
|
|
while (TRUE)
|
|
{
|
|
pcei = (INTERNET_CACHE_ENTRY_INFO *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pcei)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
fRet = FindNextUrlCacheEntry(hFind, pcei, &cb);
|
|
if (fRet)
|
|
{
|
|
break;
|
|
}
|
|
hr = myHLastError();
|
|
if (!fRetried || HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
|
|
{
|
|
_JumpError2(
|
|
hr,
|
|
error,
|
|
"FindNextUrlCacheEntry",
|
|
HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS));
|
|
}
|
|
LocalFree(pcei);
|
|
pcei = NULL;
|
|
fRetried = TRUE;
|
|
}
|
|
*pcb = cb;
|
|
*ppcei = pcei;
|
|
pcei = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (!fRet)
|
|
{
|
|
CSASSERT(FAILED(hr));
|
|
SetLastError(hr);
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(S_OK == hr);
|
|
}
|
|
return(fRet);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CachedURLIsCRL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hStore = NULL;
|
|
BOOL fIsCRL = FALSE;
|
|
CRL_CONTEXT const *pCRL = NULL;
|
|
|
|
if (!CryptRetrieveObjectByUrl(
|
|
pwszURL,
|
|
CONTEXT_OID_CRL,
|
|
CRYPT_CACHE_ONLY_RETRIEVAL |
|
|
CRYPT_RETRIEVE_MULTIPLE_OBJECTS,
|
|
0,
|
|
(VOID **) &hStore,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr2(hr, error, "CryptRetrieveObjectByUrl", pwszURL, hr);
|
|
}
|
|
|
|
pCRL = CertEnumCRLsInStore(hStore, NULL);
|
|
if (NULL == pCRL)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertEnumCRLsInStore");
|
|
|
|
}
|
|
fIsCRL = TRUE;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pCRL)
|
|
{
|
|
CertFreeCRLContext(pCRL);
|
|
}
|
|
if (NULL != hStore)
|
|
{
|
|
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
return(fIsCRL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnumWinINetCache(
|
|
IN BOOL fDelete,
|
|
IN BOOL fCRLsOnly)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
HANDLE hFind = NULL;
|
|
DWORD cDelete = 0;
|
|
DWORD cEntries = 0;
|
|
INTERNET_CACHE_ENTRY_INFO *pcei = NULL;
|
|
DWORD cb;
|
|
|
|
hFind = myFindFirstUrlCacheEntry(
|
|
NULL, // lpszUrlSearchPattern
|
|
&pcei,
|
|
&cb);
|
|
if (NULL == hFind)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myFindFirstUrlCacheEntry");
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!fCRLsOnly || CachedURLIsCRL(pcei->lpszSourceUrlName))
|
|
{
|
|
if (g_fVerbose)
|
|
{
|
|
hr = DisplayCacheEntryInfo(pcei->lpszSourceUrlName);
|
|
_PrintIfError(hr, "DisplayCacheEntryInfo");
|
|
|
|
if (1 < g_fVerbose)
|
|
{
|
|
BOOL fVerbose = g_fVerbose;
|
|
|
|
g_fVerbose -= 2;
|
|
hr = ReadURL(NULL, pcei->lpszSourceUrlName);
|
|
_PrintIfError(hr, "ReadURL");
|
|
g_fVerbose = fVerbose;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"%ws\n", pcei->lpszSourceUrlName);
|
|
}
|
|
wprintf(wszNewLine);
|
|
cEntries++;
|
|
|
|
if (fDelete)
|
|
{
|
|
if (!DeleteUrlCacheEntry(pcei->lpszSourceUrlName))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "DeleteUrlCacheEntry");
|
|
}
|
|
else
|
|
{
|
|
cDelete++;
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree(pcei);
|
|
pcei = NULL;
|
|
|
|
if (!myFindNextUrlCacheEntry(hFind, &pcei, &cb))
|
|
{
|
|
hr = myHLastError();
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpError(hr, error, "myFindNextUrlCacheEntry");
|
|
}
|
|
}
|
|
if (fDelete)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_FORMAT_DELETED_WININETCACHE), cDelete);
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_FORMAT_WININETCACHE), cEntries);
|
|
}
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hFind)
|
|
{
|
|
if (!FindCloseUrlCache(hFind))
|
|
{
|
|
hr2 = myHLastError();
|
|
_PrintError(hr2, "FindCloseUrlCache");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pcei)
|
|
{
|
|
LocalFree(pcei);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayWinINetURL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
HINTERNET hInternetSession = NULL;
|
|
HINTERNET hInternetFile = NULL;
|
|
|
|
wprintf(
|
|
L"**** %ws ****\n",
|
|
myLoadResourceString(g_fForce? IDS_ONLINE : IDS_OFFLINE));
|
|
|
|
hInternetSession = InternetOpen(
|
|
L"CertUtil URL Agent", // lpszAgent
|
|
INTERNET_OPEN_TYPE_PRECONFIG, // dwAccessType
|
|
NULL, // lpszProxy
|
|
NULL, // lpszProxyBypass
|
|
g_fForce? 0 : INTERNET_FLAG_FROM_CACHE);
|
|
if (NULL == hInternetSession)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "InternetOpen");
|
|
}
|
|
|
|
hInternetFile = InternetOpenUrl(
|
|
hInternetSession,
|
|
pwszURL,
|
|
L"Accept: */*\r\n", // lpszHeaders
|
|
MAXDWORD, // dwHeadersLength
|
|
INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
|
|
(g_fForce? INTERNET_FLAG_RELOAD : 0),
|
|
0); // dwContext
|
|
if (NULL == hInternetFile)
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"InternetOpenUrl",
|
|
pwszURL,
|
|
HRESULT_FROM_WIN32(ERROR_INTERNET_UNRECOGNIZED_SCHEME));
|
|
}
|
|
|
|
if (g_fForce)
|
|
{
|
|
if (g_fVerbose)
|
|
{
|
|
hr = DisplayCacheEntryInfo(pwszURL);
|
|
_PrintIfError(hr, "DisplayCacheEntryInfo");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_fVerbose && NULL != hInternetFile)
|
|
{
|
|
hr = DisplayQueryInfo(hInternetFile);
|
|
_PrintIfError(hr, "DisplayQueryInfo");
|
|
}
|
|
}
|
|
hr = ReadURL(hInternetFile, pwszURL);
|
|
_PrintIfError(hr, "ReadURL");
|
|
|
|
if (!g_fForce && g_fVerbose)
|
|
{
|
|
hr = DisplayCacheEntryInfo(pwszURL);
|
|
_PrintIfError(hr, "DisplayCacheEntryInfo");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hInternetFile)
|
|
{
|
|
if (!InternetCloseHandle(hInternetFile))
|
|
{
|
|
hr2 = myHLastError();
|
|
_PrintError(hr2, "InternetCloseHandle");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != hInternetSession)
|
|
{
|
|
if (!InternetCloseHandle(hInternetSession))
|
|
{
|
|
hr2 = myHLastError();
|
|
_PrintError(hr2, "InternetCloseHandle(Session)");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DeleteWinINetCachedURL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!DeleteUrlCacheEntry(pwszURL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "DeleteUrlCacheEntry");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
typedef BOOL (WINAPI FNCRYPTNETENUMURLCACHEENTRY)(
|
|
IN DWORD dwFlags,
|
|
IN LPVOID pvReserved,
|
|
IN LPVOID pvArg,
|
|
IN PFN_CRYPTNET_ENUM_URL_CACHE_ENTRY_CALLBACK pfnEnumCallback);
|
|
|
|
FNCRYPTNETENUMURLCACHEENTRY *g_pfnCryptNetEnumUrlCacheEntry = NULL;
|
|
|
|
HRESULT
|
|
LoadWinINetCacheFunction()
|
|
{
|
|
HRESULT hr;
|
|
HMODULE hModule;
|
|
|
|
hModule = GetModuleHandle(TEXT("cryptnet.dll"));
|
|
if (NULL == hModule)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "GetModuleHandle", L"cryptnet.dll");
|
|
}
|
|
|
|
// load system function
|
|
g_pfnCryptNetEnumUrlCacheEntry = (FNCRYPTNETENUMURLCACHEENTRY *)
|
|
GetProcAddress(hModule, "I_CryptNetEnumUrlCacheEntry");
|
|
|
|
if (NULL == g_pfnCryptNetEnumUrlCacheEntry)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "GetProcAddress", L"I_CryptNetEnumUrlCacheEntry");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
typedef struct _ENUM_ARG
|
|
{
|
|
WCHAR const *pwszUrlSubString; // NULL implies display/delete all
|
|
BOOL fDelete;
|
|
BOOL fCRLsOnly;
|
|
DWORD cUrl;
|
|
DWORD cUrlDeleted;
|
|
} ENUM_ARG;
|
|
|
|
|
|
BOOL
|
|
IsURLMatch(
|
|
WCHAR const *pwszCacheUrl,
|
|
WCHAR const *pwszUrlSubString)
|
|
{
|
|
BOOL fMatch = FALSE;
|
|
|
|
if (NULL == pwszUrlSubString)
|
|
{
|
|
fMatch = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Do case sensitive substring matching
|
|
|
|
if (0 == lstrcmpi(pwszCacheUrl, pwszUrlSubString) ||
|
|
wcsstr(pwszCacheUrl, pwszUrlSubString))
|
|
{
|
|
fMatch = TRUE;
|
|
}
|
|
}
|
|
return(fMatch);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WinHttpCacheEntryWorker(
|
|
IN CRYPTNET_URL_CACHE_ENTRY const *pUrlCacheEntry,
|
|
IN DWORD dwFlags,
|
|
IN VOID *pvReserved,
|
|
IN VOID *pvArg)
|
|
{
|
|
HRESULT hr;
|
|
ENUM_ARG *pArg = (ENUM_ARG *) pvArg;
|
|
DWORD cbBlob;
|
|
DWORD i;
|
|
BYTE *pbContent = NULL;
|
|
DWORD cbContent;
|
|
BYTE *pb;
|
|
|
|
if (!IsURLMatch(pUrlCacheEntry->pwszUrl, pArg->pwszUrlSubString))
|
|
{
|
|
goto error; // skip non-matching URLs
|
|
}
|
|
|
|
cbBlob = 0;
|
|
for (i = 0; i < pUrlCacheEntry->cBlob; i++)
|
|
{
|
|
cbBlob += pUrlCacheEntry->pcbBlob[i];
|
|
}
|
|
|
|
if (g_fVerbose || pArg->fCRLsOnly)
|
|
{
|
|
hr = DecodeFileW(
|
|
pUrlCacheEntry->pwszContentFileName,
|
|
&pbContent,
|
|
&cbContent,
|
|
CRYPT_STRING_ANY);
|
|
_PrintIfError(hr, "DecodeFileW");
|
|
|
|
if (NULL != pbContent && cbBlob != cbContent)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_PrintError(hr, "cuDumpFileTime");
|
|
if (cbBlob > cbContent)
|
|
{
|
|
LocalFree(pbContent); // invalid content
|
|
pbContent = NULL;
|
|
}
|
|
}
|
|
if (NULL != pbContent && pArg->fCRLsOnly)
|
|
{
|
|
BOOL fCRL = FALSE;
|
|
|
|
pb = pbContent;
|
|
for (i = 0; i < pUrlCacheEntry->cBlob; i++)
|
|
{
|
|
CRL_CONTEXT const *pCRL;
|
|
|
|
pCRL = CertCreateCRLContext(
|
|
X509_ASN_ENCODING,
|
|
pb,
|
|
pUrlCacheEntry->pcbBlob[i]);
|
|
if (NULL != pCRL)
|
|
{
|
|
CertFreeCRLContext(pCRL);
|
|
fCRL = TRUE;
|
|
break;
|
|
}
|
|
pb += pUrlCacheEntry->pcbBlob[i];
|
|
}
|
|
if (!fCRL)
|
|
{
|
|
goto error; // skip non-CRLS
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!g_fVerbose)
|
|
{
|
|
wprintf(L"%ws\n", pUrlCacheEntry->pwszUrl);
|
|
}
|
|
else
|
|
{
|
|
wprintf(
|
|
L"%ws %d %ws\n",
|
|
myLoadResourceString(IDS_WINHTTP_CACHE_ENTRY_COLON),
|
|
pUrlCacheEntry->cbSize,
|
|
myLoadResourceString(IDS_BYTES));
|
|
|
|
wprintf(
|
|
L" %ws \"%ws\"\n",
|
|
myLoadResourceString(IDS_FORMAT_SOURCE_URL),
|
|
pUrlCacheEntry->pwszUrl);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(
|
|
L" %ws \"%ws\"\n",
|
|
myLoadResourceString(IDS_FORMAT_LOCAL_FILENAME),
|
|
pUrlCacheEntry->pwszContentFileName);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(
|
|
L" %ws \"%ws\"\n",
|
|
myLoadResourceString(IDS_FORMAT_META_FILENAME),
|
|
pUrlCacheEntry->pwszMetaDataFileName);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_FILE_SIZE), cbBlob);
|
|
wprintf(wszNewLine);
|
|
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_LAST_SYNC_TIME_COLON));
|
|
cuDumpFileTime(0, NULL, &pUrlCacheEntry->LastSyncTime);
|
|
|
|
if (NULL != pbContent && 1 < g_fVerbose)
|
|
{
|
|
BOOL fVerbose = g_fVerbose;
|
|
|
|
g_fVerbose -= 2;
|
|
|
|
pb = pbContent;
|
|
for (i = 0; i < pUrlCacheEntry->cBlob; i++)
|
|
{
|
|
hr = cuDumpAsnBinary(pb, pUrlCacheEntry->pcbBlob[i], i);
|
|
if (S_OK != hr || 1 < g_fVerbose)
|
|
{
|
|
_PrintIfError(hr, "cuDumpAsnBinary");
|
|
DumpHex(0, pb, pUrlCacheEntry->pcbBlob[i]);
|
|
}
|
|
pb += pUrlCacheEntry->pcbBlob[i];
|
|
}
|
|
g_fVerbose = fVerbose;
|
|
}
|
|
}
|
|
if (pArg->fDelete)
|
|
{
|
|
hr = S_OK;
|
|
if (!DeleteFile(pUrlCacheEntry->pwszContentFileName))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr(hr, "DeleteFile", pUrlCacheEntry->pwszContentFileName);
|
|
}
|
|
if (!DeleteFile(pUrlCacheEntry->pwszMetaDataFileName))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr(hr, "DeleteFile", pUrlCacheEntry->pwszMetaDataFileName);
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
pArg->cUrlDeleted++;
|
|
}
|
|
}
|
|
wprintf(wszNewLine);
|
|
pArg->cUrl++;
|
|
|
|
error:
|
|
if (NULL != pbContent)
|
|
{
|
|
LocalFree(pbContent);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnumWinHttpCache(
|
|
OPTIONAL IN WCHAR const *pwszURL,
|
|
IN BOOL fDelete,
|
|
IN BOOL fCRLsOnly)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL != g_pfnCryptNetEnumUrlCacheEntry)
|
|
{
|
|
ENUM_ARG EnumArg;
|
|
|
|
memset(&EnumArg, 0, sizeof(EnumArg));
|
|
EnumArg.pwszUrlSubString = pwszURL;
|
|
EnumArg.fDelete = fDelete;
|
|
EnumArg.fCRLsOnly = fCRLsOnly;
|
|
|
|
if (!(*g_pfnCryptNetEnumUrlCacheEntry)(
|
|
0, // dwFlags
|
|
NULL, // pvReserved
|
|
&EnumArg,
|
|
WinHttpCacheEntryWorker))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "I_CryptNetEnumUrlCacheEntry");
|
|
}
|
|
if (fDelete)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_FORMAT_DELETED_WINHTTPCACHE), EnumArg.cUrlDeleted);
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_FORMAT_WINHTTPCACHE), EnumArg.cUrl);
|
|
}
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayWinHttpURL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = EnumWinHttpCache(pwszURL, FALSE, FALSE);
|
|
_JumpIfError(hr, error, "EnumWinHttpCache");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DeleteWinHttpCachedURL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = EnumWinHttpCache(pwszURL, TRUE, FALSE);
|
|
_JumpIfError(hr, error, "EnumWinHttpCache");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CacheSelectHResult(
|
|
IN HRESULT hr1,
|
|
IN HRESULT hr2)
|
|
{
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr1 ||
|
|
(S_OK != hr2 && HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr2))
|
|
{
|
|
hr1 = hr2;
|
|
}
|
|
return(hr1);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnumURLCache(
|
|
IN BOOL fDelete,
|
|
IN BOOL fCRLsOnly)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
|
|
hr = EnumWinINetCache(fDelete, fCRLsOnly);
|
|
_PrintIfError(hr, "EnumWinINetCache");
|
|
|
|
hr2 = EnumWinHttpCache(NULL, fDelete, fCRLsOnly);
|
|
_PrintIfError(hr2, "EnumWinHttpCache");
|
|
|
|
hr = CacheSelectHResult(hr, hr2);
|
|
_JumpIfError(hr, error, "EnumURLCache");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayURL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
|
|
hr = DisplayWinINetURL(pwszURL);
|
|
_PrintIfError(hr, "DisplayWinINetURL");
|
|
|
|
hr2 = DisplayWinHttpURL(pwszURL);
|
|
_PrintIfError(hr2, "DisplayWinHttpURL");
|
|
|
|
hr = CacheSelectHResult(hr, hr2);
|
|
_JumpIfError(hr, error, "DisplayURL");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DeleteCachedURL(
|
|
IN WCHAR const *pwszURL)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
|
|
hr = DeleteWinINetCachedURL(pwszURL);
|
|
_PrintIfError(hr, "DeleteWinINetCachedURL");
|
|
|
|
hr2 = DeleteWinHttpCachedURL(pwszURL);
|
|
_PrintIfError(hr2, "DeleteWinHttpCachedURL");
|
|
|
|
hr = CacheSelectHResult(hr, hr2);
|
|
_JumpIfError(hr, error, "DeleteCachedURL");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbURLCache(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszURL,
|
|
IN WCHAR const *pwszDelete,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = LoadWinINetCacheFunction();
|
|
_PrintIfError(hr, "LoadWinINetCacheFunction");
|
|
|
|
if (NULL != pwszDelete)
|
|
{
|
|
if (0 != LSTRCMPIS(pwszDelete, L"Delete"))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad delete arg");
|
|
}
|
|
if (0 == lstrcmp(L"*", pwszURL))
|
|
{
|
|
hr = EnumURLCache(TRUE, FALSE); // fDelete, fCRLsOnly (delete all)
|
|
_JumpIfError(hr, error, "EnumURLCache(Delete all)");
|
|
|
|
hr = DeleteCacheGroups();
|
|
_JumpIfError(hr, error, "DeleteCacheGroups");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszURL, L"crl"))
|
|
{
|
|
hr = EnumURLCache(TRUE, TRUE); // fDelete, fCRLsOnly (delete CRLs)
|
|
_JumpIfError(hr, error, "EnumURLCache(Delete CRLs)");
|
|
}
|
|
else
|
|
{
|
|
hr = DeleteCachedURL(pwszURL); // delete single URL
|
|
_JumpIfError(hr, error, "DeleteCachedURL");
|
|
}
|
|
}
|
|
else if (NULL == pwszURL || 0 == lstrcmp(L"*", pwszURL))
|
|
{
|
|
hr = EnumURLCache(FALSE, FALSE); // fDelete, fCRLsOnly (display all)
|
|
_JumpIfError(hr, error, "EnumURLCache");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszURL, L"crl"))
|
|
{
|
|
hr = EnumURLCache(FALSE, TRUE); // fDelete, fCRLsOnly (display CRLs)
|
|
_JumpIfError(hr, error, "EnumURLCache(CRLs)");
|
|
}
|
|
else
|
|
{
|
|
hr = DisplayURL(pwszURL);
|
|
_JumpIfError(hr, error, "DisplayURL");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|