windows-nt/Source/XPSP1/NT/ds/security/protocols/xtcb/mgroup.c
2020-09-26 16:20:57 +08:00

732 lines
15 KiB
C

//+---------------------------------------------------------------------------
//
// 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 );
}