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

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