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

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
keycache.h
Abstract:
This module contains routines for accessing cached masterkeys.
Author:
Scott Field (sfield) 07-Nov-98
Revision History:
--*/
#include <pch.cpp>
#pragma hdrstop
//
// masterkey cache.
//
typedef struct {
LIST_ENTRY Next;
LUID LogonId;
GUID guidMasterKey;
FILETIME ftLastAccess;
DWORD cbMasterKey;
BYTE pbMasterKey[ 64 ];
} MASTERKEY_CACHE_ENTRY, *PMASTERKEY_CACHE_ENTRY, *LPMASTERKEY_CACHE_ENTRY;
RTL_CRITICAL_SECTION g_MasterKeyCacheCritSect;
LIST_ENTRY g_MasterKeyCacheList;
BOOL
RemoveMasterKeyCache(
IN PLUID pLogonId
);
#if DBG
void
DumpMasterKeyEntry(
PMASTERKEY_CACHE_ENTRY pCacheEntry)
{
WCHAR wszguidMasterKey[MAX_GUID_SZ_CHARS];
#if 0
BYTE rgbMasterKey[256];
DWORD cbMasterKey;
#endif
D_DebugLog((DEB_TRACE, "LogonId: %d.%d\n", pCacheEntry->LogonId.LowPart, pCacheEntry->LogonId.HighPart));
if( MyGuidToStringW( &pCacheEntry->guidMasterKey, wszguidMasterKey ) != 0 )
{
D_DebugLog((DEB_TRACE, "Invalid GUID:\n"));
D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)&pCacheEntry->guidMasterKey, sizeof(pCacheEntry->guidMasterKey));
}
else
{
D_DebugLog((DEB_TRACE, "GUID: %ws\n", wszguidMasterKey));
}
#if 0
cbMasterKey = min(pCacheEntry->cbMasterKey, sizeof(rgbMasterKey));
CopyMemory(rgbMasterKey, pCacheEntry->pbMasterKey, cbMasterKey);
LsaProtectMemory(rgbMasterKey, cbMasterKey);
D_DebugLog((DEB_TRACE, "Master key:\n"));
D_DPAPIDumpHexData(DEB_TRACE, " ", rgbMasterKey, cbMasterKey);
#endif
}
#endif
#if DBG
void
DumpMasterKeyCache(void)
{
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
PMASTERKEY_CACHE_ENTRY pCacheEntry;
ULONG i = 0;
RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
D_DebugLog((DEB_TRACE, "Master key cache\n"));
ListHead = &g_MasterKeyCacheList;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink )
{
pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
D_DebugLog((DEB_TRACE, "---- %d ----\n", ++i));
DumpMasterKeyEntry(pCacheEntry);
}
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
}
#endif
BOOL
SearchMasterKeyCache(
IN PLUID pLogonId,
IN GUID *pguidMasterKey,
IN OUT PBYTE *ppbMasterKey,
OUT PDWORD pcbMasterKey
)
/*++
Search the masterkey sorted masterkey cache by pLogonId then by
pguidMasterKey.
On success, return value is true, and ppbMasterKey will point to a buffer
allocated on behalf of the caller containing the specified masterkey.
The caller must free the buffer using SSFree().
--*/
{
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
BOOL fSuccess = FALSE;
#if DBG
WCHAR wszguidMasterKey[MAX_GUID_SZ_CHARS];
#endif
RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
#if DBG
D_DebugLog((DEB_TRACE, "SearchMasterKeyCache\n"));
D_DebugLog((DEB_TRACE, "LogonId: %d.%d\n", pLogonId->LowPart, pLogonId->HighPart));
if( MyGuidToStringW( pguidMasterKey, wszguidMasterKey ) != 0 )
{
D_DebugLog((DEB_TRACE, "Invalid GUID:\n"));
D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)pguidMasterKey, sizeof(GUID));
}
else
{
D_DebugLog((DEB_TRACE, "GUID: %ws\n", wszguidMasterKey));
}
//DumpMasterKeyCache();
#endif
ListHead = &g_MasterKeyCacheList;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
PMASTERKEY_CACHE_ENTRY pCacheEntry;
signed int comparator;
pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
//
// search by LogonId, then by GUID.
//
comparator = memcmp(pLogonId, &pCacheEntry->LogonId, sizeof(LUID));
if( comparator < 0 )
continue;
if( comparator > 0 )
break;
comparator = memcmp(pguidMasterKey, &pCacheEntry->guidMasterKey, sizeof(GUID));
if( comparator < 0 )
continue;
if( comparator > 0 )
break;
//
// match found.
//
*pcbMasterKey = pCacheEntry->cbMasterKey;
*ppbMasterKey = (PBYTE)SSAlloc( *pcbMasterKey );
if( *ppbMasterKey != NULL ) {
CopyMemory( *ppbMasterKey, pCacheEntry->pbMasterKey, *pcbMasterKey );
fSuccess = TRUE;
}
//
// update last access time.
//
GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
break;
}
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
if( fSuccess ) {
//
// decrypt (in-place) the returned encrypted cache entry.
//
LsaUnprotectMemory( *ppbMasterKey, *pcbMasterKey );
}
D_DebugLog((DEB_TRACE, "SearchMasterKeyCache returned %s\n", fSuccess ? "FOUND" : "NOT FOUND"));
return fSuccess;
}
BOOL
InsertMasterKeyCache(
IN PLUID pLogonId,
IN GUID *pguidMasterKey,
IN PBYTE pbMasterKey,
IN DWORD cbMasterKey
)
/*++
Insert the specified masterkey into the cahce sorted by pLogonId then by
pguidMasterKey.
The return value is TRUE on success.
--*/
{
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
PMASTERKEY_CACHE_ENTRY pCacheEntry;
PMASTERKEY_CACHE_ENTRY pThisCacheEntry = NULL;
BOOL fInserted = FALSE;
D_DebugLog((DEB_TRACE, "InsertMasterKeyCache\n"));
if( cbMasterKey > sizeof(pCacheEntry->pbMasterKey) )
return FALSE;
pCacheEntry = (PMASTERKEY_CACHE_ENTRY)SSAlloc( sizeof( MASTERKEY_CACHE_ENTRY ) );
if( pCacheEntry == NULL )
return FALSE;
CopyMemory( &pCacheEntry->LogonId, pLogonId, sizeof(LUID) );
CopyMemory( &pCacheEntry->guidMasterKey, pguidMasterKey, sizeof(GUID) );
pCacheEntry->cbMasterKey = cbMasterKey;
CopyMemory( pCacheEntry->pbMasterKey, pbMasterKey, cbMasterKey );
LsaProtectMemory( pCacheEntry->pbMasterKey, cbMasterKey );
GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
#if DBG
DumpMasterKeyEntry(pCacheEntry);
#endif
ListHead = &g_MasterKeyCacheList;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
signed int comparator;
pThisCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
//
// insert into list sorted by LogonId, then sorted by GUID.
//
comparator = memcmp(pLogonId, &pThisCacheEntry->LogonId, sizeof(LUID));
if( comparator < 0 )
continue;
if( comparator == 0 ) {
comparator = memcmp( pguidMasterKey, &pThisCacheEntry->guidMasterKey, sizeof(GUID));
if( comparator < 0 )
continue;
if( comparator == 0 ) {
//
// don't insert duplicate records.
// this would only happen in a race condition with multiple threads.
//
RtlSecureZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
SSFree( pCacheEntry );
fInserted = TRUE;
break;
}
}
//
// insert prior to current record.
//
InsertHeadList( pThisCacheEntry->Next.Blink, &pCacheEntry->Next );
fInserted = TRUE;
break;
}
if( !fInserted ) {
if( pThisCacheEntry == NULL ) {
InsertHeadList( ListHead, &pCacheEntry->Next );
} else {
InsertHeadList( &pThisCacheEntry->Next, &pCacheEntry->Next );
}
}
#if DBG
//DumpMasterKeyCache();
#endif
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
return TRUE;
}
BOOL
PurgeMasterKeyCache(
VOID
)
/*++
Purge masterkey cache of timed-out entries, or entries associated with
terminated logon sessions.
--*/
{
//
// build active session table.
//
// don't touch entries that have an entry in active session table.
// assume LUID_SYSTEM in table.
//
// entries not in table: discard after 15 minute timeout.
//
// if entry in table, find next LUID
// else, if entry expired, check timeout. if expired, remove.
//
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
ListHead = &g_MasterKeyCacheList;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
PMASTERKEY_CACHE_ENTRY pCacheEntry;
// signed int comparator;
pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
}
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
return FALSE;
}
BOOL
RemoveMasterKeyCache(
IN PLUID pLogonId
)
/*++
Remove all entries from the masterkey cache corresponding to the specified
pLogonId.
The purpose of this routine is to purge the masterkey cache of entries
associated with (now) non-existent logon sessions.
--*/
{
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
D_DebugLog((DEB_TRACE, "RemoveMasterKeyCache\n"));
D_DebugLog((DEB_TRACE, "LogonId: %d.%d\n", pLogonId->LowPart, pLogonId->HighPart));
ListHead = &g_MasterKeyCacheList;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
PMASTERKEY_CACHE_ENTRY pCacheEntry;
signed int comparator;
pCacheEntry = CONTAINING_RECORD( ListEntry, MASTERKEY_CACHE_ENTRY, Next );
//
// remove all entries with matching LogonId.
//
comparator = memcmp(pLogonId, &pCacheEntry->LogonId, sizeof(LUID));
if( comparator > 0 )
break;
if( comparator < 0 )
continue;
//
// match found.
//
RemoveEntryList( &pCacheEntry->Next );
RtlSecureZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
SSFree( pCacheEntry );
}
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
return TRUE;
}
BOOL
InitializeKeyCache(
VOID
)
{
NTSTATUS Status;
Status = RtlInitializeCriticalSection( &g_MasterKeyCacheCritSect );
if(!NT_SUCCESS(Status))
{
return FALSE;
}
InitializeListHead( &g_MasterKeyCacheList );
return TRUE;
}
VOID
DeleteKeyCache(
VOID
)
{
//
// remove all list entries.
//
RtlEnterCriticalSection( &g_MasterKeyCacheCritSect );
while ( !IsListEmpty( &g_MasterKeyCacheList ) ) {
PMASTERKEY_CACHE_ENTRY pCacheEntry;
pCacheEntry = CONTAINING_RECORD(
g_MasterKeyCacheList.Flink,
MASTERKEY_CACHE_ENTRY,
Next
);
RemoveEntryList( &pCacheEntry->Next );
RtlSecureZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
SSFree( pCacheEntry );
}
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
RtlDeleteCriticalSection( &g_MasterKeyCacheCritSect );
}