2025-04-27 07:49:33 -04:00

407 lines
9.0 KiB
C++

/*++
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
);
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;
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 );
//
// 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 );
}
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;
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 );
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.
//
ZeroMemory( 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 );
}
}
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 );
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 );
ZeroMemory( 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 );
ZeroMemory( pCacheEntry, sizeof(MASTERKEY_CACHE_ENTRY) );
SSFree( pCacheEntry );
}
RtlLeaveCriticalSection( &g_MasterKeyCacheCritSect );
RtlDeleteCriticalSection( &g_MasterKeyCacheCritSect );
}