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.
1184 lines
36 KiB
1184 lines
36 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows NT Security
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: scheme.cpp
|
|
//
|
|
// Contents: Generic Scheme Provider Utility Functions
|
|
//
|
|
// History: 18-Aug-97 kirtd Created
|
|
// 01-Jan-02 philh Moved from wininet to winhttp
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <global.hxx>
|
|
#include <userenv.h>
|
|
#include <userenvp.h> // for GetUserAppDataPathW
|
|
#include <dbgdef.h>
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// For impersonation, return thread token, otherwise, return process token
|
|
//--------------------------------------------------------------------------
|
|
HANDLE
|
|
WINAPI
|
|
I_SchemeGetToken()
|
|
{
|
|
HANDLE hToken = NULL;
|
|
DWORD dwErr;
|
|
|
|
//
|
|
// first, attempt to look at the thread token. If none exists,
|
|
// which is true if the thread is not impersonating, try the
|
|
// process token.
|
|
//
|
|
|
|
if (!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&hToken
|
|
)) {
|
|
dwErr = GetLastError();
|
|
if (ERROR_NO_TOKEN != dwErr)
|
|
goto OpenThreadTokenError;
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &hToken)) {
|
|
dwErr = GetLastError();
|
|
goto OpenProcessTokenError;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
return hToken;
|
|
ErrorReturn:
|
|
hToken = NULL;
|
|
goto CommonReturn;
|
|
SET_ERROR_VAR(OpenThreadTokenError, dwErr)
|
|
SET_ERROR_VAR(OpenProcessTokenError, dwErr)
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Ensure LastError is preserved
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
WINAPI
|
|
I_SchemeCloseHandle(
|
|
IN HANDLE h
|
|
)
|
|
{
|
|
if (h) {
|
|
DWORD dwErr = GetLastError();
|
|
|
|
CloseHandle(h);
|
|
|
|
SetLastError(dwErr);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Returns %UserProfile%\Microsoft\CryptnetUrlCache\ which must be
|
|
// freed via PkiFree().
|
|
//--------------------------------------------------------------------------
|
|
LPWSTR
|
|
WINAPI
|
|
I_SchemeGetCryptnetUrlCacheDir()
|
|
{
|
|
DWORD dwErr;
|
|
HANDLE hToken = NULL;
|
|
LPWSTR pwszDir = NULL;
|
|
DWORD cchDir;
|
|
WCHAR wszAppDataPath[MAX_PATH + 1];
|
|
|
|
hToken = I_SchemeGetToken();
|
|
|
|
wszAppDataPath[0] = L'\0';
|
|
dwErr = GetUserAppDataPathW(
|
|
hToken,
|
|
FALSE, // fLocalAppData
|
|
wszAppDataPath
|
|
);
|
|
|
|
if (ERROR_SUCCESS != dwErr || L'\0' == wszAppDataPath[0])
|
|
goto GetUserAppDataPathError;
|
|
|
|
wszAppDataPath[MAX_PATH] = L'\0';
|
|
|
|
#if DBG
|
|
DbgPrintf(DBG_SS_CRYPT32, "userenv!GetUserAppDataPathW:: %S\n",
|
|
wszAppDataPath);
|
|
#endif
|
|
|
|
cchDir = wcslen(wszAppDataPath) + wcslen(SCHEME_CRYPTNET_URL_CACHE_DIR) + 1;
|
|
|
|
pwszDir = (LPWSTR) PkiNonzeroAlloc(cchDir * sizeof(WCHAR));
|
|
if (NULL == pwszDir)
|
|
goto OutOfMemory;
|
|
|
|
wcscpy(pwszDir, wszAppDataPath);
|
|
wcscat(pwszDir, SCHEME_CRYPTNET_URL_CACHE_DIR);
|
|
|
|
CommonReturn:
|
|
if (hToken)
|
|
I_SchemeCloseHandle(hToken);
|
|
return pwszDir;
|
|
ErrorReturn:
|
|
pwszDir = NULL;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR_VAR(GetUserAppDataPathError, dwErr)
|
|
TRACE_ERROR(OutOfMemory)
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Converts the bytes into UNICODE HEX
|
|
//
|
|
// Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
WINAPI
|
|
I_SchemeBytesToWStr(DWORD cb, void* pv, LPWSTR wsz)
|
|
{
|
|
BYTE* pb = (BYTE*) pv;
|
|
for (DWORD i = 0; i<cb; i++) {
|
|
int b;
|
|
b = (*pb & 0xF0) >> 4;
|
|
*wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
|
|
b = *pb & 0x0F;
|
|
*wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
|
|
pb++;
|
|
}
|
|
*wsz++ = 0;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Gets the URL's filename by formatting its MD5 hash as UNICODE hex
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
WINAPI
|
|
I_SchemeGetUrlFileName(
|
|
IN LPCWSTR pwszUrl,
|
|
OUT WCHAR wszUrlFileName[SCHEME_URL_FILENAME_LEN]
|
|
)
|
|
{
|
|
MD5_CTX md5ctx;
|
|
|
|
MD5Init(&md5ctx);
|
|
MD5Update(&md5ctx, (const BYTE *) pwszUrl, wcslen(pwszUrl) * sizeof(WCHAR));
|
|
MD5Final(&md5ctx);
|
|
|
|
// convert to a string
|
|
I_SchemeBytesToWStr(MD5DIGESTLEN, md5ctx.digest, wszUrlFileName);
|
|
}
|
|
|
|
static DWORD rgdwCreateFileRetryMilliseconds[] =
|
|
{ 1, 10, 100, 500, 1000, 5000 };
|
|
|
|
#define MAX_CREATE_FILE_RETRY_COUNT \
|
|
(sizeof(rgdwCreateFileRetryMilliseconds) / \
|
|
sizeof(rgdwCreateFileRetryMilliseconds[0]))
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// For ERROR_SHARING_VIOLATION or ERROR_ACCESS_DENIED errors returned
|
|
// by CreateFileW(), retries after sleeping the above times.
|
|
//
|
|
// Note, the file to be created is under %UserProfile%. Therefore, unless
|
|
// opened by another thread shouldn't get the above errors.
|
|
//
|
|
// If unable to create the file, returns NULL and not INVALID_HANDLE_VALUE.
|
|
//--------------------------------------------------------------------------
|
|
HANDLE
|
|
WINAPI
|
|
I_SchemeCreateFile(
|
|
IN LPCWSTR pwszFileName,
|
|
IN BOOL fWrite
|
|
)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD dwErr;
|
|
DWORD dwRetryCount;
|
|
|
|
dwRetryCount = 0;
|
|
while (INVALID_HANDLE_VALUE == (hFile = CreateFileW(
|
|
pwszFileName,
|
|
fWrite ? (GENERIC_WRITE | GENERIC_READ) : GENERIC_READ,
|
|
fWrite ? 0 : FILE_SHARE_READ,
|
|
NULL, // lpsa
|
|
fWrite ? CREATE_ALWAYS : OPEN_EXISTING,
|
|
fWrite ? FILE_ATTRIBUTE_SYSTEM : FILE_ATTRIBUTE_NORMAL,
|
|
NULL // hTemplateFile
|
|
))) {
|
|
dwErr = GetLastError();
|
|
if ((ERROR_SHARING_VIOLATION == dwErr ||
|
|
ERROR_ACCESS_DENIED == dwErr) &&
|
|
MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
|
|
Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
|
|
dwRetryCount++;
|
|
} else {
|
|
if (ERROR_PATH_NOT_FOUND == dwErr)
|
|
dwErr = ERROR_FILE_NOT_FOUND;
|
|
goto CreateFileError;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
return hFile;
|
|
ErrorReturn:
|
|
hFile = NULL;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR_VAR(CreateFileError, dwErr)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// The MetaData file is always opened first and closed last.
|
|
// Its opened for writing without sharing.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
I_SchemeCreateCacheFiles(
|
|
IN LPCWSTR pwszUrl,
|
|
IN BOOL fWrite,
|
|
OUT HANDLE *phMetaDataFile,
|
|
OUT HANDLE *phContentFile
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
LPWSTR pwszCryptnetUrlCacheDir = NULL;
|
|
DWORD cchCryptnetUrlCacheDir;
|
|
LPWSTR pwszMetaDataFile = NULL;
|
|
LPWSTR pwszContentFile = NULL;
|
|
|
|
HANDLE hMetaDataFile = NULL;
|
|
HANDLE hContentFile = NULL;
|
|
WCHAR wszUrlFileName[SCHEME_URL_FILENAME_LEN];
|
|
|
|
pwszCryptnetUrlCacheDir = I_SchemeGetCryptnetUrlCacheDir();
|
|
if (NULL == pwszCryptnetUrlCacheDir)
|
|
goto GetCryptnetUrlCacheDirError;
|
|
|
|
cchCryptnetUrlCacheDir = wcslen(pwszCryptnetUrlCacheDir);
|
|
|
|
pwszMetaDataFile = (LPWSTR) PkiNonzeroAlloc(
|
|
(cchCryptnetUrlCacheDir + wcslen(SCHEME_META_DATA_SUBDIR) + 1 +
|
|
SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
|
|
pwszContentFile = (LPWSTR) PkiNonzeroAlloc(
|
|
(cchCryptnetUrlCacheDir + wcslen(SCHEME_CONTENT_SUBDIR) + 1 +
|
|
SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
|
|
|
|
if (NULL == pwszMetaDataFile || NULL == pwszContentFile)
|
|
goto OutOfMemory;
|
|
|
|
wcscpy(pwszMetaDataFile, pwszCryptnetUrlCacheDir);
|
|
wcscat(pwszMetaDataFile, SCHEME_META_DATA_SUBDIR);
|
|
wcscpy(pwszContentFile, pwszCryptnetUrlCacheDir);
|
|
wcscat(pwszContentFile, SCHEME_CONTENT_SUBDIR);
|
|
|
|
|
|
if (fWrite) {
|
|
if (!I_RecursiveCreateDirectory(pwszMetaDataFile, NULL))
|
|
goto CreateMetaDataDirError;
|
|
if (!I_RecursiveCreateDirectory(pwszContentFile, NULL))
|
|
goto CreateContentDirError;
|
|
}
|
|
|
|
I_SchemeGetUrlFileName(pwszUrl, wszUrlFileName);
|
|
|
|
wcscat(pwszMetaDataFile, L"\\");
|
|
wcscat(pwszMetaDataFile, wszUrlFileName);
|
|
hMetaDataFile = I_SchemeCreateFile(pwszMetaDataFile, fWrite);
|
|
if (NULL == hMetaDataFile)
|
|
goto CreateMetaDataFileError;
|
|
|
|
wcscat(pwszContentFile, L"\\");
|
|
wcscat(pwszContentFile, wszUrlFileName);
|
|
hContentFile = I_SchemeCreateFile(pwszContentFile, fWrite);
|
|
if (NULL == hContentFile)
|
|
goto CreateContentFileError;
|
|
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
PkiFree(pwszCryptnetUrlCacheDir);
|
|
PkiFree(pwszMetaDataFile);
|
|
PkiFree(pwszContentFile);
|
|
|
|
*phMetaDataFile = hMetaDataFile;
|
|
*phContentFile = hContentFile;
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
if (NULL != hContentFile) {
|
|
I_SchemeCloseHandle(hContentFile);
|
|
hContentFile = NULL;
|
|
}
|
|
if (NULL != hMetaDataFile) {
|
|
I_SchemeCloseHandle(hMetaDataFile);
|
|
hMetaDataFile = NULL;
|
|
}
|
|
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetCryptnetUrlCacheDirError)
|
|
TRACE_ERROR(OutOfMemory)
|
|
TRACE_ERROR(CreateMetaDataDirError)
|
|
TRACE_ERROR(CreateContentDirError)
|
|
TRACE_ERROR(CreateMetaDataFileError)
|
|
TRACE_ERROR(CreateContentFileError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// The returned MetaDataHeader must be freed via PkiFree(). Returns NULL
|
|
// for any errors. pcbBlob and pwszUrl point to memory following the
|
|
// header and don't need to be freed.
|
|
//
|
|
// The pwsUrl is guaranteed to be NULL terminated.
|
|
//--------------------------------------------------------------------------
|
|
PSCHEME_CACHE_META_DATA_HEADER
|
|
WINAPI
|
|
I_SchemeReadAndValidateMetaDataFile(
|
|
IN HANDLE hMetaDataFile,
|
|
OUT OPTIONAL DWORD **ppcbBlob, // Not allocated
|
|
OUT OPTIONAL LPCWSTR *ppwszUrl // Not allocated
|
|
)
|
|
{
|
|
PSCHEME_CACHE_META_DATA_HEADER pMetaDataHeader = NULL;
|
|
DWORD *pcbBlob = NULL;
|
|
LPWSTR pwszUrl = NULL;
|
|
|
|
DWORD cbMetaData;
|
|
DWORD cbBytesRead;
|
|
DWORD cBlob;
|
|
DWORD cchUrl;
|
|
DWORD dwUrlOffset;
|
|
|
|
cbMetaData = GetFileSize(hMetaDataFile, NULL);
|
|
if (INVALID_FILE_SIZE == cbMetaData ||
|
|
sizeof(SCHEME_CACHE_META_DATA_HEADER) > cbMetaData)
|
|
goto InvalidMetaDataFile;
|
|
|
|
pMetaDataHeader = (PSCHEME_CACHE_META_DATA_HEADER) PkiZeroAlloc(
|
|
cbMetaData);
|
|
if (NULL == pMetaDataHeader)
|
|
goto OutOfMemory;
|
|
|
|
if (!ReadFile(
|
|
hMetaDataFile,
|
|
pMetaDataHeader,
|
|
cbMetaData,
|
|
&cbBytesRead,
|
|
NULL // lpOverlapped
|
|
) || cbMetaData != cbBytesRead)
|
|
goto ReadMetaDataFileError;
|
|
|
|
cBlob = pMetaDataHeader->cBlob;
|
|
|
|
if (sizeof(SCHEME_CACHE_META_DATA_HEADER) > pMetaDataHeader->cbSize ||
|
|
cbMetaData < pMetaDataHeader->cbSize ||
|
|
0 != (pMetaDataHeader->cbSize % sizeof(DWORD)) ||
|
|
cBlob > (cbMetaData - pMetaDataHeader->cbSize) / sizeof(DWORD))
|
|
goto InvalidMetaDataFile;
|
|
|
|
pcbBlob = (DWORD *) (((BYTE*)pMetaDataHeader) + pMetaDataHeader->cbSize);
|
|
|
|
cchUrl = pMetaDataHeader->cbUrl / sizeof(WCHAR);
|
|
dwUrlOffset = pMetaDataHeader->cbSize + sizeof(DWORD) * cBlob;
|
|
if (0 == cchUrl ||
|
|
cchUrl > (cbMetaData - dwUrlOffset) / sizeof(WCHAR))
|
|
goto InvalidMetaDataFile;
|
|
pwszUrl = (LPWSTR) (((BYTE*)pMetaDataHeader) + dwUrlOffset);
|
|
pwszUrl[cchUrl - 1] = L'\0';
|
|
|
|
CommonReturn:
|
|
if (ppcbBlob)
|
|
*ppcbBlob = pcbBlob;
|
|
if (ppwszUrl)
|
|
*ppwszUrl = (LPCWSTR) pwszUrl;
|
|
|
|
return pMetaDataHeader;
|
|
|
|
ErrorReturn:
|
|
if (pMetaDataHeader) {
|
|
PkiFree(pMetaDataHeader);
|
|
pMetaDataHeader = NULL;
|
|
}
|
|
pcbBlob = NULL;
|
|
pwszUrl = NULL;
|
|
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(InvalidMetaDataFile, CRYPT_E_FILE_ERROR)
|
|
TRACE_ERROR(OutOfMemory)
|
|
TRACE_ERROR(ReadMetaDataFileError)
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeCacheCryptBlobArray
|
|
//
|
|
// Synopsis: cache the crypt blob array under the given URL
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SchemeCacheCryptBlobArray (
|
|
IN LPCWSTR pwszUrl,
|
|
IN DWORD dwRetrievalFlags,
|
|
IN PCRYPT_BLOB_ARRAY pcba,
|
|
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
SCHEME_CACHE_META_DATA_HEADER MetaDataHeader;
|
|
HANDLE hMetaDataFile = NULL;
|
|
HANDLE hContentFile = NULL;
|
|
DWORD cbBytesWritten;
|
|
DWORD i;
|
|
|
|
if (!I_SchemeCreateCacheFiles(
|
|
pwszUrl,
|
|
TRUE, // fWrite
|
|
&hMetaDataFile,
|
|
&hContentFile
|
|
))
|
|
goto CreateCacheFilesError;
|
|
|
|
memset(&MetaDataHeader, 0, sizeof(MetaDataHeader));
|
|
MetaDataHeader.cbSize = sizeof(MetaDataHeader);
|
|
MetaDataHeader.dwMagic = SCHEME_CACHE_META_DATA_MAGIC;
|
|
MetaDataHeader.cBlob = pcba->cBlob;
|
|
MetaDataHeader.cbUrl = (wcslen(pwszUrl) + 1) * sizeof(WCHAR);
|
|
GetSystemTimeAsFileTime(&MetaDataHeader.LastSyncTime);
|
|
|
|
if (!WriteFile(
|
|
hMetaDataFile,
|
|
&MetaDataHeader,
|
|
sizeof(MetaDataHeader),
|
|
&cbBytesWritten,
|
|
NULL // lpOverlapped
|
|
))
|
|
goto WriteMetaDataHeaderError;
|
|
|
|
for (i = 0; i < pcba->cBlob; i++) {
|
|
DWORD cbBlob = pcba->rgBlob[i].cbData;
|
|
|
|
if (!WriteFile(
|
|
hMetaDataFile,
|
|
&cbBlob,
|
|
sizeof(cbBlob),
|
|
&cbBytesWritten,
|
|
NULL // lpOverlapped
|
|
))
|
|
goto WriteBlobLengthError;
|
|
|
|
if (0 != cbBlob) {
|
|
if (!WriteFile(
|
|
hContentFile,
|
|
pcba->rgBlob[i].pbData,
|
|
cbBlob,
|
|
&cbBytesWritten,
|
|
NULL // lpOverlapped
|
|
))
|
|
goto WriteBlobContentError;
|
|
}
|
|
}
|
|
|
|
if (!WriteFile(
|
|
hMetaDataFile,
|
|
pwszUrl,
|
|
MetaDataHeader.cbUrl,
|
|
&cbBytesWritten,
|
|
NULL // lpOverlapped
|
|
))
|
|
goto WriteUrlError;
|
|
|
|
if (pAuxInfo &&
|
|
offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
|
|
pAuxInfo->cbSize && pAuxInfo->pLastSyncTime)
|
|
*pAuxInfo->pLastSyncTime = MetaDataHeader.LastSyncTime;
|
|
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
if (NULL != hContentFile)
|
|
I_SchemeCloseHandle(hContentFile);
|
|
if (NULL != hMetaDataFile)
|
|
I_SchemeCloseHandle(hMetaDataFile);
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR(CreateCacheFilesError)
|
|
TRACE_ERROR(WriteMetaDataHeaderError)
|
|
TRACE_ERROR(WriteBlobLengthError)
|
|
TRACE_ERROR(WriteBlobContentError)
|
|
TRACE_ERROR(WriteUrlError)
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeRetrieveCachedCryptBlobArray
|
|
//
|
|
// Synopsis: retrieve cached blob array bits
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SchemeRetrieveCachedCryptBlobArray (
|
|
IN LPCWSTR pwszUrl,
|
|
IN DWORD dwRetrievalFlags,
|
|
OUT PCRYPT_BLOB_ARRAY pcba,
|
|
OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
|
|
OUT LPVOID* ppvFreeContext,
|
|
IN OUT PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
HANDLE hMetaDataFile = NULL;
|
|
HANDLE hContentFile = NULL;
|
|
PSCHEME_CACHE_META_DATA_HEADER pMetaDataHeader = NULL;
|
|
DWORD *pcbBlob; // not allocated
|
|
DWORD cbContent;
|
|
DWORD cBlob;
|
|
PCRYPT_BLOB_ARRAY pCachedArray = NULL;
|
|
PCRYPT_DATA_BLOB pBlob; // not allocated
|
|
BYTE *pbBlob; // not allocated
|
|
DWORD cbBlobHeader;
|
|
DWORD cbBytesRead;
|
|
DWORD i;
|
|
|
|
if (!I_SchemeCreateCacheFiles(
|
|
pwszUrl,
|
|
FALSE, // fWrite
|
|
&hMetaDataFile,
|
|
&hContentFile
|
|
))
|
|
goto CreateCacheFilesError;
|
|
|
|
pMetaDataHeader = I_SchemeReadAndValidateMetaDataFile(
|
|
hMetaDataFile,
|
|
&pcbBlob,
|
|
NULL // ppwszUrl
|
|
);
|
|
if (NULL == pMetaDataHeader)
|
|
goto ReadMetaDataFileError;
|
|
|
|
cBlob = pMetaDataHeader->cBlob;
|
|
|
|
cbContent = 0;
|
|
for (i = 0; i < cBlob; i++)
|
|
cbContent += pcbBlob[i];
|
|
|
|
cbBlobHeader = sizeof(CRYPT_BLOB_ARRAY) + cBlob * sizeof(CRYPT_DATA_BLOB);
|
|
pCachedArray = (PCRYPT_BLOB_ARRAY) PkiZeroAlloc(
|
|
cbBlobHeader + cbContent);
|
|
if (NULL == pCachedArray)
|
|
goto OutOfMemory;
|
|
|
|
pBlob = (PCRYPT_DATA_BLOB) &pCachedArray[1];
|
|
pbBlob = (BYTE *) &pBlob[cBlob];
|
|
|
|
if (0 != cbContent) {
|
|
if (!ReadFile(
|
|
hContentFile,
|
|
pbBlob,
|
|
cbContent,
|
|
&cbBytesRead,
|
|
NULL // lpOverlapped
|
|
) || cbContent != cbBytesRead)
|
|
goto ReadContentFileError;
|
|
}
|
|
|
|
pCachedArray->cBlob = cBlob;
|
|
pCachedArray->rgBlob = pBlob;
|
|
|
|
for (i = 0; i < cBlob; i++) {
|
|
pBlob[i].cbData = pcbBlob[i];
|
|
pBlob[i].pbData = pbBlob;
|
|
pbBlob += pcbBlob[i];
|
|
}
|
|
|
|
pcba->cBlob = pCachedArray->cBlob;
|
|
pcba->rgBlob = pCachedArray->rgBlob;
|
|
|
|
*ppfnFreeObject = SchemeFreeEncodedCryptBlobArray;
|
|
*ppvFreeContext = (LPVOID) pCachedArray;
|
|
|
|
if (pAuxInfo && offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
|
|
pAuxInfo->cbSize && pAuxInfo->pLastSyncTime)
|
|
*pAuxInfo->pLastSyncTime = pMetaDataHeader->LastSyncTime;
|
|
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
if (NULL != hContentFile)
|
|
I_SchemeCloseHandle(hContentFile);
|
|
if (NULL != hMetaDataFile)
|
|
I_SchemeCloseHandle(hMetaDataFile);
|
|
PkiFree(pMetaDataHeader);
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
PkiFree(pCachedArray);
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(CreateCacheFilesError)
|
|
TRACE_ERROR(OutOfMemory)
|
|
TRACE_ERROR(ReadMetaDataFileError)
|
|
TRACE_ERROR(ReadContentFileError)
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// For ERROR_SHARING_VIOLATION or ERROR_ACCESS_DENIED errors returned
|
|
// by DeleteFileW(), retries after sleeping an increasing array of times.
|
|
//
|
|
// Note, the file to be deleted is under %UserProfile%. Therefore, unless
|
|
// opened by another thread shouldn't get the above errors.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
I_SchemeDeleteFile(
|
|
IN LPCWSTR pwszFileName
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD dwErr;
|
|
DWORD dwRetryCount;
|
|
|
|
dwRetryCount = 0;
|
|
while (!DeleteFileU(pwszFileName)) {
|
|
dwErr = GetLastError();
|
|
if ((ERROR_SHARING_VIOLATION == dwErr ||
|
|
ERROR_ACCESS_DENIED == dwErr) &&
|
|
MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
|
|
Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
|
|
dwRetryCount++;
|
|
} else
|
|
goto DeleteFileError;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
return fResult;
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR_VAR(DeleteFileError, dwErr)
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeDeleteUrlCacheEntry
|
|
//
|
|
// Synopsis: delete URL cache entry
|
|
//
|
|
// For no cache entry returns FALSE with LastError set to
|
|
// ERROR_FILE_NOT_FOUND
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SchemeDeleteUrlCacheEntry (
|
|
IN LPCWSTR pwszUrl
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
LPWSTR pwszCryptnetUrlCacheDir = NULL;
|
|
DWORD cchCryptnetUrlCacheDir;
|
|
LPWSTR pwszMetaDataFile = NULL;
|
|
LPWSTR pwszContentFile = NULL;
|
|
WCHAR wszUrlFileName[SCHEME_URL_FILENAME_LEN];
|
|
|
|
|
|
// Format the MetaData and Content filenames
|
|
// - %UserProfile%\Microsoft\CryptnetUrlCache\MetaData\14A1AE3A6A7648689AE8F94F367AC606
|
|
// - %UserProfile%\Microsoft\CryptnetUrlCache\Content\14A1AE3A6A7648689AE8F94F367AC606
|
|
// Where 14A1AE3A6A7648689AE8F94F367AC606 is the Unicode Hex of md5 hash
|
|
// of the URL string
|
|
|
|
pwszCryptnetUrlCacheDir = I_SchemeGetCryptnetUrlCacheDir();
|
|
if (NULL == pwszCryptnetUrlCacheDir)
|
|
goto GetCryptnetUrlCacheDirError;
|
|
|
|
cchCryptnetUrlCacheDir = wcslen(pwszCryptnetUrlCacheDir);
|
|
|
|
pwszMetaDataFile = (LPWSTR) PkiNonzeroAlloc(
|
|
(cchCryptnetUrlCacheDir + wcslen(SCHEME_META_DATA_SUBDIR) + 1 +
|
|
SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
|
|
pwszContentFile = (LPWSTR) PkiNonzeroAlloc(
|
|
(cchCryptnetUrlCacheDir + wcslen(SCHEME_CONTENT_SUBDIR) + 1 +
|
|
SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
|
|
|
|
if (NULL == pwszMetaDataFile || NULL == pwszContentFile)
|
|
goto OutOfMemory;
|
|
|
|
I_SchemeGetUrlFileName(pwszUrl, wszUrlFileName);
|
|
|
|
wcscpy(pwszMetaDataFile, pwszCryptnetUrlCacheDir);
|
|
wcscat(pwszMetaDataFile, SCHEME_META_DATA_SUBDIR);
|
|
wcscat(pwszMetaDataFile, L"\\");
|
|
wcscat(pwszMetaDataFile, wszUrlFileName);
|
|
|
|
wcscpy(pwszContentFile, pwszCryptnetUrlCacheDir);
|
|
wcscat(pwszContentFile, SCHEME_CONTENT_SUBDIR);
|
|
wcscat(pwszContentFile, L"\\");
|
|
wcscat(pwszContentFile, wszUrlFileName);
|
|
|
|
// Delete both the content and meta data files.
|
|
if (!I_SchemeDeleteFile(pwszContentFile)) {
|
|
if (ERROR_FILE_NOT_FOUND != GetLastError())
|
|
goto DeleteContentFileError;
|
|
}
|
|
|
|
fResult = I_SchemeDeleteFile(pwszMetaDataFile);
|
|
|
|
CommonReturn:
|
|
PkiFree(pwszCryptnetUrlCacheDir);
|
|
PkiFree(pwszMetaDataFile);
|
|
PkiFree(pwszContentFile);
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetCryptnetUrlCacheDirError)
|
|
TRACE_ERROR(OutOfMemory)
|
|
TRACE_ERROR(DeleteContentFileError)
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeFreeEncodedCryptBlobArray
|
|
//
|
|
// Synopsis: free encoded crypt blob array
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SchemeFreeEncodedCryptBlobArray (
|
|
IN LPCSTR pszObjectOid,
|
|
IN PCRYPT_BLOB_ARRAY pcba,
|
|
IN LPVOID pvFreeContext
|
|
)
|
|
{
|
|
PkiFree(pvFreeContext);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeGetPasswordCredentialsW
|
|
//
|
|
// Synopsis: get password credentials from crypt credentials
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SchemeGetPasswordCredentialsW (
|
|
IN PCRYPT_CREDENTIALS pCredentials,
|
|
OUT PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials,
|
|
OUT BOOL* pfFreeCredentials
|
|
)
|
|
{
|
|
DWORD cwUsername;
|
|
DWORD cwPassword;
|
|
PCRYPT_PASSWORD_CREDENTIALSA pPassCredA;
|
|
PCRYPT_PASSWORD_CREDENTIALSW pPassCredW;
|
|
LPWSTR pszUsername;
|
|
LPWSTR pszPassword;
|
|
|
|
if ( pPasswordCredentials->cbSize != sizeof( CRYPT_PASSWORD_CREDENTIALS ) )
|
|
{
|
|
SetLastError( (DWORD) E_INVALIDARG );
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( pCredentials == NULL )
|
|
{
|
|
pPasswordCredentials->pszUsername = NULL;
|
|
pPasswordCredentials->pszPassword = NULL;
|
|
*pfFreeCredentials = FALSE;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
if ( pCredentials->pszCredentialsOid ==
|
|
CREDENTIAL_OID_PASSWORD_CREDENTIALS_W )
|
|
{
|
|
pPassCredW = (PCRYPT_PASSWORD_CREDENTIALSW)pCredentials->pvCredentials;
|
|
*pPasswordCredentials = *pPassCredW;
|
|
*pfFreeCredentials = FALSE;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
if ( pCredentials->pszCredentialsOid !=
|
|
CREDENTIAL_OID_PASSWORD_CREDENTIALS_A )
|
|
{
|
|
SetLastError( (DWORD) E_INVALIDARG );
|
|
return( FALSE );
|
|
}
|
|
|
|
pPassCredA = (PCRYPT_PASSWORD_CREDENTIALSA)pCredentials->pvCredentials;
|
|
cwUsername = strlen( pPassCredA->pszUsername ) + 1;
|
|
cwPassword = strlen( pPassCredA->pszPassword ) + 1;
|
|
|
|
pszUsername = new WCHAR [ cwUsername ];
|
|
pszPassword = new WCHAR [ cwPassword ];
|
|
|
|
if ( ( pszUsername == NULL ) || ( pszPassword == NULL ) )
|
|
{
|
|
delete [] pszUsername;
|
|
delete [] pszPassword;
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
*pfFreeCredentials = TRUE;
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pPassCredA->pszUsername,
|
|
cwUsername,
|
|
pszUsername,
|
|
cwUsername
|
|
);
|
|
pszUsername[cwUsername - 1] = L'\0';
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pPassCredA->pszPassword,
|
|
cwPassword,
|
|
pszPassword,
|
|
cwPassword
|
|
);
|
|
pszPassword[cwPassword - 1] = L'\0';
|
|
|
|
pPasswordCredentials->pszUsername = pszUsername;
|
|
pPasswordCredentials->pszPassword = pszPassword;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeFreePasswordCredentialsA
|
|
//
|
|
// Synopsis: free password credentials
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SchemeFreePasswordCredentialsW (
|
|
IN PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials
|
|
)
|
|
{
|
|
DWORD cch;
|
|
|
|
// Ensure allocated credentials are cleared out before being freed.
|
|
|
|
if (pPasswordCredentials->pszUsername)
|
|
{
|
|
cch = wcslen(pPasswordCredentials->pszUsername);
|
|
SecureZeroMemory(pPasswordCredentials->pszUsername,
|
|
cch * sizeof(WCHAR));
|
|
delete [] pPasswordCredentials->pszUsername;
|
|
}
|
|
|
|
|
|
if (pPasswordCredentials->pszPassword)
|
|
{
|
|
cch = wcslen(pPasswordCredentials->pszPassword);
|
|
SecureZeroMemory(pPasswordCredentials->pszPassword,
|
|
cch * sizeof(WCHAR));
|
|
delete [] pPasswordCredentials->pszPassword;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeGetAuthIdentityFromPasswordCredentialsW
|
|
//
|
|
// Synopsis: converts a CRYPT_PASSWORD_CREDENTIALSW to a
|
|
// SEC_WINNT_AUTH_IDENTITY_W
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SchemeGetAuthIdentityFromPasswordCredentialsW (
|
|
IN PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials,
|
|
OUT PSEC_WINNT_AUTH_IDENTITY_W pAuthIdentity
|
|
)
|
|
{
|
|
DWORD cDomain = 0;
|
|
|
|
if ( pPasswordCredentials->pszUsername == NULL )
|
|
{
|
|
pAuthIdentity->User = NULL;
|
|
pAuthIdentity->UserLength = 0;
|
|
pAuthIdentity->Domain = NULL;
|
|
pAuthIdentity->DomainLength = 0;
|
|
pAuthIdentity->Password = NULL;
|
|
pAuthIdentity->PasswordLength = 0;
|
|
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
|
return TRUE;
|
|
}
|
|
|
|
while ( ( pPasswordCredentials->pszUsername[cDomain] != L'\0' ) &&
|
|
( pPasswordCredentials->pszUsername[cDomain] != L'\\' ) )
|
|
{
|
|
cDomain += 1;
|
|
}
|
|
|
|
if ( cDomain != (DWORD)wcslen( pPasswordCredentials->pszUsername ) )
|
|
{
|
|
LPWSTR pwszDomain;
|
|
|
|
pwszDomain = new WCHAR [ cDomain + 1 ];
|
|
|
|
if ( pwszDomain == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
memcpy(pwszDomain, pPasswordCredentials->pszUsername,
|
|
cDomain * sizeof(WCHAR));
|
|
pwszDomain[cDomain] = L'\0';
|
|
|
|
pAuthIdentity->Domain = (USHORT *)pwszDomain;
|
|
pAuthIdentity->DomainLength = cDomain;
|
|
|
|
pAuthIdentity->User = (USHORT *)&pPasswordCredentials->pszUsername[
|
|
cDomain+1
|
|
];
|
|
|
|
pAuthIdentity->UserLength = wcslen( (LPCWSTR)pAuthIdentity->User );
|
|
}
|
|
else
|
|
{
|
|
pAuthIdentity->Domain = NULL;
|
|
pAuthIdentity->DomainLength = 0;
|
|
pAuthIdentity->User = (USHORT *)pPasswordCredentials->pszUsername;
|
|
pAuthIdentity->UserLength = cDomain;
|
|
}
|
|
|
|
pAuthIdentity->Password = (USHORT *)pPasswordCredentials->pszPassword;
|
|
pAuthIdentity->PasswordLength = wcslen( (LPCWSTR)pAuthIdentity->Password );
|
|
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeFreeAuthIdentityFromPasswordCredentialsW
|
|
//
|
|
// Synopsis: restore the backslash to the domain username pair
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SchemeFreeAuthIdentityFromPasswordCredentialsW (
|
|
IN PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials,
|
|
IN OUT PSEC_WINNT_AUTH_IDENTITY_W pAuthIdentity
|
|
)
|
|
{
|
|
if ( pAuthIdentity->Domain != NULL )
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
|
|
delete [] pAuthIdentity->Domain;
|
|
|
|
SetLastError(dwLastError);
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SchemeRetrieveUncachedAuxInfo
|
|
//
|
|
// Synopsis: update the LastSyncTime in the retrieval AuxInfo with the
|
|
// current time.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SchemeRetrieveUncachedAuxInfo (
|
|
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
|
|
)
|
|
{
|
|
if ( pAuxInfo &&
|
|
offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
|
|
pAuxInfo->cbSize &&
|
|
pAuxInfo->pLastSyncTime )
|
|
{
|
|
GetSystemTimeAsFileTime( pAuxInfo->pLastSyncTime );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Iterate through the Url Cache MetaData files in:
|
|
// %UserProfile%\Microsoft\CryptnetUrlCache\MetaData
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
I_CryptNetEnumUrlCacheEntry(
|
|
IN DWORD dwFlags,
|
|
IN LPVOID pvReserved,
|
|
IN LPVOID pvArg,
|
|
IN PFN_CRYPTNET_ENUM_URL_CACHE_ENTRY_CALLBACK pfnEnumCallback
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD dwLastError = 0;
|
|
DWORD cchCryptnetUrlCacheDir;
|
|
LPWSTR pwszCryptnetUrlCacheDir = NULL;
|
|
DWORD cchMetaDataDir;
|
|
LPWSTR pwszMetaDataFile = NULL;
|
|
DWORD cchContentDir;
|
|
LPWSTR pwszContentFile = NULL;
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATAW FindFileData;
|
|
|
|
pwszCryptnetUrlCacheDir = I_SchemeGetCryptnetUrlCacheDir();
|
|
if (NULL == pwszCryptnetUrlCacheDir)
|
|
goto GetCryptnetUrlCacheDirError;
|
|
|
|
cchCryptnetUrlCacheDir = wcslen(pwszCryptnetUrlCacheDir);
|
|
cchMetaDataDir = cchCryptnetUrlCacheDir + SCHEME_CCH_META_DATA_SUBDIR + 1;
|
|
cchContentDir = cchCryptnetUrlCacheDir + SCHEME_CCH_CONTENT_SUBDIR + 1;
|
|
|
|
pwszMetaDataFile = (LPWSTR) PkiNonzeroAlloc(
|
|
(cchMetaDataDir + SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
|
|
pwszContentFile = (LPWSTR) PkiNonzeroAlloc(
|
|
(cchContentDir + SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
|
|
|
|
if (NULL == pwszMetaDataFile || NULL == pwszContentFile)
|
|
goto OutOfMemory;
|
|
|
|
memcpy(pwszMetaDataFile, pwszCryptnetUrlCacheDir,
|
|
cchCryptnetUrlCacheDir * sizeof(WCHAR));
|
|
memcpy(pwszMetaDataFile + cchCryptnetUrlCacheDir,
|
|
SCHEME_META_DATA_SUBDIR,
|
|
SCHEME_CCH_META_DATA_SUBDIR * sizeof(WCHAR));
|
|
wcscpy(&pwszMetaDataFile[cchMetaDataDir - 1], L"\\*");
|
|
|
|
if (INVALID_HANDLE_VALUE == (hFindFile = FindFirstFileW(
|
|
pwszMetaDataFile,
|
|
&FindFileData
|
|
))) {
|
|
dwLastError = GetLastError();
|
|
if (ERROR_PATH_NOT_FOUND == dwLastError)
|
|
dwLastError = ERROR_FILE_NOT_FOUND;
|
|
goto FindFirstFileError;
|
|
}
|
|
|
|
memcpy(pwszContentFile, pwszCryptnetUrlCacheDir,
|
|
cchCryptnetUrlCacheDir * sizeof(WCHAR));
|
|
memcpy(pwszContentFile + cchCryptnetUrlCacheDir,
|
|
SCHEME_CONTENT_SUBDIR, SCHEME_CCH_CONTENT_SUBDIR * sizeof(WCHAR));
|
|
pwszContentFile[cchContentDir - 1] = L'\\';
|
|
|
|
|
|
while (TRUE) {
|
|
DWORD cchFileName = wcslen(FindFileData.cFileName);
|
|
|
|
if (0 == (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes) &&
|
|
0 == FindFileData.nFileSizeHigh &&
|
|
0 != FindFileData.nFileSizeLow &&
|
|
L'\0' != FindFileData.cFileName[0] &&
|
|
SCHEME_URL_FILENAME_LEN > cchFileName) {
|
|
|
|
HANDLE hMetaDataFile;
|
|
|
|
memcpy(pwszMetaDataFile + cchMetaDataDir,
|
|
FindFileData.cFileName, (cchFileName + 1) * sizeof(WCHAR));
|
|
memcpy(pwszContentFile + cchContentDir,
|
|
FindFileData.cFileName, (cchFileName + 1) * sizeof(WCHAR));
|
|
|
|
hMetaDataFile = I_SchemeCreateFile(
|
|
pwszMetaDataFile,
|
|
FALSE // fWrite
|
|
);
|
|
if (NULL != hMetaDataFile) {
|
|
PSCHEME_CACHE_META_DATA_HEADER pMetaDataHeader;
|
|
CRYPTNET_URL_CACHE_ENTRY UrlCacheEntry;
|
|
|
|
pMetaDataHeader = I_SchemeReadAndValidateMetaDataFile(
|
|
hMetaDataFile,
|
|
&UrlCacheEntry.pcbBlob, // Not allocated
|
|
&UrlCacheEntry.pwszUrl // Not allocated
|
|
);
|
|
|
|
I_SchemeCloseHandle(hMetaDataFile);
|
|
|
|
if (NULL != pMetaDataHeader) {
|
|
UrlCacheEntry.cbSize = sizeof(UrlCacheEntry);
|
|
UrlCacheEntry.dwMagic = pMetaDataHeader->dwMagic;
|
|
UrlCacheEntry.LastSyncTime = pMetaDataHeader->LastSyncTime;
|
|
UrlCacheEntry.cBlob = pMetaDataHeader->cBlob;
|
|
// UrlCacheEntry.pcbBlob =
|
|
// UrlCacheEntry.pwszUrl =
|
|
UrlCacheEntry.pwszMetaDataFileName = pwszMetaDataFile;
|
|
UrlCacheEntry.pwszContentFileName = pwszContentFile;
|
|
|
|
fResult = pfnEnumCallback(
|
|
&UrlCacheEntry,
|
|
0, // dwFlags
|
|
NULL, // pvReserved
|
|
pvArg
|
|
);
|
|
|
|
PkiFree(pMetaDataHeader);
|
|
if (!fResult)
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FindNextFileW(hFindFile, &FindFileData)) {
|
|
dwLastError = GetLastError();
|
|
if (ERROR_NO_MORE_FILES == dwLastError)
|
|
goto SuccessReturn;
|
|
else
|
|
goto FindNextFileError;
|
|
}
|
|
}
|
|
|
|
SuccessReturn:
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
PkiFree(pwszCryptnetUrlCacheDir);
|
|
PkiFree(pwszMetaDataFile);
|
|
PkiFree(pwszContentFile);
|
|
if (INVALID_HANDLE_VALUE != hFindFile)
|
|
FindClose(hFindFile);
|
|
|
|
SetLastError(dwLastError);
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
dwLastError = GetLastError();
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetCryptnetUrlCacheDirError)
|
|
TRACE_ERROR(OutOfMemory)
|
|
SET_ERROR_VAR(FindFirstFileError, dwLastError)
|
|
SET_ERROR_VAR(FindNextFileError, dwLastError)
|
|
}
|