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.
2422 lines
55 KiB
2422 lines
55 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
|
//
|
|
// File: domcache.c
|
|
//
|
|
// Contents: Restructuring the Domain Cache to get away from direct LSA
|
|
// calls whenever possible.
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 3-29-96 RichardW Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <msgina.h>
|
|
#include <stdio.h>
|
|
|
|
#define LockDomainCache( x ) RtlEnterCriticalSection( &(x)->CriticalSection )
|
|
#define UnlockDomainCache( x ) RtlLeaveCriticalSection( &(x)->CriticalSection )
|
|
|
|
#define TWO_MINUTES ((LONGLONG) 0x47868C00)
|
|
#define TWO_WEEKS ((LONGLONG) 0xB0051C88000I64)
|
|
|
|
WCHAR szCache[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache");
|
|
WCHAR szCacheValue[] = TEXT("DCache");
|
|
WCHAR szCacheUpdate[] = TEXT("DCacheUpdate");
|
|
WCHAR szCacheInterval[] = TEXT("DCacheMinInterval");
|
|
WCHAR szCachePrimary[] = TEXT("CachePrimaryDomain");
|
|
|
|
LONGLONG CacheUpdateMin;
|
|
LONGLONG CacheUpdateMax;
|
|
|
|
BOOL CacheAppendDomainInfo = FALSE ;
|
|
BOOL CacheShowDnsNames = FALSE ;
|
|
|
|
#define DOMAIN_MOD_ALWAYS 0x00000001
|
|
|
|
typedef struct _DOMAIN_MODIFIER {
|
|
ULONG StringId ;
|
|
ULONG Flags ;
|
|
UNICODE_STRING String ;
|
|
} DOMAIN_MODIFIER ;
|
|
|
|
|
|
DOMAIN_MODIFIER CacheDomainModifiers[ DomainTypeMax ] = {
|
|
{ 0 }, // Invalid
|
|
{ IDS_DTYPE_UPNDOMAIN, 0 }, // UPN Domain
|
|
{ IDS_DTYPE_THISCOMPUTER, DOMAIN_MOD_ALWAYS }, // This computer
|
|
{ IDS_DTYPE_NT4DOMAIN, 0 }, // NT4 domains
|
|
{ IDS_DTYPE_NT5DOMAIN, 0 }, // NT5 domains
|
|
{ IDS_DTYPE_MITDOMAIN, DOMAIN_MOD_ALWAYS }, // MIT domains
|
|
{ IDS_DTYPE_MITXDOMAIN, DOMAIN_MOD_ALWAYS }, // Untrusted MIT domains
|
|
{ IDS_DTYPE_NETPROVIDER, DOMAIN_MOD_ALWAYS } // Network provider
|
|
};
|
|
|
|
|
|
DWORD
|
|
DCacheUpdateThread(
|
|
PDOMAIN_CACHE Cache
|
|
);
|
|
|
|
|
|
VOID
|
|
DCacheDereferenceEntry(
|
|
PDOMAIN_CACHE_ENTRY Entry
|
|
)
|
|
{
|
|
if ( InterlockedDecrement( &Entry->RefCount ) == 0 )
|
|
{
|
|
LocalFree( Entry );
|
|
}
|
|
}
|
|
|
|
|
|
PDOMAIN_CACHE_ARRAY
|
|
DCacheCreateArray(
|
|
ULONG Size,
|
|
BOOL Sorted
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ARRAY Array ;
|
|
|
|
Array = LocalAlloc( LMEM_FIXED, sizeof( DOMAIN_CACHE_ARRAY ) );
|
|
|
|
if ( Array )
|
|
{
|
|
Array->List = LocalAlloc( LMEM_FIXED, sizeof( PDOMAIN_CACHE_ENTRY ) * Size );
|
|
|
|
if ( Array->List )
|
|
{
|
|
|
|
Array->Count = 0 ;
|
|
Array->MaxCount = Size ;
|
|
Array->Sorted = Sorted ;
|
|
|
|
return Array ;
|
|
}
|
|
|
|
LocalFree( Array );
|
|
}
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
BOOL
|
|
DCachepExpandArray(
|
|
PDOMAIN_CACHE_ARRAY Array,
|
|
ULONG Size
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ENTRY * NewArray ;
|
|
|
|
NewArray = LocalReAlloc( Array->List,
|
|
(Array->Count + Size) * sizeof( PDOMAIN_CACHE_ENTRY ),
|
|
0 );
|
|
|
|
if ( NewArray )
|
|
{
|
|
Array->List = NewArray ;
|
|
|
|
Array->MaxCount = Array->Count + Size ;
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
return FALSE ;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
DCacheInsertArray(
|
|
PDOMAIN_CACHE_ARRAY Array,
|
|
PDOMAIN_CACHE_ENTRY Entry
|
|
)
|
|
{
|
|
ULONG i ;
|
|
LONG Compare ;
|
|
PDOMAIN_CACHE_ENTRY Scan ;
|
|
|
|
if ( Array->Count == Array->MaxCount )
|
|
{
|
|
if ( !DCachepExpandArray( Array, 10 ) )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|
|
DCacheReferenceEntry( Entry );
|
|
|
|
|
|
if ( ( Array->Sorted == FALSE ) ||
|
|
( Array->Count == 0 ) )
|
|
{
|
|
Array->List[ Array->Count ] = Entry ;
|
|
|
|
Array->Count++ ;
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
else
|
|
{
|
|
Scan = Array->List[ Array->Count - 1 ];
|
|
|
|
Compare = RtlCompareUnicodeString( &Entry->FlatName,
|
|
&Scan->FlatName,
|
|
TRUE );
|
|
|
|
//
|
|
// Efficient check for sorted input:
|
|
//
|
|
|
|
if ( Compare > 0 )
|
|
{
|
|
Array->List[ Array->Count ] = Entry ;
|
|
|
|
Array->Count ++ ;
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
//
|
|
// this is not a terribly efficient sort.
|
|
// However, we're expecting
|
|
// on the order of <100 objects in the array, so it
|
|
// shouldn't be too bad.
|
|
//
|
|
|
|
for ( i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
Scan = Array->List[ i ];
|
|
|
|
Compare = RtlCompareUnicodeString( & Entry->FlatName,
|
|
& Scan->FlatName,
|
|
TRUE );
|
|
|
|
if ( Compare == 0 )
|
|
{
|
|
DCacheDereferenceEntry( Entry );
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
if ( Compare < 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
&Array->List[ i + 1 ],
|
|
&Array->List[ i ],
|
|
(Array->Count - i) * sizeof( PVOID ) );
|
|
|
|
Array->List[ i ] = Entry ;
|
|
|
|
Array->Count++ ;
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PDOMAIN_CACHE_ENTRY
|
|
DCacheSearchArray(
|
|
PDOMAIN_CACHE_ARRAY Array,
|
|
PUNICODE_STRING DomainName
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PDOMAIN_CACHE_ENTRY Scan = NULL ;
|
|
LONG Compare ;
|
|
|
|
|
|
for (i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
Scan = Array->List[ i ];
|
|
|
|
if ( Scan->FlatName.Length == 0 )
|
|
{
|
|
Scan = NULL ;
|
|
|
|
continue;
|
|
}
|
|
|
|
Compare = RtlCompareUnicodeString( &Scan->FlatName,
|
|
DomainName,
|
|
TRUE );
|
|
|
|
if ( Compare == 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( ( Compare > 0 ) &&
|
|
( Array->Sorted ) )
|
|
{
|
|
Scan = NULL ;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Scan ;
|
|
|
|
}
|
|
|
|
PDOMAIN_CACHE_ENTRY
|
|
DCacheSearchArrayByDns(
|
|
PDOMAIN_CACHE_ARRAY Array,
|
|
PUNICODE_STRING DnsDomainName
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PDOMAIN_CACHE_ENTRY Scan = NULL ;
|
|
|
|
|
|
for (i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
Scan = Array->List[ i ];
|
|
|
|
if ( Scan->DnsName.Length )
|
|
{
|
|
if ( RtlEqualUnicodeString( &Scan->DnsName,
|
|
DnsDomainName,
|
|
TRUE ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
Scan = NULL ;
|
|
|
|
}
|
|
|
|
return Scan ;
|
|
|
|
}
|
|
|
|
PDOMAIN_CACHE_ENTRY
|
|
DCacheFindDefaultEntry(
|
|
PDOMAIN_CACHE_ARRAY Array
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PDOMAIN_CACHE_ENTRY Scan = NULL ;
|
|
|
|
|
|
for (i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
Scan = Array->List[ i ];
|
|
|
|
if ( Scan->Flags & DCE_DEFAULT_ENTRY )
|
|
{
|
|
break;
|
|
}
|
|
|
|
Scan = NULL ;
|
|
}
|
|
|
|
return Scan ;
|
|
|
|
}
|
|
|
|
VOID
|
|
DCacheFreeArray(
|
|
PDOMAIN_CACHE_ARRAY Array
|
|
)
|
|
{
|
|
ULONG i ;
|
|
|
|
for ( i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
DCacheDereferenceEntry( Array->List[ i ] );
|
|
}
|
|
|
|
LocalFree( Array->List );
|
|
|
|
LocalFree( Array );
|
|
|
|
}
|
|
|
|
PDOMAIN_CACHE_ARRAY
|
|
DCacheCopyArray(
|
|
PDOMAIN_CACHE_ARRAY Source
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ARRAY Array ;
|
|
ULONG i ;
|
|
|
|
Array = DCacheCreateArray( Source->MaxCount,
|
|
Source->Sorted );
|
|
|
|
if ( Array )
|
|
{
|
|
for (i = 0 ; i < Source->Count ; i++ )
|
|
{
|
|
Array->List[ i ] = Source->List[ i ];
|
|
|
|
DCacheReferenceEntry( Array->List[ i ] );
|
|
}
|
|
|
|
Array->Count = Source->Count ;
|
|
}
|
|
|
|
return Array ;
|
|
}
|
|
|
|
|
|
|
|
PDOMAIN_CACHE_ENTRY
|
|
DCacheCreateEntry(
|
|
DOMAIN_ENTRY_TYPE Type,
|
|
PUNICODE_STRING FlatName OPTIONAL,
|
|
PUNICODE_STRING DnsName OPTIONAL,
|
|
PUNICODE_STRING DisplayName OPTIONAL
|
|
)
|
|
{
|
|
ULONG Size ;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
PUNICODE_STRING DisplayBase = NULL ;
|
|
PUNICODE_STRING Modifier = NULL ;
|
|
PUCHAR Current ;
|
|
|
|
//
|
|
// Validation rules:
|
|
//
|
|
// Display Name is optional if either of FlatName or
|
|
// DNS name is present. If both are present, FlatName
|
|
// is defaulted over Dns name
|
|
//
|
|
|
|
Size = sizeof( DOMAIN_CACHE_ENTRY );
|
|
|
|
if ( FlatName )
|
|
{
|
|
Size += FlatName->Length + sizeof( WCHAR );
|
|
}
|
|
|
|
if ( DnsName )
|
|
{
|
|
Size += DnsName->Length + sizeof( WCHAR );
|
|
}
|
|
|
|
if ( DisplayName )
|
|
{
|
|
Size += DisplayName->Length + sizeof( WCHAR );
|
|
|
|
DisplayBase = DisplayName ;
|
|
}
|
|
else
|
|
{
|
|
if ( CacheShowDnsNames ||
|
|
( ( Type == DomainMitRealm ) ||
|
|
( Type == DomainMitUntrusted ) ) )
|
|
{
|
|
if ( DnsName )
|
|
{
|
|
DisplayBase = DnsName ;
|
|
}
|
|
else if ( FlatName )
|
|
{
|
|
DisplayBase = FlatName ;
|
|
}
|
|
else
|
|
{
|
|
return NULL ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( FlatName )
|
|
{
|
|
DisplayBase = FlatName ;
|
|
}
|
|
else if ( DnsName )
|
|
{
|
|
DisplayBase = DnsName ;
|
|
}
|
|
else
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
}
|
|
|
|
Size += DisplayBase->Length + sizeof( WCHAR );
|
|
|
|
if ( ( CacheAppendDomainInfo ) ||
|
|
( CacheDomainModifiers[ Type ].Flags & DOMAIN_MOD_ALWAYS ) )
|
|
{
|
|
Modifier = &CacheDomainModifiers[ Type ].String ;
|
|
|
|
if ( Modifier->Length )
|
|
{
|
|
Size += CacheDomainModifiers[ Type ].String.Length;
|
|
}
|
|
else
|
|
{
|
|
Modifier = NULL ;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Entry = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Size );
|
|
|
|
if ( !Entry )
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
Entry->RefCount = 1 ;
|
|
Entry->Flags = 0 ;
|
|
Entry->Type = Type ;
|
|
|
|
Current = (PUCHAR) ( Entry + 1 );
|
|
|
|
//
|
|
// Copy and pack the strings:
|
|
//
|
|
|
|
if ( FlatName )
|
|
{
|
|
Entry->FlatName.Buffer = (PWSTR) Current ;
|
|
Entry->FlatName.Length = FlatName->Length ;
|
|
Entry->FlatName.MaximumLength = FlatName->Length + sizeof( WCHAR );
|
|
|
|
RtlCopyMemory(
|
|
Current,
|
|
FlatName->Buffer,
|
|
FlatName->Length );
|
|
|
|
Current += FlatName->Length ;
|
|
|
|
*Current++ = '\0';
|
|
*Current++ = '\0';
|
|
|
|
}
|
|
|
|
if ( DnsName )
|
|
{
|
|
Entry->DnsName.Buffer = (PWSTR) Current ;
|
|
Entry->DnsName.Length = DnsName->Length ;
|
|
Entry->DnsName.MaximumLength = DnsName->Length + sizeof( WCHAR );
|
|
|
|
RtlCopyMemory(
|
|
Current,
|
|
DnsName->Buffer,
|
|
DnsName->Length );
|
|
|
|
Current += DnsName->Length ;
|
|
|
|
*Current++ = '\0';
|
|
*Current++ = '\0';
|
|
}
|
|
|
|
ASSERT( DisplayBase );
|
|
|
|
Entry->DisplayName.Buffer = (PWSTR) Current ;
|
|
Entry->DisplayName.Length = DisplayBase->Length ;
|
|
if ( Modifier )
|
|
{
|
|
Entry->DisplayName.Length = Entry->DisplayName.Length + Modifier->Length ;
|
|
}
|
|
|
|
Entry->DisplayName.MaximumLength = Entry->DisplayName.Length + sizeof( WCHAR );
|
|
|
|
RtlCopyMemory(
|
|
Current,
|
|
DisplayBase->Buffer,
|
|
DisplayBase->Length );
|
|
|
|
Current += DisplayBase->Length ;
|
|
|
|
if ( Modifier )
|
|
{
|
|
RtlCopyMemory(
|
|
Current,
|
|
Modifier->Buffer,
|
|
Modifier->Length );
|
|
|
|
Current += Modifier->Length ;
|
|
}
|
|
|
|
*Current++ = '\0';
|
|
*Current++ = '\0';
|
|
|
|
return Entry ;
|
|
|
|
}
|
|
|
|
LONG
|
|
DCacheGetTrustedDomains(
|
|
PDOMAIN_CACHE_ARRAY * pArray
|
|
)
|
|
{
|
|
LONG NetStatus ;
|
|
PDOMAIN_CACHE_ARRAY Array ;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
PDS_DOMAIN_TRUSTS Trusts ;
|
|
ULONG TrustCount ;
|
|
ULONG i ;
|
|
UNICODE_STRING Flat ;
|
|
UNICODE_STRING Dns ;
|
|
DOMAIN_ENTRY_TYPE Type ;
|
|
|
|
*pArray = NULL ;
|
|
|
|
NetStatus = DsEnumerateDomainTrusts(
|
|
NULL,
|
|
DS_DOMAIN_IN_FOREST |
|
|
DS_DOMAIN_DIRECT_OUTBOUND,
|
|
&Trusts,
|
|
&TrustCount );
|
|
|
|
if ( NetStatus != NERR_Success )
|
|
{
|
|
return NetStatus ;
|
|
}
|
|
|
|
Array = DCacheCreateArray( TrustCount + 5,
|
|
TRUE );
|
|
|
|
if ( !Array )
|
|
{
|
|
NetApiBufferFree( Trusts );
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY ;
|
|
}
|
|
|
|
for ( i = 0 ; i < TrustCount ; i++ )
|
|
{
|
|
|
|
if ( Trusts[ i ].NetbiosDomainName )
|
|
{
|
|
RtlInitUnicodeString( &Flat, Trusts[ i ].NetbiosDomainName );
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory( &Flat, sizeof( Flat ) );
|
|
}
|
|
|
|
if ( Trusts[ i ].DnsDomainName )
|
|
{
|
|
RtlInitUnicodeString( &Dns, Trusts[ i ].DnsDomainName );
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory( &Dns, sizeof( Dns ) );
|
|
}
|
|
|
|
switch ( Trusts[ i ].TrustType )
|
|
{
|
|
case TRUST_TYPE_DOWNLEVEL :
|
|
Type = DomainNt4 ;
|
|
break;
|
|
|
|
case TRUST_TYPE_UPLEVEL:
|
|
Type = DomainNt5 ;
|
|
break;
|
|
|
|
case TRUST_TYPE_MIT:
|
|
Type = DomainMitRealm ;
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
|
|
DebugLog(( DEB_TRACE_CACHE, "Processing domain (%d) %ws\n",
|
|
Type,
|
|
Trusts[ i ].NetbiosDomainName ));
|
|
|
|
Entry = DCacheCreateEntry(
|
|
Type,
|
|
( Flat.Buffer ? &Flat : NULL ),
|
|
( Dns.Buffer ? &Dns : NULL ),
|
|
NULL );
|
|
|
|
if ( Entry )
|
|
{
|
|
DCacheInsertArray(
|
|
Array,
|
|
Entry );
|
|
|
|
DCacheDereferenceEntry( Entry );
|
|
}
|
|
|
|
}
|
|
|
|
NetApiBufferFree( Trusts );
|
|
|
|
*pArray = Array ;
|
|
|
|
return 0 ;
|
|
|
|
}
|
|
|
|
BOOL
|
|
DCacheAddMitRealms(
|
|
PDOMAIN_CACHE_ARRAY Array
|
|
)
|
|
{
|
|
HKEY MitKey ;
|
|
DWORD Index ;
|
|
PWSTR Realms;
|
|
DWORD RealmSize;
|
|
int err ;
|
|
DWORD NumRealms;
|
|
DWORD MaxRealmLength ;
|
|
FILETIME KeyTime ;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
PDOMAIN_CACHE_ENTRY TrustedDomain ;
|
|
UNICODE_STRING DnsName ;
|
|
|
|
err = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("System\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Domains"),
|
|
0,
|
|
KEY_READ,
|
|
&MitKey );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
err = RegQueryInfoKey( MitKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&NumRealms,
|
|
&MaxRealmLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
MaxRealmLength++ ;
|
|
|
|
Realms = LocalAlloc( LMEM_FIXED, MaxRealmLength * sizeof( WCHAR ));
|
|
|
|
|
|
if ( Realms)
|
|
{
|
|
|
|
for ( Index = 0 ; Index < NumRealms ; Index++ )
|
|
{
|
|
RealmSize = MaxRealmLength ;
|
|
|
|
err = RegEnumKeyEx( MitKey,
|
|
Index,
|
|
Realms,
|
|
&RealmSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&KeyTime );
|
|
|
|
|
|
if ( err == 0 )
|
|
{
|
|
DebugLog(( DEB_TRACE_CACHE, "Found realm %ws\n", Realms ));
|
|
|
|
RtlInitUnicodeString( &DnsName, Realms );
|
|
|
|
Entry = DCacheCreateEntry(
|
|
DomainMitUntrusted,
|
|
&DnsName,
|
|
&DnsName,
|
|
NULL );
|
|
|
|
if ( Entry )
|
|
{
|
|
Entry->Flags |= DCE_REACHABLE_MIT ;
|
|
|
|
if ( !DCacheInsertArray( Array, Entry ) )
|
|
{
|
|
//
|
|
// If the insert failed, then there's already an entry
|
|
// in the list for this domain. Locate it, and tag it
|
|
// so that it will be displayed
|
|
//
|
|
|
|
TrustedDomain = DCacheSearchArray( Array, &DnsName );
|
|
|
|
if ( TrustedDomain )
|
|
{
|
|
TrustedDomain->Flags |= DCE_REACHABLE_MIT ;
|
|
}
|
|
|
|
}
|
|
|
|
DCacheDereferenceEntry( Entry );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree( Realms );
|
|
|
|
}
|
|
|
|
RegCloseKey( MitKey );
|
|
}
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
BOOL
|
|
DCacheAddNetworkProviders(
|
|
PDOMAIN_CACHE_ARRAY Array
|
|
)
|
|
{
|
|
WCHAR szProviderName[128];
|
|
WCHAR szKeyPath[MAX_PATH];
|
|
PWSTR pszProviders;
|
|
PWSTR pszScan;
|
|
PWSTR pszStart;
|
|
WCHAR Save;
|
|
HKEY hKey;
|
|
DWORD dwType;
|
|
DWORD dwLen;
|
|
DWORD Class;
|
|
int err;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
UNICODE_STRING String ;
|
|
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
|
|
0,
|
|
KEY_READ,
|
|
&hKey );
|
|
|
|
if ( err )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
err = RegQueryValueEx( hKey,
|
|
TEXT("ProviderOrder"),
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&dwLen );
|
|
|
|
if ( (err) || (dwType != REG_SZ) )
|
|
{
|
|
RegCloseKey( hKey );
|
|
return FALSE ;
|
|
}
|
|
|
|
pszProviders = LocalAlloc( LMEM_FIXED, dwLen );
|
|
|
|
if ( !pszProviders )
|
|
{
|
|
RegCloseKey( hKey );
|
|
return FALSE ;
|
|
}
|
|
|
|
err = RegQueryValueEx( hKey,
|
|
TEXT("ProviderOrder"),
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) pszProviders,
|
|
&dwLen );
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if ( err )
|
|
{
|
|
LocalFree( pszProviders );
|
|
return FALSE ;
|
|
}
|
|
|
|
//
|
|
// Initialize things.
|
|
//
|
|
|
|
pszStart = pszProviders;
|
|
|
|
|
|
szProviderName[0] = TEXT('<');
|
|
szProviderName[1] = TEXT(' ');
|
|
|
|
|
|
while ( *pszStart )
|
|
{
|
|
pszScan = pszStart;
|
|
while ( (*pszScan) && (*pszScan != TEXT(',') ) )
|
|
{
|
|
pszScan++;
|
|
}
|
|
|
|
Save = *pszScan;
|
|
|
|
*pszScan = TEXT('\0');
|
|
|
|
wsprintf( szKeyPath,
|
|
TEXT("System\\CurrentControlSet\\Services\\%s\\networkprovider"),
|
|
pszStart );
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szKeyPath,
|
|
0,
|
|
KEY_READ,
|
|
&hKey );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
|
|
dwLen = sizeof(DWORD) ;
|
|
|
|
err = RegQueryValueEx( hKey,
|
|
TEXT("Class"),
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &Class,
|
|
&dwLen );
|
|
|
|
if ( (err == 0) && (dwType == REG_DWORD) )
|
|
{
|
|
if ( Class & WN_CREDENTIAL_CLASS )
|
|
{
|
|
|
|
dwLen = 126 * sizeof(WCHAR);
|
|
|
|
err = RegQueryValueEx( hKey,
|
|
TEXT("Name"),
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &szProviderName[2],
|
|
&dwLen );
|
|
|
|
wcscpy( &szProviderName[ (dwLen / sizeof(WCHAR) ) + 2 ],
|
|
TEXT(" >") );
|
|
|
|
RtlInitUnicodeString( &String, szProviderName );
|
|
|
|
Entry = DCacheCreateEntry(
|
|
DomainNetworkProvider,
|
|
&String,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( Entry )
|
|
{
|
|
DCacheInsertArray( Array, Entry );
|
|
|
|
DCacheDereferenceEntry( Entry );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
}
|
|
|
|
*pszScan = Save;
|
|
if ( *pszScan )
|
|
{
|
|
pszStart = pszScan + 1;
|
|
}
|
|
else
|
|
{
|
|
pszStart = NULL;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree( pszProviders );
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
BOOL
|
|
DCacheGetDomainsFromCache(
|
|
PDOMAIN_CACHE_ARRAY *pArray,
|
|
PLARGE_INTEGER RegistryTime
|
|
)
|
|
{
|
|
HKEY Key ;
|
|
int err ;
|
|
DWORD NumDomains ;
|
|
DWORD i ;
|
|
WCHAR FlatName[ DNLEN + 2 ];
|
|
WCHAR DnsDomain[ MAX_PATH ];
|
|
DWORD dwType ;
|
|
DWORD FlatNameSize ;
|
|
DWORD DnsDomainSize ;
|
|
UNICODE_STRING Flat ;
|
|
UNICODE_STRING Dns ;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
PDOMAIN_CACHE_ARRAY Array = NULL;
|
|
DWORD dwSize ;
|
|
PWSTR DomainBuffer ;
|
|
PWSTR DomainBufferEnd ;
|
|
PWSTR Scan ;
|
|
ULONG Disp ;
|
|
BOOL ReturnFalseAnyway = FALSE ;
|
|
|
|
if ( SafeBootMode == SAFEBOOT_MINIMAL )
|
|
{
|
|
RegistryTime->QuadPart = 0 ;
|
|
return FALSE ;
|
|
}
|
|
|
|
//
|
|
// The following appears to be a transfer of
|
|
// HKLM\Microsoft\Windows NT\CurrentVersion\Winlogon\DCache
|
|
// in the form of a multistring to the current DomainCache format
|
|
// Legacy migration?
|
|
// In any case, let's not worry if any of this fails.
|
|
//
|
|
dwSize = 0 ;
|
|
err = RegQueryValueEx(
|
|
WinlogonKey,
|
|
szCacheValue,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&dwSize );
|
|
|
|
if ( ( err == ERROR_MORE_DATA ) ||
|
|
( err == ERROR_BUFFER_OVERFLOW ) ||
|
|
( err == 0 ) )
|
|
{
|
|
//
|
|
//
|
|
|
|
DomainBuffer = LocalAlloc( LMEM_FIXED, dwSize );
|
|
|
|
if ( DomainBuffer )
|
|
{
|
|
err = RegQueryValueEx(
|
|
WinlogonKey,
|
|
szCacheValue,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) DomainBuffer,
|
|
&dwSize );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
DomainBufferEnd = (PWSTR)((PUCHAR) DomainBuffer + dwSize);
|
|
|
|
Scan = DomainBuffer ;
|
|
|
|
err = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szCache,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&Key,
|
|
&Disp );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
while ( Scan != DomainBufferEnd )
|
|
{
|
|
err = RegSetValueEx(
|
|
Key,
|
|
Scan,
|
|
0,
|
|
REG_SZ,
|
|
(PUCHAR) TEXT(""),
|
|
sizeof( WCHAR ) );
|
|
|
|
Scan += wcslen(Scan) ;
|
|
|
|
while ( (*Scan == L'\0' ) &&
|
|
(Scan != DomainBufferEnd ) )
|
|
{
|
|
Scan++ ;
|
|
}
|
|
|
|
}
|
|
|
|
RegCloseKey( Key );
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree( DomainBuffer );
|
|
}
|
|
|
|
RegDeleteValue( WinlogonKey, szCacheValue );
|
|
|
|
ReturnFalseAnyway = TRUE ;
|
|
}
|
|
// End of Legacy migration
|
|
|
|
|
|
// Since the DomainCache is "managed" by all sessions w/o protection,
|
|
// we need to implement a little bit of retry logic here
|
|
//
|
|
Key = NULL;
|
|
dwSize = 10; // Number of retries
|
|
do
|
|
{
|
|
if (dwSize < 10)
|
|
{
|
|
Sleep(100); // Let the other session finish its work
|
|
}
|
|
|
|
err = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szCache,
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if ( err == ERROR_SUCCESS)
|
|
{
|
|
// Query the number of values in the DomainCache
|
|
err = RegQueryInfoKey( Key,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&NumDomains,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
if (Array) // Initialized during a previous attempt
|
|
{
|
|
DCacheFreeArray(Array);
|
|
}
|
|
Array = DCacheCreateArray( NumDomains + 5, TRUE );
|
|
|
|
if ( Array )
|
|
{
|
|
for ( i = 0 ; i < NumDomains ; i++ )
|
|
{
|
|
FlatNameSize = DNLEN + 2 ;
|
|
DnsDomainSize = MAX_PATH ;
|
|
|
|
err = RegEnumValue(
|
|
Key,
|
|
i,
|
|
FlatName,
|
|
&FlatNameSize,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) DnsDomain,
|
|
&DnsDomainSize );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
RtlInitUnicodeString( &Flat, FlatName );
|
|
|
|
RtlInitUnicodeString( &Dns, DnsDomain );
|
|
|
|
Entry = DCacheCreateEntry(
|
|
( Dns.Length ? DomainNt5 : DomainNt4),
|
|
&Flat,
|
|
( Dns.Length ? &Dns : NULL ),
|
|
NULL );
|
|
|
|
if ( Entry )
|
|
{
|
|
DCacheInsertArray( Array, Entry );
|
|
|
|
DCacheDereferenceEntry( Entry );
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((i < NumDomains) && (err == ERROR_NO_MORE_ITEMS))
|
|
{
|
|
// Hit the end of enumeration although we
|
|
// knew how many values we had?
|
|
// The key was probably deleted in another
|
|
// session. Retry.
|
|
err = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
RegCloseKey( Key );
|
|
}
|
|
} while (((err == ERROR_FILE_NOT_FOUND) || (err == ERROR_KEY_DELETED)) && (--dwSize));
|
|
|
|
//
|
|
// Note that we may not have succeeded in the end
|
|
// We will return success anyway, with no array or a partial array.
|
|
// The callers seem to handle that.
|
|
//
|
|
|
|
if ( RegistryTime )
|
|
{
|
|
dwSize = sizeof( LARGE_INTEGER ) ;
|
|
|
|
if ( RegQueryValueEx( WinlogonKey,
|
|
szCacheUpdate,
|
|
0,
|
|
&dwType,
|
|
(PUCHAR) RegistryTime,
|
|
&dwSize ) ||
|
|
(dwType != REG_BINARY ) ||
|
|
(dwSize != sizeof( LARGE_INTEGER ) ) )
|
|
{
|
|
RegistryTime->QuadPart = 0 ;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
*pArray = Array ;
|
|
|
|
if ( ReturnFalseAnyway )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
else
|
|
{
|
|
return TRUE ;
|
|
}
|
|
}
|
|
|
|
|
|
PDOMAIN_CACHE_ENTRY
|
|
DCacheEntryFromRegistry(
|
|
PUNICODE_STRING FlatName
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ENTRY Entry = NULL ;
|
|
HKEY Key ;
|
|
int err ;
|
|
DWORD dwType ;
|
|
WCHAR DnsName[ MAX_PATH ];
|
|
DWORD dwSize ;
|
|
UNICODE_STRING Dns ;
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szCache,
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
dwSize = MAX_PATH ;
|
|
DnsName[ 0 ] = L'\0';
|
|
|
|
err = RegQueryValueEx(
|
|
Key,
|
|
FlatName->Buffer,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) DnsName,
|
|
&dwSize );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
if ( dwType == REG_SZ )
|
|
{
|
|
RtlInitUnicodeString( &Dns, DnsName );
|
|
|
|
Entry = DCacheCreateEntry(
|
|
( Dns.Length ? DomainNt5 : DomainNt4 ),
|
|
FlatName,
|
|
( Dns.Length ? &Dns : NULL ),
|
|
NULL );
|
|
|
|
}
|
|
}
|
|
|
|
RegCloseKey( Key );
|
|
|
|
}
|
|
|
|
return Entry ;
|
|
}
|
|
|
|
VOID
|
|
DCacheWriteDomainsToCache(
|
|
PDOMAIN_CACHE_ARRAY Array
|
|
)
|
|
{
|
|
HKEY Key ;
|
|
ULONG i ;
|
|
ULONG Disp ;
|
|
int err ;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
LARGE_INTEGER Now ;
|
|
|
|
|
|
//
|
|
// Delete what's there. Ignore the error, since we are
|
|
// just going to rewrite all the values, anyway.
|
|
//
|
|
|
|
err = RegDeleteKey( HKEY_LOCAL_MACHINE,
|
|
szCache );
|
|
|
|
|
|
err = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szCache,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&Key,
|
|
&Disp );
|
|
|
|
if ( err )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
for ( i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
Entry = Array->List[ i ];
|
|
|
|
if ( ( Entry->Type == DomainNt5 ) )
|
|
{
|
|
if ( ( Entry->FlatName.Buffer == NULL ) ||
|
|
( Entry->DnsName.Buffer == NULL ) )
|
|
{
|
|
DebugLog(( DEB_ERROR, "Corrupt uplevel domain cache entry at %p\n", Entry ));
|
|
continue;
|
|
}
|
|
RegSetValueEx(
|
|
Key,
|
|
Entry->FlatName.Buffer,
|
|
0,
|
|
REG_SZ,
|
|
(PUCHAR) Entry->DnsName.Buffer,
|
|
Entry->DnsName.Length + sizeof(WCHAR) );
|
|
}
|
|
else if ( Entry->Type == DomainNt4 )
|
|
{
|
|
if ( Entry->FlatName.Buffer == NULL )
|
|
{
|
|
DebugLog(( DEB_ERROR, "Corrupt downlevel domain cache entry at %p\n", Entry ));
|
|
}
|
|
|
|
RegSetValueEx(
|
|
Key,
|
|
Entry->FlatName.Buffer,
|
|
0,
|
|
REG_SZ,
|
|
(PUCHAR) TEXT(""),
|
|
sizeof(WCHAR) );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Other types don't get to live in the cache
|
|
//
|
|
|
|
NOTHING ;
|
|
}
|
|
|
|
}
|
|
|
|
RegCloseKey( Key );
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &Now );
|
|
|
|
RegSetValueEx(
|
|
WinlogonKey,
|
|
szCacheUpdate,
|
|
0,
|
|
REG_BINARY,
|
|
(PUCHAR) &Now,
|
|
sizeof( LARGE_INTEGER ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DCacheInitialize(
|
|
VOID
|
|
)
|
|
{
|
|
DOMAIN_ENTRY_TYPE Types ;
|
|
WCHAR StringBuffer[ MAX_PATH ];
|
|
LONG Size ;
|
|
int err ;
|
|
DWORD dwSize ;
|
|
DWORD dwType ;
|
|
|
|
for (Types = 0 ; Types < DomainTypeMax ; Types++ )
|
|
{
|
|
if ( CacheDomainModifiers[ Types ].StringId )
|
|
{
|
|
Size = LoadString( hDllInstance,
|
|
CacheDomainModifiers[ Types ].StringId,
|
|
StringBuffer,
|
|
MAX_PATH );
|
|
|
|
if ( Size )
|
|
{
|
|
RtlCreateUnicodeString( &CacheDomainModifiers[ Types ].String,
|
|
StringBuffer );
|
|
}
|
|
}
|
|
}
|
|
|
|
dwSize = sizeof( CacheShowDnsNames );
|
|
|
|
err = RegQueryValueEx(
|
|
WinlogonKey,
|
|
DCACHE_SHOW_DNS_NAMES,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &CacheShowDnsNames,
|
|
&dwSize );
|
|
|
|
dwSize = sizeof( CacheAppendDomainInfo );
|
|
err = RegQueryValueEx(
|
|
WinlogonKey,
|
|
DCACHE_SHOW_DOMAIN_TAGS,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &CacheAppendDomainInfo,
|
|
&dwSize );
|
|
|
|
//
|
|
// Convert and delete old cache:
|
|
//
|
|
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
DCachepInitializeCache(
|
|
PDOMAIN_CACHE pCache
|
|
)
|
|
{
|
|
NTSTATUS Status ;
|
|
|
|
ZeroMemory( pCache, sizeof(DOMAIN_CACHE) );
|
|
|
|
Status = RtlInitializeCriticalSectionAndSpinCount(
|
|
& pCache->CriticalSection,
|
|
0x80000000 );
|
|
|
|
return NT_SUCCESS( Status );
|
|
}
|
|
|
|
|
|
|
|
PDOMAIN_CACHE
|
|
DCacheCreate(
|
|
VOID
|
|
)
|
|
{
|
|
PDOMAIN_CACHE Cache ;
|
|
|
|
Cache = (PDOMAIN_CACHE) LocalAlloc( LMEM_FIXED, sizeof( DOMAIN_CACHE ) );
|
|
|
|
if ( !Cache )
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
if ( !DCachepInitializeCache( Cache ) )
|
|
{
|
|
LocalFree( Cache );
|
|
|
|
return NULL ;
|
|
|
|
}
|
|
|
|
Cache->State = DomainCacheEmpty ;
|
|
|
|
if ( !g_Console )
|
|
{
|
|
Cache->Flags |= DCACHE_READ_ONLY ;
|
|
}
|
|
|
|
if ( SafeBootMode == SAFEBOOT_MINIMAL )
|
|
{
|
|
Cache->Flags |= DCACHE_MIT_MODE ;
|
|
}
|
|
|
|
return Cache ;
|
|
}
|
|
|
|
BOOL
|
|
DCacheGetMinimalArray(
|
|
PDOMAIN_CACHE_ARRAY Array,
|
|
PWSTR DefaultDomain OPTIONAL,
|
|
PBOOL DomainMember OPTIONAL,
|
|
PBOOL NewDomain OPTIONAL
|
|
)
|
|
{
|
|
BOOL SidPresent = FALSE ;
|
|
UNICODE_STRING String = { 0 } ;
|
|
UNICODE_STRING DnsDomain = { 0 } ;
|
|
PDOMAIN_CACHE_ENTRY Entry = NULL ;
|
|
PDOMAIN_CACHE_ENTRY ComputerEntry = NULL ;
|
|
PDOMAIN_CACHE_ENTRY OldDefault = NULL ;
|
|
NT_PRODUCT_TYPE ProductType = NtProductWinNt;
|
|
WCHAR ComputerName[ CNLEN + 1 ];
|
|
ULONG Size ;
|
|
ULONG Type ;
|
|
WCHAR LastPrimary[ DNLEN + 1 ];
|
|
UNICODE_STRING LastPrimary_U ;
|
|
|
|
//
|
|
// First, find out what we are
|
|
//
|
|
|
|
RtlGetNtProductType( &ProductType );
|
|
|
|
if ( Array == NULL )
|
|
{
|
|
Array = DCacheCreateArray( 5, TRUE );
|
|
}
|
|
|
|
if ( Array == NULL )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
if ( SafeBootMode != SAFEBOOT_MINIMAL )
|
|
{
|
|
if ( GetPrimaryDomainEx( &String, &DnsDomain, NULL, &SidPresent ) )
|
|
{
|
|
//
|
|
// Ok, we are configured to be part of a domain.
|
|
//
|
|
|
|
if ( SidPresent )
|
|
{
|
|
|
|
//
|
|
// Ok, this is an NT domain.
|
|
//
|
|
|
|
Entry = DCacheCreateEntry(
|
|
( DnsDomain.Buffer ? DomainNt5 : DomainNt4 ),
|
|
&String,
|
|
( DnsDomain.Buffer ? &DnsDomain : NULL),
|
|
NULL );
|
|
|
|
|
|
if ( Entry )
|
|
{
|
|
if ( ProductType == NtProductLanManNt )
|
|
{
|
|
//
|
|
// We're a DC. Until we know otherwise, tag this as the default
|
|
//
|
|
|
|
Entry->Flags |= DCE_DEFAULT_ENTRY ;
|
|
}
|
|
|
|
DCacheInsertArray( Array, Entry );
|
|
|
|
DCacheDereferenceEntry( Entry );
|
|
|
|
Entry = NULL ;
|
|
}
|
|
|
|
//
|
|
// Check to see if we've changed domains:
|
|
//
|
|
|
|
if ( NewDomain )
|
|
{
|
|
Size = sizeof( LastPrimary );
|
|
|
|
if ( RegQueryValueEx(
|
|
WinlogonKey,
|
|
szCachePrimary,
|
|
0,
|
|
&Type,
|
|
(PUCHAR) LastPrimary,
|
|
&Size ) == 0 )
|
|
{
|
|
RtlInitUnicodeString( &LastPrimary_U, LastPrimary );
|
|
|
|
*NewDomain = !RtlEqualUnicodeString( &LastPrimary_U,
|
|
&String,
|
|
TRUE );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the value can't be read for any reason, assume that it's
|
|
// missing and we're in a different domain than last time.
|
|
//
|
|
|
|
*NewDomain = TRUE ;
|
|
}
|
|
}
|
|
|
|
|
|
RegSetValueEx(
|
|
WinlogonKey,
|
|
szCachePrimary,
|
|
0,
|
|
REG_SZ,
|
|
(PUCHAR) String.Buffer,
|
|
String.Length + sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Part of an MIT realm, skip for now. It will get added
|
|
// below when all the MIT realms are added.
|
|
//
|
|
|
|
NOTHING ;
|
|
}
|
|
|
|
if ( String.Buffer )
|
|
{
|
|
LocalFree( String.Buffer );
|
|
}
|
|
|
|
if ( DnsDomain.Buffer )
|
|
{
|
|
LocalFree( DnsDomain.Buffer );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ( ( ProductType != NtProductLanManNt ) ||
|
|
( SafeBootMode == SAFEBOOT_MINIMAL ) )
|
|
{
|
|
//
|
|
// Do the machine name:
|
|
//
|
|
|
|
Size = CNLEN + 1;
|
|
|
|
GetComputerName( ComputerName, &Size );
|
|
|
|
RtlInitUnicodeString( &String, ComputerName );
|
|
|
|
ComputerEntry = DCacheCreateEntry(
|
|
DomainMachine,
|
|
&String,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( ComputerEntry )
|
|
{
|
|
DCacheInsertArray( Array, ComputerEntry );
|
|
|
|
DCacheDereferenceEntry( ComputerEntry );
|
|
}
|
|
}
|
|
|
|
DCacheAddMitRealms( Array );
|
|
|
|
if ( DefaultDomain && (*DefaultDomain) )
|
|
{
|
|
RtlInitUnicodeString( &String, DefaultDomain );
|
|
|
|
OldDefault = DCacheFindDefaultEntry( Array );
|
|
|
|
if ( Entry )
|
|
{
|
|
Entry->Flags &= ~(DCE_DEFAULT_ENTRY);
|
|
}
|
|
|
|
Entry = DCacheSearchArray( Array, &String );
|
|
|
|
if ( !Entry )
|
|
{
|
|
Entry = DCacheEntryFromRegistry( &String );
|
|
|
|
if ( Entry )
|
|
{
|
|
DCacheInsertArray( Array, Entry );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DCacheReferenceEntry( Entry );
|
|
}
|
|
|
|
if ( Entry )
|
|
{
|
|
Entry->Flags |= DCE_DEFAULT_ENTRY ;
|
|
|
|
DCacheDereferenceEntry( Entry );
|
|
|
|
if ( OldDefault )
|
|
{
|
|
OldDefault->Flags &= ~(DCE_DEFAULT_ENTRY);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( DomainMember )
|
|
{
|
|
*DomainMember = SidPresent ;
|
|
}
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
DCacheUpdateMinimal(
|
|
PDOMAIN_CACHE Cache,
|
|
PWSTR DefaultDomain OPTIONAL,
|
|
BOOL CompleteAsync
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ARRAY Array = NULL ;
|
|
LARGE_INTEGER RegistryTime = { 0 };
|
|
BOOL DomainMember = FALSE ;
|
|
BOOL NewDomain = FALSE ;
|
|
BOOL RetryDomain = FALSE ;
|
|
BOOL NoCache = FALSE ;
|
|
BOOL StartThread = FALSE ;
|
|
WCHAR ComputerName[ 20 ];
|
|
ULONG Size ;
|
|
|
|
if ( !DCacheGetDomainsFromCache( &Array, &RegistryTime ) ||
|
|
( Array == NULL ) )
|
|
{
|
|
NoCache = TRUE ;
|
|
}
|
|
|
|
//
|
|
// In rare events, we will leave a domain, and the cache
|
|
// will still be in the registry. This is caught later,
|
|
// and deleted, and this is the retry point.
|
|
//
|
|
|
|
ReloadWithoutCache:
|
|
|
|
if ( !Array )
|
|
{
|
|
Array = DCacheCreateArray( 5, TRUE );
|
|
|
|
if ( !Array )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|
|
|
|
if ( !DCacheGetMinimalArray( Array,
|
|
DefaultDomain,
|
|
&DomainMember,
|
|
&NewDomain ) )
|
|
{
|
|
DCacheFreeArray( Array );
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
|
|
//
|
|
// If we are no longer in the same domain, either in a workgroup, or
|
|
// in a different domain, toss the cache. If we just retried this
|
|
// don't keep doing it...
|
|
//
|
|
|
|
if ( ( RetryDomain == FALSE ) &&
|
|
( ( ( NoCache == FALSE ) &&
|
|
( DomainMember == FALSE ) ) ||
|
|
( NewDomain == TRUE ) ) )
|
|
{
|
|
//
|
|
// Cleanup. The cache is still present, but we are no longer part of a domain
|
|
//
|
|
|
|
DCacheFreeArray( Array );
|
|
|
|
RegDeleteKey( HKEY_LOCAL_MACHINE, szCache );
|
|
|
|
RegDeleteValue( WinlogonKey, szCachePrimary );
|
|
|
|
if ( DefaultDomain )
|
|
{
|
|
Size = 20 ;
|
|
|
|
if ( GetComputerName( ComputerName, &Size ) )
|
|
{
|
|
if ( _wcsicmp( DefaultDomain, ComputerName ) )
|
|
{
|
|
DefaultDomain = NULL ;
|
|
|
|
RegSetValueEx(
|
|
WinlogonKey,
|
|
DEFAULT_DOMAIN_NAME_KEY,
|
|
0,
|
|
REG_SZ,
|
|
(PUCHAR) ComputerName,
|
|
(Size + 1) * sizeof( WCHAR ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
NoCache = TRUE ;
|
|
|
|
Array = NULL ;
|
|
|
|
RetryDomain = TRUE ;
|
|
|
|
goto ReloadWithoutCache;
|
|
|
|
}
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
if ( Cache->Array )
|
|
{
|
|
DCacheFreeArray( Cache->Array );
|
|
}
|
|
|
|
Cache->Array = Array ;
|
|
|
|
Cache->RegistryUpdateTime = RegistryTime ;
|
|
|
|
if ( NoCache )
|
|
{
|
|
Cache->Flags |= DCACHE_NO_CACHE ;
|
|
}
|
|
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &Cache->CacheUpdateTime );
|
|
|
|
if ( DomainMember )
|
|
{
|
|
if ( !NoCache )
|
|
{
|
|
if ( Cache->CacheUpdateTime.QuadPart - Cache->RegistryUpdateTime.QuadPart < TWO_WEEKS )
|
|
{
|
|
Cache->State = DomainCacheRegistryCache ;
|
|
}
|
|
else
|
|
{
|
|
Cache->State = DomainCacheDefaultOnly ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Cache->State = DomainCacheDefaultOnly ;
|
|
}
|
|
|
|
Cache->Flags |= DCACHE_MEMBER ;
|
|
}
|
|
else
|
|
{
|
|
Cache->State = DomainCacheReady ;
|
|
}
|
|
|
|
if ( DCacheFindDefaultEntry( Array ) == NULL )
|
|
{
|
|
Cache->Flags |= DCACHE_DEF_UNKNOWN ;
|
|
}
|
|
|
|
|
|
if ( ( Cache->State != DomainCacheReady ) &&
|
|
( CompleteAsync ) )
|
|
{
|
|
StartThread = TRUE ;
|
|
|
|
if ( DefaultDomain )
|
|
{
|
|
Cache->DefaultDomain = DupString( DefaultDomain );
|
|
}
|
|
else
|
|
{
|
|
Cache->DefaultDomain = NULL ;
|
|
}
|
|
}
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
if ( StartThread )
|
|
{
|
|
DCacheUpdateFullAsync( Cache );
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
void
|
|
DCacheUpdateFullAsync(
|
|
PDOMAIN_CACHE Cache
|
|
)
|
|
{
|
|
HANDLE hThread ;
|
|
DWORD tid ;
|
|
|
|
hThread = CreateThread( NULL,
|
|
0,
|
|
DCacheUpdateThread,
|
|
Cache,
|
|
0,
|
|
&tid );
|
|
|
|
if ( hThread )
|
|
{
|
|
CloseHandle( hThread );
|
|
}
|
|
else
|
|
{
|
|
LockDomainCache( Cache );
|
|
|
|
Cache->State = DomainCacheReady ;
|
|
|
|
UnlockDomainCache( Cache );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
DCacheUpdateFull(
|
|
PDOMAIN_CACHE Cache,
|
|
PWSTR Default OPTIONAL
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ARRAY Array = NULL ;
|
|
ULONG NetStatus = 0 ;
|
|
ULONG RetryCount = 3 ;
|
|
BOOL DomainMember = FALSE ;
|
|
NT_PRODUCT_TYPE ProductType = NtProductWinNt;
|
|
LARGE_INTEGER RegistryTime = { 0 };
|
|
|
|
if ( ( Cache->Flags & DCACHE_MEMBER ) != 0 )
|
|
{
|
|
|
|
DomainMember = TRUE ;
|
|
|
|
RtlGetNtProductType( &ProductType );
|
|
|
|
if ( ProductType == NtProductLanManNt )
|
|
{
|
|
RetryCount = 3600 ;
|
|
}
|
|
//
|
|
// now, call netlogon, and see if it has the list.
|
|
//
|
|
|
|
NetStatus = DCacheGetTrustedDomains( &Array );
|
|
|
|
if ( NetStatus != 0 )
|
|
{
|
|
while ( RetryCount-- )
|
|
{
|
|
Sleep( 3000 );
|
|
|
|
NetStatus = DCacheGetTrustedDomains( &Array );
|
|
|
|
if ( NetStatus == 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( RPC_S_UNKNOWN_IF == NetStatus )
|
|
{
|
|
// exit the loop if no interface (netlogon stopped)
|
|
RetryCount = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( NetStatus != 0 )
|
|
{
|
|
//
|
|
// Try to read from the cache
|
|
//
|
|
|
|
DCacheGetDomainsFromCache( &Array, &RegistryTime );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( Array )
|
|
{
|
|
DCacheGetMinimalArray( Array, Default, &DomainMember, NULL );
|
|
}
|
|
|
|
if ( Array )
|
|
{
|
|
LockDomainCache( Cache );
|
|
|
|
if ( Cache->Array )
|
|
{
|
|
DCacheFreeArray( Cache->Array );
|
|
}
|
|
|
|
Cache->Array = Array ;
|
|
|
|
if ( DomainMember )
|
|
{
|
|
Cache->Flags |= DCACHE_MEMBER ;
|
|
}
|
|
else
|
|
{
|
|
Cache->Flags &= ~( DCACHE_MEMBER ) ;
|
|
}
|
|
|
|
if ( NetStatus == 0 )
|
|
{
|
|
Cache->State = DomainCacheReady ;
|
|
|
|
if ( ( Cache->Flags & DCACHE_READ_ONLY ) == 0 )
|
|
{
|
|
DCacheWriteDomainsToCache( Array );
|
|
}
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &Cache->RegistryUpdateTime );
|
|
|
|
Cache->Flags &= ~(DCACHE_NO_CACHE);
|
|
}
|
|
else if ( (Cache->Flags & DCACHE_NO_CACHE) == 0 )
|
|
{
|
|
Cache->State = DomainCacheRegistryCache ;
|
|
|
|
Cache->RegistryUpdateTime = RegistryTime ;
|
|
}
|
|
else
|
|
{
|
|
Cache->State = DomainCacheDefaultOnly ;
|
|
|
|
Cache->RegistryUpdateTime.QuadPart = 0 ;
|
|
}
|
|
|
|
|
|
if ( Cache->DefaultDomain )
|
|
{
|
|
DCacheSetDefaultEntry( Cache,
|
|
Cache->DefaultDomain,
|
|
NULL );
|
|
|
|
Free( Cache->DefaultDomain );
|
|
|
|
Cache->DefaultDomain = NULL ;
|
|
|
|
}
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
}
|
|
|
|
return ( Array != NULL ) ;
|
|
|
|
|
|
}
|
|
|
|
DWORD
|
|
DCacheUpdateThread(
|
|
PDOMAIN_CACHE Cache
|
|
)
|
|
{
|
|
HWND Notify ;
|
|
UINT Message ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
if ( ( Cache->Flags & DCACHE_ASYNC_UPDATE ) != 0 )
|
|
{
|
|
//
|
|
// Another thread is already doing this.
|
|
//
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
Cache->Flags |= DCACHE_ASYNC_UPDATE ;
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
DCacheUpdateFull( Cache, NULL );
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
Notify = Cache->UpdateNotifyWindow ;
|
|
Message = Cache->Message ;
|
|
|
|
Cache->UpdateNotifyWindow = NULL ;
|
|
Cache->Message = 0 ;
|
|
|
|
Cache->Flags &= ~( DCACHE_ASYNC_UPDATE );
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
if ( Notify )
|
|
{
|
|
DebugLog(( DEB_TRACE_CACHE, "Notifying window %x of cache complete\n" ));
|
|
PostMessage( Notify, Message, 0, 0 );
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
DCachePopulateListBoxFromArray(
|
|
PDOMAIN_CACHE_ARRAY Array,
|
|
HWND ComboBox,
|
|
LPWSTR LastKey OPTIONAL
|
|
)
|
|
{
|
|
ULONG i ;
|
|
ULONG_PTR Index ;
|
|
PDOMAIN_CACHE_ENTRY Default = NULL ;
|
|
LRESULT Result ;
|
|
|
|
//
|
|
// Reset the combo box
|
|
//
|
|
|
|
DebugLog((DEB_TRACE_CACHE, "Flushing listbox\n" ));
|
|
SendMessage( ComboBox, CB_RESETCONTENT, 0, 0);
|
|
|
|
for ( i = 0 ; i < Array->Count ; i++ )
|
|
{
|
|
DebugLog(( DEB_TRACE_CACHE, "Adding domain %ws (%d) to listbox\n",
|
|
Array->List[ i ]->DisplayName.Buffer,
|
|
Array->List[ i ]->Type ));
|
|
|
|
if ( Array->List[ i ]->Type == DomainMitRealm )
|
|
{
|
|
if ( (Array->List[ i ]->Flags & DCE_REACHABLE_MIT ) == 0 )
|
|
{
|
|
DebugLog(( DEB_TRACE_CACHE, "MIT Realm %ws is not reachable, skipping\n",
|
|
Array->List[ i ]->FlatName.Buffer ));
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
Index = SendMessage( ComboBox,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM) Array->List[ i ]->DisplayName.Buffer );
|
|
|
|
if ( Index != CB_ERR )
|
|
{
|
|
SendMessage( ComboBox,
|
|
CB_SETITEMDATA,
|
|
(WPARAM) Index,
|
|
(LPARAM) Array->List[ i ] );
|
|
|
|
}
|
|
|
|
if ( ( Array->List[ i ]->Type == DomainMachine ) &&
|
|
( Default == NULL ) )
|
|
{
|
|
Default = Array->List[ i ] ;
|
|
}
|
|
|
|
if ( Array->List[ i ]->Flags & DCE_DEFAULT_ENTRY )
|
|
{
|
|
Default = Array->List[ i ];
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Select the default entry:
|
|
//
|
|
|
|
if ( LastKey && (*LastKey) )
|
|
{
|
|
Result = SendMessage( ComboBox,
|
|
CB_SELECTSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) LastKey );
|
|
|
|
#if DBG
|
|
if ( Result != CB_ERR )
|
|
{
|
|
DebugLog(( DEB_TRACE_CACHE, "Selected first entry starting with %ws\n", LastKey ));
|
|
}
|
|
else
|
|
{
|
|
DebugLog(( DEB_TRACE_CACHE, "No entry found starting with %ws. Trying default\n", LastKey ));
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Result = CB_ERR ;
|
|
}
|
|
|
|
if ( ( Result == CB_ERR ) &&
|
|
( Default != NULL ) )
|
|
{
|
|
SendMessage( ComboBox,
|
|
CB_SELECTSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) Default->DisplayName.Buffer );
|
|
|
|
DebugLog(( DEB_TRACE_CACHE, "Selecting '%ws' as the default entry\n",
|
|
Default->DisplayName.Buffer ));
|
|
}
|
|
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
DCacheSetNotifyWindowIfNotReady(
|
|
PDOMAIN_CACHE Cache,
|
|
HWND Window,
|
|
UINT Message
|
|
)
|
|
{
|
|
BOOL IsReady = FALSE ;
|
|
HANDLE hThread ;
|
|
DWORD tid ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
IsReady = ( Cache->State == DomainCacheReady );
|
|
|
|
if ( !IsReady )
|
|
{
|
|
Cache->UpdateNotifyWindow = Window ;
|
|
Cache->Message = Message ;
|
|
}
|
|
else
|
|
{
|
|
if ( ( Cache->Flags & DCACHE_ASYNC_UPDATE ) == 0 )
|
|
{
|
|
hThread = CreateThread( NULL,
|
|
0,
|
|
DCacheUpdateThread,
|
|
Cache,
|
|
0,
|
|
&tid );
|
|
|
|
}
|
|
}
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return IsReady ;
|
|
|
|
}
|
|
|
|
|
|
PDOMAIN_CACHE_ARRAY
|
|
DCacheCopyCacheArray(
|
|
PDOMAIN_CACHE Cache
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ARRAY Array = NULL ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
if ( Cache->Array )
|
|
{
|
|
Array = DCacheCopyArray( Cache->Array );
|
|
}
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return Array ;
|
|
}
|
|
|
|
BOOL
|
|
DCacheValidateCache(
|
|
PDOMAIN_CACHE Cache
|
|
)
|
|
{
|
|
LARGE_INTEGER Now ;
|
|
LARGE_INTEGER Diff ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME) &Now );
|
|
|
|
Diff.QuadPart = Now.QuadPart - Cache->CacheUpdateTime.QuadPart ;
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return (Diff.QuadPart < TWO_MINUTES );
|
|
|
|
}
|
|
|
|
DOMAIN_CACHE_STATE
|
|
DCacheGetCacheState(
|
|
PDOMAIN_CACHE Cache
|
|
)
|
|
{
|
|
DOMAIN_CACHE_STATE State ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
State = Cache->State ;
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return State ;
|
|
}
|
|
|
|
BOOL
|
|
DCacheSetDefaultEntry(
|
|
PDOMAIN_CACHE Cache,
|
|
PWSTR FlatName OPTIONAL,
|
|
PWSTR DnsName OPTIONAL
|
|
)
|
|
{
|
|
UNICODE_STRING String ;
|
|
PDOMAIN_CACHE_ENTRY Entry ;
|
|
BOOL Result ;
|
|
|
|
if ( ( FlatName == NULL ) &&
|
|
( DnsName == NULL ) )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
Entry = DCacheFindDefaultEntry( Cache->Array );
|
|
|
|
if ( Entry )
|
|
{
|
|
Entry->Flags &= ~(DCE_DEFAULT_ENTRY) ;
|
|
}
|
|
|
|
if ( FlatName )
|
|
{
|
|
RtlInitUnicodeString( &String, FlatName );
|
|
|
|
Entry = DCacheSearchArray( Cache->Array,
|
|
&String );
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString( &String, DnsName );
|
|
|
|
Entry = DCacheSearchArrayByDns( Cache->Array,
|
|
&String );
|
|
|
|
}
|
|
|
|
if ( Entry )
|
|
{
|
|
Entry->Flags |= DCE_DEFAULT_ENTRY ;
|
|
|
|
Result = TRUE ;
|
|
|
|
DebugLog(( DEB_TRACE_CACHE, "Setting '%ws' to be the default\n",
|
|
Entry->DisplayName.Buffer ));
|
|
}
|
|
else
|
|
{
|
|
Result = FALSE ;
|
|
}
|
|
|
|
if ( Result )
|
|
{
|
|
Cache->Flags &= ~(DCACHE_DEF_UNKNOWN) ;
|
|
}
|
|
else
|
|
{
|
|
Cache->Flags |= DCACHE_DEF_UNKNOWN ;
|
|
}
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return Result ;
|
|
}
|
|
|
|
PDOMAIN_CACHE_ENTRY
|
|
DCacheLocateEntry(
|
|
PDOMAIN_CACHE Cache,
|
|
PWSTR Domain
|
|
)
|
|
{
|
|
PDOMAIN_CACHE_ENTRY Entry = NULL ;
|
|
UNICODE_STRING String ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
if ( Domain )
|
|
{
|
|
RtlInitUnicodeString( &String, Domain );
|
|
|
|
Entry = DCacheSearchArray( Cache->Array,
|
|
&String );
|
|
|
|
if ( Entry )
|
|
{
|
|
DCacheReferenceEntry( Entry );
|
|
}
|
|
}
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return Entry ;
|
|
}
|
|
|
|
|
|
ULONG
|
|
DCacheGetFlags(
|
|
PDOMAIN_CACHE Cache
|
|
)
|
|
{
|
|
ULONG Flags ;
|
|
|
|
LockDomainCache( Cache );
|
|
|
|
Flags = Cache->Flags ;
|
|
|
|
UnlockDomainCache( Cache );
|
|
|
|
return Flags ;
|
|
}
|