4800 lines
129 KiB
C
4800 lines
129 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
dns.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Routines to register DNS names.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Cliff Van Dyke (CliffV) 28-May-1996
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
//
|
|||
|
// Common include files.
|
|||
|
//
|
|||
|
|
|||
|
#include "logonsrv.h" // Include files common to entire service
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
BOOL NlDnsWriteServerFailureEventLog = FALSE;
|
|||
|
ULONG NlDnsInitCount = 0; // The number of times we have been started
|
|||
|
|
|||
|
//
|
|||
|
// The timeout after our start when it's OK to write DNS errors into
|
|||
|
// the event log. We postpone error output because the DNS server
|
|||
|
// (if it runs locally) may not have started yet.
|
|||
|
//
|
|||
|
#define NL_DNS_EVENTLOG_TIMEOUT (2 * 60 * 1000) // 2 minutes
|
|||
|
|
|||
|
//
|
|||
|
// State of a DNS name.
|
|||
|
//
|
|||
|
|
|||
|
typedef enum {
|
|||
|
RegisterMe, // Name needs to be registered
|
|||
|
Registered, // Name is registered
|
|||
|
DeregisterMe, // Name needs to be deregistered
|
|||
|
DelayedDeregister, // Name will be marked for deregistration in the future
|
|||
|
DeleteMe // This entry should be deleted.
|
|||
|
} NL_DNS_NAME_STATE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Structure representing an added DNS name.
|
|||
|
// (All fields serialized by NlGlobalDnsCritSect)
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _NL_DNS_NAME {
|
|||
|
|
|||
|
//
|
|||
|
// Link in list of all such structures headed by NlGlobalDnsList
|
|||
|
//
|
|||
|
LIST_ENTRY Next;
|
|||
|
|
|||
|
//
|
|||
|
// Reference count
|
|||
|
//
|
|||
|
ULONG NlDnsNameRefCount;
|
|||
|
|
|||
|
//
|
|||
|
// Type of name registed.
|
|||
|
//
|
|||
|
NL_DNS_NAME_TYPE NlDnsNameType;
|
|||
|
|
|||
|
//
|
|||
|
// Domain this entry refers to.
|
|||
|
//
|
|||
|
PDOMAIN_INFO DomainInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Flags describing the entry.
|
|||
|
//
|
|||
|
|
|||
|
ULONG Flags;
|
|||
|
|
|||
|
#define NL_DNS_REGISTER_DOMAIN 0x0001 // All names for domain being registered.
|
|||
|
#define NL_DNS_REGISTERED_ONCE 0x0002 // Name has been registered at least once
|
|||
|
|
|||
|
//
|
|||
|
// The time of the first failure to deregister this name.
|
|||
|
// Reset to zero on successful deregistration.
|
|||
|
//
|
|||
|
|
|||
|
LARGE_INTEGER FirstDeregFailureTime;
|
|||
|
|
|||
|
//
|
|||
|
// Each regisration is periodically re-done (whether successful or not).
|
|||
|
// This timer indicates when the next re-registration should be done.
|
|||
|
//
|
|||
|
// The initial re-registration is done after 5 minute. The period then
|
|||
|
// doubles until it reaches a maximum of DnsRefreshInterval.
|
|||
|
//
|
|||
|
|
|||
|
TIMER ScavengeTimer;
|
|||
|
|
|||
|
#define ORIG_DNS_SCAVENGE_PERIOD (5*60*1000) // 5 minute
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Actual DNS name registered.
|
|||
|
//
|
|||
|
LPSTR DnsRecordName;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Data for the SRV record
|
|||
|
//
|
|||
|
ULONG Priority;
|
|||
|
ULONG Weight;
|
|||
|
ULONG Port;
|
|||
|
LPSTR DnsHostName;
|
|||
|
|
|||
|
//
|
|||
|
// Data for the A record
|
|||
|
//
|
|||
|
ULONG IpAddress;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// State of this entry.
|
|||
|
//
|
|||
|
NL_DNS_NAME_STATE State;
|
|||
|
|
|||
|
//
|
|||
|
// Last DNS update status for this name
|
|||
|
//
|
|||
|
NET_API_STATUS NlDnsNameLastStatus;
|
|||
|
|
|||
|
} NL_DNS_NAME, *PNL_DNS_NAME;
|
|||
|
|
|||
|
//
|
|||
|
// Context describing a series of DNS registrations or deregistrations
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _NL_DNS_CONTEXT {
|
|||
|
|
|||
|
ULONG StartTime;
|
|||
|
#define NL_DNS_THRESHOLD (30*1000) // 30 seconds
|
|||
|
|
|||
|
} NL_DNS_CONTEXT, *PNL_DNS_CONTEXT;
|
|||
|
|
|||
|
//
|
|||
|
// Header for binary Dns log file.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _NL_DNSLOG_HEADER {
|
|||
|
|
|||
|
ULONG Version;
|
|||
|
|
|||
|
} NL_DNSLOG_HEADER, *PNL_DNSLOG_HEADER;
|
|||
|
|
|||
|
#define NL_DNSLOG_VERSION 1
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Entry in the binary Dns log file.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _NL_DNSLOG_ENTRY {
|
|||
|
|
|||
|
//
|
|||
|
// Size (in bytes) of this entry
|
|||
|
//
|
|||
|
ULONG EntrySize;
|
|||
|
|
|||
|
//
|
|||
|
// Type of name registed.
|
|||
|
//
|
|||
|
NL_DNS_NAME_TYPE NlDnsNameType;
|
|||
|
|
|||
|
//
|
|||
|
// Data for the SRV record
|
|||
|
//
|
|||
|
ULONG Priority;
|
|||
|
ULONG Weight;
|
|||
|
ULONG Port;
|
|||
|
|
|||
|
//
|
|||
|
// Data for the A record
|
|||
|
//
|
|||
|
ULONG IpAddress;
|
|||
|
|
|||
|
} NL_DNSLOG_ENTRY, *PNL_DNSLOG_ENTRY;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Globals specific to this .c file.
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsScavengeOne(
|
|||
|
IN PNL_DNS_CONTEXT NlDnsContext,
|
|||
|
IN PNL_DNS_NAME NlDnsName
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// True if the DNS list needs to be output to netlogon.dns
|
|||
|
//
|
|||
|
BOOLEAN NlGlobalDnsListDirty;
|
|||
|
|
|||
|
//
|
|||
|
// True if the initial cleanup of previously registered names has been done.
|
|||
|
//
|
|||
|
BOOLEAN NlGlobalDnsInitialCleanupDone;
|
|||
|
|
|||
|
//
|
|||
|
// Time when netlogon was started.
|
|||
|
//
|
|||
|
DWORD NlGlobalDnsStartTime;
|
|||
|
#define NL_DNS_INITIAL_CLEANUP_TIME (10 * 60 * 1000) // 10 minutes
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsNameToStr(
|
|||
|
IN PNL_DNS_NAME NlDnsName,
|
|||
|
OUT CHAR Utf8DnsRecord[NL_DNS_RECORD_STRING_SIZE]
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine builds a textual representation of NlDnsName
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsName - Name to register or deregister.
|
|||
|
|
|||
|
Utf8DnsRecord - Preallocated buffer to build the text string into.
|
|||
|
The built record is a UTF-8 zero terminated string.
|
|||
|
The string is concatenated to this buffer.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
CHAR Number[33];
|
|||
|
|
|||
|
//
|
|||
|
// Write the record name
|
|||
|
//
|
|||
|
|
|||
|
strcat( Utf8DnsRecord, NlDnsName->DnsRecordName );
|
|||
|
|
|||
|
//
|
|||
|
// Concatenate the TTL
|
|||
|
//
|
|||
|
|
|||
|
_ltoa( NlGlobalParameters.DnsTtl, Number, 10 );
|
|||
|
strcat( Utf8DnsRecord, " " );
|
|||
|
strcat( Utf8DnsRecord, Number );
|
|||
|
|
|||
|
//
|
|||
|
// Build an A record.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsARecord( NlDnsName->NlDnsNameType ) ) {
|
|||
|
CHAR IpAddressString[NL_IP_ADDRESS_LENGTH+1];
|
|||
|
|
|||
|
strcat( Utf8DnsRecord, NL_DNS_A_RR_VALUE_1 );
|
|||
|
NetpIpAddressToStr( NlDnsName->IpAddress, IpAddressString );
|
|||
|
strcat( Utf8DnsRecord, IpAddressString );
|
|||
|
|
|||
|
//
|
|||
|
// Build a CNAME record
|
|||
|
//
|
|||
|
|
|||
|
} else if ( NlDnsCnameRecord( NlDnsName->NlDnsNameType ) ) {
|
|||
|
strcat( Utf8DnsRecord, NL_DNS_CNAME_RR_VALUE_1 );
|
|||
|
strcat( Utf8DnsRecord, NlDnsName->DnsHostName );
|
|||
|
strcat( Utf8DnsRecord, "." );
|
|||
|
|
|||
|
//
|
|||
|
// Build a SRV record
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
strcat( Utf8DnsRecord, NL_DNS_SRV_RR_VALUE_1 );
|
|||
|
|
|||
|
_ltoa( NlDnsName->Priority, Number, 10 );
|
|||
|
strcat( Utf8DnsRecord, Number );
|
|||
|
strcat( Utf8DnsRecord, " " );
|
|||
|
|
|||
|
_ltoa( NlDnsName->Weight, Number, 10 );
|
|||
|
strcat( Utf8DnsRecord, Number );
|
|||
|
strcat( Utf8DnsRecord, " " );
|
|||
|
|
|||
|
_ltoa( NlDnsName->Port, Number, 10 );
|
|||
|
strcat( Utf8DnsRecord, Number );
|
|||
|
strcat( Utf8DnsRecord, " " );
|
|||
|
|
|||
|
strcat( Utf8DnsRecord, NlDnsName->DnsHostName );
|
|||
|
strcat( Utf8DnsRecord, "." );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LPWSTR
|
|||
|
NlDnsNameToWStr(
|
|||
|
IN PNL_DNS_NAME NlDnsName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine builds a textual representation of NlDnsName
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsName - Name to register or deregister.
|
|||
|
|
|||
|
Utf8DnsRecord - Preallocated buffer to build the text string into.
|
|||
|
The built record is a UTF-8 zero terminated string.
|
|||
|
The string is concatenated to this buffer.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Buffer containing a textual representation of NlDnsName
|
|||
|
NULL: Buffer could not be allocated
|
|||
|
|
|||
|
Buffer should be free by calling NetApiBufferFree();
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPSTR DnsRecord = NULL;
|
|||
|
LPWSTR UnicodeDnsRecord;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer for the UTF-8 version of the string.
|
|||
|
//
|
|||
|
DnsRecord = LocalAlloc( 0, NL_DNS_RECORD_STRING_SIZE + 1 );
|
|||
|
|
|||
|
if ( DnsRecord == NULL ) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
DnsRecord[0] = '\0';
|
|||
|
|
|||
|
//
|
|||
|
// Create the text string in UTF-8
|
|||
|
//
|
|||
|
NlDnsNameToStr( NlDnsName, DnsRecord );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Convert to Unicode
|
|||
|
//
|
|||
|
UnicodeDnsRecord = NetpAllocWStrFromUtf8Str( DnsRecord );
|
|||
|
|
|||
|
LocalFree( DnsRecord );
|
|||
|
|
|||
|
return UnicodeDnsRecord;
|
|||
|
}
|
|||
|
|
|||
|
#if NETLOGONDBG
|
|||
|
#define NlPrintDns(_x_) NlPrintDnsRoutine _x_
|
|||
|
#else
|
|||
|
#define NlPrintDns(_x_)
|
|||
|
#endif // NETLOGONDBG
|
|||
|
|
|||
|
#if NETLOGONDBG
|
|||
|
VOID
|
|||
|
NlPrintDnsRoutine(
|
|||
|
IN DWORD DebugFlag,
|
|||
|
IN PNL_DNS_NAME NlDnsName,
|
|||
|
IN LPSTR Format,
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
CHAR Utf8DnsRecord[NL_DNS_RECORD_STRING_SIZE];
|
|||
|
|
|||
|
//
|
|||
|
// vsprintf isn't multithreaded + we don't want to intermingle output
|
|||
|
// from different threads.
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalLogFileCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Prefix the printed line with the domain name
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalServicedDomainCount > 1 ) {
|
|||
|
if ( NlDnsName->DomainInfo == NULL ) {
|
|||
|
NlPrint(( DebugFlag, "%ws: ", L"[Unknown]" ));
|
|||
|
} else if ( NlDnsName->DomainInfo->DomUnicodeDomainName != NULL &&
|
|||
|
*(NlDnsName->DomainInfo->DomUnicodeDomainName) != UNICODE_NULL ) {
|
|||
|
NlPrint(( DebugFlag, "%ws: ", NlDnsName->DomainInfo->DomUnicodeDomainName ));
|
|||
|
} else {
|
|||
|
NlPrint(( DebugFlag, "%ws: ", NlDnsName->DomainInfo->DomUnicodeDnsDomainName ));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Simply change arguments to va_list form and call NlPrintRoutineV
|
|||
|
//
|
|||
|
|
|||
|
va_start(arglist, Format);
|
|||
|
|
|||
|
NlPrintRoutineV( DebugFlag, Format, arglist );
|
|||
|
|
|||
|
va_end(arglist);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Finally print a description of the DNS record in question.
|
|||
|
//
|
|||
|
|
|||
|
Utf8DnsRecord[0] = '\0';
|
|||
|
NlDnsNameToStr( NlDnsName, Utf8DnsRecord );
|
|||
|
|
|||
|
NlPrint(( DebugFlag,
|
|||
|
": %ws: %s\n",
|
|||
|
NlDcDnsNameTypeDesc[NlDnsName->NlDnsNameType].Name,
|
|||
|
Utf8DnsRecord ));
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalLogFileCritSect );
|
|||
|
|
|||
|
}
|
|||
|
#endif // NETLOGONDBG
|
|||
|
|
|||
|
BOOL
|
|||
|
NlDnsSetAvoidRegisterNameParam(
|
|||
|
IN LPTSTR_ARRAY NewDnsAvoidRegisterRecords
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the names of DNS records this DC should avoid registering.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NewSiteCoverage - Specifies the new list of names to avoid registering
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE: iff the list of names to avoid registering changed
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL DnsAvoidRegisterRecordsChanged = FALSE;
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalParametersCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Handle DnsAvoidRegisterRecords changing
|
|||
|
//
|
|||
|
|
|||
|
DnsAvoidRegisterRecordsChanged = !NetpEqualTStrArrays(
|
|||
|
NlGlobalParameters.DnsAvoidRegisterRecords,
|
|||
|
NewDnsAvoidRegisterRecords );
|
|||
|
|
|||
|
if ( DnsAvoidRegisterRecordsChanged ) {
|
|||
|
//
|
|||
|
// Swap in the new value.
|
|||
|
(VOID) NetApiBufferFree( NlGlobalParameters.DnsAvoidRegisterRecords );
|
|||
|
NlGlobalParameters.DnsAvoidRegisterRecords = NewDnsAvoidRegisterRecords;
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalParametersCritSect );
|
|||
|
return DnsAvoidRegisterRecordsChanged;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlGetConfiguredDnsDomainName(
|
|||
|
OUT LPWSTR *DnsDomainName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets the DNS domain name of domain as configured by DNS or DHCP
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsDomainName - Returns the DNS domain name of the domain.
|
|||
|
The returned name has a trailing . since the name is an absolute name.
|
|||
|
The allocated buffer must be freed via NetApiBufferFree.
|
|||
|
Returns NO_ERROR and a pointer to a NULL buffer if there is no
|
|||
|
domain name configured.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
WCHAR LocalDnsDomainNameBuffer[NL_MAX_DNS_LENGTH+1];
|
|||
|
LPWSTR LocalDnsDomainName = NULL;
|
|||
|
|
|||
|
LPNET_CONFIG_HANDLE SectionHandle = NULL;
|
|||
|
|
|||
|
*DnsDomainName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Get the domain name from the registery
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
NetStatus = NetpOpenConfigData(
|
|||
|
&SectionHandle,
|
|||
|
NULL, // no server name.
|
|||
|
SERVICE_TCPIP,
|
|||
|
TRUE ); // we only want readonly access
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
//
|
|||
|
// Simply return success if TCP/IP isn't configured.
|
|||
|
//
|
|||
|
if ( NetStatus == NERR_CfgCompNotFound ) {
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
}
|
|||
|
SectionHandle = NULL;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the "Domain" parameter from the TCPIP service.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpGetConfigValue (
|
|||
|
SectionHandle,
|
|||
|
L"Domain", // key wanted
|
|||
|
&LocalDnsDomainName ); // Must be freed by NetApiBufferFree().
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && *LocalDnsDomainName == L'\0' ) {
|
|||
|
NetStatus = NERR_CfgParamNotFound;
|
|||
|
NetApiBufferFree( LocalDnsDomainName );
|
|||
|
LocalDnsDomainName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (NetStatus != NERR_CfgParamNotFound ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Fall back to the "DhcpDomain" parameter from the TCPIP service.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpGetConfigValue (
|
|||
|
SectionHandle,
|
|||
|
L"DhcpDomain", // key wanted
|
|||
|
&LocalDnsDomainName ); // Must be freed by NetApiBufferFree().
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && *LocalDnsDomainName == L'\0' ) {
|
|||
|
NetStatus = NERR_CfgParamNotFound;
|
|||
|
NetApiBufferFree( LocalDnsDomainName );
|
|||
|
LocalDnsDomainName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (NetStatus == NERR_CfgParamNotFound ) {
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
if ( LocalDnsDomainName != NULL ) {
|
|||
|
ULONG LocalDnsDomainNameLen = wcslen(LocalDnsDomainName);
|
|||
|
if ( LocalDnsDomainNameLen != 0 ) {
|
|||
|
if ( LocalDnsDomainNameLen > NL_MAX_DNS_LENGTH-1 ) {
|
|||
|
NetStatus = ERROR_INVALID_DOMAINNAME;
|
|||
|
} else {
|
|||
|
NetStatus = NetapipBufferAllocate(
|
|||
|
(LocalDnsDomainNameLen + 2) * sizeof(WCHAR),
|
|||
|
DnsDomainName );
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
wcscpy( *DnsDomainName, LocalDnsDomainName );
|
|||
|
if ( (*DnsDomainName)[LocalDnsDomainNameLen-1] != L'.' ) {
|
|||
|
wcscat( *DnsDomainName, L"." );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if ( SectionHandle != NULL ) {
|
|||
|
(VOID) NetpCloseConfigData( SectionHandle );
|
|||
|
}
|
|||
|
if ( LocalDnsDomainName != NULL ) {
|
|||
|
NetApiBufferFree( LocalDnsDomainName );
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsDereferenceEntry(
|
|||
|
PNL_DNS_NAME NlDnsName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Dereference a DNS name entry on the global list of DNS names
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsName - The DNS name entry
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlAssert( NlDnsName->NlDnsNameRefCount > 0 );
|
|||
|
NlDnsName->NlDnsNameRefCount --;
|
|||
|
|
|||
|
//
|
|||
|
// If the ref count reaches zero,
|
|||
|
// delink this entry and free it.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsName->NlDnsNameRefCount == 0 ) {
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDereferenceEntry: Deleting DNS name" ));
|
|||
|
|
|||
|
NlAssert( NlDnsName->State == DeleteMe );
|
|||
|
RemoveEntryList( &NlDnsName->Next );
|
|||
|
LocalFree( NlDnsName );
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsSetState(
|
|||
|
PNL_DNS_NAME NlDnsName,
|
|||
|
NL_DNS_NAME_STATE State
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Set the state of the entry.
|
|||
|
|
|||
|
If the state is DeleteMe, NlDnsName must have at least 2 references:
|
|||
|
one for being on the global list and one reference by the caller.
|
|||
|
For the deleted state, this routine will dereference the name removing
|
|||
|
the reference for being on the global list. When the caller derefereces
|
|||
|
this entry after the return from this routine and removes the caller's
|
|||
|
reference, this entry will be delinked and freed if ref count reaches 0.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsName - Structure describing name.
|
|||
|
|
|||
|
State - New state for the name.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// If this name got registered,
|
|||
|
// remember that fact
|
|||
|
//
|
|||
|
|
|||
|
if ( State == Registered ) {
|
|||
|
NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the state changes, do appropriate updates
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsName->State != State ) {
|
|||
|
NlDnsName->State = State;
|
|||
|
NlGlobalDnsListDirty = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// If the new state says I need to update the DNS server,
|
|||
|
// set the retry period to indicate to do that now.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsName->State == RegisterMe ||
|
|||
|
NlDnsName->State == DeregisterMe ) {
|
|||
|
|
|||
|
NlDnsName->ScavengeTimer.StartTime.QuadPart = 0;
|
|||
|
NlDnsName->ScavengeTimer.Period = 0;
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is to be deleted,
|
|||
|
// derefernce it
|
|||
|
//
|
|||
|
|
|||
|
} else if ( NlDnsName->State == DeleteMe ) {
|
|||
|
|
|||
|
//
|
|||
|
// There must be at least 2 references
|
|||
|
//
|
|||
|
NlAssert( NlDnsName->NlDnsNameRefCount > 1 );
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsBuildName(
|
|||
|
IN PDOMAIN_INFO DomainInfo,
|
|||
|
IN NL_DNS_NAME_TYPE NlDnsNameType,
|
|||
|
IN LPWSTR SiteName,
|
|||
|
IN BOOL DnsNameAlias,
|
|||
|
OUT char DnsName[NL_MAX_DNS_LENGTH+1]
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the textual DNS name for a particular domain and
|
|||
|
name type.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DomainInfo - Domain the name is for.
|
|||
|
|
|||
|
NlDnsNameType - The specific type of name.
|
|||
|
|
|||
|
SiteName - If NlDnsNameType is any of the *AtSite values,
|
|||
|
the site name of the site this name is registered for.
|
|||
|
|
|||
|
DnsNameAlias - If TRUE, the built name should correspond to the
|
|||
|
alias of the domain/forest name.
|
|||
|
|
|||
|
DnsName - Textual representation of the name. If the name is not
|
|||
|
applicable (DnsNameAlias is TRUE but there is no alias for
|
|||
|
the name), the returned string will be empty.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: The name was returned;
|
|||
|
|
|||
|
ERROR_NO_SUCH_DOMAIN: No (active) domain name is known for this domain.
|
|||
|
|
|||
|
ERROR_INVALID_DOMAINNAME: Domain's name is too long. Additional labels
|
|||
|
cannot be concatenated.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
GUID DomainGuid;
|
|||
|
LPSTR DnsDomainName = NULL;
|
|||
|
BOOLEAN UseForestName = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory( DnsName, (NL_MAX_DNS_LENGTH+1)*sizeof(char) );
|
|||
|
|
|||
|
//
|
|||
|
// Get the Domain GUID for the case where the DC domain name.
|
|||
|
// The Domain GUID is registered at the TreeName
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection(&NlGlobalDomainCritSect);
|
|||
|
if ( NlDnsDcGuid( NlDnsNameType ) ) {
|
|||
|
if ( DomainInfo->DomDomainGuid == NULL ) {
|
|||
|
NlPrintDom((NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsBuildName: Domain has no GUID.\n" ));
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
DomainGuid = *(DomainInfo->DomDomainGuid);
|
|||
|
|
|||
|
UseForestName = TRUE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the DSA Guid for the case where the DC is renamed.
|
|||
|
//
|
|||
|
|
|||
|
} else if ( NlDnsCnameRecord( NlDnsNameType) ) {
|
|||
|
|
|||
|
if ( IsEqualGUID( &NlGlobalDsaGuid, &NlGlobalZeroGuid) ) {
|
|||
|
NlPrintDom((NL_DNS, DomainInfo,
|
|||
|
"NlDnsBuildName: DSA has no GUID.\n" ));
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
DomainGuid = NlGlobalDsaGuid;
|
|||
|
|
|||
|
UseForestName = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ensure site specific names have been passed a site name
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDcDnsNameTypeDesc[NlDnsNameType].IsSiteSpecific ) {
|
|||
|
if ( SiteName == NULL ) {
|
|||
|
NlPrintDom((NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsBuildName: DC has no Site Name.\n" ));
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// GC's are registered at the Forest name.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsGcName( NlDnsNameType ) ) {
|
|||
|
UseForestName = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pick up the ForestName or DomainName as flagged above.
|
|||
|
//
|
|||
|
|
|||
|
if ( UseForestName ) {
|
|||
|
if ( !DnsNameAlias ) {
|
|||
|
DnsDomainName = NlGlobalUtf8DnsForestName;
|
|||
|
|
|||
|
//
|
|||
|
// We must have an active forest name
|
|||
|
//
|
|||
|
if ( NlGlobalUtf8DnsForestName == NULL ) {
|
|||
|
NlPrintDom((NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsBuildName: Domain has no Forest Name.\n" ));
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
} else {
|
|||
|
DnsDomainName = NlGlobalUtf8DnsForestNameAlias;
|
|||
|
}
|
|||
|
} else {
|
|||
|
if ( !DnsNameAlias ) {
|
|||
|
DnsDomainName = DomainInfo->DomUtf8DnsDomainName;
|
|||
|
|
|||
|
//
|
|||
|
// We must have an active domain name
|
|||
|
//
|
|||
|
if ( DomainInfo->DomUtf8DnsDomainName == NULL ) {
|
|||
|
NlPrintDom((NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsBuildName: Domain has no Domain Name.\n" ));
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
} else {
|
|||
|
DnsDomainName = DomainInfo->DomUtf8DnsDomainNameAlias;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build the appropriate name as applicable
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsDomainName != NULL ) {
|
|||
|
NetStatus = NetpDcBuildDnsName( NlDnsNameType,
|
|||
|
&DomainGuid,
|
|||
|
SiteName,
|
|||
|
DnsDomainName,
|
|||
|
DnsName );
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
LeaveCriticalSection(&NlGlobalDomainCritSect);
|
|||
|
return NetStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HKEY
|
|||
|
NlOpenNetlogonKey(
|
|||
|
LPSTR KeyName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Create/Open the Netlogon key in the registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyName - Name of the key to open
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return a handle to the key. NULL means the key couldn't be opened.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONG RegStatus;
|
|||
|
|
|||
|
HKEY ParmHandle = NULL;
|
|||
|
ULONG Disposition;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Open the key for Netlogon\Parameters
|
|||
|
//
|
|||
|
|
|||
|
RegStatus = RegCreateKeyExA(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
KeyName,
|
|||
|
0, //Reserved
|
|||
|
NULL, // Class
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY,
|
|||
|
NULL, // Security descriptor
|
|||
|
&ParmHandle,
|
|||
|
&Disposition );
|
|||
|
|
|||
|
if ( RegStatus != ERROR_SUCCESS ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlOpenNetlogonKey: Cannot create registy key %s %ld.\n",
|
|||
|
KeyName,
|
|||
|
RegStatus ));
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
return ParmHandle;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsWriteBinaryLog(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Write the list of registered DNS names to the registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
|
|||
|
ULONG DnsRecordBufferSize;
|
|||
|
PNL_DNSLOG_HEADER DnsRecordBuffer = NULL;
|
|||
|
PNL_DNSLOG_ENTRY DnsLogEntry;
|
|||
|
ULONG CurrentSize;
|
|||
|
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
//
|
|||
|
// Compute the size of the buffer to allocate.
|
|||
|
//
|
|||
|
|
|||
|
DnsRecordBufferSize = ROUND_UP_COUNT( sizeof(NL_DNSLOG_HEADER), ALIGN_WORST );
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is marked for deletion,
|
|||
|
// skip it
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Only do entries that have been registered.
|
|||
|
//
|
|||
|
// The whole purpose of this log is to keep track of names that
|
|||
|
// need to be deregistered sooner or later.
|
|||
|
//
|
|||
|
if ( NlDnsName->Flags & NL_DNS_REGISTERED_ONCE ) {
|
|||
|
|
|||
|
//
|
|||
|
// Compute the size of this entry.
|
|||
|
//
|
|||
|
|
|||
|
CurrentSize = sizeof(NL_DNSLOG_ENTRY);
|
|||
|
CurrentSize += strlen( NlDnsName->DnsRecordName ) + 1;
|
|||
|
if ( NlDnsName->DnsHostName != NULL ) {
|
|||
|
CurrentSize += strlen( NlDnsName->DnsHostName ) + 1;
|
|||
|
}
|
|||
|
CurrentSize = ROUND_UP_COUNT( CurrentSize, ALIGN_WORST );
|
|||
|
|
|||
|
//
|
|||
|
// Add it to the size needed for the file.
|
|||
|
//
|
|||
|
|
|||
|
DnsRecordBufferSize += CurrentSize;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a block to build the binary log into.
|
|||
|
// (and the build the file name in)
|
|||
|
//
|
|||
|
|
|||
|
DnsRecordBuffer = LocalAlloc( LMEM_ZEROINIT, DnsRecordBufferSize );
|
|||
|
|
|||
|
if ( DnsRecordBuffer == NULL ) {
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
DnsRecordBuffer->Version = NL_DNSLOG_VERSION;
|
|||
|
DnsLogEntry = (PNL_DNSLOG_ENTRY)ROUND_UP_POINTER( (DnsRecordBuffer + 1), ALIGN_WORST );
|
|||
|
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
ULONG DnsRecordNameSize;
|
|||
|
ULONG DnsHostNameSize;
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is marked for deletion,
|
|||
|
// skip it
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Only do entries that have been registered.
|
|||
|
//
|
|||
|
// The whole purpose of this log is to keep track of names that
|
|||
|
// need to be deregistered sooner or later.
|
|||
|
//
|
|||
|
if ( NlDnsName->Flags & NL_DNS_REGISTERED_ONCE ) {
|
|||
|
|
|||
|
//
|
|||
|
// Compute the size of this entry.
|
|||
|
//
|
|||
|
|
|||
|
DnsRecordNameSize = strlen( NlDnsName->DnsRecordName ) + 1;
|
|||
|
|
|||
|
CurrentSize = sizeof(NL_DNSLOG_ENTRY) + DnsRecordNameSize;
|
|||
|
if ( NlDnsName->DnsHostName != NULL ) {
|
|||
|
DnsHostNameSize = strlen( NlDnsName->DnsHostName ) + 1;
|
|||
|
CurrentSize += DnsHostNameSize;
|
|||
|
}
|
|||
|
CurrentSize = ROUND_UP_COUNT( CurrentSize, ALIGN_WORST );
|
|||
|
|
|||
|
//
|
|||
|
// Put the constant size fields in the buffer.
|
|||
|
//
|
|||
|
|
|||
|
DnsLogEntry->EntrySize = CurrentSize;
|
|||
|
DnsLogEntry->NlDnsNameType = NlDnsName->NlDnsNameType;
|
|||
|
DnsLogEntry->IpAddress = NlDnsName->IpAddress;
|
|||
|
DnsLogEntry->Priority = NlDnsName->Priority;
|
|||
|
DnsLogEntry->Weight = NlDnsName->Weight;
|
|||
|
DnsLogEntry->Port = NlDnsName->Port;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the variable length entries.
|
|||
|
//
|
|||
|
|
|||
|
Where = (LPBYTE) (DnsLogEntry+1);
|
|||
|
strcpy( Where, NlDnsName->DnsRecordName );
|
|||
|
Where += DnsRecordNameSize;
|
|||
|
|
|||
|
if ( NlDnsName->DnsHostName != NULL ) {
|
|||
|
strcpy( Where, NlDnsName->DnsHostName );
|
|||
|
Where += DnsHostNameSize;
|
|||
|
}
|
|||
|
Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
|
|||
|
|
|||
|
NlAssert( (ULONG)(Where-(LPBYTE)DnsLogEntry) == CurrentSize );
|
|||
|
NlAssert( (ULONG)(Where-(LPBYTE)DnsRecordBuffer) <= DnsRecordBufferSize );
|
|||
|
|
|||
|
//
|
|||
|
// Move on to the next entry.
|
|||
|
//
|
|||
|
|
|||
|
DnsLogEntry = (PNL_DNSLOG_ENTRY)Where;
|
|||
|
} else {
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsWriteBinaryLog: not written to binary log file." ));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Write the buffer to the file.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NlWriteBinaryLog(
|
|||
|
NL_DNS_BINARY_LOG_FILE,
|
|||
|
(LPBYTE) DnsRecordBuffer,
|
|||
|
DnsRecordBufferSize );
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Write event log on error
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
LPWSTR MsgStrings[2];
|
|||
|
|
|||
|
MsgStrings[0] = NL_DNS_BINARY_LOG_FILE;
|
|||
|
MsgStrings[1] = (LPWSTR) UlongToPtr( NetStatus );
|
|||
|
|
|||
|
NlpWriteEventlog (NELOG_NetlogonFailedFileCreate,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
(LPBYTE) &NetStatus,
|
|||
|
sizeof(NetStatus),
|
|||
|
MsgStrings,
|
|||
|
2 | NETP_LAST_MESSAGE_IS_NETSTATUS );
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( DnsRecordBuffer != NULL ) {
|
|||
|
LocalFree( DnsRecordBuffer );
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PNL_DNS_NAME
|
|||
|
NlDnsAllocateEntry(
|
|||
|
IN NL_DNS_NAME_TYPE NlDnsNameType,
|
|||
|
IN LPSTR DnsRecordName,
|
|||
|
IN ULONG Priority,
|
|||
|
IN ULONG Weight,
|
|||
|
IN ULONG Port,
|
|||
|
IN LPCSTR DnsHostName OPTIONAL,
|
|||
|
IN ULONG IpAddress,
|
|||
|
IN NL_DNS_NAME_STATE State
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocate and initialize a DNS name entry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fields of the structure.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to the allocated structure.
|
|||
|
|
|||
|
NULL: not enough memory to allocate the structure
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
ULONG Utf8DnsHostNameSize;
|
|||
|
ULONG DnsRecordNameSize;
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a structure to represent this name.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsARecord( NlDnsNameType ) ) {
|
|||
|
Utf8DnsHostNameSize = 0;
|
|||
|
} else {
|
|||
|
Utf8DnsHostNameSize = strlen(DnsHostName) + 1;
|
|||
|
}
|
|||
|
DnsRecordNameSize = strlen( DnsRecordName ) + 1;
|
|||
|
|
|||
|
NlDnsName = LocalAlloc( LMEM_ZEROINIT, sizeof( NL_DNS_NAME ) +
|
|||
|
Utf8DnsHostNameSize +
|
|||
|
DnsRecordNameSize );
|
|||
|
|
|||
|
if ( NlDnsName == NULL ) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
Where = (LPBYTE)(NlDnsName+1);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize it and link it in.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName->NlDnsNameType = NlDnsNameType;
|
|||
|
|
|||
|
NlDnsName->DnsRecordName = Where;
|
|||
|
RtlCopyMemory( Where, DnsRecordName, DnsRecordNameSize );
|
|||
|
Where += DnsRecordNameSize;
|
|||
|
|
|||
|
|
|||
|
if ( NlDnsARecord( NlDnsNameType ) ) {
|
|||
|
NlDnsName->IpAddress = IpAddress;
|
|||
|
|
|||
|
} else if ( NlDnsCnameRecord( NlDnsNameType ) ) {
|
|||
|
NlDnsName->DnsHostName = Where;
|
|||
|
RtlCopyMemory( Where, DnsHostName, Utf8DnsHostNameSize );
|
|||
|
// Where += Utf8DnsHostNameSize;
|
|||
|
|
|||
|
} else {
|
|||
|
NlDnsName->Priority = Priority;
|
|||
|
NlDnsName->Port = Port;
|
|||
|
NlDnsName->Weight = Weight;
|
|||
|
|
|||
|
NlDnsName->DnsHostName = Where;
|
|||
|
RtlCopyMemory( Where, DnsHostName, Utf8DnsHostNameSize );
|
|||
|
// Where += Utf8DnsHostNameSize;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// There is a reference for being on the global list
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName->NlDnsNameRefCount = 1;
|
|||
|
|
|||
|
NlDnsName->State = State;
|
|||
|
NlGlobalDnsListDirty = TRUE;
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
InsertTailList(&NlGlobalDnsList, &NlDnsName->Next);
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
return NlDnsName;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsWriteLog(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Write the list of registered DNS names to
|
|||
|
%SystemRoot%\System32\Config\netlogon.dns.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
LPWSTR AllocatedBuffer = NULL;
|
|||
|
LPWSTR FileName;
|
|||
|
|
|||
|
LPSTR DnsRecord;
|
|||
|
LPSTR DnsName;
|
|||
|
|
|||
|
UINT WindowsDirectoryLength;
|
|||
|
HANDLE FileHandle = INVALID_HANDLE_VALUE;
|
|||
|
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
if ( !NlGlobalDnsListDirty ) {
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer for storage local to this procedure.
|
|||
|
// (Don't put it on the stack since we don't want to commit a huge stack.)
|
|||
|
//
|
|||
|
|
|||
|
AllocatedBuffer = LocalAlloc( 0, sizeof(WCHAR) * (MAX_PATH+1) +
|
|||
|
NL_MAX_DNS_LENGTH+1 +
|
|||
|
NL_DNS_RECORD_STRING_SIZE + 1 );
|
|||
|
|
|||
|
if ( AllocatedBuffer == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
FileName = AllocatedBuffer;
|
|||
|
DnsName = (LPSTR)(&AllocatedBuffer[MAX_PATH+1]);
|
|||
|
DnsRecord = &DnsName[NL_MAX_DNS_LENGTH+1];
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Write the binary version of the log first.
|
|||
|
//
|
|||
|
NlDnsWriteBinaryLog();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Build the name of the log file
|
|||
|
//
|
|||
|
|
|||
|
WindowsDirectoryLength = GetSystemWindowsDirectoryW(
|
|||
|
FileName,
|
|||
|
sizeof(WCHAR) * (MAX_PATH+1) );
|
|||
|
|
|||
|
if ( WindowsDirectoryLength == 0 ) {
|
|||
|
|
|||
|
NetStatus = GetLastError();
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsWriteLog: Unable to GetSystemWindowsDirectoryW (%ld)\n",
|
|||
|
NetStatus ));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( WindowsDirectoryLength * sizeof(WCHAR) +
|
|||
|
sizeof(WCHAR) +
|
|||
|
sizeof(NL_DNS_LOG_FILE)
|
|||
|
>= sizeof(WCHAR) * MAX_PATH ) {
|
|||
|
|
|||
|
NlPrint((NL_CRITICAL,
|
|||
|
"NlDnsWriteLog: file name length is too long \n" ));
|
|||
|
goto Cleanup;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
wcscat( FileName, NL_DNS_LOG_FILE );
|
|||
|
|
|||
|
//
|
|||
|
// Create a file to write to.
|
|||
|
// If it exists already then truncate it.
|
|||
|
//
|
|||
|
|
|||
|
FileHandle = CreateFileW(
|
|||
|
FileName,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ, // allow backups and debugging
|
|||
|
NULL, // Supply better security ??
|
|||
|
CREATE_ALWAYS, // Overwrites always
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
NULL ); // No template
|
|||
|
|
|||
|
if ( FileHandle == INVALID_HANDLE_VALUE) {
|
|||
|
LPWSTR MsgStrings[2];
|
|||
|
|
|||
|
NetStatus = GetLastError();
|
|||
|
NlPrint((NL_CRITICAL,
|
|||
|
"NlDnsWriteLog: %ws: Unable to create file: %ld \n",
|
|||
|
FileName,
|
|||
|
NetStatus));
|
|||
|
|
|||
|
MsgStrings[0] = FileName;
|
|||
|
MsgStrings[1] = (LPWSTR) UlongToPtr( NetStatus );
|
|||
|
|
|||
|
NlpWriteEventlog (NELOG_NetlogonFailedFileCreate,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
(LPBYTE) &NetStatus,
|
|||
|
sizeof(NetStatus),
|
|||
|
MsgStrings,
|
|||
|
2 | NETP_LAST_MESSAGE_IS_NETSTATUS );
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of DNS names writing each one to the log
|
|||
|
//
|
|||
|
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
ULONG DnsRecordLength;
|
|||
|
ULONG BytesWritten;
|
|||
|
|
|||
|
//
|
|||
|
// If this entry really doesn't exist,
|
|||
|
// comment it out.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is marked for deletion,
|
|||
|
// skip it (we must have successfully
|
|||
|
// deregistered it and only need to
|
|||
|
// delink and free this entry).
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
DnsRecord[0] = '\0';
|
|||
|
switch (NlDnsName->State) {
|
|||
|
case RegisterMe:
|
|||
|
case Registered:
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsWriteLog: %ld: Invalid state\n",
|
|||
|
NlDnsName->State ));
|
|||
|
/* Drop through */
|
|||
|
case DeregisterMe:
|
|||
|
case DelayedDeregister:
|
|||
|
strcat( DnsRecord, "; " );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create the text string to write.
|
|||
|
//
|
|||
|
NlDnsNameToStr( NlDnsName, DnsRecord );
|
|||
|
strcat( DnsRecord, NL_DNS_RR_EOL );
|
|||
|
|
|||
|
//
|
|||
|
// Write the record to the file.
|
|||
|
//
|
|||
|
DnsRecordLength = strlen( DnsRecord );
|
|||
|
|
|||
|
if ( !WriteFile( FileHandle,
|
|||
|
DnsRecord,
|
|||
|
DnsRecordLength,
|
|||
|
&BytesWritten,
|
|||
|
NULL ) ) { // Not Overlapped
|
|||
|
|
|||
|
NetStatus = GetLastError();
|
|||
|
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsWriteLog: %ws: Unable to WriteFile. %ld\n",
|
|||
|
FileName,
|
|||
|
NetStatus ));
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( BytesWritten != DnsRecordLength) {
|
|||
|
NlPrint((NL_CRITICAL,
|
|||
|
"NlDnsWriteLog: %ws: Write bad byte count %ld s.b. %ld\n",
|
|||
|
FileName,
|
|||
|
BytesWritten,
|
|||
|
DnsRecordLength ));
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NlGlobalDnsListDirty = FALSE;
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ( FileHandle != INVALID_HANDLE_VALUE ) {
|
|||
|
CloseHandle( FileHandle );
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
if ( AllocatedBuffer != NULL ) {
|
|||
|
LocalFree(AllocatedBuffer);
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
NlDnsHasDnsServers(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns TRUE if this machine has one or more DNS servers configured.
|
|||
|
|
|||
|
If FALSE, it is highly unlikely that DNS name resolution will work.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE: This machine has one or more DNS servers configured.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN RetVal;
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
PDNS_RECORD DnsARecords = NULL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If there are no IP addresses,
|
|||
|
// there are no DNS servers.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalWinsockPnpAddresses == NULL ) {
|
|||
|
|
|||
|
RetVal = FALSE;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Try getting the A records for the DNS servers from DNS
|
|||
|
//
|
|||
|
// REVIEW: consider having DNS notify us when the DNS server state changes.
|
|||
|
// Then we wouldn't have to bother DNS each time we need to know.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DnsQuery_UTF8(
|
|||
|
"", // Ask for addresses of the DNS servers
|
|||
|
DNS_TYPE_A,
|
|||
|
0, // No special flags
|
|||
|
NULL, // No list of DNS servers
|
|||
|
&DnsARecords,
|
|||
|
NULL );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
RetVal = FALSE;
|
|||
|
} else {
|
|||
|
RetVal = (DnsARecords != NULL);
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsARecords != NULL ) {
|
|||
|
DnsRecordListFree( DnsARecords, DnsFreeRecordListDeep );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return RetVal;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
NlDnsCheckLastStatus(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Query the status of DNS updates for all records as they
|
|||
|
were registered/deregistered last time.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE if there was no error for last DNS updates
|
|||
|
for all records. Otherwise returns FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
|
|||
|
BOOL Result = TRUE;
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
if ( NlDnsName->State != DeleteMe &&
|
|||
|
NlDnsName->NlDnsNameLastStatus != NO_ERROR ) {
|
|||
|
Result = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsServerFailureOutputCheck(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Check if it's OK to write DNS server failure event logs
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SC_HANDLE ScManagerHandle = NULL;
|
|||
|
SC_HANDLE ServiceHandle = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// If we have already determined on any previous
|
|||
|
// start on this boot that we should write the
|
|||
|
// event log, there is nothing we need to check.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsWriteServerFailureEventLog ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the service controller to see
|
|||
|
// whether the DNS service exists
|
|||
|
//
|
|||
|
|
|||
|
ScManagerHandle = OpenSCManager(
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
SC_MANAGER_CONNECT );
|
|||
|
|
|||
|
//
|
|||
|
// If we couldn't open the SC,
|
|||
|
// proceed with checking the timeout
|
|||
|
//
|
|||
|
|
|||
|
if ( ScManagerHandle == NULL ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsServerFailureOutputCheck: OpenSCManager failed: 0x%lx\n",
|
|||
|
GetLastError()));
|
|||
|
} else {
|
|||
|
ServiceHandle = OpenService(
|
|||
|
ScManagerHandle,
|
|||
|
L"DNS",
|
|||
|
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
|
|||
|
|
|||
|
(VOID) CloseServiceHandle( ScManagerHandle );
|
|||
|
|
|||
|
//
|
|||
|
// If DNS service does not exits locally,
|
|||
|
// we should write DNS server failure errors
|
|||
|
//
|
|||
|
if ( ServiceHandle == NULL ) {
|
|||
|
if ( GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST ) {
|
|||
|
NlDnsWriteServerFailureEventLog = TRUE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Service exists. Proceed with checking the timeout
|
|||
|
//
|
|||
|
} else {
|
|||
|
(VOID) CloseServiceHandle( ServiceHandle );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is not the first time we have been started or
|
|||
|
// the timeout has elapsed, it is time to write event errors
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsInitCount > 1 ||
|
|||
|
NetpDcElapsedTime(NlGlobalDnsStartTime) > NL_DNS_EVENTLOG_TIMEOUT ) {
|
|||
|
NlDnsWriteServerFailureEventLog = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsUpdate(
|
|||
|
IN PNL_DNS_NAME NlDnsName,
|
|||
|
IN BOOLEAN Register
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does the actual call to DNS to register or deregister a name.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsName - Name to register or deregister.
|
|||
|
|
|||
|
Register - True to register the name.
|
|||
|
False to deregister the name.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: The name was registered or deregistered.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
DNS_RECORD DnsRecord;
|
|||
|
LPWSTR MsgStrings[3];
|
|||
|
ULONG DnsUpdateFlags = DNS_UPDATE_SECURITY_USE_DEFAULT;
|
|||
|
DNS_FAILED_UPDATE_INFO DnsFailedUpdateInfo;
|
|||
|
WCHAR DnsServerIpAddressString[NL_IP_ADDRESS_LENGTH+1];
|
|||
|
|
|||
|
static BOOL NetlogonNoDynamicDnsLogged = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Don't let the service controller think we've hung.
|
|||
|
//
|
|||
|
if ( !GiveInstallHints( FALSE ) ) {
|
|||
|
NetStatus = ERROR_DNS_NOT_CONFIGURED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If dynamic DNS is manually disabled,
|
|||
|
// warn the user to update DNS manually.
|
|||
|
// But do not abuse the event log, write only once
|
|||
|
//
|
|||
|
if ( !NlGlobalParameters.UseDynamicDns ) {
|
|||
|
NetStatus = ERROR_DYNAMIC_DNS_NOT_SUPPORTED;
|
|||
|
|
|||
|
if ( !NetlogonNoDynamicDnsLogged ) {
|
|||
|
NlpWriteEventlog( NELOG_NetlogonNoDynamicDns,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
(LPBYTE) &NetStatus,
|
|||
|
sizeof(NetStatus),
|
|||
|
NULL,
|
|||
|
0 );
|
|||
|
|
|||
|
NetlogonNoDynamicDnsLogged = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
|
|||
|
//
|
|||
|
// Otherwise, reset the boolean to account for the case when
|
|||
|
// dynamic DNS being disabled gets enabled and then disabled again.
|
|||
|
//
|
|||
|
} else {
|
|||
|
NetlogonNoDynamicDnsLogged = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build the common parts of the RR.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory( &DnsRecord, sizeof(DnsRecord) );
|
|||
|
DnsRecord.pNext = NULL;
|
|||
|
DnsRecord.pName = (LPTSTR) NlDnsName->DnsRecordName;
|
|||
|
DnsRecord.dwTtl = NlGlobalParameters.DnsTtl;
|
|||
|
|
|||
|
//
|
|||
|
// Build an A RR
|
|||
|
//
|
|||
|
if ( NlDnsARecord( NlDnsName->NlDnsNameType ) ) {
|
|||
|
DnsRecord.wType = DNS_TYPE_A;
|
|||
|
DnsRecord.wDataLength = sizeof( DNS_A_DATA );
|
|||
|
DnsRecord.Data.A.IpAddress = NlDnsName->IpAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Build a CNAME RR
|
|||
|
//
|
|||
|
} else if ( NlDnsCnameRecord( NlDnsName->NlDnsNameType ) ) {
|
|||
|
DnsRecord.wType = DNS_TYPE_CNAME;
|
|||
|
DnsRecord.wDataLength = sizeof( DNS_PTR_DATA );
|
|||
|
DnsRecord.Data.CNAME.pNameHost = (LPTSTR) NlDnsName->DnsHostName;
|
|||
|
|
|||
|
//
|
|||
|
// Build a SRV RR
|
|||
|
//
|
|||
|
} else {
|
|||
|
DnsRecord.wType = DNS_TYPE_SRV;
|
|||
|
DnsRecord.wDataLength = sizeof( DNS_SRV_DATA );
|
|||
|
DnsRecord.Data.SRV.pNameTarget = (LPTSTR) NlDnsName->DnsHostName;
|
|||
|
DnsRecord.Data.SRV.wPriority = (WORD) NlDnsName->Priority;
|
|||
|
DnsRecord.Data.SRV.wWeight = (WORD) NlDnsName->Weight;
|
|||
|
DnsRecord.Data.SRV.wPort = (WORD) NlDnsName->Port;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Tell DNS to skip adapters where dynamic DNS updates
|
|||
|
// are disabled unless we are instructed otherwise
|
|||
|
//
|
|||
|
if ( !NlGlobalParameters.DnsUpdateOnAllAdapters ) {
|
|||
|
DnsUpdateFlags |= DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call DNS to do the update.
|
|||
|
//
|
|||
|
|
|||
|
if ( Register ) {
|
|||
|
|
|||
|
// According to RFC 2136 (and bug 173936) we need to replace the RRSet for
|
|||
|
// CNAME records to avoid an error if other records exist by the
|
|||
|
// same name.
|
|||
|
//
|
|||
|
// Note that the dynamic DNS RFC says that CNAME records ALWAYS overwrite the
|
|||
|
// existing single record (ignoring the DNS_UPDATE_SHARED).
|
|||
|
//
|
|||
|
// Also, replace the record if this is a PDC name (there should be only one PDC)
|
|||
|
//
|
|||
|
if ( NlDnsCnameRecord( NlDnsName->NlDnsNameType ) ||
|
|||
|
NlDnsPdcName( NlDnsName->NlDnsNameType ) ) {
|
|||
|
NetStatus = DnsReplaceRecordSetUTF8(
|
|||
|
&DnsRecord, // New record set
|
|||
|
DnsUpdateFlags,
|
|||
|
NULL, // No context handle
|
|||
|
NULL, // All DNS servers
|
|||
|
NULL ); // reserved
|
|||
|
} else {
|
|||
|
NetStatus = DnsModifyRecordsInSet_UTF8(
|
|||
|
&DnsRecord, // Add record
|
|||
|
NULL, // No delete records
|
|||
|
DnsUpdateFlags,
|
|||
|
NULL, // No context handle
|
|||
|
NULL, // All DNS servers
|
|||
|
NULL ); // reserved
|
|||
|
}
|
|||
|
} else {
|
|||
|
NetStatus = DnsModifyRecordsInSet_UTF8(
|
|||
|
NULL, // No add records
|
|||
|
&DnsRecord, // Delete this record
|
|||
|
DnsUpdateFlags,
|
|||
|
NULL, // No context handle
|
|||
|
NULL, // All DNS servers
|
|||
|
NULL ); // reserved
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the status codes to ones we understand.
|
|||
|
//
|
|||
|
|
|||
|
switch ( NetStatus ) {
|
|||
|
case NO_ERROR:
|
|||
|
NlDnsName->NlDnsNameLastStatus = NetStatus;
|
|||
|
break;
|
|||
|
|
|||
|
case ERROR_TIMEOUT: // DNS server isn't available
|
|||
|
case DNS_ERROR_RCODE_SERVER_FAILURE: // Server failed
|
|||
|
|
|||
|
//
|
|||
|
// Don't log an error specific to the DnsRecordName since all of them
|
|||
|
// are probably going to fail.
|
|||
|
//
|
|||
|
if ( NlDnsWriteServerFailureEventLog ) {
|
|||
|
NlDnsName->NlDnsNameLastStatus = NetStatus;
|
|||
|
|
|||
|
NlpWriteEventlog( NELOG_NetlogonDynamicDnsServerFailure,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
(LPBYTE) &NetStatus,
|
|||
|
sizeof(NetStatus),
|
|||
|
NULL,
|
|||
|
0 );
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = ERROR_DNS_NOT_AVAILABLE;
|
|||
|
break;
|
|||
|
|
|||
|
case DNS_ERROR_NO_TCPIP: // TCP/IP not configured
|
|||
|
case DNS_ERROR_NO_DNS_SERVERS: // DNS not configured
|
|||
|
case WSAEAFNOSUPPORT: // Winsock Address Family not supported ??
|
|||
|
|
|||
|
NlDnsName->NlDnsNameLastStatus = NetStatus;
|
|||
|
|
|||
|
MsgStrings[0] = (LPWSTR) UlongToPtr( NetStatus );
|
|||
|
|
|||
|
// Don't log an error specific to the DnsRecordName since all of them
|
|||
|
// are probably going to fail.
|
|||
|
NlpWriteEventlog( NELOG_NetlogonDynamicDnsFailure,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
(LPBYTE) &NetStatus,
|
|||
|
sizeof(NetStatus),
|
|||
|
MsgStrings,
|
|||
|
1 | NETP_LAST_MESSAGE_IS_NETSTATUS );
|
|||
|
|
|||
|
NetStatus = ERROR_DNS_NOT_CONFIGURED;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
NlDnsName->NlDnsNameLastStatus = NetStatus;
|
|||
|
|
|||
|
RtlZeroMemory( &DnsFailedUpdateInfo, sizeof(DnsFailedUpdateInfo) );
|
|||
|
RtlZeroMemory( DnsServerIpAddressString, sizeof(DnsServerIpAddressString) );
|
|||
|
|
|||
|
DnsGetLastFailedUpdateInfo( &DnsFailedUpdateInfo );
|
|||
|
|
|||
|
if ( DnsFailedUpdateInfo.Ip4Address != 0 ) {
|
|||
|
NetpIpAddressToWStr( DnsFailedUpdateInfo.Ip4Address,
|
|||
|
DnsServerIpAddressString );
|
|||
|
} else {
|
|||
|
wcsncpy( DnsServerIpAddressString,
|
|||
|
L"<UNAVAILABLE>",
|
|||
|
sizeof(DnsServerIpAddressString)/sizeof(WCHAR) - 1 );
|
|||
|
}
|
|||
|
|
|||
|
MsgStrings[0] = DnsServerIpAddressString;
|
|||
|
|
|||
|
// Old server that doesn't understand dynamic DNS
|
|||
|
if ( NetStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
|
|||
|
NlpWriteEventlog( NELOG_NetlogonNoDynamicDns,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
(LPBYTE) &DnsFailedUpdateInfo.Rcode,
|
|||
|
sizeof(DnsFailedUpdateInfo.Rcode),
|
|||
|
MsgStrings,
|
|||
|
1 );
|
|||
|
|
|||
|
NetStatus = ERROR_DYNAMIC_DNS_NOT_SUPPORTED;
|
|||
|
|
|||
|
// All other errors
|
|||
|
} else {
|
|||
|
MsgStrings[1] = NlDnsNameToWStr( NlDnsName );
|
|||
|
if ( MsgStrings[1] != NULL ) {
|
|||
|
MsgStrings[2] = (LPWSTR) UlongToPtr( NetStatus );
|
|||
|
|
|||
|
NlpWriteEventlog( Register ?
|
|||
|
NELOG_NetlogonDynamicDnsRegisterFailure :
|
|||
|
NELOG_NetlogonDynamicDnsDeregisterFailure,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
(LPBYTE) &DnsFailedUpdateInfo.Rcode,
|
|||
|
sizeof(DnsFailedUpdateInfo.Rcode),
|
|||
|
MsgStrings,
|
|||
|
3 | NETP_LAST_MESSAGE_IS_NETSTATUS );
|
|||
|
|
|||
|
NetApiBufferFree( MsgStrings[1] );
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute when we want to try this name again.
|
|||
|
//
|
|||
|
|
|||
|
Cleanup:
|
|||
|
NlQuerySystemTime( &NlDnsName->ScavengeTimer.StartTime );
|
|||
|
|
|||
|
if ( NlDnsName->ScavengeTimer.Period == 0 ) {
|
|||
|
NlDnsName->ScavengeTimer.Period = min( ORIG_DNS_SCAVENGE_PERIOD, NlGlobalParameters.DnsRefreshIntervalPeriod );
|
|||
|
} else if ( NlDnsName->ScavengeTimer.Period < NlGlobalParameters.DnsRefreshIntervalPeriod / 2 ) {
|
|||
|
NlDnsName->ScavengeTimer.Period *= 2;
|
|||
|
} else {
|
|||
|
NlDnsName->ScavengeTimer.Period = NlGlobalParameters.DnsRefreshIntervalPeriod;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this period is shorter than that of the scavenger timer,
|
|||
|
// reset the scavenger timer.
|
|||
|
//
|
|||
|
EnterCriticalSection( &NlGlobalScavengerCritSect );
|
|||
|
if ( NlDnsName->ScavengeTimer.Period < NlGlobalDnsScavengerTimer.Period ) {
|
|||
|
|
|||
|
NlGlobalDnsScavengerTimer = NlDnsName->ScavengeTimer;
|
|||
|
NlPrint(( NL_DNS_MORE,
|
|||
|
"NlDnsUpdate: Set DNS scavenger to run in %ld minutes (%ld).\n",
|
|||
|
(NlGlobalDnsScavengerTimer.Period+59999)/60000,
|
|||
|
NlGlobalDnsScavengerTimer.Period ));
|
|||
|
|
|||
|
if ( !SetEvent( NlGlobalTimerEvent ) ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsUpdate: SetEvent failed %ld\n",
|
|||
|
GetLastError() ));
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalScavengerCritSect );
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsRegisterOne(
|
|||
|
IN PNL_DNS_CONTEXT NlDnsContext,
|
|||
|
IN PNL_DNS_NAME NlDnsName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine registers a SRV record for a particular name with DNS.
|
|||
|
|
|||
|
Name must be referenced by the caller
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsContext - Context describing a series of registrations or deregistration
|
|||
|
|
|||
|
NlDnsName - Structure describing name to register.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: The name was registered
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon is shutting down,
|
|||
|
// or Netlogon is starting and the name was added before anyway,
|
|||
|
// and we've already spent a long time doing this batch of DNS records,
|
|||
|
// just give up.
|
|||
|
//
|
|||
|
|
|||
|
if ( (NlGlobalTerminate ||
|
|||
|
(NlGlobalChangeLogNetlogonState == NetlogonStarting &&
|
|||
|
(NlDnsName->Flags & NL_DNS_REGISTERED_ONCE) != 0 ) ) &&
|
|||
|
NetpDcElapsedTime(NlDnsContext->StartTime) > NL_DNS_THRESHOLD ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsRegisterOne: DNS really slow during startup. (Registration skipped) %ld",
|
|||
|
NetpDcElapsedTime(NlDnsContext->StartTime) ));
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Register the name with DNS
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NlDnsUpdate( NlDnsName, TRUE );
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Mark that the name is really registered.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsSetState( NlDnsName, Registered );
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterOne: registered (success)" ));
|
|||
|
|
|||
|
//
|
|||
|
// If DNS is not configured on this machine,
|
|||
|
// silently ignore the error.
|
|||
|
//
|
|||
|
} else if ( NetStatus == ERROR_DNS_NOT_CONFIGURED ) {
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterOne: not registered (dns not configured)" ));
|
|||
|
|
|||
|
//
|
|||
|
// If the DNS server cannot be reached at this time,
|
|||
|
// simply don't mark the name as registered. We'll register it later.
|
|||
|
//
|
|||
|
} else if ( NetStatus == ERROR_DNS_NOT_AVAILABLE ) {
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterOne: not registered (dns server not available)" ));
|
|||
|
|
|||
|
//
|
|||
|
// If Dynamic Dns is not supported,
|
|||
|
// complain so the names can be added manually.
|
|||
|
//
|
|||
|
|
|||
|
} else if ( NetStatus == ERROR_DYNAMIC_DNS_NOT_SUPPORTED ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterOne: not registered (dynamic dns not supported)" ));
|
|||
|
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsRegisterName(
|
|||
|
IN PNL_DNS_CONTEXT NlDnsContext,
|
|||
|
IN PDOMAIN_INFO DomainInfo,
|
|||
|
IN NL_DNS_NAME_TYPE NlDnsNameType,
|
|||
|
IN LPWSTR SiteName,
|
|||
|
IN ULONG IpAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine registers a particular name with DNS.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsContext - Context describing a series of registrations or deregistration
|
|||
|
|
|||
|
DomainInfo - Domain the name is to be registered for.
|
|||
|
|
|||
|
NlDnsNameType - The specific type of name to be registered.
|
|||
|
|
|||
|
SiteName - If NlDnsNameType is any of the *AtSite values,
|
|||
|
the site name of the site this name is registered for.
|
|||
|
|
|||
|
IpAddress - If NlDnsNameType is NlDnsLdapIpAddress or NlDnsGcIpAddress,
|
|||
|
the IP address of the DC.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: The name was registered or queued to be registered.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
CHAR DnsRecordName[NL_MAX_DNS_LENGTH+1];
|
|||
|
PNL_DNS_NAME NlDnsName = NULL;
|
|||
|
PNL_DNS_NAME FoundNlDnsName = NULL;
|
|||
|
ULONG Weight;
|
|||
|
ULONG Port;
|
|||
|
ULONG Priority;
|
|||
|
ULONG LoopCount;
|
|||
|
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If there is no DNS domain name for this domain,
|
|||
|
// silently return;
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainInfo->DomUtf8DnsDomainName == NULL ) {
|
|||
|
NlPrintDom(( NL_DNS, DomainInfo,
|
|||
|
"NlDnsRegister: %ws: Domain has no DNS domain name (silently return)\n",
|
|||
|
NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is a SRV or CNAME record,
|
|||
|
// require that there is a dns host name.
|
|||
|
//
|
|||
|
|
|||
|
if ( (NlDnsSrvRecord( NlDnsNameType ) || NlDnsCnameRecord( NlDnsNameType ) ) &&
|
|||
|
DomainInfo->DomUtf8DnsHostName == NULL ) {
|
|||
|
NlPrintDom(( NL_DNS, DomainInfo,
|
|||
|
"NlDnsRegister: %ws: Domain has no DNS host name (silently return)\n",
|
|||
|
NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Grab the parameters we're going to register.
|
|||
|
//
|
|||
|
|
|||
|
Priority = NlGlobalParameters.LdapSrvPriority;
|
|||
|
Weight = NlGlobalParameters.LdapSrvWeight;
|
|||
|
|
|||
|
if ( NlDnsGcName( NlDnsNameType ) ) {
|
|||
|
Port = NlGlobalParameters.LdapGcSrvPort;
|
|||
|
} else if ( NlDnsKpwdRecord( NlDnsNameType )) {
|
|||
|
Port = 464;
|
|||
|
} else if ( NlDnsKdcRecord( NlDnsNameType ) ) {
|
|||
|
Port = NlGlobalParameters.KdcSrvPort;
|
|||
|
} else {
|
|||
|
Port = NlGlobalParameters.LdapSrvPort;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Register the record for the name and for the name alias, if any
|
|||
|
//
|
|||
|
|
|||
|
for ( LoopCount = 0; LoopCount < 2; LoopCount++ ) {
|
|||
|
NlDnsName = NULL;
|
|||
|
FoundNlDnsName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Build the name of this DNS record.
|
|||
|
//
|
|||
|
// On the first loop iteration, build the active name.
|
|||
|
// On the second loop iteration, build the name alias, if any.
|
|||
|
//
|
|||
|
NetStatus = NlDnsBuildName( DomainInfo,
|
|||
|
NlDnsNameType,
|
|||
|
SiteName,
|
|||
|
(LoopCount == 0) ?
|
|||
|
FALSE : // active name
|
|||
|
TRUE, // name alias
|
|||
|
DnsRecordName );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// If the domain has no DNS domain name,
|
|||
|
// simply bypass the name registration forever.
|
|||
|
//
|
|||
|
if ( NetStatus == ERROR_NO_SUCH_DOMAIN ) {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegisterName: %ws: NlDnsBuildName indicates something is missing and this DNS name cannot be built (ignored)\n",
|
|||
|
NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
|
|||
|
return NO_ERROR;
|
|||
|
} else {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegisterName: %ws: Cannot NlDnsBuildName %ld\n",
|
|||
|
NlDcDnsNameTypeDesc[NlDnsNameType].Name,
|
|||
|
NetStatus ));
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this name doesn't exist, skip it
|
|||
|
//
|
|||
|
if ( *DnsRecordName == '\0' ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of DNS names finding any that match the one we're
|
|||
|
// about to register.
|
|||
|
//
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
) {
|
|||
|
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is marked for deletion,
|
|||
|
// skip it
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Increase the ref count because we
|
|||
|
// potentially mark this entry for deletion below
|
|||
|
//
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// The names will only be equal if the name types are equal,
|
|||
|
// the domains are compatible (equal or not specified),
|
|||
|
// and the DnsRecordName is identical.
|
|||
|
//
|
|||
|
// This first test sees if the record "identifies" the same record.
|
|||
|
//
|
|||
|
//
|
|||
|
if ( NlDnsName->NlDnsNameType == NlDnsNameType &&
|
|||
|
(NlDnsName->DomainInfo == DomainInfo ||
|
|||
|
NlDnsName->DomainInfo == NULL ) &&
|
|||
|
NlDnsName->IpAddress == IpAddress &&
|
|||
|
NlEqualDnsNameUtf8( DnsRecordName, NlDnsName->DnsRecordName ) ) {
|
|||
|
|
|||
|
BOOLEAN Identical;
|
|||
|
BOOLEAN DeleteIt;
|
|||
|
|
|||
|
//
|
|||
|
// Assume the records are identical.
|
|||
|
//
|
|||
|
// This second test sees if any of the "data" portion of the record
|
|||
|
// changes.
|
|||
|
//
|
|||
|
// The Dynamic DNS RFC says that the Ttl field isn't used to
|
|||
|
// distiguish the record. So, ignore it here knowing we'll
|
|||
|
// simply re-register with the new value if the Ttl has changed.
|
|||
|
//
|
|||
|
|
|||
|
DeleteIt = FALSE;
|
|||
|
Identical = TRUE;
|
|||
|
|
|||
|
// Compare A records
|
|||
|
if ( NlDnsARecord( NlDnsNameType ) ) {
|
|||
|
// Nothing else to compare
|
|||
|
|
|||
|
// Compare CNAME records
|
|||
|
} else if ( NlDnsCnameRecord( NlDnsNameType ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// The Dynamic DNS RFC says that the host name part of the
|
|||
|
// CNAME record isn't used for comparison purposes. There
|
|||
|
// can only be one record for a particular name.
|
|||
|
// So, if the host name is different, simply ditch this entry and
|
|||
|
// allocate a new one with the right host name.
|
|||
|
//
|
|||
|
if ( !NlEqualDnsNameUtf8( DomainInfo->DomUtf8DnsHostName, NlDnsName->DnsHostName )) {
|
|||
|
DeleteIt = TRUE;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterName: CNAME Host not equal. %s %s",
|
|||
|
DomainInfo->DomUtf8DnsHostName,
|
|||
|
NlDnsName->DnsHostName ));
|
|||
|
}
|
|||
|
|
|||
|
// Compare SRV records
|
|||
|
} else {
|
|||
|
if ( NlDnsName->Priority != Priority ) {
|
|||
|
Identical = FALSE;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterName: Priority not equal. %ld %ld",
|
|||
|
NlDnsName->Priority,
|
|||
|
Priority ));
|
|||
|
} else if ( NlDnsName->Port != Port ) {
|
|||
|
Identical = FALSE;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterName: Port not equal. %ld %ld",
|
|||
|
NlDnsName->Port,
|
|||
|
Port ));
|
|||
|
} else if ( NlDnsName->Weight != Weight ) {
|
|||
|
Identical = FALSE;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterName: Weight not equal. %ld %ld",
|
|||
|
NlDnsName->Weight,
|
|||
|
Weight ));
|
|||
|
} else if ( !NlEqualDnsNameUtf8( DomainInfo->DomUtf8DnsHostName, NlDnsName->DnsHostName )) {
|
|||
|
Identical = FALSE;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS_MORE, NlDnsName,
|
|||
|
"NlDnsRegisterName: Host not equal. %s %s",
|
|||
|
DomainInfo->DomUtf8DnsHostName,
|
|||
|
NlDnsName->DnsHostName ));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the entry should simply be deleted,
|
|||
|
// do so now.
|
|||
|
//
|
|||
|
|
|||
|
if ( DeleteIt ) {
|
|||
|
|
|||
|
NlDnsSetState( NlDnsName, DeleteMe );
|
|||
|
|
|||
|
NlPrintDns(( NL_CRITICAL, NlDnsName,
|
|||
|
"NlDnsRegisterName: Annoying entry found (recovering)" ));
|
|||
|
//
|
|||
|
// If this is the exact record,
|
|||
|
// simply mark it for registration.
|
|||
|
//
|
|||
|
|
|||
|
} else if ( Identical ) {
|
|||
|
|
|||
|
//
|
|||
|
// If this is the second such entry we've found,
|
|||
|
// this is an internal error.
|
|||
|
// But recover by deleting the entry.
|
|||
|
//
|
|||
|
|
|||
|
if ( FoundNlDnsName != NULL ) {
|
|||
|
|
|||
|
NlDnsSetState( NlDnsName, DeleteMe );
|
|||
|
|
|||
|
NlPrintDns(( NL_CRITICAL, NlDnsName,
|
|||
|
"NlDnsRegisterName: Duplicate entry found (recovering)" ));
|
|||
|
} else {
|
|||
|
|
|||
|
if ( NlDnsName->State != Registered ) {
|
|||
|
NlDnsSetState( NlDnsName, RegisterMe );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// DomainInfo might be NULL if this was a record marked for
|
|||
|
// deletion.
|
|||
|
//
|
|||
|
NlDnsName->DomainInfo = DomainInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Cooperate with NlDnsRegisterDomain and tell it that
|
|||
|
// this entry can be kept.
|
|||
|
//
|
|||
|
NlDnsName->Flags &= ~NL_DNS_REGISTER_DOMAIN;
|
|||
|
|
|||
|
FoundNlDnsName = NlDnsName;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this record isn't exact,
|
|||
|
// deregister the previous value.
|
|||
|
//
|
|||
|
// Don't scavenge yet. We'll pick this up when the scavenger gets
|
|||
|
// around to running.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
NlDnsSetState( NlDnsName, DeregisterMe );
|
|||
|
|
|||
|
NlPrintDns(( NL_CRITICAL, NlDnsName,
|
|||
|
"NlDnsRegisterName: Similar entry found and marked for deregistration" ));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Grab the pointer to the next entry
|
|||
|
// before dereferencing this entry as we
|
|||
|
// may delink this entry upon dereferencing
|
|||
|
//
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the name was found,
|
|||
|
// use it.
|
|||
|
|
|||
|
if ( FoundNlDnsName != NULL ) {
|
|||
|
NlDnsName = FoundNlDnsName;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If not,
|
|||
|
// allocate the structure now.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
NlDnsName = NlDnsAllocateEntry(
|
|||
|
NlDnsNameType,
|
|||
|
DnsRecordName,
|
|||
|
Priority,
|
|||
|
Weight,
|
|||
|
Port,
|
|||
|
DomainInfo->DomUtf8DnsHostName,
|
|||
|
IpAddress,
|
|||
|
RegisterMe );
|
|||
|
|
|||
|
if ( NlDnsName == NULL ) {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegister: %ws: Cannot allocate DnsName structure\n",
|
|||
|
NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
NlDnsName->DomainInfo = DomainInfo;
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsRegister: registering name" ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Increase the ref count so that this entry
|
|||
|
// doesn't get deleted behind our back
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// Scavenge now to attempt to register the name.
|
|||
|
//
|
|||
|
// Avoid having crit sect locked while doing network IO
|
|||
|
//
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlDnsScavengeOne( NlDnsContext, NlDnsName );
|
|||
|
|
|||
|
//
|
|||
|
// Now it's safe to remove our reference
|
|||
|
//
|
|||
|
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
}
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsDeregisterOne(
|
|||
|
IN PNL_DNS_CONTEXT NlDnsContext,
|
|||
|
IN PNL_DNS_NAME NlDnsName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine deregisters a the SRV record for a particular name with DNS.
|
|||
|
|
|||
|
Name must be referenced by the caller
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsContext - Context describing a series of registrations or deregistration
|
|||
|
|
|||
|
NlDnsName - Structure describing name to deregister.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: The name was deregistered
|
|||
|
Otherwise, the name was not deregistered. The operation should be retried.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
BOOL EntryDeleted = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon is shutting down or starting,
|
|||
|
// and we've already spent a long time doing this batch of DNS records,
|
|||
|
// just give up.
|
|||
|
//
|
|||
|
|
|||
|
if ( (NlGlobalTerminate ||
|
|||
|
NlGlobalChangeLogNetlogonState == NetlogonStarting ) &&
|
|||
|
NetpDcElapsedTime(NlDnsContext->StartTime) > NL_DNS_THRESHOLD ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterOne: DNS really slow during shutdown. (Deregistration skipped) %ld",
|
|||
|
NetpDcElapsedTime(NlDnsContext->StartTime) ));
|
|||
|
|
|||
|
return ERROR_DNS_NOT_AVAILABLE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Deregister the name with DNS
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NlDnsUpdate( NlDnsName, FALSE );
|
|||
|
|
|||
|
//
|
|||
|
// If the name has been removed for all practical purposes,
|
|||
|
// Indicate this routine was successful.
|
|||
|
//
|
|||
|
if ( NetStatus == NO_ERROR ||
|
|||
|
NetStatus == ERROR_DYNAMIC_DNS_NOT_SUPPORTED ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterOne: being deregistered (success) %ld",
|
|||
|
NetStatus ));
|
|||
|
|
|||
|
NlDnsSetState( NlDnsName, DeleteMe );
|
|||
|
EntryDeleted = TRUE;
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
//
|
|||
|
// If the DNS server cannot be reached at this time,
|
|||
|
// we'll deregister it later.
|
|||
|
//
|
|||
|
|
|||
|
} else if ( NetStatus == ERROR_DNS_NOT_AVAILABLE ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterOne: being deregistered (DNS server not available)" ));
|
|||
|
|
|||
|
//
|
|||
|
// If the DNS server is not configured,
|
|||
|
// we'll deregister it later.
|
|||
|
//
|
|||
|
// DNS was available when we registered the name. So this is probably
|
|||
|
// a temporary condition (such as we temporarily don't have an IP address).
|
|||
|
//
|
|||
|
|
|||
|
} else if ( NetStatus == ERROR_DNS_NOT_CONFIGURED ) {
|
|||
|
|
|||
|
//
|
|||
|
// If it's never really been registered,
|
|||
|
// ditch the name
|
|||
|
//
|
|||
|
if ( NlDnsName->Flags & NL_DNS_REGISTERED_ONCE ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterOne: being deregistered (DNS not configured) (Try later)" ));
|
|||
|
} else {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterOne: being deregistered (DNS not configured) (Ditch it)" ));
|
|||
|
NlDnsSetState( NlDnsName, DeleteMe );
|
|||
|
EntryDeleted = TRUE;
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we successfully deregistered,
|
|||
|
// reset the first deregistration failure time stamp
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
NlDnsName->FirstDeregFailureTime.QuadPart = 0;
|
|||
|
|
|||
|
//
|
|||
|
// If we failed to deregister and we postponed it until later,
|
|||
|
// check if it's time to give up on this entry
|
|||
|
//
|
|||
|
|
|||
|
} else if ( !EntryDeleted ) {
|
|||
|
ULONG LocalDnsFailedDeregisterTimeout;
|
|||
|
BOOLEAN FirstFailure = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Set the first deregistration failure time stamp
|
|||
|
//
|
|||
|
if ( NlDnsName->FirstDeregFailureTime.QuadPart == 0 ) {
|
|||
|
NlQuerySystemTime( &NlDnsName->FirstDeregFailureTime );
|
|||
|
FirstFailure = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the reg value for failed deregistration timeout (in seconds)
|
|||
|
// and convert it to milliseconds
|
|||
|
//
|
|||
|
LocalDnsFailedDeregisterTimeout = NlGlobalParameters.DnsFailedDeregisterTimeout;
|
|||
|
|
|||
|
// if the value converted into milliseconds fits into a ULONG, use it
|
|||
|
if ( LocalDnsFailedDeregisterTimeout <= MAXULONG/1000 ) {
|
|||
|
LocalDnsFailedDeregisterTimeout *= 1000; // convert into milliseconds
|
|||
|
|
|||
|
// otherwise, use the max ULONG
|
|||
|
} else {
|
|||
|
LocalDnsFailedDeregisterTimeout = MAXULONG; // infinity
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine if it's time to give up on this entry
|
|||
|
//
|
|||
|
// If timeout is zero we are to delete immediately
|
|||
|
// after the first failure
|
|||
|
// Otherwise, if this is not the first failure,
|
|||
|
// check the timestamp
|
|||
|
//
|
|||
|
if ( LocalDnsFailedDeregisterTimeout == 0 ||
|
|||
|
(!FirstFailure &&
|
|||
|
NetpLogonTimeHasElapsed(NlDnsName->FirstDeregFailureTime,
|
|||
|
LocalDnsFailedDeregisterTimeout)) ) {
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterOne: Ditch it due to time expire" ));
|
|||
|
NlDnsSetState( NlDnsName, DeleteMe );
|
|||
|
EntryDeleted = TRUE;
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsScavengeOne(
|
|||
|
IN PNL_DNS_CONTEXT NlDnsContext,
|
|||
|
IN PNL_DNS_NAME NlDnsName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Register or Deregister any DNS names that need it.
|
|||
|
|
|||
|
Enter with NlDnsName referenced at least twice. If this name gets deregistered
|
|||
|
successfully it will be marked for deletion and dereferenced. The caller
|
|||
|
will dereference the name, too, and if the ref count reaches 0 the entry will
|
|||
|
be delinked and freed by the caller. Thus, if there is less than 2 references
|
|||
|
on input, we may delink and free the entry in this routine resulting in AV if
|
|||
|
the caller attempts to use the freed name upon return from this routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsContext - Context describing a series of registrations or deregistration
|
|||
|
|
|||
|
NlDnsName - Name to scavenge. This structure will be marked for deletion
|
|||
|
if it is no longer needed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
BOOLEAN EntryNeeded = FALSE;
|
|||
|
LARGE_INTEGER TimeNow;
|
|||
|
ULONG Timeout;
|
|||
|
|
|||
|
//
|
|||
|
// There must be at least 2 references on this entry:
|
|||
|
// one for beign on the global list and one reference
|
|||
|
// by the caller.
|
|||
|
//
|
|||
|
NlAssert( NlDnsName->NlDnsNameRefCount > 1 );
|
|||
|
|
|||
|
//
|
|||
|
// Only scavenge this entry if its timer has expired
|
|||
|
//
|
|||
|
Timeout = (DWORD) -1;
|
|||
|
NlQuerySystemTime( &TimeNow );
|
|||
|
if ( TimerExpired( &NlDnsName->ScavengeTimer, &TimeNow, &Timeout)) {
|
|||
|
|
|||
|
//
|
|||
|
// If the name needs to be deregistered,
|
|||
|
// do it now.
|
|||
|
//
|
|||
|
|
|||
|
switch ( NlDnsName->State ) {
|
|||
|
case DeregisterMe:
|
|||
|
|
|||
|
NlDnsDeregisterOne( NlDnsContext, NlDnsName );
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the name needs to be registered,
|
|||
|
// do it now.
|
|||
|
//
|
|||
|
|
|||
|
case RegisterMe:
|
|||
|
case Registered:
|
|||
|
|
|||
|
NlDnsRegisterOne( NlDnsContext, NlDnsName );
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsScavenge(
|
|||
|
IN LPVOID ScavengerParam
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Register or Deregister any DNS names that need it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
LARGE_INTEGER TimeNow;
|
|||
|
ULONG Timeout;
|
|||
|
NL_DNS_CONTEXT NlDnsContext;
|
|||
|
|
|||
|
ULONG Flags = NL_DNSPNP_SITECOV_CHANGE_ONLY;
|
|||
|
|
|||
|
//
|
|||
|
// The DNS scavenger has good backoff characteristics so
|
|||
|
// take this opportunity to ensure the DomainName<1B> names are
|
|||
|
// properly registered.
|
|||
|
//
|
|||
|
|
|||
|
(VOID) NlEnumerateDomains( FALSE, NlBrowserFixAllNames, NULL );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
NlPrint(( NL_DNS,
|
|||
|
"NlDnsScavenge: Starting scavenge of DNS names.\n" ));
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon has been started for a long time,
|
|||
|
// deregister any names that have been registered in
|
|||
|
// a previous incarnation, but have not been registered in this incarnation.
|
|||
|
//
|
|||
|
// We wait a while to do these deregistrations because:
|
|||
|
//
|
|||
|
// * Some of the registrations done by netlogon are a function of multiple
|
|||
|
// hosted domains. The initialization of such domains are done asynchronously.
|
|||
|
// * Some of the registrations done by netlogon are done as a function of
|
|||
|
// other processes telling us that a name needs registration. (e.g., the
|
|||
|
// GC name is registered only after the DS starts completely.)
|
|||
|
//
|
|||
|
// So, it is better to wait a long time to deregister these old registrations
|
|||
|
// than to risk deregistering them then immediately re-registering them.
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
if ( !NlGlobalDnsInitialCleanupDone &&
|
|||
|
NetpDcElapsedTime(NlGlobalDnsStartTime) > NL_DNS_INITIAL_CLEANUP_TIME ) {
|
|||
|
|
|||
|
NlPrint(( NL_DNS,
|
|||
|
"NlDnsScavenge: Mark all delayed deregistrations for deregistration.\n" ));
|
|||
|
|
|||
|
//
|
|||
|
// Mark all delayed deregistrations to deregister now.
|
|||
|
//
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
if ( NlDnsName->State == DelayedDeregister ) {
|
|||
|
NlDnsSetState( NlDnsName, DeregisterMe );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NlGlobalDnsInitialCleanupDone = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if it's time to log "DNS server failure" errors.
|
|||
|
// We do this check before the series of updates so that
|
|||
|
// we don't miss an error for any given name we register.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsServerFailureOutputCheck();
|
|||
|
|
|||
|
//
|
|||
|
// Fix up the registrations if the site coverage changed
|
|||
|
//
|
|||
|
// Avoid having crit sect locked while doing network IO
|
|||
|
//
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlEnumerateDomains( TRUE, NlDnsRegisterDomainOnPnp, &Flags );
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of DNS names finding any that need attention
|
|||
|
//
|
|||
|
|
|||
|
NlDnsContext.StartTime = GetTickCount();
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
) {
|
|||
|
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
if ( NlGlobalTerminate ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is marked for deletion,
|
|||
|
// skip it
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Increase the ref count so that this entry
|
|||
|
// doesn't get deleted behind our back
|
|||
|
//
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// Scavenge this entry
|
|||
|
//
|
|||
|
// Avoid having crit sect locked while doing network IO
|
|||
|
//
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlDnsScavengeOne( &NlDnsContext, NlDnsName );
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Grab the pointer to the next entry
|
|||
|
// before dereferencing this entry as we
|
|||
|
// may delink this entry upon dereferencing
|
|||
|
//
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// In all cases,
|
|||
|
// flush any changes to disk.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsWriteLog();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Determine when we should scavenge next
|
|||
|
//
|
|||
|
|
|||
|
Timeout = (DWORD) -1;
|
|||
|
NlQuerySystemTime( &TimeNow );
|
|||
|
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
//
|
|||
|
// If this entry is marked for deletion,
|
|||
|
// skip it
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if ( TimerExpired( &NlDnsName->ScavengeTimer, &TimeNow, &Timeout)) {
|
|||
|
Timeout = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalScavengerCritSect );
|
|||
|
NlGlobalDnsScavengerTimer.StartTime.QuadPart = TimeNow.QuadPart;
|
|||
|
NlGlobalDnsScavengerTimer.Period = Timeout;
|
|||
|
NlPrint(( NL_DNS_MORE,
|
|||
|
"NlDnsScavenge: Set DNS scavenger to run in %ld minutes (%ld).\n",
|
|||
|
(NlGlobalDnsScavengerTimer.Period+59999)/60000,
|
|||
|
NlGlobalDnsScavengerTimer.Period ));
|
|||
|
|
|||
|
// Wait a couple of extra seconds. There are multiple DNS entries. They
|
|||
|
// won't all expire at the same time. They typically expire within
|
|||
|
// a couple of seconds of one another. Doing this will increase the
|
|||
|
// likelihood that all DNS names will get scavenged in a single
|
|||
|
// scavenge cycle.
|
|||
|
NlGlobalDnsScavengerTimer.Period += 2000;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Indicate that we're done running.
|
|||
|
//
|
|||
|
|
|||
|
NlGlobalDnsScavengerIsRunning = FALSE;
|
|||
|
LeaveCriticalSection( &NlGlobalScavengerCritSect );
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
UNREFERENCED_PARAMETER( ScavengerParam );
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsPnp(
|
|||
|
BOOL TransportChanged
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
When each new IP transport is PNP'ed, this routine attempts to register
|
|||
|
all the DNS names again.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TransportChanged - TRUE if transport was changed. FALSE if names have change.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
DWORD DomFlags = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Nothing to register on a workstation
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalMemberWorkstation ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Mark every DNS name for re-registration.
|
|||
|
//
|
|||
|
// The behavior of dynamic DNS is unclear when there are multiple
|
|||
|
// adapters, each with its own DNS server. If each DNS server supports
|
|||
|
// dynamic DNS for the names we register, do the names actually get
|
|||
|
// registered on both DNS server. I'm assuming YES. In that case,
|
|||
|
// when a new transport comes online, I re-register all names to allow
|
|||
|
// the registration to occur on the new transport.
|
|||
|
//
|
|||
|
// ?? If later the transport is removed, I'll have no opportunity to remove
|
|||
|
// the name. Even worse, if I try to remove the name, I'll succeed because
|
|||
|
// I'll remove the name from the transport that's still on-line. It seems
|
|||
|
// that dynamic DNS needs some conceptual work done here...
|
|||
|
//
|
|||
|
|
|||
|
if ( TransportChanged ) {
|
|||
|
NlPrint(( NL_DNS,
|
|||
|
"NlDnsPnp: Mark all DNS names for re-registration.\n" ));
|
|||
|
|
|||
|
DomFlags = DOM_DNSPNPREREG_UPDATE_NEEDED;
|
|||
|
} else {
|
|||
|
DomFlags = DOM_DNSPNP_UPDATE_NEEDED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if it's time to log "DNS server failure" errors.
|
|||
|
// We do this check before the series of updates so that
|
|||
|
// we don't miss an error for any given name we register.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsServerFailureOutputCheck();
|
|||
|
|
|||
|
//
|
|||
|
// Do the updates for each domain/forest/NDNC in the domain threads
|
|||
|
//
|
|||
|
|
|||
|
NlEnumerateDomains( TRUE, NlStartDomainThread, &DomFlags );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsNtdsDsaDeleteOne(
|
|||
|
IN PNL_DNS_CONTEXT NlDnsContext,
|
|||
|
IN NL_DNS_NAME_TYPE NlDnsNameType,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCWSTR SiteName OPTIONAL,
|
|||
|
IN LPCSTR DnsDomainName,
|
|||
|
IN LPCSTR DnsHostName OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine deletes a single DNS record.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NlDnsContext - Context describing a series of registrations or deregistration
|
|||
|
|
|||
|
NlDnsNameType - The specific type of name.
|
|||
|
|
|||
|
DomainGuid - Guid to append to DNS name.
|
|||
|
For NlDnsDcByGuid, this is the GUID of the domain being located.
|
|||
|
For NlDnsDsaCname, this is the GUID of the DSA being located.
|
|||
|
|
|||
|
SiteName - Name of the site to append to DNS name.
|
|||
|
If NlDnsNameType is any of the *AtSite values,
|
|||
|
this is the name of the site the DC is in.
|
|||
|
|
|||
|
DnsDomainName - Specifies the DNS domain for the name.
|
|||
|
|
|||
|
For NlDnsDcByGuid or any of the GC names,
|
|||
|
this is the DNS domain name of the domain at the root of the tree of
|
|||
|
domains.
|
|||
|
For all others, this is the DNS domain for the DC.
|
|||
|
|
|||
|
DnsHostName - Specifies the DnsHostName for the record.
|
|||
|
|
|||
|
For SRV and CNAME records, this name must be specified
|
|||
|
For A records, this name is ignored
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: The name was returned;
|
|||
|
|
|||
|
ERROR_INVALID_DOMAINNAME: Domain's name is too long. Additional labels
|
|||
|
cannot be concatenated.
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY: Not enough memory to complete the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
ULONG Port;
|
|||
|
ULONG DefaultPort;
|
|||
|
char DnsRecordName[NL_MAX_DNS_LENGTH+1];
|
|||
|
|
|||
|
//
|
|||
|
// Build the name of the record to delete
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpDcBuildDnsName( NlDnsNameType,
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
DnsDomainName,
|
|||
|
DnsRecordName );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Compute the port number for this SRV record
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsGcName( NlDnsNameType ) ) {
|
|||
|
Port = NlGlobalParameters.LdapGcSrvPort;
|
|||
|
DefaultPort = DEFAULT_LDAPGCSRVPORT;
|
|||
|
} else if ( NlDnsKpwdRecord( NlDnsNameType )) {
|
|||
|
Port = 464;
|
|||
|
DefaultPort = 464;
|
|||
|
} else if ( NlDnsKdcRecord( NlDnsNameType )) {
|
|||
|
Port = NlGlobalParameters.KdcSrvPort;
|
|||
|
DefaultPort = DEFAULT_KDCSRVPORT;
|
|||
|
} else {
|
|||
|
Port = NlGlobalParameters.LdapSrvPort;
|
|||
|
DefaultPort = DEFAULT_LDAPSRVPORT;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Queue the entry for deletion.
|
|||
|
//
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlDnsName = NlDnsAllocateEntry( NlDnsNameType,
|
|||
|
DnsRecordName,
|
|||
|
NlGlobalParameters.LdapSrvPriority, // Priority
|
|||
|
NlGlobalParameters.LdapSrvWeight, // Weight
|
|||
|
Port, // Port
|
|||
|
DnsHostName,
|
|||
|
0, // IpAddress
|
|||
|
DeregisterMe );
|
|||
|
|
|||
|
if ( NlDnsName == NULL ) {
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Persist this entry so we try to delete it after a reboot
|
|||
|
//
|
|||
|
NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsNtdsDsaDelete: Name queued for deletion" ));
|
|||
|
|
|||
|
//
|
|||
|
// Increase the ref count so that this entry
|
|||
|
// doesn't get deleted behind our back
|
|||
|
//
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// Try once to delete it now.
|
|||
|
//
|
|||
|
// Avoid having crit sect locked while doing network IO
|
|||
|
//
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlDnsScavengeOne( NlDnsContext, NlDnsName );
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
|
|||
|
//
|
|||
|
// If any of the parameters configured on this machine aren't the default values,
|
|||
|
// try the defaults, too
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalParameters.LdapSrvPriority != DEFAULT_LDAPSRVPRIORITY ||
|
|||
|
NlGlobalParameters.LdapSrvWeight != DEFAULT_LDAPSRVWEIGHT ||
|
|||
|
Port != DefaultPort ) {
|
|||
|
|
|||
|
//
|
|||
|
// Queue the entry for deletion.
|
|||
|
//
|
|||
|
NlDnsName = NlDnsAllocateEntry( NlDnsNameType,
|
|||
|
DnsRecordName,
|
|||
|
DEFAULT_LDAPSRVPRIORITY, // Priority
|
|||
|
DEFAULT_LDAPSRVWEIGHT, // Weight
|
|||
|
DefaultPort, // Port
|
|||
|
DnsHostName,
|
|||
|
0, // IpAddress
|
|||
|
DeregisterMe );
|
|||
|
|
|||
|
if ( NlDnsName == NULL ) {
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Persist this entry so we try to delete it after a reboot
|
|||
|
//
|
|||
|
NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsNtdsDsaDelete: Name queued for deletion" ));
|
|||
|
|
|||
|
//
|
|||
|
// Increase the ref count so that this entry
|
|||
|
// doesn't get deleted behind our back
|
|||
|
//
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// Try once to delete it now.
|
|||
|
//
|
|||
|
// Avoid having crit sect locked while doing network IO
|
|||
|
//
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlDnsScavengeOne( NlDnsContext, NlDnsName );
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NlDnsNtdsDsaDeletion (
|
|||
|
IN LPWSTR DnsDomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN GUID *DsaGuid OPTIONAL,
|
|||
|
IN LPWSTR DnsHostName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function deletes all DNS entries associated with a particular
|
|||
|
NtDsDsa object and/or a particular DNS host name.
|
|||
|
|
|||
|
This routine does NOT delete A records registered by the DC. We have
|
|||
|
no way of finding out the IP addresses of the long gone DC.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsDomainName - DNS domain name of the domain the DC was in.
|
|||
|
This need not be a domain hosted by this DC.
|
|||
|
If NULL, it is implied to be the DnsHostName with the leftmost label
|
|||
|
removed.
|
|||
|
|
|||
|
DomainGuid - Domain Guid of the domain specified by DnsDomainName
|
|||
|
If NULL, GUID specific names will not be removed.
|
|||
|
|
|||
|
DsaGuid - GUID of the NtdsDsa object that is being deleted.
|
|||
|
|
|||
|
DnsHostName - DNS host name of the DC whose NTDS-DSA object is being deleted.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
LPSTR Utf8DnsDomainName = NULL;
|
|||
|
LPSTR Utf8DnsHostName = NULL;
|
|||
|
PLSAP_SITE_INFO SiteInformation = NULL;
|
|||
|
NL_DNS_CONTEXT NlDnsContext;
|
|||
|
|
|||
|
ULONG i;
|
|||
|
ULONG NameIndex;
|
|||
|
|
|||
|
NlDnsContext.StartTime = GetTickCount();
|
|||
|
|
|||
|
//
|
|||
|
// Validate passed parameters
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsHostName == NULL ||
|
|||
|
!NetpDcValidDnsDomain(DnsHostName) ) {
|
|||
|
NetStatus = ERROR_INVALID_NAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If DNS domain name isn't specified,
|
|||
|
// infer it from the DnsHostName
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsDomainName == NULL ) {
|
|||
|
DnsDomainName = wcschr( DnsHostName, L'.' );
|
|||
|
|
|||
|
if ( DnsDomainName == NULL ) {
|
|||
|
NetStatus = ERROR_INVALID_NAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
DnsDomainName ++;
|
|||
|
if ( *DnsDomainName == '\0' ) {
|
|||
|
NetStatus = ERROR_INVALID_NAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
} else if ( !NetpDcValidDnsDomain(DnsDomainName) ) {
|
|||
|
NetStatus = ERROR_INVALID_NAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
Utf8DnsDomainName = NetpAllocUtf8StrFromWStr( DnsDomainName );
|
|||
|
|
|||
|
if ( Utf8DnsDomainName == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
Utf8DnsHostName = NetpAllocUtf8StrFromWStr( DnsHostName );
|
|||
|
|
|||
|
if ( Utf8DnsHostName == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate the sites supported by this forest so we can delete
|
|||
|
// the records that are named by site.
|
|||
|
//
|
|||
|
// We need to delete the records for all sites since we don't know which
|
|||
|
// sites are "covered" by the removed DC.
|
|||
|
//
|
|||
|
|
|||
|
Status = LsaIQuerySiteInfo( &SiteInformation );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsNtdsDsaDeletion: Cannot LsaIQuerySiteInfo 0x%lx\n", Status ));
|
|||
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of names Netlogon understands deleting them all
|
|||
|
//
|
|||
|
|
|||
|
for ( NameIndex = 0;
|
|||
|
NameIndex < NL_DNS_NAME_TYPE_COUNT;
|
|||
|
NameIndex++) {
|
|||
|
LPSTR LocalDomainName;
|
|||
|
GUID *LocalGuid;
|
|||
|
|
|||
|
//
|
|||
|
// If the name is obsolete,
|
|||
|
// ignore it.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDcDnsNameTypeDesc[NameIndex].DsGetDcFlags == 0 ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We don't know how to delete the A records since we don't know the IP address.
|
|||
|
//
|
|||
|
// We'd ask DNS what the IP address is, but the name might not exist. If it does
|
|||
|
// we don't know whether the IP address has already been assign to another DC.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsARecord( NameIndex ) ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Use either the DomainName or ForestName
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDcDnsNameTypeDesc[NameIndex].IsForestRelative ) {
|
|||
|
LocalDomainName = NlGlobalUtf8DnsForestName;
|
|||
|
} else {
|
|||
|
LocalDomainName = Utf8DnsDomainName;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Figure out which GUID to use for this name.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsCnameRecord( NameIndex ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// If we don't know the Dsa GUID,
|
|||
|
// ignore names that need it.
|
|||
|
//
|
|||
|
if ( DsaGuid == NULL || IsEqualGUID( DsaGuid, &NlGlobalZeroGuid) ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
LocalGuid = DsaGuid;
|
|||
|
|
|||
|
} else if ( NlDnsDcGuid( NameIndex )) {
|
|||
|
|
|||
|
//
|
|||
|
// If we don't know the Domain GUID,
|
|||
|
// ignore names that need it.
|
|||
|
//
|
|||
|
if ( DomainGuid == NULL || IsEqualGUID( DomainGuid, &NlGlobalZeroGuid) ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
LocalGuid = DomainGuid;
|
|||
|
|
|||
|
} else {
|
|||
|
LocalGuid = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the name isn't site specific,
|
|||
|
// just delete the one name.
|
|||
|
//
|
|||
|
|
|||
|
if ( !NlDcDnsNameTypeDesc[NameIndex].IsSiteSpecific ) {
|
|||
|
|
|||
|
|
|||
|
NetStatus = NlDnsNtdsDsaDeleteOne( &NlDnsContext,
|
|||
|
(NL_DNS_NAME_TYPE) NameIndex,
|
|||
|
LocalGuid,
|
|||
|
NULL, // No site name
|
|||
|
LocalDomainName,
|
|||
|
Utf8DnsHostName );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the name is site specific,
|
|||
|
// we need to delete the records for all sites since we don't know which
|
|||
|
// sites are "covered" by the removed DC.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Loop deleting entries for each Site
|
|||
|
//
|
|||
|
|
|||
|
for ( i=0; i<SiteInformation->SiteCount; i++ ) {
|
|||
|
|
|||
|
NetStatus = NlDnsNtdsDsaDeleteOne( &NlDnsContext,
|
|||
|
(NL_DNS_NAME_TYPE) NameIndex,
|
|||
|
LocalGuid,
|
|||
|
SiteInformation->Sites[i].SiteName.Buffer,
|
|||
|
LocalDomainName,
|
|||
|
Utf8DnsHostName );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
//
|
|||
|
// Clean up locally used resources.
|
|||
|
//
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( Utf8DnsDomainName != NULL ) {
|
|||
|
NetpMemoryFree( Utf8DnsDomainName );
|
|||
|
}
|
|||
|
if ( Utf8DnsHostName != NULL ) {
|
|||
|
NetpMemoryFree( Utf8DnsHostName );
|
|||
|
}
|
|||
|
if ( SiteInformation != NULL ) {
|
|||
|
LsaIFree_LSAP_SITE_INFO( SiteInformation );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Flush the log
|
|||
|
//
|
|||
|
|
|||
|
NlDnsWriteLog();
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsRegisterDomainOnPnp(
|
|||
|
IN PDOMAIN_INFO DomainInfo,
|
|||
|
IN PULONG Flags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine registers all of the DNS names that are supposed to be
|
|||
|
registered for a particular domain. It deregisters any name that should
|
|||
|
not be registered.
|
|||
|
|
|||
|
?? This routine should be called when ANY of the information changing the
|
|||
|
registration changes. For instance, if the domain name changes, simply
|
|||
|
call this routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DomainInfo - Domain the names are to be registered for.
|
|||
|
|
|||
|
Flags - Indicates the actions to take:
|
|||
|
|
|||
|
NL_DNSPNP_SITECOV_CHANGE_ONLY - Register only if site coverage changes
|
|||
|
NL_DNSPNP_FORCE_REREGISTER - Force re-registration of all previously
|
|||
|
registered records
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: All names could be registered
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
WCHAR CapturedSiteName[NL_MAX_DNS_LABEL_LENGTH+1];
|
|||
|
PISM_CONNECTIVITY SiteConnect = NULL;
|
|||
|
ULONG SiteCount = 0;
|
|||
|
ULONG ThisSiteIndex = 0xFFFFFFFF;
|
|||
|
|
|||
|
PSOCKET_ADDRESS SocketAddresses = NULL;
|
|||
|
ULONG SocketAddressCount = 0;
|
|||
|
ULONG BufferSize;
|
|||
|
PNL_SITE_ENTRY SiteEntry = NULL;
|
|||
|
LPWSTR IpAddressList = NULL;
|
|||
|
ULONG Index;
|
|||
|
|
|||
|
BOOLEAN SiteCoverageChanged = FALSE;
|
|||
|
HANDLE DsHandle = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// This operation is meaningless on a workstation
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalMemberWorkstation ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Capture the name of the site this machine is in.
|
|||
|
//
|
|||
|
|
|||
|
if ( !NlCaptureSiteName( CapturedSiteName ) ) {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegisterDomainOnPnp: Cannot NlCaptureSiteName.\n" ));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we are to automatically determine site coverage,
|
|||
|
// get the site link costs.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalParameters.AutoSiteCoverage ) {
|
|||
|
|
|||
|
if ( NlSitesGetIsmConnect(
|
|||
|
CapturedSiteName,
|
|||
|
&SiteConnect,
|
|||
|
&ThisSiteIndex ) ) {
|
|||
|
|
|||
|
SiteCount = SiteConnect->cNumSites;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ensure that ntdsapi.dll is loaded
|
|||
|
//
|
|||
|
|
|||
|
Status = NlLoadNtDsApiDll();
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegisterDomainOnPnp: Cannot NlLoadNtDsApiDll 0x%lx.\n",
|
|||
|
Status ));
|
|||
|
DsHandle = NULL;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Bind to the DS
|
|||
|
//
|
|||
|
NetStatus = (*NlGlobalpDsBindW)(
|
|||
|
// L"localhost",
|
|||
|
DomainInfo->DomUnicodeComputerNameString.Buffer,
|
|||
|
NULL,
|
|||
|
&DsHandle );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegisterDomainOnPnp: Cannot DsBindW %ld.\n",
|
|||
|
NetStatus ));
|
|||
|
DsHandle = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update the site coverage for each role we play in
|
|||
|
// this forest/domain/NDNC
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainInfo->DomFlags & DOM_REAL_DOMAIN ) {
|
|||
|
|
|||
|
NlSitesUpdateSiteCoverageForRole( DomainInfo,
|
|||
|
DOM_FOREST,
|
|||
|
DsHandle,
|
|||
|
SiteConnect,
|
|||
|
CapturedSiteName,
|
|||
|
ThisSiteIndex,
|
|||
|
&SiteCoverageChanged );
|
|||
|
|
|||
|
NlSitesUpdateSiteCoverageForRole( DomainInfo,
|
|||
|
DOM_REAL_DOMAIN,
|
|||
|
DsHandle,
|
|||
|
SiteConnect,
|
|||
|
CapturedSiteName,
|
|||
|
ThisSiteIndex,
|
|||
|
&SiteCoverageChanged );
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainInfo->DomFlags & DOM_NON_DOMAIN_NC ) {
|
|||
|
NlSitesUpdateSiteCoverageForRole( DomainInfo,
|
|||
|
DOM_NON_DOMAIN_NC,
|
|||
|
DsHandle,
|
|||
|
SiteConnect,
|
|||
|
CapturedSiteName,
|
|||
|
ThisSiteIndex,
|
|||
|
&SiteCoverageChanged );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Finally register all records for this domain
|
|||
|
//
|
|||
|
|
|||
|
if ( ((*Flags) & NL_DNSPNP_SITECOV_CHANGE_ONLY) == 0 ||
|
|||
|
SiteCoverageChanged ) {
|
|||
|
|
|||
|
NetStatus = NlDnsRegisterDomain( DomainInfo, *Flags );
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
NlPrintDom(( NL_CRITICAL, DomainInfo,
|
|||
|
"NlDnsRegisterDomainOnPnp: Cannot NlDnsRegisterDomain 0x%lx.\n",
|
|||
|
NetStatus ));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Inform the user if none of our IP addresses maps to our site.
|
|||
|
// Do it only once (for the primary domain processing).
|
|||
|
// ?? When we support multihosting, our site will be different depending
|
|||
|
// on the forest of a particular domain we host. So we will need to do
|
|||
|
// this check for each site.
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainInfo->DomFlags & DOM_PRIMARY_DOMAIN ) {
|
|||
|
SocketAddressCount = NlTransportGetIpAddresses(
|
|||
|
0, // No special header,
|
|||
|
FALSE, // Return pointers
|
|||
|
&SocketAddresses,
|
|||
|
&BufferSize );
|
|||
|
|
|||
|
for ( Index = 0; Index < SocketAddressCount; Index++ ) {
|
|||
|
SiteEntry = NlFindSiteEntryBySockAddr( SocketAddresses[Index].lpSockaddr );
|
|||
|
|
|||
|
if ( SiteEntry != NULL ) {
|
|||
|
if ( _wcsicmp(SiteEntry->SiteName, CapturedSiteName) == 0 ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
NlDerefSiteEntry( SiteEntry );
|
|||
|
SiteEntry = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Log the error
|
|||
|
//
|
|||
|
if ( SiteEntry == NULL && SocketAddressCount != 0 ) {
|
|||
|
LPWSTR MsgStrings[2];
|
|||
|
|
|||
|
//
|
|||
|
// Form the list of IP addresses for event log output
|
|||
|
//
|
|||
|
IpAddressList = LocalAlloc( LMEM_ZEROINIT,
|
|||
|
SocketAddressCount * (NL_SOCK_ADDRESS_LENGTH+1) * sizeof(WCHAR) );
|
|||
|
|
|||
|
if ( IpAddressList == NULL ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop adding all addresses to the list
|
|||
|
//
|
|||
|
for ( Index = 0; Index < SocketAddressCount; Index++ ) {
|
|||
|
WCHAR IpAddressString[NL_SOCK_ADDRESS_LENGTH+1] = {0};
|
|||
|
|
|||
|
NetStatus = NetpSockAddrToWStr(
|
|||
|
SocketAddresses[Index].lpSockaddr,
|
|||
|
SocketAddresses[Index].iSockaddrLength,
|
|||
|
IpAddressString );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is not the first address on the list,
|
|||
|
// separate addresses by space
|
|||
|
//
|
|||
|
if ( *IpAddressList != UNICODE_NULL ) {
|
|||
|
wcscat( IpAddressList, L" " );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add this address to the list
|
|||
|
//
|
|||
|
wcscat( IpAddressList, IpAddressString );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now write the event
|
|||
|
//
|
|||
|
MsgStrings[0] = CapturedSiteName;
|
|||
|
MsgStrings[1] = IpAddressList;
|
|||
|
|
|||
|
NlpWriteEventlog( NELOG_NetlogonNoAddressToSiteMapping,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
MsgStrings,
|
|||
|
2 );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( DsHandle != NULL ) {
|
|||
|
(*NlGlobalpDsUnBindW)( &DsHandle );
|
|||
|
}
|
|||
|
if ( SiteConnect != NULL ) {
|
|||
|
I_ISMFree( SiteConnect );
|
|||
|
}
|
|||
|
if ( SocketAddresses != NULL ) {
|
|||
|
LocalFree( SocketAddresses );
|
|||
|
}
|
|||
|
if ( IpAddressList != NULL ) {
|
|||
|
LocalFree( IpAddressList );
|
|||
|
}
|
|||
|
if ( SiteEntry != NULL ) {
|
|||
|
NlDerefSiteEntry( SiteEntry );
|
|||
|
}
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsRegisterDomain(
|
|||
|
IN PDOMAIN_INFO DomainInfo,
|
|||
|
IN ULONG Flags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine registers all of the DNS names that are supposed to be
|
|||
|
registered for a particular domain. It deregisters any name that should
|
|||
|
not be registered.
|
|||
|
|
|||
|
?? This routine should be called when ANY of the information changing the
|
|||
|
registration changes. For instance, if the domain name changes, simply
|
|||
|
call this routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DomainInfo - Domain the names are to be registered for.
|
|||
|
|
|||
|
Flags - Indicates the actions to take:
|
|||
|
|
|||
|
NL_DNSPNP_FORCE_REREGISTER - Force re-registration of all previously
|
|||
|
registered records
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: All names could be registered
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
NET_API_STATUS SaveNetStatus = NO_ERROR;
|
|||
|
PNL_DNS_NAME NlDnsName = NULL;
|
|||
|
NL_DNS_CONTEXT NlDnsContext;
|
|||
|
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
ULONG DomainFlags;
|
|||
|
|
|||
|
ULONG i;
|
|||
|
ULONG SocketAddressCount;
|
|||
|
PSOCKET_ADDRESS SocketAddresses = NULL;
|
|||
|
ULONG BufferSize;
|
|||
|
/*
|
|||
|
PUNICODE_STRING DcSiteNames = NULL;
|
|||
|
ULONG DcSiteCount;
|
|||
|
*/
|
|||
|
PNL_SITE_NAME_ARRAY DcSiteNames = NULL;
|
|||
|
/*
|
|||
|
PUNICODE_STRING GcSiteNames = NULL;
|
|||
|
ULONG GcSiteCount;
|
|||
|
*/
|
|||
|
PNL_SITE_NAME_ARRAY GcSiteNames = NULL;
|
|||
|
|
|||
|
ULONG SiteIndex;
|
|||
|
ULONG NameIndex;
|
|||
|
|
|||
|
EnterCriticalSection( &DomainInfo->DomDnsRegisterCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Get the list of IP Addresses for this machine.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsContext.StartTime = GetTickCount();
|
|||
|
SocketAddressCount = NlTransportGetIpAddresses(
|
|||
|
0, // No special header,
|
|||
|
FALSE, // Return pointers
|
|||
|
&SocketAddresses,
|
|||
|
&BufferSize );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop marking all of the current entries for this domain.
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
//
|
|||
|
// If entry is for this domain,
|
|||
|
// mark it.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
if ( NlDnsName->DomainInfo == DomainInfo ) {
|
|||
|
NlDnsName->Flags |= NL_DNS_REGISTER_DOMAIN;
|
|||
|
|
|||
|
//
|
|||
|
// If we are to force the re-registration of this record,
|
|||
|
// mark the name as RegisterMe to force us to try again
|
|||
|
//
|
|||
|
if ( (Flags & NL_DNSPNP_FORCE_REREGISTER) != 0 ) {
|
|||
|
if ( NlDnsName->State == Registered ) {
|
|||
|
NlDnsSetState ( NlDnsName, RegisterMe );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the hosted domain still exists,
|
|||
|
// register all of the appropriate names.
|
|||
|
//
|
|||
|
|
|||
|
if ( (DomainInfo->DomFlags & DOM_DELETED) == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Determine which names should be registered now.
|
|||
|
//
|
|||
|
DomainFlags = NlGetDomainFlags( DomainInfo );
|
|||
|
|
|||
|
// Always register the DS names regardless of whether the DS is
|
|||
|
// actually running.
|
|||
|
//
|
|||
|
// We actually think this will always be a no-op except during
|
|||
|
// installation and when booted to use the registry version of SAM.
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainInfo->DomFlags & DOM_REAL_DOMAIN ) {
|
|||
|
DomainFlags |= DS_DS_FLAG;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the list of Sites covered by this DC/NDNC
|
|||
|
//
|
|||
|
NetStatus = NlSitesGetCloseSites( DomainInfo,
|
|||
|
DOM_REAL_DOMAIN | DOM_NON_DOMAIN_NC,
|
|||
|
&DcSiteNames );
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
NlPrintDom((NL_INIT, DomainInfo,
|
|||
|
"Couldn't NlSitesGetCloseSites %ld 0x%lx.\n",
|
|||
|
NetStatus, NetStatus ));
|
|||
|
SaveNetStatus = NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the list of Sites covered by this GC
|
|||
|
//
|
|||
|
NetStatus = NlSitesGetCloseSites( DomainInfo,
|
|||
|
DOM_FOREST,
|
|||
|
&GcSiteNames );
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
NlPrintDom((NL_INIT, DomainInfo,
|
|||
|
"Couldn't NlSitesGetCloseSites (GcAtSite) %ld 0x%lx.\n",
|
|||
|
NetStatus, NetStatus ));
|
|||
|
SaveNetStatus = NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop through each name seeing if it needs to be registered.
|
|||
|
//
|
|||
|
|
|||
|
for ( NameIndex = 0;
|
|||
|
NameIndex < NL_DNS_NAME_TYPE_COUNT;
|
|||
|
NameIndex++) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If this DC is playing the role described by this name,
|
|||
|
// register the name.
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainFlags & NlDcDnsNameTypeDesc[NameIndex].DsGetDcFlags ) {
|
|||
|
BOOL SkipName = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Don't register this name if we are to avoid it
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalParametersCritSect );
|
|||
|
if ( NlGlobalParameters.DnsAvoidRegisterRecords != NULL ) {
|
|||
|
LPTSTR_ARRAY TStrArray;
|
|||
|
|
|||
|
TStrArray = NlGlobalParameters.DnsAvoidRegisterRecords;
|
|||
|
while ( !NetpIsTStrArrayEmpty(TStrArray) ) {
|
|||
|
|
|||
|
if ( _wcsicmp(TStrArray,
|
|||
|
NlDcDnsNameTypeDesc[NameIndex].Name + NL_DNS_NAME_PREFIX_LENGTH) == 0 ) {
|
|||
|
SkipName = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
TStrArray = NetpNextTStrArrayEntry(TStrArray);
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalParametersCritSect );
|
|||
|
|
|||
|
if ( SkipName ) {
|
|||
|
NlPrintDom(( NL_INIT, DomainInfo,
|
|||
|
"NlDnsRegisterDomain: Skipping name %ws (per registry)\n",
|
|||
|
NlDcDnsNameTypeDesc[NameIndex].Name ));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do other checks since we have to support the old
|
|||
|
// ways of disabling DNS registrations
|
|||
|
//
|
|||
|
// If the name registers an A record,
|
|||
|
// register it for each IP address.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsARecord( NameIndex) ) {
|
|||
|
|
|||
|
//
|
|||
|
// If we aren't supposed to register A records,
|
|||
|
// Just skip this name
|
|||
|
//
|
|||
|
|
|||
|
if ( !NlGlobalParameters.RegisterDnsARecords ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Register the domain name for each IP address of the machine.
|
|||
|
//
|
|||
|
|
|||
|
for ( i=0; i<SocketAddressCount; i++ ) {
|
|||
|
ULONG IpAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Require AF_INET for now
|
|||
|
//
|
|||
|
if ( SocketAddresses[i].lpSockaddr->sa_family != AF_INET ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
IpAddress =
|
|||
|
((PSOCKADDR_IN) SocketAddresses[i].lpSockaddr)->sin_addr.S_un.S_addr;
|
|||
|
|
|||
|
NetStatus = NlDnsRegisterName( &NlDnsContext,
|
|||
|
DomainInfo,
|
|||
|
(NL_DNS_NAME_TYPE)NameIndex,
|
|||
|
NULL,
|
|||
|
IpAddress );
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
#if NETLOGONDBG
|
|||
|
CHAR IpAddressString[NL_IP_ADDRESS_LENGTH+1];
|
|||
|
NetpIpAddressToStr( IpAddress, IpAddressString );
|
|||
|
NlPrintDom((NL_INIT, DomainInfo,
|
|||
|
"Couldn't NlDnsRegisterName (%ws %s) %ld 0x%lx.\n",
|
|||
|
NlDcDnsNameTypeDesc[NameIndex].Name,
|
|||
|
IpAddressString,
|
|||
|
NetStatus, NetStatus ));
|
|||
|
|
|||
|
#endif // NETLOGONDBG
|
|||
|
SaveNetStatus = NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the name isn't site specific,
|
|||
|
// just register the single name.
|
|||
|
//
|
|||
|
|
|||
|
} else if ( !NlDcDnsNameTypeDesc[NameIndex].IsSiteSpecific ) {
|
|||
|
|
|||
|
|
|||
|
NetStatus = NlDnsRegisterName( &NlDnsContext,
|
|||
|
DomainInfo,
|
|||
|
(NL_DNS_NAME_TYPE)NameIndex,
|
|||
|
NULL,
|
|||
|
0 );
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
NlPrintDom((NL_INIT, DomainInfo,
|
|||
|
"Couldn't NlDnsRegisterName (%ws) %ld 0x%lx.\n",
|
|||
|
NlDcDnsNameTypeDesc[NameIndex].Name,
|
|||
|
NetStatus, NetStatus ));
|
|||
|
SaveNetStatus = NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the name is site specific,
|
|||
|
// register the name for each covered site.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PUNICODE_STRING SiteNames;
|
|||
|
ULONG SiteCount;
|
|||
|
|
|||
|
//
|
|||
|
// Use a different site coverage list depending on the role.
|
|||
|
//
|
|||
|
if ( NlDnsGcName( NameIndex) ) {
|
|||
|
if ( GcSiteNames != NULL ) {
|
|||
|
SiteNames = GcSiteNames->SiteNames;
|
|||
|
SiteCount = GcSiteNames->EntryCount;
|
|||
|
} else {
|
|||
|
SiteNames = NULL;
|
|||
|
SiteCount = 0;
|
|||
|
}
|
|||
|
//
|
|||
|
// Use the domain/NDNC specific sites
|
|||
|
//
|
|||
|
} else {
|
|||
|
// ???: Should KDCs have their own site coverage list?
|
|||
|
if ( DcSiteNames != NULL ) {
|
|||
|
SiteNames = DcSiteNames->SiteNames;
|
|||
|
SiteCount = DcSiteNames->EntryCount;
|
|||
|
} else {
|
|||
|
SiteNames = NULL;
|
|||
|
SiteCount = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of sites.
|
|||
|
//
|
|||
|
|
|||
|
for ( SiteIndex=0; SiteIndex < SiteCount; SiteIndex ++) {
|
|||
|
|
|||
|
NetStatus = NlDnsRegisterName( &NlDnsContext,
|
|||
|
DomainInfo,
|
|||
|
(NL_DNS_NAME_TYPE)NameIndex,
|
|||
|
SiteNames[SiteIndex].Buffer,
|
|||
|
0 );
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
NlPrintDom((NL_INIT, DomainInfo,
|
|||
|
"Couldn't NlDnsRegisterName (%ws %ws) %ld 0x%lx.\n",
|
|||
|
NlDcDnsNameTypeDesc[NameIndex].Name,
|
|||
|
SiteNames[SiteIndex].Buffer,
|
|||
|
NetStatus, NetStatus ));
|
|||
|
SaveNetStatus = NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Any names that are still marked should be deleted.
|
|||
|
//
|
|||
|
// However, do not deregister on shutdown (when DOM_DELETED is set)
|
|||
|
// unless we are forced to do it (when the DC is beign demotted,
|
|||
|
// in particular).
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
if ( NlGlobalDcDemotionInProgress ||
|
|||
|
!(NlGlobalParameters.AvoidDnsDeregOnShutdown) ||
|
|||
|
(DomainInfo->DomFlags & DOM_DELETED) == 0 ) {
|
|||
|
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
) {
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the entry is marked for deletion,
|
|||
|
// skip it
|
|||
|
//
|
|||
|
if ( NlDnsName->State == DeleteMe ) {
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If entry is still marked,
|
|||
|
// deregister it as needed.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDnsName->DomainInfo == DomainInfo &&
|
|||
|
(NlDnsName->Flags & NL_DNS_REGISTER_DOMAIN) != 0 ) {
|
|||
|
|
|||
|
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsRegisterDomain: being deregistered" ));
|
|||
|
|
|||
|
NlDnsSetState( NlDnsName, DeregisterMe );
|
|||
|
|
|||
|
//
|
|||
|
// Increase the ref count so that this entry
|
|||
|
// doesn't get deleted behind our back
|
|||
|
//
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// Avoid having crit sect locked while doing network IO
|
|||
|
//
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlDnsScavengeOne( &NlDnsContext, NlDnsName );
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// This entry might be delinked below.
|
|||
|
// So grab the pointer to the next entry
|
|||
|
// before dereferencing this entry.
|
|||
|
//
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
|
|||
|
//
|
|||
|
// Otherwise, proceed with the next entry
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ditch any dangling pointer to the domain info structure.
|
|||
|
//
|
|||
|
if ( DomainInfo->DomFlags & DOM_DELETED ) {
|
|||
|
|
|||
|
for ( ListEntry = NlGlobalDnsList.Flink ;
|
|||
|
ListEntry != &NlGlobalDnsList ;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
//
|
|||
|
// If entry didn't deregister,
|
|||
|
// simply ditch the DomainInfo field.
|
|||
|
//
|
|||
|
// This leaves the entry around so we'll deregister it sooner or
|
|||
|
// later. (Perhaps after the next boot.)
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
|
|||
|
if ( NlDnsName->DomainInfo == DomainInfo ) {
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsDeregisterDomain: Name didn't get deregistered (try later)" ));
|
|||
|
|
|||
|
NlDnsName->DomainInfo = NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// In all cases,
|
|||
|
// flush any changes to disk.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsWriteLog();
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
if ( SocketAddresses != NULL ) {
|
|||
|
LocalFree( SocketAddresses );
|
|||
|
}
|
|||
|
|
|||
|
if ( DcSiteNames != NULL ) {
|
|||
|
NetApiBufferFree( DcSiteNames );
|
|||
|
}
|
|||
|
|
|||
|
if ( GcSiteNames != NULL ) {
|
|||
|
NetApiBufferFree( GcSiteNames );
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &DomainInfo->DomDnsRegisterCritSect );
|
|||
|
|
|||
|
return SaveNetStatus;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlDnsInitialize(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize the dynamic DNS code.
|
|||
|
|
|||
|
Read the list of registered DNS names from the binary log file. Put each entry in the
|
|||
|
list of registered DNS names. The names will be marked as DelayedDeregister.
|
|||
|
Such names will be marked for deleting if they aren't re-registered
|
|||
|
during the Netlogon startup process.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PNL_DNS_NAME NlDnsName;
|
|||
|
|
|||
|
ULONG DnsRecordBufferSize;
|
|||
|
PNL_DNSLOG_HEADER DnsRecordBuffer = NULL;
|
|||
|
LPBYTE DnsRecordBufferEnd;
|
|||
|
PNL_DNSLOG_ENTRY DnsLogEntry;
|
|||
|
ULONG CurrentSize;
|
|||
|
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlGlobalDnsStartTime = GetTickCount();
|
|||
|
NlGlobalDnsInitialCleanupDone = FALSE;
|
|||
|
NlGlobalDnsListDirty = FALSE;
|
|||
|
NlDnsInitCount ++;
|
|||
|
|
|||
|
//
|
|||
|
// That's it for a workstation.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalMemberWorkstation ) {
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the DNS scavenger timer
|
|||
|
//
|
|||
|
|
|||
|
NlQuerySystemTime( &NlGlobalDnsScavengerTimer.StartTime );
|
|||
|
NlGlobalDnsScavengerTimer.Period = min( ORIG_DNS_SCAVENGE_PERIOD, NlGlobalParameters.DnsRefreshIntervalPeriod );
|
|||
|
|
|||
|
//
|
|||
|
// Read the file into a buffer.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NlReadBinaryLog(
|
|||
|
NL_DNS_BINARY_LOG_FILE,
|
|||
|
FALSE, // Don't delete the file
|
|||
|
(LPBYTE *) &DnsRecordBuffer,
|
|||
|
&DnsRecordBufferSize );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: error reading binary log: %ld.\n",
|
|||
|
NL_DNS_BINARY_LOG_FILE,
|
|||
|
DnsRecordBufferSize ));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate the returned data.
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsRecordBufferSize < sizeof(NL_DNSLOG_HEADER) ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: %ws: size too small: %ld.\n",
|
|||
|
NL_DNS_BINARY_LOG_FILE,
|
|||
|
DnsRecordBufferSize ));
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsRecordBuffer->Version != NL_DNSLOG_VERSION ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: %ws: Version wrong: %ld.\n",
|
|||
|
NL_DNS_BINARY_LOG_FILE,
|
|||
|
DnsRecordBuffer->Version ));
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop through each log entry.
|
|||
|
//
|
|||
|
|
|||
|
DnsRecordBufferEnd = ((LPBYTE)DnsRecordBuffer) + DnsRecordBufferSize;
|
|||
|
DnsLogEntry = (PNL_DNSLOG_ENTRY)ROUND_UP_POINTER( (DnsRecordBuffer + 1), ALIGN_WORST );
|
|||
|
|
|||
|
while ( (LPBYTE)(DnsLogEntry+1) <= DnsRecordBufferEnd ) {
|
|||
|
LPSTR DnsRecordName;
|
|||
|
LPSTR DnsHostName;
|
|||
|
LPBYTE DnsLogEntryEnd;
|
|||
|
|
|||
|
DnsLogEntryEnd = ((LPBYTE)DnsLogEntry) + DnsLogEntry->EntrySize;
|
|||
|
|
|||
|
//
|
|||
|
// Ensure this entry is entirely within the allocated buffer.
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsLogEntryEnd > DnsRecordBufferEnd ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: Entry too big: %lx %lx.\n",
|
|||
|
((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer),
|
|||
|
DnsLogEntry->EntrySize ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Validate the entry
|
|||
|
//
|
|||
|
|
|||
|
if ( !COUNT_IS_ALIGNED(DnsLogEntry->EntrySize, ALIGN_DWORD) ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: size not aligned %lx.\n",
|
|||
|
DnsLogEntry->EntrySize ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsLogEntry->NlDnsNameType < 0 ||
|
|||
|
DnsLogEntry->NlDnsNameType >= NlDnsInvalid ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: Bogus DnsNameType: %lx.\n",
|
|||
|
DnsLogEntry->NlDnsNameType ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsLogEntry->Priority > 0xFFFF ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: Bogus priority: %lx.\n",
|
|||
|
DnsLogEntry->Priority ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsLogEntry->Weight > 0xFFFF ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: Bogus weight %lx.\n",
|
|||
|
DnsLogEntry->Weight ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsLogEntry->Port > 0xFFFF ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: Bogus port %lx.\n",
|
|||
|
DnsLogEntry->Port ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Grab the DnsRecordName from the entry.
|
|||
|
//
|
|||
|
|
|||
|
Where = (LPBYTE) (DnsLogEntry+1);
|
|||
|
if ( Where >= DnsLogEntryEnd ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: DnsRecordName missing: %lx\n",
|
|||
|
((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DnsRecordName = Where;
|
|||
|
while ( *Where != '\0' && Where < DnsLogEntryEnd ) {
|
|||
|
Where ++;
|
|||
|
}
|
|||
|
|
|||
|
if ( Where >= DnsLogEntryEnd ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: DnsRecordName has no trailing 0: %lx\n",
|
|||
|
((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
|
|||
|
break;
|
|||
|
}
|
|||
|
Where ++;
|
|||
|
|
|||
|
//
|
|||
|
// Grab the DnsHostName from the entry.
|
|||
|
//
|
|||
|
|
|||
|
if ( !NlDnsARecord( DnsLogEntry->NlDnsNameType ) ) {
|
|||
|
if ( Where >= DnsLogEntryEnd ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: DnsHostName missing: %lx\n",
|
|||
|
((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DnsHostName = Where;
|
|||
|
while ( *Where != '\0' && Where < DnsLogEntryEnd ) {
|
|||
|
Where ++;
|
|||
|
}
|
|||
|
|
|||
|
if ( Where >= DnsLogEntryEnd ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: DnsHostName has no trailing 0: %lx\n",
|
|||
|
((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
|
|||
|
break;
|
|||
|
}
|
|||
|
Where ++;
|
|||
|
} else {
|
|||
|
DnsHostName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the entry and mark it as DelayedDeregister.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsName = NlDnsAllocateEntry(
|
|||
|
DnsLogEntry->NlDnsNameType,
|
|||
|
DnsRecordName,
|
|||
|
DnsLogEntry->Priority,
|
|||
|
DnsLogEntry->Weight,
|
|||
|
DnsLogEntry->Port,
|
|||
|
DnsHostName,
|
|||
|
DnsLogEntry->IpAddress,
|
|||
|
DelayedDeregister );
|
|||
|
|
|||
|
if ( NlDnsName == NULL ) {
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsInitialize: %s: Cannot allocate DnsName structure %lx\n",
|
|||
|
((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This name has been registered once or it wouldn't be here.
|
|||
|
//
|
|||
|
NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
|
|||
|
NlPrintDns(( NL_DNS, NlDnsName,
|
|||
|
"NlDnsInitialize: Previously registered name noticed" ));
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next entry.
|
|||
|
//
|
|||
|
|
|||
|
DnsLogEntry = (PNL_DNSLOG_ENTRY)(((LPBYTE)DnsLogEntry) + DnsLogEntry->EntrySize);
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Be tidy.
|
|||
|
//
|
|||
|
Cleanup:
|
|||
|
if ( DnsRecordBuffer != NULL ) {
|
|||
|
LocalFree( DnsRecordBuffer );
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlDnsShutdown(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Cleanup DNS names upon shutdown.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_DNS_NAME NlDnsName = NULL;
|
|||
|
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
|
|||
|
//
|
|||
|
// Ensure we're flushed.
|
|||
|
//
|
|||
|
|
|||
|
NlDnsWriteLog();
|
|||
|
|
|||
|
//
|
|||
|
// Loop deleting all the entries.
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
while ( !IsListEmpty( &NlGlobalDnsList ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// All of the domains are now cleaned up.
|
|||
|
//
|
|||
|
NlDnsName = CONTAINING_RECORD( NlGlobalDnsList.Flink, NL_DNS_NAME, Next );
|
|||
|
NlAssert( NlDnsName->DomainInfo == NULL );
|
|||
|
|
|||
|
//
|
|||
|
// Mark the name for deletion
|
|||
|
//
|
|||
|
NlDnsName->NlDnsNameRefCount ++;
|
|||
|
NlDnsSetState( NlDnsName, DeleteMe );
|
|||
|
|
|||
|
//
|
|||
|
// Wait for any other references to disappear
|
|||
|
//
|
|||
|
while ( NlDnsName->NlDnsNameRefCount != 1 ) {
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NlDnsShutdown: Sleeping a second waiting for RefCount to one.\n"));
|
|||
|
Sleep( 1000 );
|
|||
|
EnterCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Actually delink and delete structure by removing the last reference
|
|||
|
//
|
|||
|
|
|||
|
NlAssert( NlDnsName->NlDnsNameRefCount == 1 );
|
|||
|
NlDnsDereferenceEntry( NlDnsName );
|
|||
|
|
|||
|
}
|
|||
|
LeaveCriticalSection( &NlGlobalDnsCritSect );
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NlSetDnsForestName(
|
|||
|
IN PUNICODE_STRING DnsForestName OPTIONAL,
|
|||
|
OUT PBOOLEAN DnsForestNameChanged OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Set the DNS tree name in the appropriate globals.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsForestName: of the tree this machine is in.
|
|||
|
|
|||
|
DnsForestNameChanged: Returns TRUE if the tree name changed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - String was saved successfully.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
ULONG DnsForestNameLength;
|
|||
|
LPWSTR LocalUnicodeDnsForestName = NULL;
|
|||
|
ULONG LocalUnicodeDnsForestNameLen = 0;
|
|||
|
LPSTR LocalUtf8DnsForestName = NULL;
|
|||
|
BOOLEAN LocalDnsForestNameChanged = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// If a tree name is specified,
|
|||
|
// allocate buffers for them.
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &NlGlobalDnsForestNameCritSect );
|
|||
|
if ( DnsForestName != NULL && DnsForestName->Length != 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// If the tree name hasn't changed,
|
|||
|
// avoid setting it.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlGlobalUnicodeDnsForestNameString.Length != 0 ) {
|
|||
|
|
|||
|
if ( NlEqualDnsNameU( &NlGlobalUnicodeDnsForestNameString, DnsForestName ) ) {
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NlPrint(( NL_DNS,
|
|||
|
"Set DnsForestName to: %wZ\n",
|
|||
|
DnsForestName ));
|
|||
|
|
|||
|
//
|
|||
|
// Save the . terminated Unicode version of the string.
|
|||
|
//
|
|||
|
|
|||
|
LocalUnicodeDnsForestNameLen = DnsForestName->Length / sizeof(WCHAR);
|
|||
|
if ( LocalUnicodeDnsForestNameLen > NL_MAX_DNS_LENGTH ) {
|
|||
|
NetStatus = ERROR_INVALID_NAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
LocalUnicodeDnsForestName = NetpMemoryAllocate( (LocalUnicodeDnsForestNameLen+2) * sizeof(WCHAR));
|
|||
|
|
|||
|
if ( LocalUnicodeDnsForestName == NULL) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory( LocalUnicodeDnsForestName,
|
|||
|
DnsForestName->Buffer,
|
|||
|
LocalUnicodeDnsForestNameLen*sizeof(WCHAR) );
|
|||
|
|
|||
|
if ( LocalUnicodeDnsForestName[LocalUnicodeDnsForestNameLen-1] != L'.' ) {
|
|||
|
LocalUnicodeDnsForestName[LocalUnicodeDnsForestNameLen++] = L'.';
|
|||
|
}
|
|||
|
LocalUnicodeDnsForestName[LocalUnicodeDnsForestNameLen] = L'\0';
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Convert it to zero terminated UTF-8
|
|||
|
//
|
|||
|
|
|||
|
LocalUtf8DnsForestName = NetpAllocUtf8StrFromWStr( LocalUnicodeDnsForestName );
|
|||
|
|
|||
|
if (LocalUtf8DnsForestName == NULL) {
|
|||
|
NetpMemoryFree( LocalUnicodeDnsForestName );
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( strlen(LocalUtf8DnsForestName) > NL_MAX_DNS_LENGTH ) {
|
|||
|
NetpMemoryFree( LocalUnicodeDnsForestName );
|
|||
|
NetpMemoryFree( LocalUtf8DnsForestName );
|
|||
|
NetStatus = ERROR_INVALID_NAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Indicate the the name has changed.
|
|||
|
//
|
|||
|
|
|||
|
LocalDnsForestNameChanged = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free any existing global tree name.
|
|||
|
//
|
|||
|
if ( NlGlobalUnicodeDnsForestName != NULL ) {
|
|||
|
NetApiBufferFree( NlGlobalUnicodeDnsForestName );
|
|||
|
}
|
|||
|
if ( NlGlobalUtf8DnsForestName != NULL ) {
|
|||
|
NetpMemoryFree( NlGlobalUtf8DnsForestName );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the new names in the globals.
|
|||
|
//
|
|||
|
|
|||
|
NlGlobalUnicodeDnsForestName = LocalUnicodeDnsForestName;
|
|||
|
NlGlobalUnicodeDnsForestNameLen = LocalUnicodeDnsForestNameLen;
|
|||
|
|
|||
|
NlGlobalUnicodeDnsForestNameString.Buffer = LocalUnicodeDnsForestName;
|
|||
|
NlGlobalUnicodeDnsForestNameString.Length = (USHORT)(LocalUnicodeDnsForestNameLen*sizeof(WCHAR));
|
|||
|
NlGlobalUnicodeDnsForestNameString.MaximumLength = (USHORT)((LocalUnicodeDnsForestNameLen+1)*sizeof(WCHAR));
|
|||
|
|
|||
|
NlGlobalUtf8DnsForestName = LocalUtf8DnsForestName;
|
|||
|
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
|
|||
|
Cleanup:
|
|||
|
LeaveCriticalSection( &NlGlobalDnsForestNameCritSect );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the name changed,
|
|||
|
// recompute the DOM_FOREST_ROOT bit on all domains.
|
|||
|
//
|
|||
|
if ( LocalDnsForestNameChanged ) {
|
|||
|
(VOID) NlEnumerateDomains( FALSE, NlSetDomainForestRoot, NULL );
|
|||
|
}
|
|||
|
|
|||
|
if ( ARGUMENT_PRESENT( DnsForestNameChanged) ) {
|
|||
|
*DnsForestNameChanged = LocalDnsForestNameChanged;
|
|||
|
}
|
|||
|
return NetStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NlCaptureDnsForestName(
|
|||
|
OUT WCHAR DnsForestName[NL_MAX_DNS_LENGTH+1]
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Captures a copy of the DnsForestName for this machine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsForestName - Returns the DNS name of the tree this machine is in.
|
|||
|
If there is none, an empty string is returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
--*/
|
|||
|
{
|
|||
|
EnterCriticalSection(&NlGlobalDnsForestNameCritSect);
|
|||
|
if ( NlGlobalUnicodeDnsForestName == NULL ) {
|
|||
|
*DnsForestName = L'\0';
|
|||
|
} else {
|
|||
|
wcscpy( DnsForestName, NlGlobalUnicodeDnsForestName );
|
|||
|
}
|
|||
|
LeaveCriticalSection(&NlGlobalDnsForestNameCritSect);
|
|||
|
|
|||
|
return;
|
|||
|
}
|