3242 lines
76 KiB
C
3242 lines
76 KiB
C
/*--
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
monutil.c
|
|
|
|
Abstract:
|
|
|
|
Trusted Domain monitor program support functions.
|
|
|
|
Author:
|
|
|
|
10-May-1993 (madana)
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
Contains NT-specific code.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define GLOBAL_DEF
|
|
|
|
#include <nlmon.h>
|
|
|
|
#define NlMonpInitUnicodeString( _dst_, _src_, _buf_) \
|
|
(_dst_)->Length = (_src_)->Length; \
|
|
(_dst_)->MaximumLength = (_src_)->Length + sizeof(WCHAR); \
|
|
(_dst_)->Buffer = (LPWSTR) (_buf_); \
|
|
RtlCopyMemory( (LPWSTR) (_buf_), (_src_)->Buffer, (_src_)->Length ); \
|
|
((LPWSTR) (_buf_))[ (_src_)->Length / sizeof(WCHAR) ] = '\0';
|
|
|
|
|
|
PLIST_ENTRY
|
|
FindNamedEntry(
|
|
PLIST_ENTRY List,
|
|
PUNICODE_STRING Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the specified named entry pointer if the entry
|
|
doesn't exist it returns NULL.
|
|
|
|
Arguments:
|
|
|
|
DCList - List to browse.
|
|
|
|
Name - name of the entry whose pointer will be returned.
|
|
|
|
Return Value:
|
|
|
|
Domain entry pointer.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PENTRY Entry;
|
|
|
|
for( NextEntry = List->Flink;
|
|
NextEntry != List; NextEntry = NextEntry->Flink ) {
|
|
|
|
Entry = (PENTRY) NextEntry;
|
|
|
|
if( RtlCompareUnicodeString( &Entry->Name, Name, TRUE ) == 0 ) {
|
|
|
|
//
|
|
// entry already there in the list. return the entry
|
|
// pointer.
|
|
//
|
|
|
|
return( NextEntry );
|
|
}
|
|
}
|
|
|
|
//
|
|
// entry not found.
|
|
//
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PDOMAIN_ENTRY
|
|
AddToDomainList(
|
|
PUNICODE_STRING DomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a new domain entry and add to GlobalDomains list.
|
|
|
|
Enter with list locked.
|
|
|
|
Arguments:
|
|
|
|
DomainName - name of the new domain added to the list.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new domain structure.
|
|
|
|
--*/
|
|
{
|
|
PDOMAIN_ENTRY NewEntry;
|
|
|
|
//
|
|
// if this domain is already in the list, just return the entry
|
|
// pointer.
|
|
//
|
|
|
|
NewEntry = (PDOMAIN_ENTRY) FindNamedEntry(
|
|
&GlobalDomains,
|
|
DomainName );
|
|
|
|
if( NewEntry != NULL ) {
|
|
|
|
//
|
|
// Domain entry already in there.
|
|
//
|
|
|
|
return(NewEntry);
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate space for the new entry
|
|
//
|
|
|
|
NewEntry = NetpMemoryAllocate(
|
|
sizeof(DOMAIN_ENTRY) +
|
|
DomainName->Length + sizeof(WCHAR) );
|
|
|
|
if( NewEntry == NULL ) {
|
|
NlMonDbgPrint(("AddToDomainList: can't allocate memory for "
|
|
"new domain entry.\n"));
|
|
return NULL;
|
|
}
|
|
|
|
NlMonpInitUnicodeString(
|
|
&NewEntry->Name, DomainName, (LPWSTR) (NewEntry + 1) );
|
|
|
|
InitializeListHead( &NewEntry->DCList );
|
|
InitializeListHead( &NewEntry->TrustedDomainList );
|
|
NewEntry->DomainState = DomainUnknown;
|
|
NewEntry->ReferenceCount = 0;
|
|
NewEntry->IsMonitoredDomain = FALSE;
|
|
NewEntry->UpdateFlags = 0;
|
|
NewEntry->ThreadHandle = NULL;
|
|
NewEntry->ThreadTerminateFlag = FALSE;
|
|
NewEntry->LastUpdateTime = 0;
|
|
|
|
//
|
|
// add it to domain list.
|
|
//
|
|
|
|
InsertTailList(&GlobalDomains, (PLIST_ENTRY)NewEntry);
|
|
|
|
return NewEntry;
|
|
}
|
|
|
|
PMONITORED_DOMAIN_ENTRY
|
|
AddToMonitoredDomainList(
|
|
PUNICODE_STRING DomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a new monitored domain entry and add it to the
|
|
GlobalDomainsMonitored list.
|
|
|
|
Enter with list locked.
|
|
|
|
Arguments:
|
|
|
|
DomainName - name of the new domain added to the list.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new domain structure.
|
|
|
|
--*/
|
|
{
|
|
PDOMAIN_ENTRY DomainEntry;
|
|
PMONITORED_DOMAIN_ENTRY NewEntry;
|
|
|
|
//
|
|
// if the domain is already monitored, just return entry pointer.
|
|
//
|
|
|
|
NewEntry = (PMONITORED_DOMAIN_ENTRY)
|
|
FindNamedEntry( &GlobalDomainsMonitored, DomainName );
|
|
|
|
if( NewEntry != NULL ) {
|
|
NewEntry->DeleteFlag = FALSE;
|
|
return NewEntry;
|
|
}
|
|
|
|
//
|
|
// allocate space for the new domain that will be monitored.
|
|
//
|
|
|
|
NewEntry = NetpMemoryAllocate(
|
|
sizeof(MONITORED_DOMAIN_ENTRY) +
|
|
DomainName->Length + sizeof(WCHAR) );
|
|
|
|
if( NewEntry == NULL ) {
|
|
NlMonDbgPrint(("AddToMonitoredDomainList: "
|
|
"can't allocate memory for "
|
|
"new domain entry.\n"));
|
|
return NULL;
|
|
}
|
|
|
|
NlMonpInitUnicodeString(
|
|
&NewEntry->Name, DomainName, (LPWSTR) (NewEntry + 1) );
|
|
|
|
DomainEntry = AddToDomainList( DomainName );
|
|
|
|
if( DomainEntry == NULL ) {
|
|
|
|
//
|
|
// can't create new domain entry.
|
|
//
|
|
|
|
NetpMemoryFree( NewEntry );
|
|
return(NULL);
|
|
}
|
|
|
|
NewEntry->DomainEntry = DomainEntry;
|
|
NewEntry->DeleteFlag = FALSE;
|
|
DomainEntry->ReferenceCount++;
|
|
DomainEntry->IsMonitoredDomain = TRUE;
|
|
|
|
|
|
//
|
|
// add it to GlobalDomainsMonitored list.
|
|
//
|
|
|
|
InsertTailList(&GlobalDomainsMonitored, (PLIST_ENTRY)NewEntry);
|
|
|
|
return(NewEntry);
|
|
}
|
|
|
|
PTRUSTED_DOMAIN_ENTRY
|
|
AddToTrustedDomainList(
|
|
PLIST_ENTRY List,
|
|
PUNICODE_STRING DomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a new monitored domain entry and add it to the
|
|
GlobalDomainsTrusted list.
|
|
|
|
Enter with list locked.
|
|
|
|
Arguments:
|
|
|
|
List - List to be modified.
|
|
|
|
DomainName - name of the new domain added to the list.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new domain structure.
|
|
|
|
--*/
|
|
{
|
|
PDOMAIN_ENTRY DomainEntry;
|
|
PTRUSTED_DOMAIN_ENTRY NewEntry;
|
|
|
|
//
|
|
// if the domain is already trusted, just return entry pointer.
|
|
//
|
|
|
|
NewEntry = (PTRUSTED_DOMAIN_ENTRY)
|
|
FindNamedEntry( List, DomainName );
|
|
|
|
if( NewEntry != NULL ) {
|
|
NewEntry->DeleteFlag = FALSE;
|
|
return NewEntry;
|
|
}
|
|
|
|
//
|
|
// allocate space for the new domain that will be monitored.
|
|
//
|
|
|
|
NewEntry = NetpMemoryAllocate(
|
|
sizeof(TRUSTED_DOMAIN_ENTRY) +
|
|
DomainName->Length + sizeof(WCHAR) );
|
|
|
|
if( NewEntry == NULL ) {
|
|
NlMonDbgPrint(("AddToTrustedDomainList: "
|
|
"can't allocate memory for "
|
|
"new domain entry.\n"));
|
|
return NULL;
|
|
}
|
|
|
|
NlMonpInitUnicodeString(
|
|
&NewEntry->Name, DomainName, (LPWSTR) (NewEntry + 1) );
|
|
|
|
DomainEntry = AddToDomainList( DomainName );
|
|
|
|
if( DomainEntry == NULL ) {
|
|
//
|
|
// can't create new domain entry.
|
|
//
|
|
|
|
NetpMemoryFree( NewEntry );
|
|
return(NULL);
|
|
}
|
|
|
|
NewEntry->DomainEntry = DomainEntry;
|
|
NewEntry->DeleteFlag = FALSE;
|
|
DomainEntry->ReferenceCount++;
|
|
|
|
|
|
//
|
|
// add it to list.
|
|
//
|
|
|
|
InsertTailList(List, (PLIST_ENTRY)NewEntry);
|
|
|
|
return(NewEntry);
|
|
}
|
|
|
|
BOOL
|
|
InitDomainListW(
|
|
LPWSTR DomainList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse comma separated domain list.
|
|
|
|
Arguments:
|
|
|
|
DomainList - comma separate domain list.
|
|
|
|
Return Value:
|
|
|
|
TRUE - if successfully parsed.
|
|
FALSE - iff the list is bad.
|
|
|
|
--*/
|
|
{
|
|
WCHAR DomainName[DNLEN + 1];
|
|
PWCHAR d;
|
|
PWCHAR p;
|
|
DWORD Len;
|
|
|
|
|
|
p = DomainList;
|
|
|
|
if( *p == L'\0' ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
while (*p != L'\0') {
|
|
|
|
d = DomainName; // destination to next domain name.
|
|
|
|
while( (*p != L'\0') && (*p == L' ') ) {
|
|
p++; // skip leading blanks.
|
|
}
|
|
|
|
//
|
|
// read next domain name.
|
|
//
|
|
|
|
while( (*p != L'\0') && (*p != L',') ) {
|
|
|
|
if( d < DomainName + DNLEN ) {
|
|
*d++ = (WCHAR) (*p++);
|
|
}
|
|
}
|
|
|
|
if( *p != L'\0' ) {
|
|
p++; // skip comma.
|
|
}
|
|
|
|
//
|
|
// delete tail end blanks.
|
|
//
|
|
|
|
while ( (d > DomainName) && (*(d-1) == L' ') ) {
|
|
d--;
|
|
}
|
|
|
|
*d = L'\0';
|
|
|
|
if( Len = wcslen(DomainName) ) {
|
|
|
|
UNICODE_STRING UnicodeDomainName;
|
|
|
|
RtlInitUnicodeString( &UnicodeDomainName, DomainName );
|
|
|
|
LOCK_LISTS();
|
|
if( AddToMonitoredDomainList( &UnicodeDomainName ) == NULL ) {
|
|
UNLOCK_LISTS();
|
|
return(FALSE);
|
|
}
|
|
UNLOCK_LISTS();
|
|
}
|
|
}
|
|
|
|
if( IsListEmpty( &GlobalDomainsMonitored ) ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
VOID
|
|
ConvertServerAcctNameToServerName(
|
|
PUNICODE_STRING ServerAccountName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert user account type name to server type name. By current convension
|
|
the servers account name has a "$" sign at the end. ie.
|
|
|
|
ServerAccountName = ServerName + "$"
|
|
|
|
Arguments:
|
|
|
|
ServerAccountName - server account name.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// strip off "$" sign from account name.
|
|
//
|
|
|
|
ServerAccountName->Length -= sizeof(WCHAR);
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
QueryLsaInfo(
|
|
PUNICODE_STRING ServerName,
|
|
ACCESS_MASK DesiredAccess,
|
|
POLICY_INFORMATION_CLASS InformationClass,
|
|
PVOID *Info,
|
|
PLSA_HANDLE ReturnHandle //optional
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open LSA database on the remote server, query requested info and
|
|
return lsa handle if asked otherwise close it.
|
|
|
|
Arguments:
|
|
|
|
ServerName - Remote machine name.
|
|
|
|
DesiredAccess - Required access.
|
|
|
|
InformationClass - info class to be returned.
|
|
|
|
Info - pointer to a location where the return info buffer pointer is
|
|
placed. Caller should free this buffer.
|
|
|
|
ReturnHandle - if this is non-NULL pointer, LSA handle is returned
|
|
here. caller should close this handle after use.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE PolicyHandle;
|
|
|
|
*Info = NULL;
|
|
|
|
//
|
|
// Open Local policy.
|
|
//
|
|
|
|
INIT_OBJ_ATTR(ObjectAttributes);
|
|
|
|
Status = LsaOpenPolicy( ServerName,
|
|
&ObjectAttributes,
|
|
DesiredAccess,
|
|
&PolicyHandle );
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
NlMonDbgPrint(("QueryLsaInfo: "
|
|
"Cannot open LSA Policy database on server %wZ, %lx.\n",
|
|
ServerName, Status ));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// read primary domain info.
|
|
//
|
|
|
|
Status = LsaQueryInformationPolicy(
|
|
PolicyHandle,
|
|
InformationClass,
|
|
Info );
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
NlMonDbgPrint(("QueryLsaInfo: "
|
|
"Can't read domain info from %wZ's database, %lx.\n",
|
|
ServerName, Status));
|
|
|
|
LsaClose(PolicyHandle);
|
|
return Status;
|
|
}
|
|
|
|
if( ReturnHandle != NULL ) {
|
|
*ReturnHandle = PolicyHandle;
|
|
}
|
|
else {
|
|
LsaClose(PolicyHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NET_API_STATUS
|
|
IsValidNTDC(
|
|
PUNICODE_STRING ServerName,
|
|
PUNICODE_STRING DomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function determines that the given server is valid NT Domain
|
|
Controller on the given domain.
|
|
|
|
Arguments:
|
|
|
|
ServerName - name of the server which has to be validated.
|
|
|
|
DomainName - name of the domain on which this DC is member.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS code.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS NetStatus;
|
|
|
|
PWKSTA_INFO_100 WkstaInfo100 = NULL;
|
|
PSERVER_INFO_101 ServerInfo101 = NULL;
|
|
|
|
//
|
|
// ServerName should be non-null string.
|
|
//
|
|
|
|
if( (ServerName->Length <= 0) ||
|
|
(ServerName->Buffer == NULL) ||
|
|
(*ServerName->Buffer == L'\0') ) {
|
|
|
|
NetStatus = NERR_BadServiceName;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// check to see that the server is still member of specified domain.
|
|
//
|
|
|
|
NetStatus = NetWkstaGetInfo(
|
|
ServerName->Buffer,
|
|
100,
|
|
(LPBYTE *)&WkstaInfo100
|
|
);
|
|
|
|
if( (GlobalTerminateFlag) || (NetStatus != NERR_Success) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( I_NetNameCompare( NULL,
|
|
DomainName->Buffer,
|
|
WkstaInfo100->wki100_langroup,
|
|
NAMETYPE_DOMAIN,
|
|
0L) != 0 ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// check the server type is appropriate.
|
|
//
|
|
|
|
NetStatus = NetServerGetInfo(
|
|
ServerName->Buffer,
|
|
101,
|
|
(LPBYTE *)&ServerInfo101
|
|
);
|
|
|
|
if( (GlobalTerminateFlag) || (NetStatus != NERR_Success) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!((ServerInfo101->sv101_type &
|
|
(SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL)) &&
|
|
(ServerInfo101->sv101_type & SV_TYPE_NT)) ) {
|
|
|
|
//
|
|
// this server isn't NT Domain Controller.
|
|
//
|
|
|
|
NetStatus = ERROR_INVALID_DOMAIN_ROLE;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
if ( ServerInfo101 != NULL ) {
|
|
NetApiBufferFree( ServerInfo101 );
|
|
}
|
|
|
|
if ( WkstaInfo100 != NULL ) {
|
|
NetApiBufferFree( WkstaInfo100 );
|
|
}
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("IsValidNTDC: ServerName = %wZ, "
|
|
"DomainName = %wZ, and NetStatus = %ld .\n",
|
|
ServerName, DomainName, NetStatus ));
|
|
}
|
|
|
|
return NetStatus;
|
|
}
|
|
|
|
NET_API_STATUS
|
|
ValidateDC(
|
|
PDC_ENTRY DCEntry,
|
|
PUNICODE_STRING DomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function validates the given DCEntry and sets various fields of
|
|
this structures.
|
|
|
|
Arguments:
|
|
|
|
DCEntry - pointer to DC entry structure.
|
|
|
|
DomainName - name of the domain of which this DC is member.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS code.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS NetStatus = NERR_Success;
|
|
PWKSTA_INFO_100 WkstaInfo100 = NULL;
|
|
PSERVER_INFO_101 ServerInfo101 = NULL;
|
|
PNETLOGON_INFO_1 NetlogonInfo1 = NULL;
|
|
LPWSTR InputDataPtr = NULL;
|
|
|
|
//
|
|
// lock this list while we update this entry status.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
|
|
//
|
|
// retry once in RETRY_COUNT calls.
|
|
//
|
|
|
|
if( ( DCEntry->State == DCOffLine ) ||
|
|
( DCEntry->DCStatus != NERR_Success) ) {
|
|
if( DCEntry->RetryCount != 0 ) {
|
|
DCEntry->RetryCount = (DCEntry->RetryCount + 1) % RETRY_COUNT;
|
|
NetStatus = DCEntry->DCStatus;
|
|
goto Cleanup;
|
|
}
|
|
DCEntry->RetryCount = (DCEntry->RetryCount + 1) % RETRY_COUNT;
|
|
}
|
|
|
|
|
|
//
|
|
// check to see that the server is still on specified domain
|
|
//
|
|
|
|
UNLOCK_LISTS();
|
|
NetStatus = NetWkstaGetInfo(
|
|
DCEntry->DCName.Buffer,
|
|
100,
|
|
(LPBYTE * )&WkstaInfo100 );
|
|
LOCK_LISTS();
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
|
|
if( NetStatus == ERROR_BAD_NETPATH ) {
|
|
DCEntry->State = DCOffLine;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( I_NetNameCompare( NULL,
|
|
DomainName->Buffer,
|
|
WkstaInfo100->wki100_langroup,
|
|
NAMETYPE_DOMAIN,
|
|
0L) != 0 ) {
|
|
|
|
NetStatus = ERROR_INVALID_DOMAIN_STATE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// check the server type is appropriate.
|
|
//
|
|
|
|
UNLOCK_LISTS();
|
|
NetStatus = NetServerGetInfo(
|
|
DCEntry->DCName.Buffer,
|
|
101,
|
|
(LPBYTE *)&ServerInfo101 );
|
|
LOCK_LISTS();
|
|
|
|
if( (GlobalTerminateFlag) || (NetStatus != NERR_Success) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( ServerInfo101->sv101_type & SV_TYPE_NT ) {
|
|
|
|
if ( ServerInfo101->sv101_type & SV_TYPE_DOMAIN_CTRL ) {
|
|
DCEntry->Type = NTPDC;
|
|
} else if ( ServerInfo101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL ) {
|
|
DCEntry->Type = NTBDC;
|
|
} else {
|
|
NetStatus = ERROR_INVALID_DOMAIN_ROLE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
if ( ServerInfo101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL ) {
|
|
DCEntry->Type = LMBDC;
|
|
}
|
|
else {
|
|
NetStatus = ERROR_INVALID_DOMAIN_ROLE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if( DCEntry->Type != LMBDC ) {
|
|
|
|
//
|
|
// Query netlogon to determine replication status and connection
|
|
// status to its PDC.
|
|
//
|
|
|
|
UNLOCK_LISTS();
|
|
NetStatus = I_NetLogonControl2(
|
|
DCEntry->DCName.Buffer,
|
|
NETLOGON_CONTROL_QUERY,
|
|
1,
|
|
(LPBYTE)&InputDataPtr,
|
|
(LPBYTE *)&NetlogonInfo1 );
|
|
LOCK_LISTS();
|
|
|
|
if( (GlobalTerminateFlag) || (NetStatus != NERR_Success) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DCEntry->ReplicationStatus = NetlogonInfo1->netlog1_flags;
|
|
DCEntry->PDCLinkStatus = NetlogonInfo1->netlog1_pdc_connection_status;
|
|
}
|
|
|
|
DCEntry->State = DCOnLine;
|
|
Cleanup:
|
|
|
|
if ( NetlogonInfo1 != NULL ) {
|
|
NetApiBufferFree( NetlogonInfo1 );
|
|
}
|
|
|
|
if ( ServerInfo101 != NULL ) {
|
|
NetApiBufferFree( ServerInfo101 );
|
|
}
|
|
|
|
if ( WkstaInfo100 != NULL ) {
|
|
NetApiBufferFree( WkstaInfo100 );
|
|
}
|
|
|
|
if ( NetStatus != NERR_Success ) {
|
|
|
|
//
|
|
// set other status to unknown.
|
|
//
|
|
|
|
DCEntry->ReplicationStatus = UNKNOWN_REPLICATION_STATE;
|
|
DCEntry->PDCLinkStatus = ERROR_BAD_NETPATH;
|
|
}
|
|
|
|
DCEntry->DCStatus = NetStatus;
|
|
UNLOCK_LISTS();
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("ValidateDC: ServerName = %wZ, "
|
|
"DomainName = %wZ, and NetStatus = %ld.\n",
|
|
&DCEntry->DCName, DomainName, NetStatus ));
|
|
}
|
|
|
|
return NetStatus;
|
|
}
|
|
|
|
PDC_ENTRY
|
|
CreateDCEntry (
|
|
PUNICODE_STRING DCName,
|
|
DC_TYPE Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a DC Entry;
|
|
|
|
Arguments:
|
|
|
|
DCName - entry name in unc form.
|
|
|
|
Type - DC type.
|
|
|
|
Return Value:
|
|
|
|
Entry pointer. If it can't allocate memory, it returns NULL pointer.
|
|
|
|
--*/
|
|
{
|
|
|
|
PDC_ENTRY DCEntry;
|
|
|
|
DCEntry = NetpMemoryAllocate(
|
|
sizeof(DC_ENTRY) +
|
|
DCName->Length + sizeof(WCHAR) );
|
|
|
|
if( DCEntry != NULL ) {
|
|
|
|
NlMonpInitUnicodeString(
|
|
&DCEntry->DCName, DCName, (LPWSTR) (DCEntry + 1) );
|
|
|
|
DCEntry->State = DCOffLine;
|
|
DCEntry->Type = Type;
|
|
DCEntry->DCStatus = ERROR_BAD_NETPATH;
|
|
DCEntry->ReplicationStatus = UNKNOWN_REPLICATION_STATE; //unknown state.
|
|
DCEntry->PDCLinkStatus = ERROR_BAD_NETPATH;
|
|
DCEntry->DeleteFlag = FALSE;
|
|
DCEntry->RetryCount = 0;
|
|
InitializeListHead( &DCEntry->TrustedDCs );
|
|
DCEntry->TDCLinkState = FALSE;
|
|
}
|
|
|
|
return( DCEntry );
|
|
}
|
|
|
|
NTSTATUS
|
|
UpdateDCListFromNTServerAccounts(
|
|
SAM_HANDLE SamHandle,
|
|
PLIST_ENTRY DCList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Merge NT server accounts defined in the database to DCList.
|
|
|
|
Arguments:
|
|
|
|
SamHandle : Handle SAM database.
|
|
|
|
DCList : linked list of DCs.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PDOMAIN_DISPLAY_MACHINE MachineInformation = NULL;
|
|
DWORD SamIndex = 0;
|
|
DWORD EntriesRead;
|
|
ULONG TotalBytesAvailable;
|
|
ULONG BytesReturned;
|
|
|
|
DWORD i;
|
|
|
|
PDC_ENTRY DCEntry;
|
|
|
|
//
|
|
// enumerate NT Server accounts
|
|
//
|
|
|
|
do {
|
|
//
|
|
// Get the list of machine accounts from SAM
|
|
//
|
|
|
|
Status = SamQueryDisplayInformation(
|
|
SamHandle,
|
|
DomainDisplayMachine,
|
|
SamIndex,
|
|
MACHINES_PER_PASS,
|
|
0xFFFFFFFF,
|
|
&TotalBytesAvailable,
|
|
&BytesReturned,
|
|
&EntriesRead,
|
|
&MachineInformation );
|
|
|
|
if ( (Status != STATUS_NO_MORE_ENTRIES) &&
|
|
(!NT_SUCCESS(Status)) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromNTServerAccounts: "
|
|
"SamrQueryDisplayInformation returned, %lx.\n",
|
|
Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set up for the next call to Sam.
|
|
//
|
|
|
|
if ( Status == STATUS_MORE_ENTRIES ) {
|
|
SamIndex = MachineInformation[EntriesRead-1].Index + 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Loop though the list of machine accounts finding the Server accounts.
|
|
//
|
|
|
|
for ( i = 0; i < EntriesRead; i++ ) {
|
|
|
|
//
|
|
// Ensure the machine account is a server account.
|
|
//
|
|
|
|
if ( MachineInformation[i].AccountControl &
|
|
USER_SERVER_TRUST_ACCOUNT ) {
|
|
|
|
WCHAR UncComputerName[MAX_PATH + 3];
|
|
UNICODE_STRING UnicodeComputerName;
|
|
|
|
ConvertServerAcctNameToServerName(
|
|
&MachineInformation[i].Machine ); // in place conversion.
|
|
|
|
//
|
|
// form unicode unc computer name.
|
|
//
|
|
|
|
UncComputerName[0] = UncComputerName[1] = L'\\';
|
|
|
|
RtlCopyMemory(
|
|
UncComputerName + 2,
|
|
MachineInformation[i].Machine.Buffer,
|
|
MachineInformation[i].Machine.Length );
|
|
|
|
UncComputerName[
|
|
MachineInformation[i].Machine.Length /
|
|
sizeof(WCHAR) + 2] = L'\0';
|
|
|
|
RtlInitUnicodeString( &UnicodeComputerName, UncComputerName);
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("UpdateDCListFromNTServerAccounts: "
|
|
"NT Server %wZ is found on database.\n",
|
|
&UnicodeComputerName ));
|
|
}
|
|
|
|
DCEntry = (PDC_ENTRY) FindNamedEntry(
|
|
DCList,
|
|
&UnicodeComputerName );
|
|
|
|
if( DCEntry != NULL ) {
|
|
|
|
DCEntry->DeleteFlag = FALSE;
|
|
}
|
|
else {
|
|
|
|
DCEntry = CreateDCEntry( &UnicodeComputerName, NTBDC );
|
|
|
|
//
|
|
// silently ignore NULL entry.
|
|
//
|
|
|
|
if( DCEntry != NULL ) {
|
|
|
|
//
|
|
// add to list.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
InsertTailList(DCList, (PLIST_ENTRY)DCEntry);
|
|
UNLOCK_LISTS();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// free up the memory used up memory.
|
|
//
|
|
|
|
if( MachineInformation != NULL ) {
|
|
(VOID) SamFreeMemory( MachineInformation );
|
|
MachineInformation = NULL;
|
|
}
|
|
|
|
} while ( Status == STATUS_MORE_ENTRIES );
|
|
|
|
Cleanup:
|
|
|
|
if( MachineInformation != NULL ) {
|
|
(VOID) SamFreeMemory( MachineInformation );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
UpdateDCListFromLMServerAccounts(
|
|
SAM_HANDLE SamHandle,
|
|
PLIST_ENTRY DCList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read LM server accounts from SAM "Servers" global group and update
|
|
the DC list using this accounts.
|
|
|
|
Arguments:
|
|
|
|
SamHandle : Handle SAM database.
|
|
|
|
DCList : linked list of DCs.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
UNICODE_STRING NameString;
|
|
PSID_NAME_USE NameUse = NULL;
|
|
PULONG RelativeId = NULL;
|
|
SAM_HANDLE GroupHandle = NULL;
|
|
|
|
PULONG MemberAttributes = NULL;
|
|
PULONG MemberIds = NULL;
|
|
ULONG MemberCount;
|
|
PUNICODE_STRING MemberNames = NULL;
|
|
PSID_NAME_USE MemberNameUse = NULL;
|
|
|
|
PDC_ENTRY DCEntry;
|
|
DWORD i;
|
|
|
|
//
|
|
// Get RID of SERVERS group.
|
|
//
|
|
|
|
RtlInitUnicodeString( &NameString, SERVERS_GROUP );
|
|
Status = SamLookupNamesInDomain(
|
|
SamHandle,
|
|
1,
|
|
&NameString,
|
|
&RelativeId,
|
|
&NameUse );
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
NlMonDbgPrint(( "UpdateDCListFromLMServerAccounts: SamLookupNamesInDomain "
|
|
" failed to transulate %wZ %lx.\n",
|
|
&NameString,
|
|
Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( *NameUse != SidTypeGroup ) {
|
|
NlMonDbgPrint(( "UpdateDCListFromLMServerAccounts: %wZ is not "
|
|
"SidTypeGroup, %ld.\n",
|
|
&NameString,
|
|
*NameUse ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// open group object.
|
|
//
|
|
|
|
Status = SamOpenGroup(
|
|
SamHandle,
|
|
GROUP_LIST_MEMBERS,
|
|
*RelativeId,
|
|
&GroupHandle);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
NlMonDbgPrint(( "UpdateDCListFromLMServerAccounts: SamOpenGroup of %wZ "
|
|
"failed, %lx.\n",
|
|
&NameString,
|
|
Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// get group members.
|
|
//
|
|
|
|
Status = SamGetMembersInGroup(
|
|
GroupHandle,
|
|
&MemberIds,
|
|
&MemberAttributes,
|
|
&MemberCount );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromLMServerAccounts: SamGetMembersInGroup "
|
|
"returned %lx.\n", Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( MemberCount == 0) {
|
|
//
|
|
// nothing more to do.
|
|
//
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// trasulate members IDs.
|
|
//
|
|
|
|
Status = SamLookupIdsInDomain(
|
|
SamHandle,
|
|
MemberCount,
|
|
MemberIds,
|
|
&MemberNames,
|
|
&MemberNameUse );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint((
|
|
"UpdateDCListFromLMServerAccounts: SamLookupIdsInDomain "
|
|
"returned %lx.\n", Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// add user members to list.
|
|
//
|
|
|
|
for (i = 0 ; i < MemberCount; i++) {
|
|
|
|
WCHAR UncComputerName[MAX_PATH + 3];
|
|
UNICODE_STRING UnicodeComputerName;
|
|
|
|
if ( MemberNameUse[i] != SidTypeUser ) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// form unicode unc computer name.
|
|
//
|
|
|
|
UncComputerName[0] = UncComputerName[1] = L'\\';
|
|
|
|
RtlCopyMemory(
|
|
UncComputerName + 2,
|
|
MemberNames[i].Buffer,
|
|
MemberNames[i].Length );
|
|
|
|
UncComputerName[MemberNames[i].Length / sizeof(WCHAR) + 2] = L'\0';
|
|
RtlInitUnicodeString( &UnicodeComputerName, UncComputerName);
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("UpdateDCListFromLMServerAccounts: "
|
|
"LM Server %wZ is found on database.\n",
|
|
&UnicodeComputerName ));
|
|
}
|
|
|
|
DCEntry = (PDC_ENTRY) FindNamedEntry(
|
|
DCList,
|
|
&UnicodeComputerName );
|
|
|
|
if( DCEntry != NULL ) {
|
|
|
|
DCEntry->DeleteFlag = FALSE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// create new entry and add to list
|
|
//
|
|
|
|
DCEntry = CreateDCEntry( &UnicodeComputerName, LMBDC );
|
|
|
|
//
|
|
// silently ignore NULL entries.
|
|
//
|
|
|
|
if( DCEntry != NULL ) {
|
|
|
|
//
|
|
// add to list.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
InsertTailList(DCList, (PLIST_ENTRY)DCEntry);
|
|
UNLOCK_LISTS();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Free up local resources.
|
|
//
|
|
|
|
if( NameUse != NULL ) {
|
|
(VOID) SamFreeMemory( NameUse );
|
|
}
|
|
|
|
if( RelativeId != NULL ) {
|
|
(VOID) SamFreeMemory( RelativeId );
|
|
}
|
|
if( MemberAttributes != NULL ) {
|
|
(VOID) SamFreeMemory( MemberAttributes );
|
|
}
|
|
|
|
if( MemberIds != NULL ) {
|
|
(VOID) SamFreeMemory( MemberIds );
|
|
}
|
|
if( MemberNames != NULL ) {
|
|
(VOID) SamFreeMemory( MemberNames );
|
|
}
|
|
|
|
if( MemberNameUse != NULL ) {
|
|
(VOID) SamFreeMemory( MemberNameUse );
|
|
}
|
|
|
|
if( GroupHandle != NULL ) {
|
|
SamCloseHandle( GroupHandle );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UpdateDCListFromDatabase(
|
|
PUNICODE_STRING DomainName,
|
|
PLIST_ENTRY DCList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the List of DCs on a given domain using database entries.
|
|
|
|
Arguments:
|
|
|
|
DomainName : name of the domain whose DCList to be updated.
|
|
|
|
DCList : linked list of DCs. DCList must be non-empty.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PUNICODE_STRING ServerName;
|
|
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
|
|
SAM_HANDLE SamConnectHandle = NULL;
|
|
SAM_HANDLE SamHandle = NULL;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
PDC_ENTRY DCEntry;
|
|
|
|
//
|
|
// pick a dc from current list.
|
|
//
|
|
|
|
ServerName = NULL;
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
break;
|
|
}
|
|
|
|
if( IsValidNTDC( &DCEntry->DCName, DomainName ) == NERR_Success ) {
|
|
ServerName = &DCEntry->DCName;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( ServerName == NULL ) {
|
|
NlMonDbgPrint(( "UpdateDCListFromDatabase: "
|
|
"No DC is valid in %wZ domain list.\n", DomainName));
|
|
return;
|
|
}
|
|
|
|
IF_DEBUG( UPDATE ) {
|
|
NlMonDbgPrint(( "UpdateDCListFromDatabase: "
|
|
"picked %wZ to get DCList from its database.\n",
|
|
ServerName));
|
|
}
|
|
|
|
//
|
|
// Get Domain SID info from policy database.
|
|
//
|
|
|
|
Status = QueryLsaInfo(
|
|
ServerName,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
PolicyAccountDomainInformation,
|
|
(PVOID *)&AccountDomainInfo,
|
|
NULL ) ;
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromDatabase: QueryLsaInfo returned %lx.\n",
|
|
Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Connect to SAM.
|
|
//
|
|
|
|
Status = SamConnect(
|
|
ServerName,
|
|
&SamConnectHandle,
|
|
SAM_SERVER_LOOKUP_DOMAIN,
|
|
NULL); // object attributes.
|
|
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromDatabase: SamConnect returned %lx.\n",
|
|
Status ));
|
|
SamConnectHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Open Account SAM domain.
|
|
//
|
|
|
|
Status = SamOpenDomain(
|
|
SamConnectHandle,
|
|
DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
|
|
AccountDomainInfo->DomainSid,
|
|
&SamHandle );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromDatabase: SamOpenDomain returned "
|
|
"%lx.\n", Status ));
|
|
SamHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// mark all entries in the current list to be deleted.
|
|
//
|
|
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
DCEntry->DeleteFlag = TRUE;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// enumerate NT Server accounts
|
|
//
|
|
|
|
Status = UpdateDCListFromNTServerAccounts( SamHandle, DCList );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromDatabase: "
|
|
"UpdateDCListFromNTServerAccounts returned "
|
|
"%lx.\n", Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Now enumerate down level DCs.
|
|
//
|
|
|
|
Status = UpdateDCListFromLMServerAccounts( SamHandle, DCList );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
NlMonDbgPrint(("UpdateDCListFromDatabase: "
|
|
"UpdateDCListFromLMServerAccounts returned "
|
|
"%lx.\n", Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup :
|
|
|
|
//
|
|
// if we have successfully updated the list then
|
|
// delete entries that are marked deleted otherwise
|
|
// mark them undelete.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
if( DCEntry->DeleteFlag ) {
|
|
|
|
if( Status == STATUS_SUCCESS ) {
|
|
DCEntry->DeleteFlag = FALSE;
|
|
}
|
|
else {
|
|
RemoveEntryList( (PLIST_ENTRY)DCEntry );
|
|
NetpMemoryFree( DCEntry );
|
|
}
|
|
}
|
|
}
|
|
UNLOCK_LISTS();
|
|
|
|
if( AccountDomainInfo != NULL ) {
|
|
(VOID) LsaFreeMemory( AccountDomainInfo );
|
|
}
|
|
|
|
if( SamHandle != NULL ) {
|
|
(VOID) SamCloseHandle ( SamHandle );
|
|
}
|
|
|
|
if( SamConnectHandle != NULL ) {
|
|
(VOID) SamCloseHandle ( SamConnectHandle );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
UpdateDCListByServerEnum(
|
|
PUNICODE_STRING DomainName,
|
|
PLIST_ENTRY DCList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the List of DCs on a given domain by calling NetServerEnum.
|
|
If NetServerEnum failes, it calls NetGetDCName to atleast determine
|
|
PDC of the domain.
|
|
|
|
Arguments:
|
|
|
|
DomainName : name of the domain whose DCList to be updated.
|
|
|
|
DCList : linked list of DCs.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS NetStatus;
|
|
|
|
PSERVER_INFO_101 ServerInfo101 = NULL;
|
|
DWORD EntriesRead;
|
|
DWORD TotalEntries;
|
|
|
|
PDC_ENTRY DCEntry;
|
|
DWORD i;
|
|
|
|
NetStatus = NetServerEnum( NULL,
|
|
101,
|
|
(LPBYTE *) &ServerInfo101,
|
|
(ULONG)(-1), // Prefmaxlen
|
|
&EntriesRead,
|
|
&TotalEntries,
|
|
SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL,
|
|
DomainName->Buffer,
|
|
NULL ); // Resume Handle
|
|
|
|
if( NetStatus != NERR_Success ) {
|
|
|
|
if( NetStatus != ERROR_NO_BROWSER_SERVERS_FOUND ) {
|
|
NlMonDbgPrint(("UpdateDCListByServerEnum: "
|
|
"NetServerEnum called with domain name %wZ Failed, "
|
|
"%ld.\n", DomainName, NetStatus));
|
|
}
|
|
|
|
ServerInfo101 = NULL;
|
|
EntriesRead = 0;
|
|
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// update DC List using ServerEnumList.
|
|
//
|
|
|
|
for( i = 0; i < EntriesRead; i++ ) {
|
|
|
|
WCHAR UncComputerName[MAX_PATH + 3];
|
|
UNICODE_STRING UnicodeComputerName;
|
|
DC_TYPE ServerType;
|
|
|
|
UncComputerName[0] = UncComputerName[1] = L'\\';
|
|
wcscpy( UncComputerName + 2, ServerInfo101[i].sv101_name );
|
|
RtlInitUnicodeString(&UnicodeComputerName, UncComputerName);
|
|
|
|
if ( (ServerInfo101[i].sv101_type & SV_TYPE_NT) ) {
|
|
if ( ServerInfo101[i].sv101_type & SV_TYPE_DOMAIN_CTRL ) {
|
|
ServerType = NTPDC;
|
|
}
|
|
else {
|
|
ServerType = NTBDC;
|
|
}
|
|
}
|
|
else {
|
|
if ( ServerInfo101[i].sv101_type & SV_TYPE_DOMAIN_BAKCTRL ) {
|
|
ServerType = LMBDC;
|
|
}
|
|
else {
|
|
NlMonDbgPrint(("UpdateDCListByServerEnum: "
|
|
"NetServerEnum called with domain name %wZ "
|
|
"returned LM PDC %wZ.\n",
|
|
DomainName, &UnicodeComputerName ));
|
|
ServerType = LMBDC;
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("UpdateDCListByServerEnum: "
|
|
"Server %wZ found in NetServerEnumList.\n",
|
|
&UnicodeComputerName ));
|
|
}
|
|
|
|
DCEntry = (PDC_ENTRY) FindNamedEntry( DCList, &UnicodeComputerName );
|
|
|
|
if( DCEntry != NULL ) {
|
|
DCEntry->Type = ServerType;
|
|
DCEntry->State = DCOnLine;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// create new entry and add to list
|
|
//
|
|
|
|
DCEntry = CreateDCEntry( &UnicodeComputerName, ServerType );
|
|
|
|
//
|
|
// silently ignore NULL entries.
|
|
//
|
|
|
|
if( DCEntry != NULL ) {
|
|
|
|
//
|
|
// add to list.
|
|
//
|
|
|
|
DCEntry->State = DCOnLine;
|
|
LOCK_LISTS();
|
|
InsertTailList(DCList, (PLIST_ENTRY)DCEntry);
|
|
UNLOCK_LISTS();
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( ServerInfo101 != NULL ) {
|
|
NetApiBufferFree( ServerInfo101 );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
UpdateTrustList(
|
|
PDOMAIN_ENTRY Domain
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates/updates the trusted domains list.
|
|
|
|
Arguments:
|
|
|
|
Domain : pointer domain structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DWORD i;
|
|
PUNICODE_STRING ServerName = NULL;
|
|
PLIST_ENTRY ListHead;
|
|
PLIST_ENTRY NextEntry;
|
|
PDC_ENTRY DCEntry;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE PolicyHandle = NULL;
|
|
LSA_ENUMERATION_HANDLE EnumContext;
|
|
PLSA_TRUST_INFORMATION TrustedDomainList = NULL;
|
|
DWORD Entries;
|
|
|
|
PTRUSTED_DOMAIN_ENTRY TDEntry;
|
|
|
|
IF_DEBUG( TRUST ) {
|
|
NlMonDbgPrint(("UpdateTrustList: called for domain %wZ.\n",
|
|
&Domain->Name ));
|
|
}
|
|
|
|
//
|
|
// pick up a DC to query the trusted domain list.
|
|
//
|
|
|
|
ListHead = &Domain->DCList;
|
|
|
|
//
|
|
// first try possibly good DCs.
|
|
//
|
|
|
|
for( NextEntry = ListHead->Flink;
|
|
NextEntry != ListHead; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
if( (DCEntry->State == DCOnLine) &&
|
|
( DCEntry->DCStatus == NERR_Success ) ) {
|
|
|
|
if( IsValidNTDC( &DCEntry->DCName, &Domain->Name ) == NERR_Success ) {
|
|
|
|
ServerName = &DCEntry->DCName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( ServerName == NULL ) {
|
|
|
|
//
|
|
// now try all.
|
|
//
|
|
|
|
for( NextEntry = ListHead->Flink;
|
|
NextEntry != ListHead; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
if( IsValidNTDC( &DCEntry->DCName, &Domain->Name ) == NERR_Success ) {
|
|
|
|
ServerName = &DCEntry->DCName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if( ServerName == NULL ) {
|
|
|
|
IF_DEBUG( TRUST ) {
|
|
NlMonDbgPrint(( "UpdateTrustList: "
|
|
"No DC is valid in %wZ domain list.\n",
|
|
&Domain->Name));
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
IF_DEBUG( TRUST ) {
|
|
NlMonDbgPrint(("UpdateTrustList: for domain %wZ picked %wZ to query "
|
|
"trusted domains.\n",
|
|
&Domain->Name, ServerName ));
|
|
}
|
|
|
|
//
|
|
// Open policy database.
|
|
//
|
|
|
|
INIT_OBJ_ATTR(ObjectAttributes);
|
|
|
|
Status = LsaOpenPolicy( ServerName,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&PolicyHandle );
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
NlMonDbgPrint(("UpdateTrustList: "
|
|
"Cannot open LSA Policy on server %wZ, %lx.\n",
|
|
ServerName, Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// enum trusted domains.
|
|
//
|
|
|
|
EnumContext = 0;
|
|
|
|
Status = LsaEnumerateTrustedDomains(
|
|
PolicyHandle,
|
|
&EnumContext,
|
|
&TrustedDomainList,
|
|
(ULONG)-1,
|
|
&Entries );
|
|
|
|
if( !NT_SUCCESS(Status) &&
|
|
(Status != STATUS_NO_MORE_ENTRIES) ) {
|
|
|
|
NlMonDbgPrint(("UpdateTrustList: "
|
|
"Cannot Enumerate trust list on server %wZ, %lx.\n",
|
|
ServerName, Status ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// update trust list.
|
|
//
|
|
|
|
ListHead = &Domain->TrustedDomainList;
|
|
|
|
for ( i = 0; i < Entries; i++) {
|
|
|
|
TDEntry = (PTRUSTED_DOMAIN_ENTRY)
|
|
FindNamedEntry(
|
|
ListHead,
|
|
&TrustedDomainList[i].Name );
|
|
|
|
if( TDEntry == NULL ) {
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("UpdateTrustList: "
|
|
"%wZ is added to %wZ domain trust list.\n",
|
|
&TrustedDomainList[i].Name,
|
|
&Domain->Name ));
|
|
}
|
|
|
|
//
|
|
// add this entry to list.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
if( AddToTrustedDomainList(
|
|
ListHead,
|
|
&TrustedDomainList[i].Name ) == NULL ) {
|
|
|
|
UNLOCK_LISTS();
|
|
NlMonDbgPrint(("UpdateTrustList: can't allocate memory for "
|
|
"new trusted domain entry.\n" ));
|
|
goto Cleanup;
|
|
}
|
|
UNLOCK_LISTS();
|
|
}
|
|
}
|
|
|
|
Cleanup :
|
|
|
|
if( TrustedDomainList != NULL ) {
|
|
LsaFreeMemory( TrustedDomainList );
|
|
}
|
|
|
|
if( PolicyHandle != NULL ) {
|
|
LsaClose( PolicyHandle );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
UpdateTrustConnectionList(
|
|
PDOMAIN_ENTRY Domain
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates/updates trust connection entries of all DCs.
|
|
|
|
Arguments:
|
|
|
|
Domain : pointer domain structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY DCList;
|
|
PLIST_ENTRY NextDCEntry;
|
|
PDC_ENTRY DCEntry;
|
|
|
|
PLIST_ENTRY TrustConnectList;
|
|
PTD_LINK TrustConnectEntry;
|
|
|
|
PLIST_ENTRY TrustList;
|
|
PLIST_ENTRY NextTrustEntry;
|
|
PTRUSTED_DOMAIN_ENTRY TrustEntry;
|
|
|
|
//
|
|
// for each DC on this domain.
|
|
//
|
|
|
|
DCList = &Domain->DCList;
|
|
TrustList = &Domain->TrustedDomainList;
|
|
|
|
for( NextDCEntry = DCList->Flink;
|
|
NextDCEntry != DCList; NextDCEntry = NextDCEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextDCEntry;
|
|
|
|
//
|
|
// do this update only for running DC
|
|
// and it should be NT DC.
|
|
//
|
|
|
|
if( (DCEntry->State != DCOnLine) ||
|
|
(DCEntry->Type == LMBDC) ){
|
|
continue;
|
|
}
|
|
|
|
|
|
TrustConnectList = &DCEntry->TrustedDCs;
|
|
|
|
//
|
|
// for each trusted domain, get connection status.
|
|
//
|
|
|
|
for( NextTrustEntry = TrustList->Flink;
|
|
NextTrustEntry != TrustList;
|
|
NextTrustEntry = NextTrustEntry->Flink ) {
|
|
|
|
TrustEntry = (PTRUSTED_DOMAIN_ENTRY) NextTrustEntry;
|
|
|
|
//
|
|
// search in the current list.
|
|
//
|
|
|
|
TrustConnectEntry = (PTD_LINK) FindNamedEntry(
|
|
TrustConnectList,
|
|
&TrustEntry->Name );
|
|
|
|
if( TrustConnectEntry == NULL ) {
|
|
|
|
PTD_LINK NewTrustConnectEntry;
|
|
|
|
//
|
|
// create new entry.
|
|
//
|
|
|
|
NewTrustConnectEntry =
|
|
NetpMemoryAllocate(
|
|
sizeof(TD_LINK) +
|
|
TrustEntry->Name.Length + sizeof(WCHAR) +
|
|
(MAX_PATH + 3) * sizeof(WCHAR)
|
|
// max computer name space + '\\' + '\0'
|
|
);
|
|
|
|
if( NewTrustConnectEntry == NULL ) {
|
|
NlMonDbgPrint(("UpdateTrustConnectionList: can't allocate "
|
|
"memory for new connect entry.\n"));
|
|
return;
|
|
}
|
|
|
|
InitializeListHead(&NewTrustConnectEntry->NextEntry);
|
|
|
|
NlMonpInitUnicodeString(
|
|
&NewTrustConnectEntry->TDName,
|
|
&TrustEntry->Name,
|
|
(LPWSTR)(NewTrustConnectEntry + 1) );
|
|
|
|
NewTrustConnectEntry->DCName.Length = 0;
|
|
NewTrustConnectEntry->DCName.MaximumLength =
|
|
(MAX_PATH + 3) * sizeof(WCHAR);
|
|
NewTrustConnectEntry->DCName.Buffer = (WCHAR *)
|
|
((PCHAR)(NewTrustConnectEntry->TDName.Buffer) +
|
|
NewTrustConnectEntry->TDName.MaximumLength);
|
|
|
|
NewTrustConnectEntry->SecureChannelStatus = ERROR_BAD_NETPATH;
|
|
NewTrustConnectEntry->DeleteFlag = FALSE;
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("UpdateTrustConnectionList: "
|
|
"Trust Connection entry for DC %wZ of "
|
|
"domain %wZ added.\n",
|
|
&DCEntry->DCName,
|
|
&TrustEntry->Name ));
|
|
|
|
}
|
|
|
|
//
|
|
// add to trust connect list.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
InsertTailList(
|
|
TrustConnectList,
|
|
(PLIST_ENTRY)NewTrustConnectEntry);
|
|
UNLOCK_LISTS();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ValidateTrustConnectionList(
|
|
PDC_ENTRY DCEntry,
|
|
BOOL ValidateTrustedDCs
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function determines trust DC for each trusted domain to which
|
|
the given DC having connection.
|
|
|
|
Arguments:
|
|
|
|
DCEntry : pointer DC entry structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY TrustConnectList;
|
|
PLIST_ENTRY NextTrustConnectEntry;
|
|
PTD_LINK TrustConnectEntry;
|
|
BOOL TDCLinkState = TRUE;
|
|
|
|
//
|
|
// do this update only for running DC
|
|
// and it should be NT DC.
|
|
//
|
|
|
|
if( (DCEntry->State != DCOnLine) ||
|
|
(DCEntry->Type == LMBDC) ) {
|
|
return;
|
|
}
|
|
|
|
IF_DEBUG( TRUST ) {
|
|
NlMonDbgPrint(("ValidateTrustConnectionList: "
|
|
"Trust Connections for the %wZ DC are validated.\n",
|
|
&DCEntry->DCName ));
|
|
}
|
|
|
|
TrustConnectList = &DCEntry->TrustedDCs;
|
|
|
|
for( NextTrustConnectEntry = TrustConnectList->Flink;
|
|
NextTrustConnectEntry != TrustConnectList;
|
|
NextTrustConnectEntry = NextTrustConnectEntry->Flink ) {
|
|
|
|
NET_API_STATUS NetStatus;
|
|
PNETLOGON_INFO_2 NetlogonInfo2 = NULL;
|
|
|
|
TrustConnectEntry = (PTD_LINK) NextTrustConnectEntry;
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// find trusted DC for this domain and its secure channel
|
|
// status.
|
|
//
|
|
|
|
NetStatus = I_NetLogonControl2(
|
|
DCEntry->DCName.Buffer,
|
|
NETLOGON_CONTROL_TC_QUERY,
|
|
2,
|
|
(LPBYTE)&TrustConnectEntry->TDName.Buffer,
|
|
(LPBYTE *)&NetlogonInfo2 );
|
|
|
|
|
|
if( NetStatus != NERR_Success ) {
|
|
|
|
IF_DEBUG( TRUST ) {
|
|
NlMonDbgPrint(("ValidateTrustConnectionList: "
|
|
"I_NetLogonControl2 (%wZ) call to query trust "
|
|
"channel status of %wZ domain failed, (%ld).\n",
|
|
&DCEntry->DCName,
|
|
&TrustConnectEntry->TDName,
|
|
NetStatus ));
|
|
}
|
|
|
|
//
|
|
// Cleanup the previous DC Name.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
TrustConnectEntry->DCName.Length = 0;
|
|
*TrustConnectEntry->DCName.Buffer = L'\0';
|
|
|
|
TrustConnectEntry->SecureChannelStatus = NetStatus;
|
|
UNLOCK_LISTS();
|
|
|
|
TDCLinkState = FALSE;
|
|
continue;
|
|
}
|
|
|
|
IF_DEBUG( VERBOSE ) {
|
|
NlMonDbgPrint(("ValidateTrustConnectionList: "
|
|
"I_NetLogonControl2 (%wZ) call to query trust "
|
|
"channel status of %wZ domain returned : "
|
|
"TDCName = %ws, TCStatus = %ld.\n",
|
|
&DCEntry->DCName,
|
|
&TrustConnectEntry->TDName,
|
|
NetlogonInfo2->netlog2_trusted_dc_name,
|
|
NetlogonInfo2->netlog2_tc_connection_status ));
|
|
}
|
|
|
|
//
|
|
// copy this DC name.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
TrustConnectEntry->DCName.Length =
|
|
wcslen( NetlogonInfo2->netlog2_trusted_dc_name ) * sizeof(WCHAR);
|
|
|
|
RtlCopyMemory(
|
|
TrustConnectEntry->DCName.Buffer,
|
|
NetlogonInfo2->netlog2_trusted_dc_name,
|
|
TrustConnectEntry->DCName.Length + sizeof(WCHAR) );
|
|
// copy terminator also
|
|
|
|
TrustConnectEntry->SecureChannelStatus =
|
|
NetlogonInfo2->netlog2_tc_connection_status;
|
|
|
|
if( TrustConnectEntry->SecureChannelStatus != NERR_Success ) {
|
|
TDCLinkState = FALSE;
|
|
}
|
|
|
|
//
|
|
// update DC status info.
|
|
//
|
|
|
|
DCEntry->ReplicationStatus = NetlogonInfo2->netlog2_flags;
|
|
DCEntry->PDCLinkStatus = NetlogonInfo2->netlog2_pdc_connection_status;
|
|
UNLOCK_LISTS();
|
|
|
|
//
|
|
// free up API memory.
|
|
//
|
|
|
|
NetApiBufferFree( NetlogonInfo2 );
|
|
NetlogonInfo2 = NULL;
|
|
|
|
//
|
|
// validate the this DC. Only non-null server and successful
|
|
// connection.
|
|
//
|
|
|
|
if( (TrustConnectEntry->SecureChannelStatus == NERR_Success) &&
|
|
(*TrustConnectEntry->DCName.Buffer != L'\0') ) {
|
|
|
|
if( ValidateTrustedDCs ) {
|
|
|
|
|
|
NetStatus = IsValidNTDC(
|
|
&TrustConnectEntry->DCName,
|
|
&TrustConnectEntry->TDName );
|
|
|
|
if( NetStatus != NERR_Success ) {
|
|
|
|
IF_DEBUG( TRUST ) {
|
|
|
|
NlMonDbgPrint(("ValidateTrustConnectionList: "
|
|
"%wZ's trust DC %wZ is invalid for "
|
|
"domain %wZ.\n",
|
|
&DCEntry->DCName,
|
|
&TrustConnectEntry->DCName,
|
|
&TrustConnectEntry->TDName ));
|
|
}
|
|
|
|
//
|
|
// hack, hack, hack ...
|
|
//
|
|
// For foreign trusted domains, the above check will
|
|
// return ERROR_LOGON_FAILURE. Just ignore this
|
|
// error for now. When the domain wide credential is
|
|
// implemeted this problem will be cured.
|
|
//
|
|
|
|
|
|
if( NetStatus != ERROR_LOGON_FAILURE ) {
|
|
TrustConnectEntry->SecureChannelStatus = NetStatus;
|
|
TDCLinkState = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// finally set the state of the trusted dc link for this DC.
|
|
//
|
|
|
|
DCEntry->TDCLinkState = TDCLinkState;
|
|
}
|
|
|
|
VOID
|
|
UpdateDomainState(
|
|
PDOMAIN_ENTRY DomainEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the status of the given domain. The status is determined as
|
|
below :
|
|
|
|
1. if all DCs status and the Trusted channel status are success then
|
|
DomainState is set to DomainSuccess.
|
|
|
|
2. if all online DCs status are success and if any of the secure
|
|
channel status is non-success or any of the BDC is offline then the
|
|
Domainstate is set to DomainProblem.
|
|
|
|
3. if any of the domain status is non-success or the PDC is
|
|
offline then the DomainState is set to DomainSick.
|
|
|
|
4. if none of the DC is online, then DomainState is set to
|
|
DomainDown.
|
|
|
|
Arguments:
|
|
|
|
DomainEntry : pointer to domain structure.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY DCList;
|
|
PLIST_ENTRY NextEntry;
|
|
PDC_ENTRY DCEntry;
|
|
BOOL DomainDownFlag = TRUE;
|
|
BOOL PDCOnLine = FALSE;
|
|
|
|
DCList = &(DomainEntry->DCList);
|
|
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
if( DCEntry->State == DCOnLine ) {
|
|
|
|
DomainDownFlag = FALSE;
|
|
|
|
if( DCEntry->DCStatus != ERROR_SUCCESS ) {
|
|
DomainEntry->DomainState = DomainSick;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if this is PDC, mark PDC is heathy.
|
|
//
|
|
|
|
if( DCEntry->Type == NTPDC ) {
|
|
PDCOnLine = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( DomainDownFlag ) {
|
|
DomainEntry->DomainState = DomainDown;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if PDC is not online ..
|
|
//
|
|
|
|
if( !PDCOnLine ) {
|
|
DomainEntry->DomainState = DomainSick;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// now determine the secure channel status
|
|
//
|
|
|
|
DCList = &(DomainEntry->DCList);
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
//
|
|
// if a DC is offline ..
|
|
//
|
|
|
|
if( DCEntry->State == DCOffLine ) {
|
|
DomainEntry->DomainState = DomainProblem;
|
|
return;
|
|
}
|
|
|
|
if( DCEntry->Type == LMBDC ) {
|
|
|
|
//
|
|
// LMBDC does not have trusted secure channel.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// examine the PDC secure channel status.
|
|
//
|
|
|
|
if( (DCEntry->PDCLinkStatus != ERROR_SUCCESS) ||
|
|
(DCEntry->TDCLinkState == FALSE) ) {
|
|
DomainEntry->DomainState = DomainProblem;
|
|
return;
|
|
}
|
|
}
|
|
|
|
DomainEntry->DomainState = DomainSuccess;
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
IsDomainUpdateThreadRunning(
|
|
HANDLE *ThreadHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Test if the Domain update thread is running
|
|
|
|
Enter with GlobalDomainUpdateThreadCritSect locked.
|
|
|
|
Arguments:
|
|
|
|
ThreadHandle - pointer to thread handle.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The domain update thread is running
|
|
|
|
FALSE - The domain update thread is not running.
|
|
|
|
--*/
|
|
{
|
|
DWORD WaitStatus;
|
|
|
|
//
|
|
// Determine if the Update thread is already running.
|
|
//
|
|
|
|
if ( *ThreadHandle != NULL ) {
|
|
|
|
//
|
|
// Time out immediately if the thread is still running.
|
|
//
|
|
|
|
WaitStatus = WaitForSingleObject(
|
|
*ThreadHandle,
|
|
0 );
|
|
|
|
if ( WaitStatus == WAIT_TIMEOUT ) {
|
|
return TRUE;
|
|
|
|
} else if ( WaitStatus == 0 ) {
|
|
CloseHandle( *ThreadHandle );
|
|
*ThreadHandle = NULL;
|
|
return FALSE;
|
|
|
|
} else {
|
|
NlMonDbgPrint((
|
|
"IsDomainUpdateThreadRunning: "
|
|
"Cannot WaitFor Domain Update thread: %ld\n",
|
|
WaitStatus ));
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
StopDomainUpdateThread(
|
|
HANDLE *ThreadHandle,
|
|
BOOL *ThreadTerminateFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stops the domain update thread if it is running and waits for it to
|
|
stop.
|
|
|
|
Enter with GlobalDomainUpdateThreadCritSect locked.
|
|
|
|
Arguments:
|
|
|
|
ThreadHandle - pointer to thread handle.
|
|
|
|
ThreadTerminateFlag - pointer to thread terminate flag.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Ask the domain update thread to stop running.
|
|
//
|
|
|
|
*ThreadTerminateFlag = TRUE;
|
|
|
|
//
|
|
// Determine if the domain update thread is already running.
|
|
//
|
|
|
|
if ( *ThreadHandle != NULL ) {
|
|
|
|
//
|
|
// We've asked the thread to stop. It should do so soon.
|
|
// Wait for it to stop.
|
|
//
|
|
|
|
DWORD WaitStatus;
|
|
|
|
WaitStatus = WaitForSingleObject( *ThreadHandle,
|
|
5*60*1000 ); // 5 minutes
|
|
|
|
if ( WaitStatus != 0 ) {
|
|
if ( WaitStatus == WAIT_TIMEOUT ) {
|
|
NlMonDbgPrint(("NlStopDomainUpdateThread"
|
|
"WaitForSingleObject 5-minute timeout.\n" ));
|
|
|
|
//
|
|
// kill the thread.
|
|
//
|
|
|
|
TerminateThread( *ThreadHandle, (DWORD)-1 );
|
|
|
|
} else {
|
|
NlMonDbgPrint(("NlStopDomainUpdateThread"
|
|
"WaitForSingleObject error: %ld\n",
|
|
WaitStatus));
|
|
}
|
|
}
|
|
|
|
CloseHandle( *ThreadHandle );
|
|
*ThreadHandle = NULL;
|
|
}
|
|
|
|
*ThreadTerminateFlag = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
StartDomainUpdateThread(
|
|
PDOMAIN_ENTRY DomainEntry,
|
|
DWORD UpdateFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start the Domain Update thread if it is not already running.
|
|
|
|
NOTE: LOCK_LISTS() should be locked when this function is called.
|
|
since we do update the domain structure here.
|
|
|
|
Arguments:
|
|
|
|
DomainEntry - Pointer to domain structure.
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DWORD LocalThreadHandle;
|
|
|
|
//
|
|
// If the domain update thread is already running, do nothing.
|
|
//
|
|
|
|
EnterCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
if ( IsDomainUpdateThreadRunning( &DomainEntry->ThreadHandle ) ) {
|
|
LeaveCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// if the last update was done within the GlobalUpdateTimeMSec
|
|
// msecs then ignore
|
|
|
|
//
|
|
// Initialize the domain update parameters
|
|
//
|
|
|
|
DomainEntry->ThreadTerminateFlag = FALSE;
|
|
DomainEntry->UpdateFlags = UpdateFlags;
|
|
DomainEntry->DomainState = DomainUnknown;
|
|
|
|
DomainEntry->ThreadHandle = CreateThread(
|
|
NULL, // No security attributes
|
|
THREAD_STACKSIZE,
|
|
(LPTHREAD_START_ROUTINE)
|
|
DomainUpdateThread,
|
|
(LPVOID)DomainEntry,
|
|
0, // No special creation flags
|
|
&LocalThreadHandle );
|
|
|
|
if ( DomainEntry->ThreadHandle == NULL ) {
|
|
|
|
NlMonDbgPrint(("StartDomainUpdateThread"
|
|
"Can't create domain update Thread %lu\n",
|
|
GetLastError() ));
|
|
|
|
LeaveCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
return FALSE;
|
|
}
|
|
|
|
LeaveCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID
|
|
DomainUpdateThread(
|
|
PDOMAIN_ENTRY DomainEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update and validate status of DCs and Trusted DCs of the specifed
|
|
Monitored domain.
|
|
|
|
Arguments:
|
|
|
|
DomainEntry : Pointer to the domain entry to be updated.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY DCList;
|
|
PLIST_ENTRY NextEntry;
|
|
PDC_ENTRY DCEntry;
|
|
DWORD UpdateFlags = DomainEntry->UpdateFlags;
|
|
BOOL ThreadTerminate = DomainEntry->ThreadTerminateFlag;
|
|
|
|
//
|
|
// monitored domain first.
|
|
//
|
|
|
|
if (DomainEntry->IsMonitoredDomain ) {
|
|
|
|
//
|
|
// update lists.
|
|
//
|
|
|
|
if( UpdateFlags & UPDATE_DCS_FROM_SERVER_ENUM ) {
|
|
UpdateDCListByServerEnum(
|
|
&DomainEntry->Name,
|
|
&DomainEntry->DCList );
|
|
}
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate ) {
|
|
return;
|
|
}
|
|
|
|
if( UpdateFlags & UPDATE_DCS_FROM_DATABASE ) {
|
|
UpdateDCListFromDatabase(
|
|
&DomainEntry->Name,
|
|
&DomainEntry->DCList );
|
|
}
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate) {
|
|
return;
|
|
}
|
|
|
|
if( UpdateFlags & UPDATE_TRUST_DOMAINS_FROM_DATABASE ) {
|
|
UpdateTrustList( DomainEntry );
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate ) {
|
|
return;
|
|
}
|
|
|
|
UpdateTrustConnectionList( DomainEntry );
|
|
|
|
//
|
|
// start update threads for new trusted domain introduced
|
|
// here.
|
|
//
|
|
|
|
if( GlobalMonitorTrust ) {
|
|
UpdateAndValidateLists( UpdateFlags, FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// validate list content.
|
|
//
|
|
|
|
if( UpdateFlags & VALIDATE_DCS ) {
|
|
|
|
DCList = &(DomainEntry->DCList);
|
|
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate ) {
|
|
return;
|
|
}
|
|
|
|
(VOID) ValidateDC( DCEntry, &DomainEntry->Name );
|
|
|
|
//
|
|
// update trust connection status.
|
|
//
|
|
|
|
ValidateTrustConnectionList(
|
|
DCEntry,
|
|
(BOOL)(UpdateFlags & VALIDATE_TRUST_CONNECTIONS) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// trusted domain.
|
|
//
|
|
|
|
else {
|
|
|
|
if( UpdateFlags & UPDATE_TRUST_DCS_FROM_SERVER_ENUM ) {
|
|
UpdateDCListByServerEnum(
|
|
&DomainEntry->Name,
|
|
&DomainEntry->DCList );
|
|
}
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate ) {
|
|
return;
|
|
}
|
|
|
|
if( UpdateFlags & UPDATE_TRUST_DCS_FROM_DATABASE ) {
|
|
UpdateDCListFromDatabase(
|
|
&DomainEntry->Name,
|
|
&DomainEntry->DCList );
|
|
}
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// validate list content.
|
|
//
|
|
|
|
if( UpdateFlags & VALIDATE_TRUST_DCS ) {
|
|
|
|
DCList = &(DomainEntry->DCList);
|
|
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag || ThreadTerminate ) {
|
|
return;
|
|
}
|
|
|
|
(VOID) ValidateDC( DCEntry, &DomainEntry->Name );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// update domain status.
|
|
//
|
|
|
|
UpdateDomainState( DomainEntry );
|
|
|
|
//
|
|
// Set GloballUpdateEvent to enable the display thread to
|
|
// display the update.
|
|
//
|
|
|
|
if ( !SetEvent( GlobalUpdateEvent ) ) {
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("UpdateAndValidateDomain: Cannot set "
|
|
"GlobalUpdateEvent: %lu\n",
|
|
WinError ));
|
|
}
|
|
|
|
//
|
|
// finally set the last update time.
|
|
//
|
|
|
|
|
|
DomainEntry->LastUpdateTime = GetCurrentTime();
|
|
}
|
|
|
|
VOID
|
|
UpdateAndValidateLists(
|
|
DWORD UpdateFlags,
|
|
BOOL ForceFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update and validate all lists.
|
|
|
|
Arguments:
|
|
|
|
UpdateFlags : This bit mapped flags indicate what need to be update
|
|
during this pass.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY DomainList;
|
|
PLIST_ENTRY NextDomainEntry;
|
|
PMONITORED_DOMAIN_ENTRY DomainMonEntry;
|
|
PDOMAIN_ENTRY DomainEntry;
|
|
DWORD CurrentTime;
|
|
|
|
//
|
|
// delete if any GlobalDomainsMonitored entry marked to be deleted.
|
|
//
|
|
|
|
LOCK_LISTS();
|
|
DomainList = &GlobalDomainsMonitored;
|
|
for( NextDomainEntry = DomainList->Flink;
|
|
NextDomainEntry != DomainList; ) {
|
|
|
|
PLIST_ENTRY TDomainList;
|
|
PLIST_ENTRY NextTDomainEntry;
|
|
PTRUSTED_DOMAIN_ENTRY TDomainEntry;
|
|
|
|
DomainMonEntry = (PMONITORED_DOMAIN_ENTRY)NextDomainEntry;
|
|
NextDomainEntry = NextDomainEntry->Flink;
|
|
|
|
if( DomainMonEntry->DeleteFlag ) {
|
|
|
|
//
|
|
// unreference from GlobalDomains.
|
|
//
|
|
|
|
DomainMonEntry->DomainEntry->ReferenceCount--;
|
|
NetpAssert(DomainMonEntry->DomainEntry->ReferenceCount >= 0);
|
|
|
|
//
|
|
// unreference the trusted domains from GlobalDomains list.
|
|
//
|
|
|
|
TDomainList = &DomainMonEntry->DomainEntry->TrustedDomainList;
|
|
|
|
for( NextTDomainEntry = TDomainList->Flink;
|
|
NextTDomainEntry != TDomainList;
|
|
NextTDomainEntry = NextTDomainEntry->Flink ) {
|
|
|
|
TDomainEntry = (PTRUSTED_DOMAIN_ENTRY)NextTDomainEntry;
|
|
|
|
TDomainEntry->DomainEntry->ReferenceCount--;
|
|
NetpAssert(TDomainEntry->DomainEntry->ReferenceCount >= 0);
|
|
}
|
|
|
|
RemoveEntryList( (PLIST_ENTRY)DomainMonEntry );
|
|
NetpMemoryFree( DomainMonEntry );
|
|
}
|
|
}
|
|
|
|
//
|
|
// remove GlobalDomains entries that are not referenced anymore.
|
|
//
|
|
|
|
DomainList = &GlobalDomains;
|
|
for( NextDomainEntry = DomainList->Flink;
|
|
NextDomainEntry != DomainList; ) {
|
|
|
|
DomainEntry = (PDOMAIN_ENTRY)NextDomainEntry;
|
|
NextDomainEntry = NextDomainEntry->Flink;
|
|
|
|
if( DomainEntry->ReferenceCount == 0 ) {
|
|
|
|
//
|
|
// if the DomainUpdateThread is running, postpone this
|
|
// delete.
|
|
//
|
|
|
|
EnterCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
if ( !IsDomainUpdateThreadRunning( &DomainEntry->ThreadHandle ) ) {
|
|
RemoveEntryList( (PLIST_ENTRY)DomainEntry );
|
|
CleanupDomainEntry( DomainEntry );
|
|
}
|
|
LeaveCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
}
|
|
}
|
|
|
|
CurrentTime = GetCurrentTime();
|
|
|
|
//
|
|
// if we are monitoring trusted domains also then update
|
|
// GlobalDomains otherwise update just GlobalDomainsMonitored.
|
|
//
|
|
|
|
if( GlobalMonitorTrust ) {
|
|
DomainList = &GlobalDomains;
|
|
}
|
|
else {
|
|
DomainList = &GlobalDomainsMonitored;
|
|
}
|
|
|
|
for( NextDomainEntry = DomainList->Flink;
|
|
NextDomainEntry != DomainList;
|
|
NextDomainEntry = NextDomainEntry->Flink ) {
|
|
|
|
if( GlobalMonitorTrust ) {
|
|
DomainEntry = (PDOMAIN_ENTRY)NextDomainEntry;
|
|
}
|
|
else {
|
|
DomainEntry =
|
|
((PMONITORED_DOMAIN_ENTRY)NextDomainEntry)->DomainEntry;
|
|
}
|
|
|
|
//
|
|
// if we are asked to terminate, do so.
|
|
//
|
|
|
|
if( GlobalTerminateFlag ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if the last update was done within the last
|
|
// GlobalUpdateTimeMSec msecs then don't start UpdateThread.
|
|
// However start the UpdateThread during startup and when
|
|
// forced.
|
|
//
|
|
// Also takecare of wrap around
|
|
//
|
|
|
|
if( (ForceFlag == TRUE) ||
|
|
(DomainEntry->LastUpdateTime == 0) ||
|
|
(CurrentTime - DomainEntry->LastUpdateTime > GlobalUpdateTimeMSec ) ) {
|
|
|
|
StartDomainUpdateThread( DomainEntry, UpdateFlags );
|
|
}
|
|
}
|
|
|
|
UNLOCK_LISTS();
|
|
}
|
|
|
|
DWORD
|
|
InitGlobals(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize all global variables.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
GlobalTrace = CONST_GLOBALTRACE;
|
|
GlobalMonitorTrust = CONST_GLOBALMONITORTRUST;
|
|
GlobalUpdateTimeMSec = CONST_GLOBALUPDATETIME * 60000;
|
|
|
|
InitializeListHead( &GlobalDomains );
|
|
InitializeListHead( &GlobalDomainsMonitored );
|
|
//
|
|
// This should be in try except.
|
|
//
|
|
// In general, this routine doesn't clean up on failure.
|
|
//
|
|
try {
|
|
InitializeCriticalSection( &GlobalListCritSect );
|
|
InitializeCriticalSection( &GlobalDomainUpdateThreadCritSect );
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
GlobalTerminateFlag = FALSE;
|
|
|
|
GlobalTerminateEvent = CreateEvent( NULL, // No security attributes
|
|
TRUE, // Must be manual reset
|
|
FALSE, // Initially not signaled
|
|
NULL );// No name
|
|
|
|
if( GlobalTerminateEvent == NULL ) {
|
|
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("Can't create GlobalTerminateEvent %lu.\n", WinError));
|
|
|
|
return( WinError );
|
|
}
|
|
|
|
GlobalRefreshEvent = CreateEvent( NULL, // No security attributes
|
|
FALSE, // Must be auto reset
|
|
FALSE, // Initially not signaled
|
|
NULL );// No name
|
|
|
|
if( GlobalRefreshEvent == NULL ) {
|
|
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("Can't create GlobalRefreshEvent %lu.\n", WinError));
|
|
|
|
CloseHandle( GlobalTerminateEvent );
|
|
return( WinError );
|
|
}
|
|
|
|
GlobalRefreshDoneEvent = CreateEvent( NULL, // No security attributes
|
|
FALSE, // Must be auto reset
|
|
FALSE, // Initially not signaled
|
|
NULL );// No name
|
|
|
|
if( GlobalRefreshDoneEvent == NULL ) {
|
|
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("Can't create GlobalRefresheDoneEvent %lu.\n", WinError));
|
|
|
|
CloseHandle( GlobalTerminateEvent );
|
|
CloseHandle( GlobalRefreshEvent );
|
|
return( WinError );
|
|
}
|
|
|
|
GlobalUpdateEvent = CreateEvent( NULL, // No security attributes
|
|
FALSE, // Must be auto reset
|
|
FALSE, // Initially not signaled
|
|
NULL ); // No name
|
|
|
|
if( GlobalUpdateEvent == NULL ) {
|
|
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("Can't create GlobalUpdateEvent %lu.\n", WinError));
|
|
|
|
CloseHandle( GlobalTerminateEvent );
|
|
CloseHandle( GlobalRefreshEvent );
|
|
CloseHandle( GlobalRefreshDoneEvent );
|
|
return( WinError );
|
|
}
|
|
|
|
GlobalInitialized = TRUE;
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
FreeList(
|
|
PLIST_ENTRY List
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Freeup entries in a given lists.
|
|
|
|
Arguments:
|
|
|
|
List : pointer to a list.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
while ( !IsListEmpty(List) ) {
|
|
NextEntry = RemoveHeadList(List);
|
|
NetpMemoryFree( NextEntry );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CleanupDomainEntry(
|
|
PDOMAIN_ENTRY DomainEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a domain entry and its lists.
|
|
|
|
Arguments:
|
|
|
|
DomainEntry : pointer to domain structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY DCList;
|
|
PLIST_ENTRY NextEntry;
|
|
PDC_ENTRY DCEntry;
|
|
|
|
|
|
//
|
|
// first free trusted dc lists
|
|
//
|
|
|
|
DCList = &(DomainEntry->DCList);
|
|
for( NextEntry = DCList->Flink;
|
|
NextEntry != DCList; NextEntry = NextEntry->Flink ) {
|
|
|
|
DCEntry = (PDC_ENTRY) NextEntry;
|
|
FreeList( &DCEntry->TrustedDCs );
|
|
}
|
|
|
|
//
|
|
// now free the DC list.
|
|
//
|
|
|
|
FreeList( &DomainEntry->DCList );
|
|
|
|
//
|
|
// now free trusted domain list.
|
|
//
|
|
|
|
FreeList( &DomainEntry->TrustedDomainList );
|
|
}
|
|
|
|
VOID
|
|
CleanupLists(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Freeup all lists.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDOMAIN_ENTRY DomainEntry;
|
|
PLIST_ENTRY NextDomainEntry;
|
|
|
|
|
|
LOCK_LISTS();
|
|
|
|
while ( !IsListEmpty(&GlobalDomains) ) {
|
|
|
|
NextDomainEntry = RemoveHeadList(&GlobalDomains);
|
|
DomainEntry = (PDOMAIN_ENTRY)NextDomainEntry;
|
|
CleanupDomainEntry( DomainEntry );
|
|
}
|
|
|
|
FreeList(&GlobalDomainsMonitored);
|
|
UNLOCK_LISTS();
|
|
}
|
|
|
|
|
|
VOID
|
|
WorkerThread(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This thread updates the lists and validate the list content.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
#define COUNT_UPDATE_FROM_DATABASE 50
|
|
#define COUNT_VALIDATE_TRUST_CONNECTIONS 5
|
|
|
|
#define WAIT_COUNT 2
|
|
#define REFRESH_EVENT 0
|
|
#define TERMINATE_EVENT 1
|
|
|
|
DWORD LoopCount;
|
|
DWORD WaitStatus;
|
|
HANDLE WaitHandles[ WAIT_COUNT ];
|
|
DWORD UpdateFlags;
|
|
|
|
//
|
|
// perpare wait event array.
|
|
//
|
|
|
|
WaitHandles[REFRESH_EVENT] = GlobalRefreshEvent;
|
|
WaitHandles[TERMINATE_EVENT] = GlobalTerminateEvent;
|
|
|
|
LoopCount = 1;
|
|
for( ;; ) {
|
|
|
|
//
|
|
// wait for one of the following event to happen :
|
|
//
|
|
// 1. GlobalRefreshEvent
|
|
// 2. GlobalTerminateEvent.
|
|
// 3. Timeout in GlobalUpdateTimeMSec
|
|
//
|
|
|
|
WaitStatus = WaitForMultipleObjects(
|
|
WAIT_COUNT,
|
|
WaitHandles,
|
|
FALSE, // Wait for ANY handle
|
|
GlobalUpdateTimeMSec );
|
|
|
|
switch ( WaitStatus ) {
|
|
case WAIT_TIMEOUT: // timeout
|
|
//
|
|
// determine what to update.
|
|
//
|
|
|
|
if( LoopCount % COUNT_UPDATE_FROM_DATABASE ) {
|
|
UpdateFlags = UPDATE_FROM_DATABASE;
|
|
}
|
|
else if( LoopCount % COUNT_VALIDATE_TRUST_CONNECTIONS) {
|
|
UpdateFlags = UPDATE_TRUST_CONNECTIONS_STATUS;
|
|
}
|
|
else {
|
|
UpdateFlags = STANDARD_UPDATE;
|
|
}
|
|
|
|
UpdateAndValidateLists( UpdateFlags, FALSE );
|
|
|
|
//
|
|
// also indicate to the UI that the domain state has been
|
|
// changed.
|
|
//
|
|
|
|
if ( !SetEvent( GlobalUpdateEvent ) ) {
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("WokerThread: Cannot set "
|
|
"GlobalUpdateEvent: %lu\n",
|
|
WinError ));
|
|
}
|
|
|
|
LoopCount++;
|
|
break;
|
|
|
|
case REFRESH_EVENT:
|
|
|
|
UpdateAndValidateLists( UPDATE_ALL, TRUE );
|
|
|
|
if ( !SetEvent( GlobalRefreshDoneEvent ) ) {
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("WokerThread: Cannot set "
|
|
"GlobalRefreshDoneEvent: %lu\n",
|
|
WinError ));
|
|
}
|
|
|
|
//
|
|
// also indicate to the UI that the domain state has been
|
|
// changed.
|
|
//
|
|
|
|
if ( !SetEvent( GlobalUpdateEvent ) ) {
|
|
DWORD WinError;
|
|
|
|
WinError = GetLastError();
|
|
NlMonDbgPrint(("WokerThread: Cannot set "
|
|
"GlobalUpdateEvent: %lu\n",
|
|
WinError ));
|
|
}
|
|
|
|
break;
|
|
|
|
case TERMINATE_EVENT:
|
|
//
|
|
// done.
|
|
//
|
|
|
|
goto Cleanup;
|
|
break;
|
|
|
|
default:
|
|
NlMonDbgPrint((
|
|
"WorkerThread: WaitForMultipleObjects error: %ld\n",
|
|
WaitStatus));
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Cleanup:
|
|
return;
|
|
}
|
|
|