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.

507 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. keycache.h
  5. Abstract:
  6. This module contains routines for accessing cached masterkeys.
  7. Author:
  8. Scott Field (sfield) 07-Nov-98
  9. Revision History:
  10. --*/
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. //
  14. // masterkey cache.
  15. //
  16. typedef struct {
  17. LIST_ENTRY Next;
  18. LUID LogonId;
  19. GUID guidMasterKey;
  20. FILETIME ftLastAccess;
  21. DWORD cbMasterKey;
  22. BYTE pbMasterKey[ 64 ];
  23. } MASTERKEY_CACHE_ENTRY, *PMASTERKEY_CACHE_ENTRY, *LPMASTERKEY_CACHE_ENTRY;
  24. RTL_CRITICAL_SECTION g_MasterKeyCacheCritSect;
  25. LIST_ENTRY g_MasterKeyCacheList;
  26. BOOL
  27. RemoveMasterKeyCache(
  28. IN PLUID pLogonId
  29. );
  30. #if DBG
  31. void
  32. DumpMasterKeyEntry(
  33. PMASTERKEY_CACHE_ENTRY pCacheEntry)
  34. {
  35. WCHAR wszguidMasterKey[MAX_GUID_SZ_CHARS];
  36. #if 0
  37. BYTE rgbMasterKey[256];
  38. DWORD cbMasterKey;
  39. #endif
  40. D_DebugLog((DEB_TRACE, "LogonId: %d.%d\n", pCacheEntry->LogonId.LowPart, pCacheEntry->LogonId.HighPart));
  41. if( MyGuidToStringW( &pCacheEntry->guidMasterKey, wszguidMasterKey ) != 0 )
  42. {
  43. D_DebugLog((DEB_TRACE, "Invalid GUID:\n"));
  44. D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)&pCacheEntry->guidMasterKey, sizeof(pCacheEntry->guidMasterKey));
  45. }
  46. else
  47. {
  48. D_DebugLog((DEB_TRACE, "GUID: %ws\n", wszguidMasterKey));
  49. }
  50. #if 0
  51. cbMasterKey = min(pCacheEntry->cbMasterKey, sizeof(rgbMasterKey));
  52. CopyMemory(rgbMasterKey, pCacheEntry->pbMasterKey, cbMasterKey);
  53. LsaProtectMemory(rgbMasterKey, cbMasterKey);
  54. D_DebugLog((DEB_TRACE, "Master key:\n"));
  55. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbMasterKey, cbMasterKey);
  56. #endif
  57. }
  58. #endif
  59. #if DBG
  60. void
  61. DumpMasterKeyCache(void)
  62. {
  63. PLIST_ENTRY ListEntry;
  64. PLIST_ENTRY ListHead;
  65. PMASTERKEY_CACHE_ENTRY pCacheEntry;
  66. ULONG i = 0;
  67. RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
  68. D_DebugLog((DEB_TRACE, "Master key cache\n"));
  69. ListHead = &g_MasterKeyCacheList;
  70. for( ListEntry = ListHead->Flink;
  71. ListEntry != ListHead;
  72. ListEntry = ListEntry->Flink )
  73. {
  74. pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
  75. D_DebugLog((DEB_TRACE, "---- %d ----\n", ++i));
  76. DumpMasterKeyEntry(pCacheEntry);
  77. }
  78. RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
  79. }
  80. #endif
  81. BOOL
  82. SearchMasterKeyCache(
  83. IN PLUID pLogonId,
  84. IN GUID *pguidMasterKey,
  85. IN OUT PBYTE *ppbMasterKey,
  86. OUT PDWORD pcbMasterKey
  87. )
  88. /*++
  89. Search the masterkey sorted masterkey cache by pLogonId then by
  90. pguidMasterKey.
  91. On success, return value is true, and ppbMasterKey will point to a buffer
  92. allocated on behalf of the caller containing the specified masterkey.
  93. The caller must free the buffer using SSFree().
  94. --*/
  95. {
  96. PLIST_ENTRY ListEntry;
  97. PLIST_ENTRY ListHead;
  98. BOOL fSuccess = FALSE;
  99. #if DBG
  100. WCHAR wszguidMasterKey[MAX_GUID_SZ_CHARS];
  101. #endif
  102. RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
  103. #if DBG
  104. D_DebugLog((DEB_TRACE, "SearchMasterKeyCache\n"));
  105. D_DebugLog((DEB_TRACE, "LogonId: %d.%d\n", pLogonId->LowPart, pLogonId->HighPart));
  106. if( MyGuidToStringW( pguidMasterKey, wszguidMasterKey ) != 0 )
  107. {
  108. D_DebugLog((DEB_TRACE, "Invalid GUID:\n"));
  109. D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)pguidMasterKey, sizeof(GUID));
  110. }
  111. else
  112. {
  113. D_DebugLog((DEB_TRACE, "GUID: %ws\n", wszguidMasterKey));
  114. }
  115. //DumpMasterKeyCache();
  116. #endif
  117. ListHead = &g_MasterKeyCacheList;
  118. for( ListEntry = ListHead->Flink;
  119. ListEntry != ListHead;
  120. ListEntry = ListEntry->Flink ) {
  121. PMASTERKEY_CACHE_ENTRY pCacheEntry;
  122. signed int comparator;
  123. pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
  124. //
  125. // search by LogonId, then by GUID.
  126. //
  127. comparator = memcmp(pLogonId, &pCacheEntry->LogonId, sizeof(LUID));
  128. if( comparator < 0 )
  129. continue;
  130. if( comparator > 0 )
  131. break;
  132. comparator = memcmp(pguidMasterKey, &pCacheEntry->guidMasterKey, sizeof(GUID));
  133. if( comparator < 0 )
  134. continue;
  135. if( comparator > 0 )
  136. break;
  137. //
  138. // match found.
  139. //
  140. *pcbMasterKey = pCacheEntry->cbMasterKey;
  141. *ppbMasterKey = (PBYTE)SSAlloc( *pcbMasterKey );
  142. if( *ppbMasterKey != NULL ) {
  143. CopyMemory( *ppbMasterKey, pCacheEntry->pbMasterKey, *pcbMasterKey );
  144. fSuccess = TRUE;
  145. }
  146. //
  147. // update last access time.
  148. //
  149. GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
  150. break;
  151. }
  152. RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
  153. if( fSuccess ) {
  154. //
  155. // decrypt (in-place) the returned encrypted cache entry.
  156. //
  157. LsaUnprotectMemory( *ppbMasterKey, *pcbMasterKey );
  158. }
  159. D_DebugLog((DEB_TRACE, "SearchMasterKeyCache returned %s\n", fSuccess ? "FOUND" : "NOT FOUND"));
  160. return fSuccess;
  161. }
  162. BOOL
  163. InsertMasterKeyCache(
  164. IN PLUID pLogonId,
  165. IN GUID *pguidMasterKey,
  166. IN PBYTE pbMasterKey,
  167. IN DWORD cbMasterKey
  168. )
  169. /*++
  170. Insert the specified masterkey into the cahce sorted by pLogonId then by
  171. pguidMasterKey.
  172. The return value is TRUE on success.
  173. --*/
  174. {
  175. PLIST_ENTRY ListEntry;
  176. PLIST_ENTRY ListHead;
  177. PMASTERKEY_CACHE_ENTRY pCacheEntry;
  178. PMASTERKEY_CACHE_ENTRY pThisCacheEntry = NULL;
  179. BOOL fInserted = FALSE;
  180. D_DebugLog((DEB_TRACE, "InsertMasterKeyCache\n"));
  181. if( cbMasterKey > sizeof(pCacheEntry->pbMasterKey) )
  182. return FALSE;
  183. pCacheEntry = (PMASTERKEY_CACHE_ENTRY)SSAlloc( sizeof( MASTERKEY_CACHE_ENTRY ) );
  184. if( pCacheEntry == NULL )
  185. return FALSE;
  186. CopyMemory( &pCacheEntry->LogonId, pLogonId, sizeof(LUID) );
  187. CopyMemory( &pCacheEntry->guidMasterKey, pguidMasterKey, sizeof(GUID) );
  188. pCacheEntry->cbMasterKey = cbMasterKey;
  189. CopyMemory( pCacheEntry->pbMasterKey, pbMasterKey, cbMasterKey );
  190. LsaProtectMemory( pCacheEntry->pbMasterKey, cbMasterKey );
  191. GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
  192. RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
  193. #if DBG
  194. DumpMasterKeyEntry(pCacheEntry);
  195. #endif
  196. ListHead = &g_MasterKeyCacheList;
  197. for( ListEntry = ListHead->Flink;
  198. ListEntry != ListHead;
  199. ListEntry = ListEntry->Flink ) {
  200. signed int comparator;
  201. pThisCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
  202. //
  203. // insert into list sorted by LogonId, then sorted by GUID.
  204. //
  205. comparator = memcmp(pLogonId, &pThisCacheEntry->LogonId, sizeof(LUID));
  206. if( comparator < 0 )
  207. continue;
  208. if( comparator == 0 ) {
  209. comparator = memcmp( pguidMasterKey, &pThisCacheEntry->guidMasterKey, sizeof(GUID));
  210. if( comparator < 0 )
  211. continue;
  212. if( comparator == 0 ) {
  213. //
  214. // don't insert duplicate records.
  215. // this would only happen in a race condition with multiple threads.
  216. //
  217. RtlSecureZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
  218. SSFree( pCacheEntry );
  219. fInserted = TRUE;
  220. break;
  221. }
  222. }
  223. //
  224. // insert prior to current record.
  225. //
  226. InsertHeadList( pThisCacheEntry->Next.Blink, &pCacheEntry->Next );
  227. fInserted = TRUE;
  228. break;
  229. }
  230. if( !fInserted ) {
  231. if( pThisCacheEntry == NULL ) {
  232. InsertHeadList( ListHead, &pCacheEntry->Next );
  233. } else {
  234. InsertHeadList( &pThisCacheEntry->Next, &pCacheEntry->Next );
  235. }
  236. }
  237. #if DBG
  238. //DumpMasterKeyCache();
  239. #endif
  240. RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
  241. return TRUE;
  242. }
  243. BOOL
  244. PurgeMasterKeyCache(
  245. VOID
  246. )
  247. /*++
  248. Purge masterkey cache of timed-out entries, or entries associated with
  249. terminated logon sessions.
  250. --*/
  251. {
  252. //
  253. // build active session table.
  254. //
  255. // don't touch entries that have an entry in active session table.
  256. // assume LUID_SYSTEM in table.
  257. //
  258. // entries not in table: discard after 15 minute timeout.
  259. //
  260. // if entry in table, find next LUID
  261. // else, if entry expired, check timeout. if expired, remove.
  262. //
  263. PLIST_ENTRY ListEntry;
  264. PLIST_ENTRY ListHead;
  265. RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
  266. ListHead = &g_MasterKeyCacheList;
  267. for( ListEntry = ListHead->Flink;
  268. ListEntry != ListHead;
  269. ListEntry = ListEntry->Flink ) {
  270. PMASTERKEY_CACHE_ENTRY pCacheEntry;
  271. // signed int comparator;
  272. pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
  273. }
  274. RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
  275. return FALSE;
  276. }
  277. BOOL
  278. RemoveMasterKeyCache(
  279. IN PLUID pLogonId
  280. )
  281. /*++
  282. Remove all entries from the masterkey cache corresponding to the specified
  283. pLogonId.
  284. The purpose of this routine is to purge the masterkey cache of entries
  285. associated with (now) non-existent logon sessions.
  286. --*/
  287. {
  288. PLIST_ENTRY ListEntry;
  289. PLIST_ENTRY ListHead;
  290. RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
  291. D_DebugLog((DEB_TRACE, "RemoveMasterKeyCache\n"));
  292. D_DebugLog((DEB_TRACE, "LogonId: %d.%d\n", pLogonId->LowPart, pLogonId->HighPart));
  293. ListHead = &g_MasterKeyCacheList;
  294. for( ListEntry = ListHead->Flink;
  295. ListEntry != ListHead;
  296. ListEntry = ListEntry->Flink ) {
  297. PMASTERKEY_CACHE_ENTRY pCacheEntry;
  298. signed int comparator;
  299. pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
  300. //
  301. // remove all entries with matching LogonId.
  302. //
  303. comparator = memcmp(pLogonId, &pCacheEntry->LogonId, sizeof(LUID));
  304. if( comparator > 0 )
  305. break;
  306. if( comparator < 0 )
  307. continue;
  308. //
  309. // match found.
  310. //
  311. RemoveEntryList( &pCacheEntry->Next );
  312. RtlSecureZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
  313. SSFree( pCacheEntry );
  314. }
  315. RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
  316. return TRUE;
  317. }
  318. BOOL
  319. InitializeKeyCache(
  320. VOID
  321. )
  322. {
  323. NTSTATUS Status;
  324. Status = RtlInitializeCriticalSection( &g_MasterKeyCacheCritSect );
  325. if(!NT_SUCCESS(Status))
  326. {
  327. return FALSE;
  328. }
  329. InitializeListHead( &g_MasterKeyCacheList );
  330. return TRUE;
  331. }
  332. VOID
  333. DeleteKeyCache(
  334. VOID
  335. )
  336. {
  337. //
  338. // remove all list entries.
  339. //
  340. RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
  341. while ( !IsListEmpty( &g_MasterKeyCacheList ) ) {
  342. PMASTERKEY_CACHE_ENTRY pCacheEntry;
  343. pCacheEntry = CONTAINING_RECORD(
  344. g_MasterKeyCacheList.Flink,
  345. MASTERKEY_CACHE_ENTRY,
  346. Next
  347. );
  348. RemoveEntryList( &pCacheEntry->Next );
  349. RtlSecureZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
  350. SSFree( pCacheEntry );
  351. }
  352. RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
  353. RtlDeleteCriticalSection( &g_MasterKeyCacheCritSect );
  354. }