//+--------------------------------------------------------------------------- // // Microsoft Windows NT Security // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: offurl.cpp // // Contents: Offline URL Caching // // History: 19-Jan-00 philh Created // 01-Jan-02 philh Changed to internally use UNICODE Urls //---------------------------------------------------------------------------- #include // // Offline URL Cache Entry. // // The earliest wire retrieval is delayed according to the number of // offline failures. // // For a successful wire URL retrieval, the entry is removed and deleted. // // Assumption: the number of offline entries is small, less than 20. // typedef struct _OFFLINE_URL_CACHE_ENTRY OFFLINE_URL_CACHE_ENTRY, *POFFLINE_URL_CACHE_ENTRY; struct _OFFLINE_URL_CACHE_ENTRY { CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; DWORD dwContextOid; OFFLINE_URL_TIME_INFO OfflineUrlTimeInfo; POFFLINE_URL_CACHE_ENTRY pNext; POFFLINE_URL_CACHE_ENTRY pPrev; }; CRITICAL_SECTION OfflineUrlCacheCriticalSection; POFFLINE_URL_CACHE_ENTRY pOfflineUrlCacheHead; // // Local Functions (Forward Reference) // // Assumption: OfflineUrlCache is locked POFFLINE_URL_CACHE_ENTRY WINAPI CreateAndAddOfflineUrlCacheEntry( IN PCRYPT_DATA_BLOB pUrlBlob, IN PCRYPT_DATA_BLOB pExtraBlob, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ); // Assumption: OfflineUrlCache is locked VOID WINAPI RemoveAndFreeOfflineUrlCacheEntry( IN OUT POFFLINE_URL_CACHE_ENTRY pEntry ); // Assumption: OfflineUrlCache is locked POFFLINE_URL_CACHE_ENTRY WINAPI FindOfflineUrlCacheEntry( IN PCRYPT_DATA_BLOB pUrlBlob, IN PCRYPT_DATA_BLOB pExtraBlob, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ); VOID WINAPI InitializeOfflineUrlCache() { Pki_InitializeCriticalSection(&OfflineUrlCacheCriticalSection); } VOID WINAPI DeleteOfflineUrlCache() { while (pOfflineUrlCacheHead) RemoveAndFreeOfflineUrlCacheEntry(pOfflineUrlCacheHead); DeleteCriticalSection(&OfflineUrlCacheCriticalSection); } // // Return status: // +1 - Online // 0 - Offline, current time >= earliest online time, hit the wire // -1 - Offline, current time < earliest onlime time // LONG WINAPI GetOfflineUrlTimeStatus( IN POFFLINE_URL_TIME_INFO pInfo ) { FILETIME CurrentTime; if (0 == pInfo->dwOfflineCnt) { return 1; } GetSystemTimeAsFileTime(&CurrentTime); if (0 <= CompareFileTime(&CurrentTime, &pInfo->EarliestOnlineTime)) { return 0; } else { return -1; } } const DWORD rgdwOfflineUrlDeltaSeconds[] = { 15, // 15 seconds 15, // 15 seconds 60, // 1 minute 60 * 5, // 5 minutes 60 * 10, // 10 minutes 60 * 30, // 30 minutes }; #define OFFLINE_URL_DELTA_SECONDS_CNT \ (sizeof(rgdwOfflineUrlDeltaSeconds) / \ sizeof(rgdwOfflineUrlDeltaSeconds[0])) VOID WINAPI SetOfflineUrlTime( IN OUT POFFLINE_URL_TIME_INFO pInfo ) { DWORD dwOfflineCnt; FILETIME CurrentTime; dwOfflineCnt = ++pInfo->dwOfflineCnt; if (OFFLINE_URL_DELTA_SECONDS_CNT < dwOfflineCnt) { dwOfflineCnt = OFFLINE_URL_DELTA_SECONDS_CNT; } GetSystemTimeAsFileTime( &CurrentTime ); I_CryptIncrementFileTimeBySeconds( &CurrentTime, rgdwOfflineUrlDeltaSeconds[dwOfflineCnt - 1], &pInfo->EarliestOnlineTime ); } VOID WINAPI SetOnlineUrlTime( IN OUT POFFLINE_URL_TIME_INFO pInfo ) { pInfo->dwOfflineCnt = 0; } // // Return status: // +1 - Online // 0 - Offline, current time >= earliest online time, hit the wire // -1 - Offline, current time < earliest onlime time // LONG WINAPI GetOriginUrlStatusW( IN CRYPT_ORIGIN_IDENTIFIER OriginIdentifier, IN LPCWSTR pwszUrl, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { LONG lStatus; POFFLINE_URL_CACHE_ENTRY pEntry; CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; UrlBlob.pbData = (BYTE *) pwszUrl; UrlBlob.cbData = wcslen(pwszUrl) * sizeof(WCHAR); ExtraBlob.pbData = OriginIdentifier; ExtraBlob.cbData = MD5DIGESTLEN; EnterCriticalSection(&OfflineUrlCacheCriticalSection); pEntry = FindOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (pEntry) lStatus = GetOfflineUrlTimeStatus(&pEntry->OfflineUrlTimeInfo); else lStatus = 1; LeaveCriticalSection(&OfflineUrlCacheCriticalSection); return lStatus; } VOID WINAPI SetOnlineOriginUrlW( IN CRYPT_ORIGIN_IDENTIFIER OriginIdentifier, IN LPCWSTR pwszUrl, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { POFFLINE_URL_CACHE_ENTRY pEntry; CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; UrlBlob.pbData = (BYTE *) pwszUrl; UrlBlob.cbData = wcslen(pwszUrl) * sizeof(WCHAR); ExtraBlob.pbData = OriginIdentifier; ExtraBlob.cbData = MD5DIGESTLEN; EnterCriticalSection(&OfflineUrlCacheCriticalSection); pEntry = FindOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (pEntry) RemoveAndFreeOfflineUrlCacheEntry(pEntry); LeaveCriticalSection(&OfflineUrlCacheCriticalSection); } VOID WINAPI SetOfflineOriginUrlW( IN CRYPT_ORIGIN_IDENTIFIER OriginIdentifier, IN LPCWSTR pwszUrl, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { POFFLINE_URL_CACHE_ENTRY pEntry; CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; UrlBlob.pbData = (BYTE *) pwszUrl; UrlBlob.cbData = wcslen(pwszUrl) * sizeof(WCHAR); ExtraBlob.pbData = OriginIdentifier; ExtraBlob.cbData = MD5DIGESTLEN; EnterCriticalSection(&OfflineUrlCacheCriticalSection); pEntry = FindOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (NULL == pEntry) pEntry = CreateAndAddOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (pEntry) SetOfflineUrlTime(&pEntry->OfflineUrlTimeInfo); LeaveCriticalSection(&OfflineUrlCacheCriticalSection); } // // Return status: // +1 - Online // 0 - Offline, current time >= earliest online time, hit the wire // -1 - Offline, current time < earliest onlime time // LONG WINAPI GetUrlStatusW( IN LPCWSTR pwszUrl, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { LONG lStatus; POFFLINE_URL_CACHE_ENTRY pEntry; CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; UrlBlob.pbData = (BYTE *) pwszUrl; UrlBlob.cbData = wcslen(pwszUrl) * sizeof(WCHAR); ExtraBlob.pbData = NULL; ExtraBlob.cbData = 0; EnterCriticalSection(&OfflineUrlCacheCriticalSection); pEntry = FindOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (pEntry) lStatus = GetOfflineUrlTimeStatus(&pEntry->OfflineUrlTimeInfo); else lStatus = 1; LeaveCriticalSection(&OfflineUrlCacheCriticalSection); return lStatus; } VOID WINAPI SetOnlineUrlW( IN LPCWSTR pwszUrl, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { POFFLINE_URL_CACHE_ENTRY pEntry; CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; UrlBlob.pbData = (BYTE *) pwszUrl; UrlBlob.cbData = wcslen(pwszUrl) * sizeof(WCHAR); ExtraBlob.pbData = NULL; ExtraBlob.cbData = 0; EnterCriticalSection(&OfflineUrlCacheCriticalSection); pEntry = FindOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (pEntry) RemoveAndFreeOfflineUrlCacheEntry(pEntry); LeaveCriticalSection(&OfflineUrlCacheCriticalSection); } VOID WINAPI SetOfflineUrlW( IN LPCWSTR pwszUrl, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { POFFLINE_URL_CACHE_ENTRY pEntry; CRYPT_DATA_BLOB UrlBlob; CRYPT_DATA_BLOB ExtraBlob; UrlBlob.pbData = (BYTE *) pwszUrl; UrlBlob.cbData = wcslen(pwszUrl) * sizeof(WCHAR); ExtraBlob.pbData = NULL; ExtraBlob.cbData = 0; EnterCriticalSection(&OfflineUrlCacheCriticalSection); pEntry = FindOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (NULL == pEntry) pEntry = CreateAndAddOfflineUrlCacheEntry( &UrlBlob, &ExtraBlob, pszContextOid, dwRetrievalFlags ); if (pEntry) SetOfflineUrlTime(&pEntry->OfflineUrlTimeInfo); LeaveCriticalSection(&OfflineUrlCacheCriticalSection); } inline DWORD GetOfflineUrlCacheContextOid( IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { DWORD dwContextOid; if (0xFFFF >= (DWORD) ((DWORD_PTR) pszContextOid)) dwContextOid = (DWORD) ((DWORD_PTR) pszContextOid); else dwContextOid = 0x10000; if (dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL) dwContextOid |= 0x20000; return dwContextOid; } // Assumption: OfflineUrlCache is locked POFFLINE_URL_CACHE_ENTRY WINAPI CreateAndAddOfflineUrlCacheEntry( IN PCRYPT_DATA_BLOB pUrlBlob, IN PCRYPT_DATA_BLOB pExtraBlob, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { POFFLINE_URL_CACHE_ENTRY pEntry; DWORD cbEntry; BYTE *pb; cbEntry = sizeof(OFFLINE_URL_CACHE_ENTRY) + pUrlBlob->cbData + pExtraBlob->cbData; pEntry = (POFFLINE_URL_CACHE_ENTRY) new BYTE [cbEntry]; if (pEntry == NULL) { SetLastError( (DWORD) E_OUTOFMEMORY ); return( NULL ); } memset( pEntry, 0, sizeof( OFFLINE_URL_CACHE_ENTRY ) ); pb = (BYTE *) &pEntry[1]; if (pUrlBlob->cbData) { pEntry->UrlBlob.pbData = pb; pEntry->UrlBlob.cbData = pUrlBlob->cbData; memcpy(pb, pUrlBlob->pbData, pUrlBlob->cbData); pb += pUrlBlob->cbData; } if (pExtraBlob->cbData) { pEntry->ExtraBlob.pbData = pb; pEntry->ExtraBlob.cbData = pExtraBlob->cbData; memcpy(pb, pExtraBlob->pbData, pExtraBlob->cbData); } pEntry->dwContextOid = GetOfflineUrlCacheContextOid(pszContextOid, dwRetrievalFlags); if (pOfflineUrlCacheHead) { assert(NULL == pOfflineUrlCacheHead->pPrev); pOfflineUrlCacheHead->pPrev = pEntry; pEntry->pNext = pOfflineUrlCacheHead; } // else // pEntry->pNext = NULL; // already zeroed above // pEntry->pPrev = NULL; // already zeroed above pOfflineUrlCacheHead = pEntry; return pEntry; } // Assumption: OfflineUrlCache is locked VOID WINAPI RemoveAndFreeOfflineUrlCacheEntry( IN OUT POFFLINE_URL_CACHE_ENTRY pEntry ) { if (pEntry->pNext) { pEntry->pNext->pPrev = pEntry->pPrev; } if (pEntry->pPrev) { pEntry->pPrev->pNext = pEntry->pNext; } else { assert(pOfflineUrlCacheHead == pEntry); pOfflineUrlCacheHead = pEntry->pNext; } delete (LPBYTE) pEntry; } // Assumption: OfflineUrlCache is locked POFFLINE_URL_CACHE_ENTRY WINAPI FindOfflineUrlCacheEntry( IN PCRYPT_DATA_BLOB pUrlBlob, IN PCRYPT_DATA_BLOB pExtraBlob, IN LPCSTR pszContextOid, IN DWORD dwRetrievalFlags ) { DWORD cbUrl = pUrlBlob->cbData; BYTE *pbUrl = pUrlBlob->pbData; DWORD cbExtra = pExtraBlob->cbData; BYTE *pbExtra = pExtraBlob->pbData; DWORD dwContextOid; POFFLINE_URL_CACHE_ENTRY pEntry; dwContextOid = GetOfflineUrlCacheContextOid(pszContextOid, dwRetrievalFlags); for (pEntry = pOfflineUrlCacheHead; pEntry; pEntry = pEntry->pNext) { if (pEntry->dwContextOid == dwContextOid && pEntry->UrlBlob.cbData == cbUrl && pEntry->ExtraBlob.cbData == cbExtra && (0 == cbExtra || 0 == memcmp( pEntry->ExtraBlob.pbData, pbExtra, cbExtra)) && (0 == cbUrl || 0 == memcmp( pEntry->UrlBlob.pbData, pbUrl, cbUrl)) ) { return pEntry; } } return ( NULL ); }