|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1997.
//
// File: mgroup.c
//
// Contents: LSA Mode Context API
//
// Classes:
//
// Functions:
//
// History: 2-24-97 RichardW Created
//
//----------------------------------------------------------------------------
#include "xtcbpkg.h"
#include <cryptdll.h>
LIST_ENTRY MachineGroupList ; CRITICAL_SECTION MachineGroupLock ; WCHAR MachineLocalName[ MAX_PATH ];
#define LOOPBACK_KEY L"Loopback"
#define GROUPKEY_VALUE L"$$GroupKey"
PXTCB_MACHINE_GROUP_ENTRY MGpCreateGroupEntry( PWSTR MachineName, PUCHAR Key ) { PXTCB_MACHINE_GROUP_ENTRY Entry ; ULONG Length ;
Length = wcslen( MachineName ) + 1; Entry = LocalAlloc( LMEM_FIXED, sizeof( XTCB_MACHINE_GROUP_ENTRY ) + (Length * sizeof(WCHAR) ) );
if ( Entry ) { Entry->MachineName = (PWSTR) (Entry + 1); CopyMemory( Entry->UniqueKey, Key, SEED_KEY_SIZE );
CopyMemory( Entry->MachineName, MachineName, Length * sizeof(WCHAR) );
if ( _wcsicmp( MachineName, MachineLocalName ) == 0 ) { Entry->Flags = MGROUP_ENTRY_SELF ; } else { Entry->Flags = 0; }
}
return Entry ; }
VOID MGpFreeGroup( PXTCB_MACHINE_GROUP Group ) { ULONG i ;
for ( i = 0 ; i < Group->Count ; i++ ) { LocalFree( Group->GroupList[ i ] ); }
LocalFree( Group ); }
PXTCB_MACHINE_GROUP MGpCreateMachineGroup( HKEY Root, PWSTR KeyName ) { ULONG Count ; ULONG Size ; ULONG Type ; UCHAR Key[ SEED_KEY_SIZE ]; PWSTR Name ; ULONG MaxName ; ULONG NameSize ; ULONG Index ; PXTCB_MACHINE_GROUP Group ; int err ;
err = RegQueryInfoKey( Root, NULL, NULL, NULL, NULL, NULL, NULL, &Count, &MaxName, NULL, NULL, NULL );
if ( err ) { return NULL ; }
MaxName++;
Name = LocalAlloc( LMEM_FIXED, (MaxName) * sizeof( WCHAR ) );
if ( !Name ) { return NULL ; }
Group = LocalAlloc( LMEM_FIXED, sizeof( XTCB_MACHINE_GROUP ) + ( Count ) * sizeof( PXTCB_MACHINE_GROUP_ENTRY ) + ( wcslen( KeyName ) + 1 ) * sizeof( WCHAR ) );
if ( !Group ) { LocalFree( Name ); return NULL ; }
//
// We've got all the base structures. Let's load it in:
//
Group->List.Flink = NULL ; Group->List.Blink = NULL ; Group->Count = 0 ; Group->GroupList = (PXTCB_MACHINE_GROUP_ENTRY *) (Group + 1); Group->Group.Buffer = (PWSTR) ((PUCHAR) Group->GroupList + (Count * sizeof( PXTCB_MACHINE_GROUP_ENTRY ) ) );
wcscpy( Group->Group.Buffer, KeyName ); Group->Group.Length = wcslen( Group->Group.Buffer ) * sizeof( WCHAR ); Group->Group.MaximumLength = Group->Group.Length + sizeof( WCHAR );
for ( Index = 0 ; Index < Count ; Index++ ) { NameSize = MaxName ; Size = SEED_KEY_SIZE ;
err = RegEnumValue( Root, Index, Name, &NameSize, NULL, &Type, Key, &Size );
if ( (err == 0) && (Type == REG_BINARY) ) { if ( _wcsicmp( Name, GROUPKEY_VALUE ) == 0 ) { CopyMemory( Group->SeedKey, Key, Size );
continue; }
Group->GroupList[ Group->Count ] = MGpCreateGroupEntry( Name, Key ); if ( Group->GroupList[ Group->Count ] ) { Group->Count++ ; } }
}
LocalFree( Name );
if ( Group->Count == 0 ) { DebugLog(( DEB_ERROR, "No machines found in group %ws\n", KeyName )); LocalFree( Group ); Group = NULL ; }
if ( Group ) { for ( Index = 0 ; Index < Group->Count ; Index++ ) { if ( Group->GroupList[ Index ]->Flags & MGROUP_ENTRY_SELF ) { break; } }
if ( Index == Group->Count ) { DebugLog(( DEB_ERROR, "No entry for self found in group %ws\n", KeyName )); MGpFreeGroup( Group ); Group = NULL ; } }
return Group ; }
VOID MGpCreateLoopback( HKEY RootKey ) { int err ; DWORD Disp ; HKEY LoopbackKey ; UCHAR Random1[ XTCB_SEED_LENGTH ]; UCHAR Random2[ XTCB_SEED_LENGTH ];
err = RegCreateKeyEx( RootKey, LOOPBACK_KEY, 0, NULL, REG_OPTION_VOLATILE, KEY_READ | KEY_WRITE, NULL, &LoopbackKey, &Disp );
if ( err == 0 ) { if ( Disp == REG_OPENED_EXISTING_KEY ) { RegCloseKey( LoopbackKey ); return; }
CDGenerateRandomBits( Random1, XTCB_SEED_LENGTH ); CDGenerateRandomBits( Random2, XTCB_SEED_LENGTH );
(VOID) RegSetValueEx( LoopbackKey, GROUPKEY_VALUE, 0, REG_BINARY, Random2, XTCB_SEED_LENGTH );
(VOID) RegSetValueEx( LoopbackKey, L"LocalHost", 0, REG_BINARY, Random1, XTCB_SEED_LENGTH );
(VOID) RegSetValueEx( LoopbackKey, XtcbUnicodeDnsName.Buffer, 0, REG_BINARY, Random1, XTCB_SEED_LENGTH );
//
// Enumerate and stick aliases for this machine in the key here.
//
RegCloseKey( LoopbackKey ); } }
BOOL MGpLoadGroups( VOID ) { HKEY RootKey = NULL ; HKEY Enum ; int err ; DWORD Index ; DWORD Disp ; PXTCB_MACHINE_GROUP Group ; DWORD MaxLen ; PWSTR KeyName = NULL ; WCHAR Buffer[ 32 ]; DWORD Len ; BOOL Success = FALSE ; ULONG KeyCount ;
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\LSA\\XTCB\\Groups", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &RootKey, &Disp );
if ( err ) { return FALSE ; }
MGpCreateLoopback( RootKey );
err = RegQueryInfoKey( RootKey, NULL, NULL, NULL, &KeyCount, &MaxLen, NULL, NULL, NULL, NULL, NULL, NULL );
if ( err ) { goto Cleanup ;
}
DebugLog(( DEB_TRACE, "Found %d groups\n", KeyCount ));
if ( MaxLen < 32 ) { KeyName = Buffer ; MaxLen = 32 ; } else { KeyName = LocalAlloc( LMEM_FIXED, (MaxLen + 1) * sizeof( WCHAR ) );
if ( KeyName == NULL ) { goto Cleanup ; } }
Index = 0 ;
while ( Index < KeyCount ) {
Len = MaxLen ; err = RegEnumKeyEx( RootKey, Index, KeyName, &Len, NULL, NULL, NULL, NULL );
if ( err ) { Index++ ; continue; }
err = RegOpenKeyEx( RootKey, KeyName, REG_OPTION_NON_VOLATILE, KEY_READ, &Enum );
if ( err ) { err = RegOpenKeyEx( RootKey, KeyName, REG_OPTION_VOLATILE, KEY_READ, &Enum ); }
if ( err == 0 ) { DebugLog(( DEB_TRACE, "Processing group %d:%ws\n", Index, KeyName ));
Group = MGpCreateMachineGroup( Enum, KeyName );
RegCloseKey( Enum );
if ( Group ) { InsertTailList( &MachineGroupList, &Group->List ); } } else { DebugLog(( DEB_TRACE, "Unable to open key %ws\n", KeyName )); }
Index++ ;
} Success = TRUE ;
Cleanup: if ( RootKey ) { RegCloseKey( RootKey ); }
if ( KeyName ) { if ( KeyName != Buffer ) { LocalFree( KeyName ); } }
return Success ;
}
BOOL MGroupReload( VOID ) { PLIST_ENTRY List ; PXTCB_MACHINE_GROUP Group ; BOOL Success ; DWORD Size = MAX_PATH ;
EnterCriticalSection( &MachineGroupLock );
while ( !IsListEmpty( &MachineGroupList ) ) { List = RemoveHeadList( &MachineGroupList );
Group = CONTAINING_RECORD( List, XTCB_MACHINE_GROUP, List );
MGpFreeGroup( Group ); }
GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, MachineLocalName, &Size );
Success = MGpLoadGroups();
LeaveCriticalSection( &MachineGroupLock );
return Success ;
}
BOOL MGroupInitialize( VOID ) { BOOL Success = TRUE ; try {
InitializeCriticalSection( &MachineGroupLock ); } except ( EXCEPTION_EXECUTE_HANDLER ) { Success = FALSE ; }
InitializeListHead( &MachineGroupList );
if ( Success ) { Success = MGroupReload(); }
return Success ; }
BOOL MGroupLocateInboundKey( IN PSECURITY_STRING GroupName, IN PSECURITY_STRING Origin, OUT PUCHAR TargetKey, OUT PUCHAR GroupKey, OUT PUCHAR MyKey ) { PLIST_ENTRY Scan ; PXTCB_MACHINE_GROUP Group ; PXTCB_MACHINE_GROUP_ENTRY Entry ; PXTCB_MACHINE_GROUP_ENTRY Self = NULL ; ULONG i ; BOOL Success = FALSE ;
EnterCriticalSection( &MachineGroupLock );
Scan = MachineGroupList.Flink ;
while ( Scan != &MachineGroupList ) { Group = CONTAINING_RECORD( Scan, XTCB_MACHINE_GROUP, List );
if ( RtlEqualUnicodeString( GroupName, &Group->Group, TRUE ) ) { for ( i = 0 ; i < Group->Count ; i++ ) { Entry = Group->GroupList[ i ]; if ( Entry->Flags & MGROUP_ENTRY_SELF ) { Self = Entry ; } if ( _wcsicmp( Origin->Buffer, Entry->MachineName ) == 0 ) { //
// We have a hit:
//
Success = TRUE ; CopyMemory( TargetKey, Entry->UniqueKey, SEED_KEY_SIZE ); CopyMemory( GroupKey, Group->SeedKey, SEED_KEY_SIZE ); break; } }
}
if ( Success ) { break; }
Scan = Scan->Flink ; Self = NULL ;
}
if ( Success && ( Self == NULL ) ) { //
// Continue through the group, looking for the
// self entry
//
for ( ; i < Group->Count ; i++ ) { if ( Group->GroupList[ i ]->Flags & MGROUP_ENTRY_SELF ) { Self = Group->GroupList[ i ]; break; } } }
if ( Success ) { CopyMemory( MyKey, Self->UniqueKey, SEED_KEY_SIZE ); }
LeaveCriticalSection( &MachineGroupLock );
return Success ;
}
BOOL MGroupLocateKeys( IN PWSTR Target, OUT PSECURITY_STRING * GroupName, OUT PUCHAR TargetKey, OUT PUCHAR GroupKey, OUT PUCHAR MyKey ) { PLIST_ENTRY Scan ; PXTCB_MACHINE_GROUP Group ; PXTCB_MACHINE_GROUP_ENTRY Entry ; PXTCB_MACHINE_GROUP_ENTRY Self = NULL ; ULONG i ; BOOL Success = FALSE ;
EnterCriticalSection( &MachineGroupLock );
Scan = MachineGroupList.Flink ;
while ( Scan != &MachineGroupList ) { Group = CONTAINING_RECORD( Scan, XTCB_MACHINE_GROUP, List );
for ( i = 0 ; i < Group->Count ; i++ ) { Entry = Group->GroupList[ i ]; if ( Entry->Flags & MGROUP_ENTRY_SELF ) { Self = Entry ; } if ( _wcsicmp( Target, Entry->MachineName ) == 0 ) { //
// We have a hit:
//
Success = TRUE ; CopyMemory( TargetKey, Entry->UniqueKey, SEED_KEY_SIZE ); CopyMemory( GroupKey, Group->SeedKey, SEED_KEY_SIZE ); *GroupName = &Group->Group ; break; } }
if ( Success ) { break; }
Scan = Scan->Flink ; Self = NULL ;
}
if ( Success && ( Self == NULL ) ) { //
// Continue through the group, looking for the
// self entry
//
for ( ; i < Group->Count ; i++ ) { if ( Group->GroupList[ i ]->Flags & MGROUP_ENTRY_SELF ) { Self = Group->GroupList[ i ]; break; } } }
if ( Success ) { CopyMemory( MyKey, Self->UniqueKey, SEED_KEY_SIZE ); }
LeaveCriticalSection( &MachineGroupLock );
return Success ; }
BOOL MGroupParseTarget( PWSTR TargetSpn, PWSTR * MachineName ) { PWSTR Scan ; PWSTR Tail ; PWSTR Copy ; ULONG Length ;
*MachineName = NULL ;
Scan = wcschr( TargetSpn, L'/' );
if ( !Scan ) { return FALSE ; }
Scan++ ; Tail = wcschr( Scan, L'/' );
if ( Tail != NULL ) { //
// three-part SPN (e.g. HOST/hostname.domain.com).
// null out this slash for now
//
*Tail = L'\0';
}
Length = wcslen( Scan );
Copy = LocalAlloc( LMEM_FIXED, (Length + 1) * sizeof( WCHAR ) );
if ( Copy ) { CopyMemory( Copy, Scan, (Length + 1) * sizeof( WCHAR ) ); }
if ( Tail ) { *Tail = L'/' ; }
*MachineName = Copy ;
return ( Copy != NULL ); }
|