//+--------------------------------------------------------------------------- // // 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 #include #include // for GetUserAppDataPathW #include //+------------------------------------------------------------------------- // 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> 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) }