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.

405 lines
8.9 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2001.
  5. //
  6. // File: mapcache.c
  7. //
  8. // Contents: Routines to manage a cache that holds issuer names we've
  9. // recently processed via many-to-one certificate mapping.
  10. // This is a negative cache, so only issuers that have failed
  11. // mapping are stored in the cache.
  12. //
  13. // The purpose of this cache is to avoid attempting to map
  14. // the same issuers over and over again. This is especially
  15. // important now that the many-to-one mapper walks up the
  16. // certificate chain, attempting to map each CA as it goes.
  17. //
  18. // This code is active on DC machines only.
  19. //
  20. // Functions:
  21. //
  22. // History: 04-12-2001 jbanes Created
  23. //
  24. //----------------------------------------------------------------------------
  25. #include "spbase.h"
  26. #include <mapper.h>
  27. ISSUER_CACHE IssuerCache;
  28. SP_STATUS
  29. SPInitIssuerCache(void)
  30. {
  31. DWORD i;
  32. NTSTATUS Status;
  33. memset(&IssuerCache, 0, sizeof(IssuerCache));
  34. IssuerCache.dwLifespan = ISSUER_CACHE_LIFESPAN;
  35. IssuerCache.dwCacheSize = ISSUER_CACHE_SIZE;
  36. IssuerCache.dwMaximumEntries = ISSUER_CACHE_SIZE;
  37. InitializeListHead(&IssuerCache.EntryList);
  38. __try {
  39. RtlInitializeResource(&IssuerCache.Lock);
  40. } __except(EXCEPTION_EXECUTE_HANDLER)
  41. {
  42. Status = STATUS_INSUFFICIENT_RESOURCES;
  43. goto cleanup;
  44. }
  45. IssuerCache.LockInitialized = TRUE;
  46. IssuerCache.Cache = (PLIST_ENTRY)SPExternalAlloc(IssuerCache.dwCacheSize * sizeof(LIST_ENTRY));
  47. if(IssuerCache.Cache == NULL)
  48. {
  49. Status = SP_LOG_RESULT(STATUS_NO_MEMORY);
  50. goto cleanup;
  51. }
  52. for(i = 0; i < IssuerCache.dwCacheSize; i++)
  53. {
  54. InitializeListHead(&IssuerCache.Cache[i]);
  55. }
  56. Status = STATUS_SUCCESS;
  57. cleanup:
  58. if(!NT_SUCCESS(Status))
  59. {
  60. SPShutdownIssuerCache();
  61. }
  62. return Status;
  63. }
  64. void
  65. SPShutdownIssuerCache(void)
  66. {
  67. ISSUER_CACHE_ENTRY *pItem;
  68. PLIST_ENTRY pList;
  69. if(IssuerCache.LockInitialized)
  70. {
  71. RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
  72. }
  73. if(IssuerCache.Cache != NULL)
  74. {
  75. pList = IssuerCache.EntryList.Flink;
  76. while(pList != &IssuerCache.EntryList)
  77. {
  78. pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, EntryList.Flink);
  79. pList = pList->Flink;
  80. SPDeleteIssuerEntry(pItem);
  81. }
  82. SPExternalFree(IssuerCache.Cache);
  83. }
  84. if(IssuerCache.LockInitialized)
  85. {
  86. RtlDeleteResource(&IssuerCache.Lock);
  87. IssuerCache.LockInitialized = FALSE;
  88. }
  89. }
  90. void
  91. SPPurgeIssuerCache(void)
  92. {
  93. ISSUER_CACHE_ENTRY *pItem;
  94. PLIST_ENTRY pList;
  95. if(!IssuerCache.LockInitialized)
  96. {
  97. return;
  98. }
  99. if(IssuerCache.dwUsedEntries == 0)
  100. {
  101. return;
  102. }
  103. RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
  104. pList = IssuerCache.EntryList.Flink;
  105. while(pList != &IssuerCache.EntryList)
  106. {
  107. pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, EntryList.Flink);
  108. pList = pList->Flink;
  109. RemoveEntryList(&pItem->IndexEntryList);
  110. RemoveEntryList(&pItem->EntryList);
  111. IssuerCache.dwUsedEntries--;
  112. SPDeleteIssuerEntry(pItem);
  113. }
  114. RtlReleaseResource(&IssuerCache.Lock);
  115. }
  116. void
  117. SPDeleteIssuerEntry(
  118. ISSUER_CACHE_ENTRY *pItem)
  119. {
  120. if(pItem == NULL)
  121. {
  122. return;
  123. }
  124. if(pItem->pbIssuer)
  125. {
  126. LogDistinguishedName(DEB_TRACE, "Delete from cache: %s\n", pItem->pbIssuer, pItem->cbIssuer);
  127. SPExternalFree(pItem->pbIssuer);
  128. }
  129. SPExternalFree(pItem);
  130. }
  131. DWORD
  132. ComputeIssuerCacheIndex(
  133. PBYTE pbIssuer,
  134. DWORD cbIssuer)
  135. {
  136. ULONG Index = 0;
  137. ULONG i;
  138. if(pbIssuer == NULL)
  139. {
  140. Index = 0;
  141. }
  142. else
  143. {
  144. for(i = 0; i < cbIssuer; i++)
  145. {
  146. Index += (pbIssuer[i] ^ 0x55);
  147. }
  148. Index %= IssuerCache.dwCacheSize;
  149. }
  150. return Index;
  151. }
  152. BOOL
  153. SPFindIssuerInCache(
  154. PBYTE pbIssuer,
  155. DWORD cbIssuer)
  156. {
  157. DWORD Index;
  158. DWORD timeNow;
  159. ISSUER_CACHE_ENTRY *pItem;
  160. PLIST_ENTRY pList;
  161. BOOL fFound = FALSE;
  162. if(pbIssuer == NULL || cbIssuer == 0)
  163. {
  164. return FALSE;
  165. }
  166. if(!IssuerCache.LockInitialized)
  167. {
  168. return FALSE;
  169. }
  170. //
  171. // Compute the cache index.
  172. //
  173. Index = ComputeIssuerCacheIndex(pbIssuer, cbIssuer);
  174. Index %= IssuerCache.dwCacheSize;
  175. //
  176. // Search through the cache entries at the computed index.
  177. //
  178. timeNow = GetTickCount();
  179. RtlAcquireResourceShared(&IssuerCache.Lock, TRUE);
  180. pList = IssuerCache.Cache[Index].Flink;
  181. while(pList != &IssuerCache.Cache[Index])
  182. {
  183. pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, IndexEntryList.Flink);
  184. pList = pList->Flink ;
  185. // Has this item expired?
  186. if(HasTimeElapsed(pItem->CreationTime, timeNow, IssuerCache.dwLifespan))
  187. {
  188. continue;
  189. }
  190. // Does the issuer name match?
  191. if(cbIssuer != pItem->cbIssuer)
  192. {
  193. continue;
  194. }
  195. if(memcmp(pbIssuer, pItem->pbIssuer, cbIssuer) != 0)
  196. {
  197. continue;
  198. }
  199. // Found item in cache!!
  200. fFound = TRUE;
  201. break;
  202. }
  203. RtlReleaseResource(&IssuerCache.Lock);
  204. return fFound;
  205. }
  206. void
  207. SPExpireIssuerCacheElements(void)
  208. {
  209. ISSUER_CACHE_ENTRY *pItem;
  210. PLIST_ENTRY pList;
  211. BOOL fDeleteEntry;
  212. DWORD timeNow;
  213. if(!IssuerCache.LockInitialized)
  214. {
  215. return;
  216. }
  217. if(IssuerCache.dwUsedEntries == 0)
  218. {
  219. return;
  220. }
  221. timeNow = GetTickCount();
  222. RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
  223. pList = IssuerCache.EntryList.Flink;
  224. while(pList != &IssuerCache.EntryList)
  225. {
  226. pItem = CONTAINING_RECORD(pList, ISSUER_CACHE_ENTRY, EntryList.Flink);
  227. pList = pList->Flink;
  228. fDeleteEntry = FALSE;
  229. // Mark all expired cache entries as non-resumable.
  230. if(HasTimeElapsed(pItem->CreationTime, timeNow, IssuerCache.dwLifespan))
  231. {
  232. fDeleteEntry = TRUE;
  233. }
  234. // If the cache has gotten too large, then expire elements early. The
  235. // cache elements are sorted by creation time, so the oldest
  236. // entries will be expired first.
  237. if(IssuerCache.dwUsedEntries > IssuerCache.dwMaximumEntries)
  238. {
  239. fDeleteEntry = TRUE;
  240. }
  241. // Remove this entry from the cache.
  242. if(fDeleteEntry)
  243. {
  244. RemoveEntryList(&pItem->IndexEntryList);
  245. RemoveEntryList(&pItem->EntryList);
  246. IssuerCache.dwUsedEntries--;
  247. SPDeleteIssuerEntry(pItem);
  248. }
  249. }
  250. RtlReleaseResource(&IssuerCache.Lock);
  251. }
  252. void
  253. SPAddIssuerToCache(
  254. PBYTE pbIssuer,
  255. DWORD cbIssuer)
  256. {
  257. DWORD Index;
  258. DWORD timeNow;
  259. ISSUER_CACHE_ENTRY *pItem = NULL;
  260. if(pbIssuer == NULL || cbIssuer == 0)
  261. {
  262. return;
  263. }
  264. if(!IssuerCache.LockInitialized)
  265. {
  266. return;
  267. }
  268. //
  269. // Determine if the issuer is already in the cache. This isn't particularly
  270. // thread-safe, so it's possible that the same issuer might sneak into
  271. // the cache multiple times, but that's harmless.
  272. //
  273. if(SPFindIssuerInCache(pbIssuer, cbIssuer))
  274. {
  275. return;
  276. }
  277. //
  278. // Compute the cache index.
  279. //
  280. Index = ComputeIssuerCacheIndex(pbIssuer, cbIssuer);
  281. Index %= IssuerCache.dwCacheSize;
  282. timeNow = GetTickCount();
  283. //
  284. // Allocate a new cache entry.
  285. //
  286. pItem = SPExternalAlloc(sizeof(ISSUER_CACHE_ENTRY));
  287. if(pItem == NULL)
  288. {
  289. SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  290. return;
  291. }
  292. //
  293. // Fill in the cache internal fields.
  294. //
  295. pItem->pbIssuer = SPExternalAlloc(cbIssuer);
  296. if(pItem->pbIssuer == NULL)
  297. {
  298. SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  299. SPExternalFree(pItem);
  300. return;
  301. }
  302. pItem->cbIssuer = cbIssuer;
  303. memcpy(pItem->pbIssuer, pbIssuer, cbIssuer);
  304. pItem->CreationTime = timeNow;
  305. //
  306. // Add the new entry to the cache.
  307. //
  308. LogDistinguishedName(DEB_TRACE, "Add to cache: %s\n", pbIssuer, cbIssuer);
  309. RtlAcquireResourceExclusive(&IssuerCache.Lock, TRUE);
  310. InsertTailList(&IssuerCache.Cache[Index], &pItem->IndexEntryList);
  311. InsertTailList(&IssuerCache.EntryList, &pItem->EntryList);
  312. IssuerCache.dwUsedEntries++;
  313. RtlReleaseResource(&IssuerCache.Lock);
  314. }