5185 lines
160 KiB
C
5185 lines
160 KiB
C
/*++
|
||
|
||
Copyright (c) 1995-1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
netname.c
|
||
|
||
Abstract:
|
||
|
||
Resource DLL for a network name.
|
||
|
||
Author:
|
||
|
||
Mike Massa (mikemas) 29-Dec-1995
|
||
|
||
Revision History:
|
||
|
||
Severely whacked on by Charlie Wickham (charlwi)
|
||
|
||
--*/
|
||
|
||
#define UNICODE 1
|
||
|
||
#include "clusres.h"
|
||
#include "clusrtl.h"
|
||
#include <lm.h>
|
||
#include <srvann.h>
|
||
#include <dsgetdc.h>
|
||
#include <dsgetdcp.h>
|
||
#include <adserr.h>
|
||
#include "netname.h"
|
||
#include "nameutil.h"
|
||
#include "namechk.h"
|
||
#include "clusudef.h"
|
||
#include "clusstrs.h"
|
||
|
||
//
|
||
// Constants
|
||
//
|
||
|
||
#define LOG_CURRENT_MODULE LOG_MODULE_NETNAME
|
||
|
||
#define IP_ADDRESS_RESOURCETYPE_NAME CLUS_RESTYPE_NAME_IPADDR
|
||
|
||
//
|
||
// Macros
|
||
//
|
||
#define ARGUMENT_PRESENT( ArgumentPointer ) (\
|
||
(CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
|
||
|
||
|
||
//
|
||
// turn on _INSTRUMENTED_LOCKS if you're trying to figure out where the lock
|
||
// is getting orphaned
|
||
//
|
||
|
||
//#define _INSTRUMENTED_LOCKS
|
||
#ifdef _INSTRUMENTED_LOCKS
|
||
|
||
#define NetNameAcquireResourceLock() \
|
||
{ \
|
||
DWORD status; \
|
||
status = WaitForSingleObject(NetNameResourceMutex, INFINITE); \
|
||
if ( status == WAIT_ABANDONED ) { \
|
||
OutputDebugStringW( L"Resource List Mutex Abandoned!\n" ); \
|
||
DebugBreak(); \
|
||
} \
|
||
(NetNameLogEvent)(L"rtNetwork Name", \
|
||
LOG_INFORMATION, \
|
||
L"++NNMutex (line %1!u!)\n", \
|
||
__LINE__); \
|
||
}
|
||
|
||
#define NetNameReleaseResourceLock() \
|
||
{ \
|
||
BOOL released; \
|
||
(NetNameLogEvent)(L"rtNetwork Name", \
|
||
LOG_INFORMATION, \
|
||
L"--NNMutex (line %1!u!)\n", \
|
||
__LINE__); \
|
||
released = ReleaseMutex(NetNameResourceMutex); \
|
||
}
|
||
|
||
#define NetNameAcquireDnsListLock( _res_ ) \
|
||
{ \
|
||
DWORD status; \
|
||
status = WaitForSingleObject((_res_)->DnsListMutex, INFINITE); \
|
||
if ( status == WAIT_ABANDONED ) { \
|
||
OutputDebugStringW( L"DNS List Mutex Abandoned!\n" ); \
|
||
DebugBreak(); \
|
||
} \
|
||
(NetNameLogEvent)(L"rtNetwork Name", \
|
||
LOG_INFORMATION, \
|
||
L"++DNSMutex (res %1!X! line %2!u!)\n", \
|
||
_res_, __LINE__); \
|
||
}
|
||
|
||
#define NetNameReleaseDnsListLock( _res_ ) \
|
||
{ \
|
||
BOOL released; \
|
||
(NetNameLogEvent)(L"rtNetwork Name", \
|
||
LOG_INFORMATION, \
|
||
L"--DNSMutex (res %1!X! line %2!u!)\n", \
|
||
_res_, __LINE__); \
|
||
released = ReleaseMutex((_res_)->DnsListMutex); \
|
||
if ( !released ) { \
|
||
(NetNameLogEvent)(L"rtNetwork Name", \
|
||
LOG_INFORMATION, \
|
||
L"ERROR %1!d! releasing DNS mutex (res %2!X! line %3!u!)\n", \
|
||
GetLastError(), _res_, __LINE__); \
|
||
} \
|
||
}
|
||
|
||
#else
|
||
|
||
#define NetNameAcquireResourceLock() \
|
||
{ \
|
||
DWORD status; \
|
||
status = WaitForSingleObject(NetNameResourceMutex, INFINITE); \
|
||
}
|
||
|
||
#define NetNameReleaseResourceLock() \
|
||
{ \
|
||
BOOL released; \
|
||
released = ReleaseMutex(NetNameResourceMutex); \
|
||
}
|
||
|
||
#define NetNameAcquireDnsListLock( _res_ ) \
|
||
{ \
|
||
DWORD status; \
|
||
status = WaitForSingleObject((_res_)->DnsListMutex, INFINITE); \
|
||
}
|
||
|
||
#define NetNameReleaseDnsListLock( _res_ ) \
|
||
{ \
|
||
BOOL released; \
|
||
released = ReleaseMutex((_res_)->DnsListMutex); \
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Local Types.
|
||
//
|
||
|
||
#define PARAM_MIN__FLAGS 0
|
||
#define PARAM_MAX__FLAGS 0xFFFFFFFF
|
||
#define PARAM_DEFAULT__FLAGS 0
|
||
|
||
//
|
||
// Local Variables
|
||
//
|
||
// Mutex for sync'ing access to the list of resources as well as each resource
|
||
// block
|
||
//
|
||
HANDLE NetNameResourceMutex = NULL;
|
||
|
||
//
|
||
// The checking of DNS names requires talking to a DNS server, hence this work
|
||
// is spun off to a separate thread. The resource context blocks are linked
|
||
// together on a doubly linked list and are ref counted to make sure that a
|
||
// block isn't changed during offline processing while its DNS name records
|
||
// are being checked.
|
||
//
|
||
// The NetNameWorkerTerminate event signals the worker routine to exit.
|
||
//
|
||
HANDLE NetNameWorkerTerminate;
|
||
|
||
//
|
||
// NetNameWorkerPendingResources is used to signal the worker thread that a
|
||
// name is moving through a pending state. It is possible for an online
|
||
// operation to time out when lots of names go online
|
||
// simultaneously. Similarly, an offline might require communication with a DC
|
||
// which could take a while. The worker thread will periodically report back
|
||
// to resmon that we're making progress.
|
||
//
|
||
HANDLE NetNameWorkerPendingResources;
|
||
|
||
//
|
||
// list head for resource context block linkage
|
||
//
|
||
LIST_ENTRY NetNameResourceListHead;
|
||
|
||
//
|
||
// the amount of seconds the worker thread waits before doing something. This
|
||
// includes querying the DNS server to make sure registrations are correct and
|
||
// reporting back to resmon when names are going online. This value gets
|
||
// smaller when server communication is suspect.
|
||
//
|
||
ULONG NetNameWorkerCheckPeriod;
|
||
|
||
//
|
||
// ladies and gentlemen, the worker thread
|
||
//
|
||
HANDLE NetNameWorkerThread;
|
||
|
||
//
|
||
// Count of opened NetName resources.
|
||
// Incremented in NetNameOpen
|
||
// Decremented in NetNameClose
|
||
//
|
||
DWORD NetNameOpenCount = 0;
|
||
|
||
//
|
||
// account description string used for computer objects
|
||
//
|
||
LPWSTR NetNameCompObjAccountDesc;
|
||
|
||
//
|
||
// Network Name resource read-write private properties.
|
||
//
|
||
// IF YOU CHANGE THESE, YOU MUST MAKE THE CORRESPONDING CHANGE IN THE COMBINED
|
||
// PROP TABLE BELOW
|
||
//
|
||
RESUTIL_PROPERTY_ITEM
|
||
NetNameResourcePrivateProperties[] = {
|
||
{
|
||
PARAM_NAME__NAME,
|
||
NULL,
|
||
CLUSPROP_FORMAT_SZ,
|
||
0, 0, 0,
|
||
RESUTIL_PROPITEM_REQUIRED,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NetworkName)
|
||
},
|
||
{
|
||
PARAM_NAME__REMAP,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__REMAP,
|
||
0, 1, 0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NetworkRemap)
|
||
},
|
||
{
|
||
PARAM_NAME__REQUIRE_DNS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__REQUIRE_DNS,
|
||
0, 1, 0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,RequireDNS)
|
||
},
|
||
{
|
||
PARAM_NAME__REQUIRE_KERBEROS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__REQUIRE_KERBEROS,
|
||
0, 1, 0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,RequireKerberos)
|
||
},
|
||
{
|
||
PARAM_NAME__UPDATE_INTERVAL,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__UPDATE_INTERVAL,
|
||
PARAM_MINIMUM__UPDATE_INTERVAL,
|
||
PARAM_MAXIMUM__UPDATE_INTERVAL,
|
||
0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,UpdateInterval)
|
||
},
|
||
{ NULL, NULL, 0, 0, 0, 0 }
|
||
};
|
||
|
||
//
|
||
// Network Name resource read-only private properties.
|
||
//
|
||
// IF YOU CHANGE THESE, YOU MUST MAKE THE CORRESPONDING CHANGE IN THE COMBINED
|
||
// PROP TABLE BELOW
|
||
//
|
||
RESUTIL_PROPERTY_ITEM
|
||
NetNameResourceROPrivateProperties[] = {
|
||
{
|
||
PARAM_NAME__RANDOM,
|
||
NULL,
|
||
CLUSPROP_FORMAT_BINARY,
|
||
0, 0, 0,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NetworkRandom)
|
||
},
|
||
{
|
||
PARAM_NAME__STATUS_NETBIOS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
0, 0, 0xFFFFFFFF,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,StatusNetBIOS)
|
||
},
|
||
{
|
||
PARAM_NAME__STATUS_DNS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
0, 0, 0xFFFFFFFF,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,StatusDNS)
|
||
},
|
||
{
|
||
PARAM_NAME__STATUS_KERBEROS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
0, 0, 0xFFFFFFFF,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,StatusKerberos)
|
||
},
|
||
{
|
||
PARAM_NAME__NEXT_UPDATE,
|
||
NULL,
|
||
CLUSPROP_FORMAT_BINARY,
|
||
0, 0, 0,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NextUpdate)
|
||
},
|
||
{ NULL, NULL, 0, 0, 0, 0 }
|
||
};
|
||
|
||
//
|
||
// Network Name resource combined private properties.
|
||
//
|
||
// IF YOU CHANGE THESE, YOU MUST MAKE THE CORRESPONDING CHANGE IN THE EITHER
|
||
// THE READONLY OR READWRITE PROP TABLE ABOVE
|
||
//
|
||
RESUTIL_PROPERTY_ITEM
|
||
NetNameResourceCombinedPrivateProperties[] = {
|
||
{
|
||
PARAM_NAME__NAME,
|
||
NULL,
|
||
CLUSPROP_FORMAT_SZ,
|
||
0, 0, 0,
|
||
RESUTIL_PROPITEM_REQUIRED,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NetworkName)
|
||
},
|
||
{
|
||
PARAM_NAME__REMAP,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__REMAP,
|
||
0, 1, 0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NetworkRemap)
|
||
},
|
||
{
|
||
PARAM_NAME__REQUIRE_DNS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__REQUIRE_DNS,
|
||
0, 1, 0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,RequireDNS)
|
||
},
|
||
{
|
||
PARAM_NAME__REQUIRE_KERBEROS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__REQUIRE_KERBEROS,
|
||
0, 1, 0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,RequireKerberos)
|
||
},
|
||
{
|
||
PARAM_NAME__UPDATE_INTERVAL,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
PARAM_DEFAULT__UPDATE_INTERVAL,
|
||
PARAM_MINIMUM__UPDATE_INTERVAL,
|
||
PARAM_MAXIMUM__UPDATE_INTERVAL,
|
||
0,
|
||
FIELD_OFFSET(NETNAME_PARAMS,UpdateInterval)
|
||
},
|
||
{
|
||
PARAM_NAME__RANDOM,
|
||
NULL,
|
||
CLUSPROP_FORMAT_BINARY,
|
||
0, 0, 0,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NetworkRandom)
|
||
},
|
||
{
|
||
PARAM_NAME__STATUS_NETBIOS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
0, 0, 0xFFFFFFFF,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,StatusNetBIOS)
|
||
},
|
||
{
|
||
PARAM_NAME__STATUS_DNS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
0, 0, 0xFFFFFFFF,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,StatusDNS)
|
||
},
|
||
{
|
||
PARAM_NAME__STATUS_KERBEROS,
|
||
NULL,
|
||
CLUSPROP_FORMAT_DWORD,
|
||
0, 0, 0xFFFFFFFF,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,StatusKerberos)
|
||
},
|
||
{
|
||
PARAM_NAME__NEXT_UPDATE,
|
||
NULL,
|
||
CLUSPROP_FORMAT_BINARY,
|
||
0, 0, 0,
|
||
RESUTIL_PROPITEM_READ_ONLY,
|
||
FIELD_OFFSET(NETNAME_PARAMS,NextUpdate)
|
||
},
|
||
{ NULL, NULL, 0, 0, 0, 0 }
|
||
};
|
||
|
||
//
|
||
// forward declarations
|
||
//
|
||
|
||
CLRES_FUNCTION_TABLE NetNameFunctionTable;
|
||
|
||
//
|
||
// Forward references
|
||
//
|
||
|
||
DWORD
|
||
NetNameGetPrivateResProperties(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
IN BOOL ReadOnly,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
);
|
||
|
||
DWORD
|
||
NetNameValidatePrivateResProperties(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PNETNAME_PARAMS Params,
|
||
OUT PBOOL NetnameHasChanged
|
||
);
|
||
|
||
DWORD
|
||
NetNameSetPrivateResProperties(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize
|
||
);
|
||
|
||
DWORD
|
||
NetNameClusterNameChanged(
|
||
IN PNETNAME_RESOURCE Resource
|
||
);
|
||
|
||
DWORD
|
||
NetNameGetNetworkName(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
);
|
||
|
||
VOID
|
||
NetNameCleanupDnsLists(
|
||
IN PNETNAME_RESOURCE Resource
|
||
);
|
||
|
||
VOID
|
||
RemoveDnsRecords(
|
||
PNETNAME_RESOURCE Resource
|
||
);
|
||
|
||
//
|
||
// Local utility functions
|
||
//
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
NetNameReleaseResource(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup all handles and memory allocations in the netname context block
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be cleaned up.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
|
||
PLIST_ENTRY entry;
|
||
|
||
|
||
ASSERT( resource != NULL );
|
||
|
||
if (resource->Params.NetworkName != NULL) {
|
||
LocalFree(resource->Params.NetworkName);
|
||
}
|
||
|
||
if (resource->Params.NetworkRandom != NULL) {
|
||
LocalFree(resource->Params.NetworkRandom);
|
||
}
|
||
|
||
if (resource->NodeName != NULL) {
|
||
LocalFree(resource->NodeName);
|
||
}
|
||
|
||
if (resource->NodeId != NULL) {
|
||
LocalFree(resource->NodeId);
|
||
}
|
||
|
||
if (resource->ParametersKey != NULL) {
|
||
ClusterRegCloseKey(resource->ParametersKey);
|
||
}
|
||
|
||
if (resource->NodeParametersKey != NULL) {
|
||
ClusterRegCloseKey(resource->NodeParametersKey);
|
||
}
|
||
|
||
if (resource->ResKey != NULL){
|
||
ClusterRegCloseKey(resource->ResKey);
|
||
}
|
||
|
||
if (resource->ClusterResourceHandle != NULL){
|
||
CloseClusterResource(resource->ClusterResourceHandle);
|
||
}
|
||
|
||
if ( resource->DnsLists != NULL ) {
|
||
NetNameCleanupDnsLists( resource );
|
||
}
|
||
|
||
if ( resource->DnsListMutex != NULL ) {
|
||
#if DBG
|
||
{
|
||
DWORD status;
|
||
|
||
status = WaitForSingleObject( resource->DnsListMutex, 0 );
|
||
if ( status == WAIT_TIMEOUT ) {
|
||
WCHAR buf[64];
|
||
|
||
_snwprintf( buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
|
||
L"res %08X DNS list mutex still signalled at delete!\n",
|
||
resource);
|
||
OutputDebugStringW( buf );
|
||
DebugBreak();
|
||
} else {
|
||
ReleaseMutex( resource->DnsListMutex );
|
||
}
|
||
}
|
||
#endif
|
||
|
||
CloseHandle( resource->DnsListMutex );
|
||
}
|
||
|
||
if (resource->ObjectGUID != NULL) {
|
||
LocalFree( resource->ObjectGUID );
|
||
}
|
||
|
||
(NetNameLogEvent)(resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"ResID %1!u! closed.\n",
|
||
Resource
|
||
);
|
||
|
||
LocalFree( resource );
|
||
|
||
} // NetNameReleaseResource
|
||
|
||
VOID
|
||
NetNameUpdateDnsServer(
|
||
PNETNAME_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update this resource's A and PTR records at its DNS server
|
||
|
||
Arguments:
|
||
|
||
Resource - pointer to netname resource context block
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PDNS_LISTS dnsLists;
|
||
DWORD numberOfDnsLists;
|
||
ULONG numberOfRegisteredNames;
|
||
|
||
NetNameAcquireDnsListLock( Resource );
|
||
|
||
numberOfDnsLists = Resource->NumberOfDnsLists;
|
||
dnsLists = Resource->DnsLists;
|
||
while ( numberOfDnsLists-- ) {
|
||
|
||
if ( dnsLists->ForwardZoneIsDynamic ) {
|
||
#if DBG_DNSLIST
|
||
{
|
||
PDNS_RECORD dnsRec = dnsLists->A_RRSet.pFirstRR;
|
||
WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
|
||
struct in_addr addr;
|
||
|
||
if ( dnsRec != NULL ) {
|
||
addr.s_addr = dnsLists->DnsServerList->AddrArray[0];
|
||
_snwprintf(buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
|
||
L"REGISTERING ON adapter %.32ws (%hs)\n",
|
||
dnsLists->ConnectoidName,
|
||
inet_ntoa( addr ) );
|
||
OutputDebugStringW( buf );
|
||
|
||
do {
|
||
addr.s_addr = dnsRec->Data.A.IpAddress;
|
||
_snwprintf(buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
|
||
L"\t(%ws, %hs)\n",
|
||
dnsRec->pName, inet_ntoa( addr ));
|
||
OutputDebugStringW( buf );
|
||
|
||
dnsRec = dnsRec->pNext;
|
||
} while ( dnsRec != NULL );
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// resource went or is going offline; no point in
|
||
// continueing. don't need to grab resource lock since we have a
|
||
// refcount on the resource block
|
||
//
|
||
if (Resource->State != ClusterResourceOnline) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// register the records to update their timestamp (if there is
|
||
// something to register). Before we used to query but eventually
|
||
// the records would time out and be scavenged (deleted). This can
|
||
// cause lots of grief (or in Exchange's case, lots of undelivered
|
||
// mail).
|
||
//
|
||
// we don't worry about logging errors or update the
|
||
// LastARecQueryStatus since all of that is done in
|
||
// RegisterDnsRecords.
|
||
//
|
||
if ( dnsLists->A_RRSet.pFirstRR != NULL ) {
|
||
RegisterDnsRecords(dnsLists,
|
||
Resource->Params.NetworkName,
|
||
Resource->ResKey,
|
||
Resource->ResourceHandle,
|
||
FALSE, /* LogRegistration */
|
||
&numberOfRegisteredNames);
|
||
}
|
||
} // Is Forward zone dynamic?
|
||
|
||
++dnsLists;
|
||
|
||
} // while numberOfDnsLists != 0
|
||
|
||
NetNameReleaseDnsListLock( Resource );
|
||
|
||
} // NetNameUpdateDnsServer
|
||
|
||
DWORD WINAPI
|
||
NetNameWorker(
|
||
IN LPVOID NotUsed
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
background worker thread. Checks on the health of the DNS registrations
|
||
and reports back to resmon while names are in the online pending
|
||
state. The netname Is/LooksAlive checks are too frequent such that they
|
||
would cause alot of DNS traffic on the network. This routine runs through
|
||
the linked list of netname resource blocks and queries the server for the
|
||
records that should be registered. Any discrepancies will cause the
|
||
records to be registered again. The success of each operation is left in
|
||
the DNS_LIST area for the particular record type.
|
||
|
||
In addition, when prompted, it will run down the list of resources and
|
||
report back the resource's status to resmon. Name registration is
|
||
serialized through srv.sys causing some names to time out before they get
|
||
registered.
|
||
|
||
Arguments:
|
||
|
||
NotUsed - not used...
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
PLIST_ENTRY entry;
|
||
PNETNAME_RESOURCE resource;
|
||
DNS_STATUS dnsStatus;
|
||
BOOL reportPending;
|
||
DWORD oldCheckPeriod;
|
||
DWORD pendingResourceCount;
|
||
RESOURCE_STATUS resourceStatus;
|
||
HANDLE waitHandles[ 2 ] = { NetNameWorkerTerminate,
|
||
NetNameWorkerPendingResources };
|
||
|
||
ResUtilInitializeResourceStatus( &resourceStatus );
|
||
|
||
do {
|
||
status = WaitForMultipleObjects(2,
|
||
waitHandles,
|
||
FALSE,
|
||
NetNameWorkerCheckPeriod * 1000);
|
||
|
||
|
||
if ( status == WAIT_OBJECT_0 ) {
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
if ( status == ( WAIT_OBJECT_0 + 1 )) {
|
||
reportPending = TRUE;
|
||
#if DBG
|
||
(NetNameLogEvent)(L"rtNetwork Name",
|
||
LOG_INFORMATION,
|
||
L"Start of pending resource reporting\n");
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// reset check frequency back to normal. if something goes wrong,
|
||
// other code will set it back to the problem check period.
|
||
//
|
||
NetNameWorkerCheckPeriod = NETNAME_WORKER_NORMAL_CHECK_PERIOD;
|
||
|
||
pendingResourceCount = 0;
|
||
|
||
NetNameAcquireResourceLock();
|
||
|
||
entry = NetNameResourceListHead.Flink;
|
||
while ( entry != &NetNameResourceListHead ) {
|
||
//
|
||
// get a pointer to the resource block
|
||
//
|
||
resource = CONTAINING_RECORD( entry, NETNAME_RESOURCE, Next );
|
||
|
||
if ( resource->State > ClusterResourcePending ) {
|
||
|
||
//
|
||
// bringing lots (40) of names online simultaneously caused
|
||
// some names to hit their pending timeouts. Each time a name
|
||
// enters a pending state, the NetNameWorkerPendingResources
|
||
// event is set to wake up this thread. The timeout is changed
|
||
// so we can report back to resmon that the operation is
|
||
// continuing. This should prevent resmon from timing out the
|
||
// resource and causing much thrashing. No other checking (DNS
|
||
// or Kerb) is done while this is happening.
|
||
//
|
||
#if DBG
|
||
(NetNameLogEvent)(resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Reporting resource pending\n");
|
||
#endif
|
||
|
||
oldCheckPeriod = NetNameWorkerCheckPeriod;
|
||
NetNameWorkerCheckPeriod = NETNAME_WORKER_PENDING_PERIOD;
|
||
|
||
resourceStatus.CheckPoint = ++resource->StatusCheckpoint;
|
||
resourceStatus.ResourceState = resource->State;
|
||
|
||
//
|
||
// never hold the resource lock when calling
|
||
// SetResourceStatus. You'll end up with deadlocks when resmon
|
||
// calls back in to the Looks/IsAlive routines. However, the
|
||
// resource state is always synch'ed by this lock. No need to
|
||
// bump refcount since this resource is still in a Pending
|
||
// state and resmon won't allow the resource delete cluster
|
||
// control to be issued.
|
||
//
|
||
NetNameReleaseResourceLock();
|
||
|
||
(NetNameSetResourceStatus)(resource->ResourceHandle,
|
||
&resourceStatus);
|
||
|
||
NetNameAcquireResourceLock();
|
||
|
||
++pendingResourceCount;
|
||
}
|
||
else if ( resource->State == ClusterResourceOnline && !reportPending ) {
|
||
//
|
||
// up the ref count so this resource doesn't go away while we
|
||
// re-register the records with the DNS server. This keeps
|
||
// them from getting scavenged (deleted).
|
||
//
|
||
++resource->RefCount;
|
||
NetNameReleaseResourceLock();
|
||
|
||
NetNameUpdateDnsServer( resource );
|
||
|
||
//
|
||
// check the status of the computer object and see if it is
|
||
// time to generate a new password.
|
||
//
|
||
if ( resource->DoKerberosCheck ) {
|
||
FILETIME currentFileTime;
|
||
|
||
status = CheckComputerObjectAttributes( resource );
|
||
InterlockedExchange( &resource->KerberosStatus, status );
|
||
|
||
GetSystemTimeAsFileTime( ¤tFileTime );
|
||
if ( CompareFileTime( ¤tFileTime, &resource->Params.NextUpdate ) == 1 ) {
|
||
ULARGE_INTEGER updateTime;
|
||
DWORD setValueStatus;
|
||
|
||
status = UpdateCompObjPassword( resource );
|
||
|
||
updateTime.LowPart = currentFileTime.dwLowDateTime;
|
||
updateTime.HighPart = currentFileTime.dwHighDateTime;
|
||
updateTime.QuadPart += ( resource->Params.UpdateInterval * 60 * 1000 * 100 );
|
||
currentFileTime.dwLowDateTime = updateTime.LowPart;
|
||
currentFileTime.dwHighDateTime = updateTime.HighPart;
|
||
|
||
setValueStatus = ResUtilSetBinaryValue(resource->ParametersKey,
|
||
PARAM_NAME__NEXT_UPDATE,
|
||
(const LPBYTE)&updateTime,
|
||
sizeof( updateTime ),
|
||
NULL,
|
||
NULL);
|
||
ASSERT( setValueStatus == ERROR_SUCCESS );
|
||
}
|
||
}
|
||
|
||
//
|
||
// reacquire the mutex so we can release our reference. If the
|
||
// resource went offline and was deleted during the
|
||
// registration, then perform "last ref" cleanup. If the
|
||
// resource just went offline, we need to inform resmon that
|
||
// we're finally going offline. This is synchronized with the
|
||
// resource delete code by not having the DNS lists in use
|
||
// when a delete resource control is sent.
|
||
//
|
||
NetNameAcquireResourceLock();
|
||
|
||
ASSERT( resource->RefCount > 0 ); /* Ruihu: 11/04/2000 */
|
||
if (resource->RefCount == 1) {
|
||
//
|
||
// we hold the last reference to this resource so it must
|
||
// have been deleted while the registration was taking
|
||
// place. Clean up and free our context block for this
|
||
// resource. Restart the loop since we don't know if the
|
||
// flink for this entry is still valid.
|
||
//
|
||
NetNameReleaseResource( resource );
|
||
|
||
entry = NetNameResourceListHead.Flink; /* start over */
|
||
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
if ( resource->State == ClusterResourceOfflinePending ) {
|
||
BOOL nameChanged;
|
||
BOOL deleteCO;
|
||
|
||
//
|
||
// The resource state was changed while we were
|
||
// dealing with DNS. Set the state to offline.
|
||
//
|
||
resourceStatus.ResourceState = ClusterResourceOffline;
|
||
resource->State = ClusterResourceOffline;
|
||
|
||
//
|
||
// note whatever cleanup we need to do while we hold the lock
|
||
//
|
||
nameChanged = resource->NameChangedWhileOnline;
|
||
resource->NameChangedWhileOnline = FALSE;
|
||
|
||
deleteCO = resource->DeleteCOWhenOffline;
|
||
resource->DeleteCOWhenOffline = FALSE;
|
||
|
||
//
|
||
// ok to release lock since we haven't released our
|
||
// reference to this block
|
||
//
|
||
NetNameReleaseResourceLock();
|
||
|
||
//
|
||
// if appropriate, do cleanup processing
|
||
//
|
||
if ( nameChanged ) {
|
||
RemoveDnsRecords( resource );
|
||
#if RENAME_SUPPORT
|
||
status = RenameComputerObject( resource, NULL );
|
||
if ( status == ERROR_NO_SUCH_DOMAIN ) {
|
||
//
|
||
// no DC is available; deal with it
|
||
//
|
||
}
|
||
else if ( status != ERROR_SUCCESS ) {
|
||
//
|
||
// something else bad happened.
|
||
//
|
||
}
|
||
#endif
|
||
resource->NameChangedWhileOnline = FALSE;
|
||
}
|
||
|
||
if ( deleteCO ) {
|
||
status = NetNameDeleteComputerObject( resource );
|
||
//
|
||
// ISSUE: log errors and make sure we handle the
|
||
// case where the resource isn't being deleted
|
||
//
|
||
if ( status == ERROR_NO_SUCH_DOMAIN ) {
|
||
//
|
||
// no DC available right now; deal with it
|
||
//
|
||
}
|
||
else if ( status != ERROR_SUCCESS && status != NERR_UserNotFound ) {
|
||
//
|
||
// some other, significant error occurred.
|
||
//
|
||
}
|
||
}
|
||
|
||
(NetNameSetResourceStatus)(resource->ResourceHandle,
|
||
&resourceStatus);
|
||
|
||
(NetNameLogEvent)(resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Resource is now offline\n");
|
||
|
||
NetNameAcquireResourceLock();
|
||
} // ( resource->State == ClusterResourceOfflinePending )
|
||
|
||
/* Ruihu: 11/04/2000 */
|
||
--resource->RefCount;
|
||
ASSERT(resource->RefCount >=0 );
|
||
if (resource->RefCount == 0) {
|
||
NetNameReleaseResource( resource );
|
||
entry = NetNameResourceListHead.Flink; /* start over */
|
||
continue;
|
||
}
|
||
/* Ruihu: 11/04/2000 */
|
||
} // end if resource count != 1
|
||
} // resource is online
|
||
|
||
entry = entry->Flink;
|
||
} // while entries in the resource block list
|
||
|
||
NetNameReleaseResourceLock();
|
||
|
||
if ( reportPending && pendingResourceCount == 0 ) {
|
||
//
|
||
// no resources are left in a pending state so revert back to
|
||
// checking DNS registrations
|
||
//
|
||
NetNameWorkerCheckPeriod = oldCheckPeriod;
|
||
reportPending = FALSE;
|
||
#if DBG
|
||
(NetNameLogEvent)(L"rtNetwork Name",
|
||
LOG_INFORMATION,
|
||
L"End of pending resource reporting\n");
|
||
#endif
|
||
}
|
||
|
||
} while ( TRUE );
|
||
|
||
} // NetNameWorker
|
||
|
||
BOOLEAN
|
||
NetNameInit(
|
||
IN HINSTANCE DllHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process attach initialization routine.
|
||
|
||
Arguments:
|
||
|
||
DllHandle - handle to clusres module
|
||
|
||
Return Value:
|
||
|
||
TRUE if initialization succeeded. FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
DWORD charsCopied;
|
||
DWORD charsAllocated = 0;
|
||
|
||
NetNameResourceMutex = CreateMutex(NULL, FALSE, NULL);
|
||
|
||
if (NetNameResourceMutex == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// create worker thread terminate event with no special security,
|
||
// auto-reset, initially nonsignalled, and no name
|
||
//
|
||
NetNameWorkerTerminate = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
if ( NetNameWorkerTerminate == NULL ) {
|
||
CloseHandle( NetNameResourceMutex );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// create worker thread online pending event with no special security,
|
||
// auto-reset, initially nonsignalled, and no name
|
||
//
|
||
NetNameWorkerPendingResources = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
if ( NetNameWorkerPendingResources == NULL ) {
|
||
CloseHandle( NetNameWorkerTerminate );
|
||
CloseHandle( NetNameResourceMutex );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// init the list head of the list of resources to check for DNS
|
||
// registrations
|
||
//
|
||
InitializeListHead( &NetNameResourceListHead );
|
||
|
||
//
|
||
// lookup the account description string resource; start with 64 char
|
||
// buffer and double until we fail or we get all of the string. Not
|
||
// considered fatal if we can't load the string
|
||
//
|
||
charsAllocated = 64;
|
||
|
||
realloc:
|
||
charsCopied = 0;
|
||
NetNameCompObjAccountDesc = HeapAlloc( GetProcessHeap(), 0, charsAllocated * sizeof( WCHAR ));
|
||
if ( NetNameCompObjAccountDesc ) {
|
||
|
||
charsCopied = LoadString(DllHandle,
|
||
RES_NETNAME_COMPUTER_ACCOUNT_DESCRIPTION,
|
||
NetNameCompObjAccountDesc,
|
||
charsAllocated);
|
||
|
||
if ( charsCopied != 0 && charsCopied == ( charsAllocated - 1 )) {
|
||
HeapFree( GetProcessHeap(), 0, NetNameCompObjAccountDesc );
|
||
charsAllocated *= 2;
|
||
goto realloc;
|
||
}
|
||
}
|
||
|
||
if ( charsCopied == 0 ) {
|
||
NetNameCompObjAccountDesc = NULL;
|
||
}
|
||
|
||
return(TRUE);
|
||
} // NetNameInit
|
||
|
||
|
||
VOID
|
||
NetNameCleanup(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process detach cleanup routine.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
if (NetNameResourceMutex != NULL) {
|
||
CloseHandle(NetNameResourceMutex);
|
||
NetNameResourceMutex = NULL;
|
||
}
|
||
|
||
if ( NetNameWorkerTerminate ) {
|
||
CloseHandle( NetNameWorkerTerminate );
|
||
NetNameWorkerTerminate = NULL;
|
||
}
|
||
|
||
if ( NetNameWorkerPendingResources ) {
|
||
CloseHandle( NetNameWorkerPendingResources );
|
||
NetNameWorkerPendingResources = NULL;
|
||
}
|
||
|
||
} // NetNameCleanup
|
||
|
||
|
||
PNETNAME_RESOURCE
|
||
NetNameAllocateResource(
|
||
IN RESOURCE_HANDLE ResourceHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates a resource object.
|
||
|
||
Arguments:
|
||
|
||
ResourceHandle - A pointer to the Resource Monitor handle to be associated
|
||
with this resource.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the new resource if successful. NULL otherwise.
|
||
|
||
--*/
|
||
{
|
||
PNETNAME_RESOURCE resource = NULL;
|
||
|
||
resource = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
||
sizeof(NETNAME_RESOURCE));
|
||
|
||
if (resource == NULL) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Resource allocation failed\n");
|
||
return(NULL);
|
||
}
|
||
|
||
resource->ResourceHandle = ResourceHandle;
|
||
|
||
return(resource);
|
||
} // NetNameAllocateResource
|
||
|
||
DWORD
|
||
NetNameGetParameters(
|
||
IN HKEY ResourceKey,
|
||
IN HKEY ParametersKey,
|
||
IN HKEY NodeParametersKey,
|
||
IN RESOURCE_HANDLE ResourceHandle,
|
||
OUT PNETNAME_PARAMS ParamBlock,
|
||
OUT DWORD * RandomSize,
|
||
OUT LPWSTR * LastName,
|
||
OUT DWORD * pdwFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the registry parameters for a netname resource.
|
||
|
||
Arguments:
|
||
|
||
|
||
ParametersKey - An open handle to the resource's parameters key.
|
||
|
||
NodeParametersKey - An open handle to the resource's node-specific
|
||
parameters key.
|
||
|
||
ResourceHandle - The Resource Monitor handle associated with this resource.
|
||
|
||
ParamBlock - A pointer to a buffer into which to place the private properties read
|
||
from the registry
|
||
|
||
RandomSize - A pointer to a buffer into which to place the number of bytes in
|
||
ParamBlock->NetworkRandom
|
||
|
||
LastName - A pointer to a buffer into which to place the unicode network name
|
||
that was last created on this node.
|
||
|
||
pdwFlags - a pointer to a DWORD that receives the flags data. Used to store the
|
||
core resource flag.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if the routine is successful.
|
||
A Win32 error code otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
DWORD bytesReturned;
|
||
|
||
//
|
||
// get the Flags parameter; hold core resource flag for cluster name
|
||
//
|
||
status = ResUtilGetDwordValue(ResourceKey,
|
||
PARAM_NAME__FLAGS,
|
||
pdwFlags,
|
||
0);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to read Flags parameter, error=%1!u!\n",
|
||
status);
|
||
*pdwFlags = 0;
|
||
}
|
||
|
||
//
|
||
// Read the private parameters. always free the existing storage areas
|
||
//
|
||
if ( ParamBlock->NetworkName != NULL ) {
|
||
LocalFree( ParamBlock->NetworkName );
|
||
ParamBlock->NetworkName = NULL;
|
||
}
|
||
|
||
ParamBlock->NetworkName = ResUtilGetSzValue( ParametersKey, PARAM_NAME__NAME );
|
||
|
||
if (ParamBlock->NetworkName == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_WARNING,
|
||
L"Unable to read NetworkName parameter, error=%1!u!\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
status = ResUtilGetDwordValue(ParametersKey,
|
||
PARAM_NAME__REMAP,
|
||
&ParamBlock->NetworkRemap,
|
||
PARAM_DEFAULT__REMAP);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_WARNING,
|
||
L"Unable to read NetworkRemap parameter, error=%1!u!\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
if ( ParamBlock->NetworkRandom != NULL ) {
|
||
LocalFree( ParamBlock->NetworkRandom );
|
||
ParamBlock->NetworkRandom = NULL;
|
||
}
|
||
|
||
status = ResUtilGetBinaryValue(ParametersKey,
|
||
PARAM_NAME__RANDOM,
|
||
&ParamBlock->NetworkRandom,
|
||
RandomSize);
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_WARNING,
|
||
L"Unable to read NetworkRandom parameter, error=%1!u!\n",
|
||
status);
|
||
}
|
||
|
||
status = ResUtilGetDwordValue(ParametersKey,
|
||
PARAM_NAME__REQUIRE_DNS,
|
||
&ParamBlock->RequireDNS,
|
||
PARAM_DEFAULT__REQUIRE_DNS);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to read RequireDNS parameter, error=%1!u!\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
status = ResUtilGetDwordValue(ParametersKey,
|
||
PARAM_NAME__REQUIRE_KERBEROS,
|
||
&ParamBlock->RequireKerberos,
|
||
PARAM_DEFAULT__REQUIRE_KERBEROS);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to read RequireKerberos parameter, error=%1!u!\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
status = ResUtilGetBinaryValue(ParametersKey,
|
||
PARAM_NAME__NEXT_UPDATE,
|
||
(LPBYTE *)&ParamBlock->NextUpdate,
|
||
&bytesReturned);
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_WARNING,
|
||
L"Unable to read NextUpdate parameter, error=%1!u!\n",
|
||
status);
|
||
}
|
||
|
||
status = ResUtilGetDwordValue(ParametersKey,
|
||
PARAM_NAME__UPDATE_INTERVAL,
|
||
&ParamBlock->UpdateInterval,
|
||
PARAM_DEFAULT__UPDATE_INTERVAL);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to read UpdateInterval parameter, error=%1!u!\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Read the node-specific parameters.
|
||
//
|
||
*LastName = ResUtilGetSzValue( NodeParametersKey, PARAM_NAME__LASTNAME );
|
||
status = ERROR_SUCCESS;
|
||
|
||
|
||
error_exit:
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
if (ParamBlock->NetworkName != NULL) {
|
||
LocalFree(ParamBlock->NetworkName);
|
||
ParamBlock->NetworkName = NULL;
|
||
}
|
||
|
||
if (ParamBlock->NetworkRandom != NULL) {
|
||
LocalFree(ParamBlock->NetworkRandom);
|
||
ParamBlock->NetworkRandom = NULL;
|
||
}
|
||
}
|
||
|
||
return(status);
|
||
} // NetNameGetParameters
|
||
|
||
#define TRANSPORT_BLOCK_SIZE 4
|
||
|
||
DWORD
|
||
GrowBlock(
|
||
PCHAR * Block,
|
||
DWORD UsedEntries,
|
||
DWORD BlockSize,
|
||
PDWORD FreeEntries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Grow the specified block to hold more entries. Block might end up pointing
|
||
to different chunk of memory as a result
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID tmp;
|
||
|
||
tmp = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
||
(UsedEntries + TRANSPORT_BLOCK_SIZE) * BlockSize);
|
||
|
||
if (tmp == NULL) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
if (*Block != NULL) {
|
||
CopyMemory( tmp, *Block, UsedEntries * BlockSize );
|
||
LocalFree( *Block );
|
||
}
|
||
|
||
*Block = tmp;
|
||
*FreeEntries = TRANSPORT_BLOCK_SIZE;
|
||
|
||
return ERROR_SUCCESS;
|
||
} // GrowBlock
|
||
|
||
DWORD
|
||
UpdateDomainMapEntry(
|
||
PDOMAIN_ADDRESS_MAPPING DomainEntry,
|
||
LPWSTR IpAddress,
|
||
LPWSTR DomainName,
|
||
LPWSTR ConnectoidName,
|
||
DWORD DnsServerCount,
|
||
PDWORD DnsServerList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update the specified DomainMap entry by making copies of the supplied
|
||
parameters
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// make copies of the address and domain and connectoid names
|
||
//
|
||
DomainEntry->IpAddress = ResUtilDupString ( IpAddress );
|
||
DomainEntry->DomainName = ResUtilDupString( DomainName );
|
||
DomainEntry->ConnectoidName = ResUtilDupString( ConnectoidName );
|
||
|
||
if ( DomainEntry->IpAddress == NULL
|
||
||
|
||
DomainEntry->DomainName == NULL
|
||
||
|
||
DomainEntry->ConnectoidName == NULL )
|
||
{
|
||
if ( DomainEntry->IpAddress != NULL ) {
|
||
LocalFree( DomainEntry->IpAddress );
|
||
}
|
||
|
||
if ( DomainEntry->DomainName != NULL ) {
|
||
LocalFree( DomainEntry->DomainName );
|
||
}
|
||
|
||
if ( DomainEntry->ConnectoidName != NULL ) {
|
||
LocalFree( DomainEntry->ConnectoidName );
|
||
}
|
||
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
//
|
||
// make a copy of the DNS server addresses to use when registering
|
||
//
|
||
if ( DnsServerCount > 0 ) {
|
||
DomainEntry->DnsServerList = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
||
sizeof( IP4_ARRAY ) +
|
||
(sizeof(IP4_ADDRESS) * (DnsServerCount - 1)));
|
||
|
||
if ( DomainEntry->DnsServerList == NULL ) {
|
||
LocalFree( DomainEntry->IpAddress );
|
||
LocalFree( DomainEntry->DomainName );
|
||
LocalFree( DomainEntry->ConnectoidName );
|
||
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
DomainEntry->DnsServerList->AddrCount = DnsServerCount;
|
||
RtlCopyMemory(DomainEntry->DnsServerList->AddrArray,
|
||
DnsServerList,
|
||
DnsServerCount * sizeof( IP4_ADDRESS ));
|
||
} else {
|
||
DomainEntry->DnsServerList = NULL;
|
||
}
|
||
|
||
return ERROR_SUCCESS;
|
||
} // UpdateDomainMapEntry
|
||
|
||
DWORD
|
||
NetNameGetLists(
|
||
IN PNETNAME_RESOURCE Resource,
|
||
IN PCLRTL_NET_ADAPTER_ENUM AdapterEnum OPTIONAL,
|
||
OUT LPWSTR ** TransportList,
|
||
OUT LPDWORD TransportCount,
|
||
OUT PDOMAIN_ADDRESS_MAPPING * DomainMapList OPTIONAL,
|
||
OUT LPDWORD DomainMapCount OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Build a list of NetBT transports, IP addresses, and Domain names on which
|
||
this name is dependent. The transport devices are used to register NETBios
|
||
names while the IP addresses and Domain Names are used if the adapter
|
||
associated with the IP address is the member of a DNS domain. Each IP
|
||
address can have a different domain name associated with it hence the need
|
||
to maintain a separate list.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
HRESOURCE providerHandle = NULL;
|
||
HKEY providerKey = NULL;
|
||
HRESENUM resEnumHandle = NULL;
|
||
DWORD i;
|
||
DWORD objectType;
|
||
DWORD providerNameSize = 0;
|
||
LPWSTR providerName = NULL;
|
||
LPWSTR providerType = NULL;
|
||
DWORD transportFreeEntries = 0;
|
||
LPWSTR * transportList = NULL;
|
||
DWORD transportCount = 0;
|
||
LPWSTR transportName = NULL;
|
||
HCLUSTER clusterHandle = NULL;
|
||
DWORD enableNetbios;
|
||
PDOMAIN_ADDRESS_MAPPING domainMapList = NULL;
|
||
DWORD domainMapCount = 0;
|
||
DWORD domainMapFreeEntries = 0;
|
||
LPWSTR ipAddress;
|
||
PCLRTL_NET_ADAPTER_INFO adapterInfo;
|
||
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
|
||
WCHAR primaryDomain[ DNS_MAX_NAME_BUFFER_LENGTH ] = { 0 };
|
||
DWORD primaryDomainSize = DNS_MAX_NAME_BUFFER_LENGTH;
|
||
|
||
//
|
||
// get the node's primary domain name, if any. Domains with only NT4 DCs
|
||
// won't necessarily have a PDN
|
||
//
|
||
if ( !GetComputerNameEx(ComputerNamePhysicalDnsDomain,
|
||
primaryDomain,
|
||
&primaryDomainSize))
|
||
{
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_WARNING,
|
||
L"Unable to get primary domain name, status %1!u!.\n",
|
||
status
|
||
);
|
||
|
||
primaryDomainSize = 0;
|
||
}
|
||
|
||
//
|
||
// Open a handle to the cluster.
|
||
//
|
||
clusterHandle = OpenCluster(NULL);
|
||
|
||
if (clusterHandle == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open handle to cluster, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Enumerate the dependencies to find the IP Addresses
|
||
//
|
||
resEnumHandle = ClusterResourceOpenEnum(
|
||
Resource->ClusterResourceHandle,
|
||
CLUSTER_RESOURCE_ENUM_DEPENDS
|
||
);
|
||
|
||
if (resEnumHandle == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open enum handle for this resource, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// enum all the dependent resources for this netname resource
|
||
//
|
||
|
||
for (i=0; ;i++) {
|
||
status = ClusterResourceEnum(
|
||
resEnumHandle,
|
||
i,
|
||
&objectType,
|
||
providerName,
|
||
&providerNameSize
|
||
);
|
||
|
||
if (status == ERROR_NO_MORE_ITEMS) {
|
||
break;
|
||
}
|
||
|
||
if ((status == ERROR_MORE_DATA) ||
|
||
((status == ERROR_SUCCESS) && (providerName == NULL))) {
|
||
if (providerName != NULL) {
|
||
LocalFree(providerName);
|
||
}
|
||
|
||
providerNameSize++;
|
||
|
||
providerName = LocalAlloc(
|
||
LMEM_FIXED,
|
||
providerNameSize * sizeof(WCHAR)
|
||
);
|
||
|
||
if (providerName == NULL) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto error_exit;
|
||
}
|
||
|
||
status = ClusterResourceEnum(
|
||
resEnumHandle,
|
||
i,
|
||
&objectType,
|
||
providerName,
|
||
&providerNameSize
|
||
);
|
||
|
||
ASSERT(status != ERROR_MORE_DATA);
|
||
}
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to enumerate resource dependencies, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Open the resource
|
||
//
|
||
providerHandle = OpenClusterResource(clusterHandle, providerName);
|
||
|
||
if (providerHandle == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open handle to provider resource %1!ws!, status %2!u!.\n",
|
||
providerName,
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Figure out what type it is.
|
||
//
|
||
providerKey = GetClusterResourceKey(providerHandle, KEY_READ);
|
||
|
||
status = GetLastError();
|
||
|
||
CloseClusterResource(providerHandle);
|
||
|
||
if (providerKey == NULL) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open provider resource key, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
providerType = ResUtilGetSzValue(providerKey, CLUSREG_NAME_RES_TYPE);
|
||
|
||
if (providerType == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get provider resource type, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// make sure it's an IP address resource
|
||
//
|
||
|
||
if (wcscmp(providerType, IP_ADDRESS_RESOURCETYPE_NAME) == 0) {
|
||
HKEY parametersKey;
|
||
|
||
//
|
||
// Open the provider's parameters key.
|
||
//
|
||
status = ClusterRegOpenKey(
|
||
providerKey,
|
||
CLUSREG_KEYNAME_PARAMETERS,
|
||
KEY_READ,
|
||
¶metersKey
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open provider's parameters key, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
if ( ARGUMENT_PRESENT( DomainMapList )) {
|
||
ASSERT( ARGUMENT_PRESENT( DomainMapCount ));
|
||
ASSERT( ARGUMENT_PRESENT( AdapterEnum ));
|
||
|
||
//
|
||
// build a list of IP address strings that we can use for
|
||
// building the appropriate DNS records
|
||
//
|
||
ipAddress = ResUtilGetSzValue( parametersKey, CLUSREG_NAME_IPADDR_ADDRESS );
|
||
|
||
if (ipAddress == NULL) {
|
||
status = GetLastError();
|
||
ClusterRegCloseKey(parametersKey);
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get provider's Address value, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// find the corresponding adapter/interface over which packets
|
||
// for this IP address would be sent. Get the domain name (if
|
||
// any) from the adapter info.
|
||
//
|
||
adapterInfo = ClRtlFindNetAdapterByInterfaceAddress(
|
||
AdapterEnum,
|
||
ipAddress,
|
||
&interfaceInfo);
|
||
|
||
if ( adapterInfo != NULL ) {
|
||
LPWSTR deviceGuid;
|
||
DWORD guidLength;
|
||
|
||
//
|
||
// argh. DeviceGuid is not bracketed by braces which the
|
||
// following Dns routines require. Dup the string and make
|
||
// it all nice and pretty for DNS.
|
||
//
|
||
guidLength = wcslen( adapterInfo->DeviceGuid );
|
||
deviceGuid = LocalAlloc(LMEM_FIXED,
|
||
(guidLength + 3) * sizeof(WCHAR));
|
||
|
||
if ( deviceGuid == NULL ) {
|
||
status = GetLastError();
|
||
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
deviceGuid[0] = L'{';
|
||
wcscpy( &deviceGuid[1], adapterInfo->DeviceGuid );
|
||
wcscpy( &deviceGuid[ guidLength + 1 ], L"}" );
|
||
|
||
//
|
||
// see if dynamic DNS is enabled for this adapter and that
|
||
// they are DNS servers associated with this adapter. Bail
|
||
// if not. This check corresponds to the "register this
|
||
// connection's addresses in DNS" checkbox in the DNS
|
||
// proppage in the advanced TCP properties
|
||
//
|
||
if ( DnsIsDynamicRegistrationEnabled( deviceGuid ) &&
|
||
adapterInfo->DnsServerCount > 0)
|
||
{
|
||
|
||
//
|
||
// set up a mapping with the Primary Domain Name if
|
||
// apropriate
|
||
//
|
||
if ( primaryDomainSize != 0 ) {
|
||
|
||
if (domainMapFreeEntries == 0) {
|
||
|
||
status = GrowBlock((PCHAR *)&domainMapList,
|
||
domainMapCount,
|
||
sizeof( *domainMapList ),
|
||
&domainMapFreeEntries);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// make copies of the address and name
|
||
//
|
||
status = UpdateDomainMapEntry(&domainMapList[ domainMapCount ],
|
||
ipAddress,
|
||
primaryDomain,
|
||
adapterInfo->ConnectoidName,
|
||
adapterInfo->DnsServerCount,
|
||
adapterInfo->DnsServerList);
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
domainMapCount++;
|
||
domainMapFreeEntries--;
|
||
}
|
||
|
||
//
|
||
// now check if we should care about the adapter
|
||
// specific name. It must be different from the
|
||
// primary domain name and have the "use this
|
||
// connection's DNS suffix" checkbox checked.
|
||
//
|
||
if ( DnsIsAdapterDomainNameRegistrationEnabled( deviceGuid ) &&
|
||
adapterInfo->AdapterDomainName != NULL &&
|
||
_wcsicmp(adapterInfo->AdapterDomainName, primaryDomain) != 0)
|
||
{
|
||
|
||
if (domainMapFreeEntries == 0) {
|
||
|
||
status = GrowBlock((PCHAR *)&domainMapList,
|
||
domainMapCount,
|
||
sizeof( *domainMapList ),
|
||
&domainMapFreeEntries);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// make copies of the address and name
|
||
//
|
||
status = UpdateDomainMapEntry(&domainMapList[ domainMapCount ],
|
||
ipAddress,
|
||
adapterInfo->AdapterDomainName,
|
||
adapterInfo->ConnectoidName,
|
||
adapterInfo->DnsServerCount,
|
||
adapterInfo->DnsServerList);
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
domainMapCount++;
|
||
domainMapFreeEntries--;
|
||
} // if register adapter domain is true and one has been specified
|
||
|
||
} // if dynamic DNS is enabled for this adapter
|
||
|
||
LocalFree( deviceGuid );
|
||
} // if we found the matching adapter in our adapter info
|
||
|
||
LocalFree( ipAddress );
|
||
} // if DomainMapList present
|
||
|
||
//
|
||
// Figure out if this resource supports NetBios.
|
||
//
|
||
status = ResUtilGetDwordValue(
|
||
parametersKey,
|
||
CLUSREG_NAME_IPADDR_ENABLE_NETBIOS,
|
||
&enableNetbios,
|
||
1
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
ClusterRegCloseKey(parametersKey);
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get provider's EnableNetbios value, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
if (enableNetbios) {
|
||
HKEY nodeParametersKey;
|
||
|
||
//
|
||
// Open the provider's node-specific parameters key.
|
||
//
|
||
status = ClusterRegOpenKey(
|
||
parametersKey,
|
||
Resource->NodeId,
|
||
KEY_READ,
|
||
&nodeParametersKey
|
||
);
|
||
|
||
ClusterRegCloseKey(parametersKey);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open provider's node parameters key, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
transportName = ResUtilGetSzValue(
|
||
nodeParametersKey,
|
||
L"NbtDeviceName"
|
||
);
|
||
|
||
status = GetLastError();
|
||
|
||
ClusterRegCloseKey(nodeParametersKey);
|
||
|
||
if (transportName == NULL) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get provider's transport name, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
if (transportFreeEntries == 0) {
|
||
|
||
status = GrowBlock((PCHAR *)&transportList,
|
||
transportCount,
|
||
sizeof( *transportList ),
|
||
&transportFreeEntries);
|
||
|
||
if ( status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
transportList[transportCount] = transportName;
|
||
transportName = NULL;
|
||
transportCount++;
|
||
transportFreeEntries--;
|
||
}
|
||
else {
|
||
ClusterRegCloseKey(parametersKey);
|
||
}
|
||
}
|
||
|
||
ClusterRegCloseKey(providerKey);
|
||
providerKey = NULL;
|
||
LocalFree(providerType);
|
||
providerType = NULL;
|
||
}
|
||
|
||
if (providerName != NULL) {
|
||
LocalFree(providerName);
|
||
providerName = NULL;
|
||
}
|
||
|
||
CloseCluster(clusterHandle);
|
||
ClusterResourceCloseEnum(resEnumHandle);
|
||
|
||
*TransportList = transportList;
|
||
*TransportCount = transportCount;
|
||
|
||
if ( ARGUMENT_PRESENT( DomainMapList )) {
|
||
*DomainMapList = domainMapList;
|
||
*DomainMapCount = domainMapCount;
|
||
}
|
||
|
||
return(ERROR_SUCCESS);
|
||
|
||
error_exit:
|
||
|
||
if (transportList != NULL) {
|
||
ASSERT(transportCount > 0);
|
||
|
||
while (transportCount > 0) {
|
||
LocalFree(transportList[--transportCount]);
|
||
}
|
||
|
||
LocalFree(transportList);
|
||
}
|
||
|
||
if ( domainMapList != NULL ) {
|
||
while (domainMapCount--) {
|
||
if ( domainMapList[ domainMapCount ].IpAddress != NULL ) {
|
||
LocalFree( domainMapList[ domainMapCount ].IpAddress );
|
||
}
|
||
if ( domainMapList[ domainMapCount ].DomainName != NULL ) {
|
||
LocalFree( domainMapList[ domainMapCount ].DomainName );
|
||
}
|
||
if ( domainMapList[ domainMapCount ].DnsServerList != NULL ) {
|
||
LocalFree( domainMapList[ domainMapCount ].DnsServerList );
|
||
}
|
||
}
|
||
LocalFree(domainMapList);
|
||
}
|
||
|
||
if (clusterHandle != NULL) {
|
||
CloseCluster(clusterHandle);
|
||
}
|
||
|
||
if (resEnumHandle != NULL) {
|
||
ClusterResourceCloseEnum(resEnumHandle);
|
||
}
|
||
|
||
if (providerName != NULL) {
|
||
LocalFree(providerName);
|
||
}
|
||
|
||
if (providerKey != NULL) {
|
||
ClusterRegCloseKey(providerKey);
|
||
}
|
||
|
||
if (providerType != NULL) {
|
||
LocalFree(providerType);
|
||
}
|
||
|
||
if (transportName != NULL) {
|
||
LocalFree(transportName);
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // NetNameGetLists
|
||
|
||
|
||
VOID
|
||
NetNameCleanupDnsLists(
|
||
IN PNETNAME_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clean up the DNS list structures associated with the resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - pointer to internal resource struct
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PDNS_LISTS dnsLists;
|
||
DNS_STATUS dnsStatus;
|
||
PDNS_RECORD dnsRecord;
|
||
|
||
dnsLists = Resource->DnsLists;
|
||
while ( Resource->NumberOfDnsLists-- ) {
|
||
|
||
#if 0
|
||
//
|
||
// we have to free the args we handed to the DNS record build routines
|
||
//
|
||
dnsRecord = dnsLists->A_RRSet.pFirstRR;
|
||
while ( dnsRecord != NULL ) {
|
||
LocalFree( dnsRecord->pName );
|
||
dnsRecord->pName = NULL;
|
||
|
||
dnsRecord = dnsRecord->pNext;
|
||
}
|
||
|
||
dnsRecord = dnsLists->PTR_RRSet.pFirstRR;
|
||
while ( dnsRecord != NULL ) {
|
||
LocalFree( dnsRecord->Data.PTR.pNameHost );
|
||
dnsRecord->Data.PTR.pNameHost = NULL;
|
||
|
||
dnsRecord = dnsRecord->pNext;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// have DNSAPI clean up its structs
|
||
//
|
||
DnsRecordListFree( dnsLists->PTR_RRSet.pFirstRR, DnsFreeRecordListDeep );
|
||
DnsRecordListFree( dnsLists->A_RRSet.pFirstRR, DnsFreeRecordListDeep );
|
||
|
||
//
|
||
// free server address info and connectoid name string
|
||
//
|
||
if ( dnsLists->DnsServerList != NULL ) {
|
||
LocalFree( dnsLists->DnsServerList );
|
||
}
|
||
|
||
if ( dnsLists->ConnectoidName != NULL ) {
|
||
LocalFree( dnsLists->ConnectoidName );
|
||
}
|
||
|
||
++dnsLists;
|
||
}
|
||
Resource->NumberOfDnsLists = 0;
|
||
|
||
if ( Resource->DnsLists != NULL ) {
|
||
LocalFree( Resource->DnsLists );
|
||
Resource->DnsLists = NULL;
|
||
}
|
||
|
||
} // NetNameCleanupDnsLists
|
||
|
||
VOID
|
||
NetNameOfflineNetbios(
|
||
IN PNETNAME_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
do final clean up when taking this resource offline.
|
||
|
||
Arguments:
|
||
|
||
Resource - A pointer to the NETNAME_RESOURCE block for this resource.
|
||
|
||
Returns:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD i;
|
||
LPWSTR * transportList = NULL;
|
||
DWORD transportCount = 0;
|
||
|
||
//
|
||
// Now we can finally do the real work of taking the netbios name offline.
|
||
//
|
||
DeleteAlternateComputerName(Resource->Params.NetworkName,
|
||
Resource->NameHandleList,
|
||
Resource->NameHandleCount,
|
||
Resource->ResourceHandle);
|
||
|
||
if (Resource->NameHandleList != NULL) {
|
||
LocalFree(Resource->NameHandleList);
|
||
Resource->NameHandleList = NULL;
|
||
Resource->NameHandleCount = 0;
|
||
}
|
||
|
||
//
|
||
// Remove the cluster service type bits
|
||
//
|
||
status = NetNameGetLists(Resource,
|
||
NULL,
|
||
&transportList,
|
||
&transportCount,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
DWORD serviceBits;
|
||
|
||
serviceBits = SV_TYPE_CLUSTER_VS_NT | SV_TYPE_CLUSTER_NT;
|
||
|
||
for (i=0; i<transportCount; i++) {
|
||
I_NetServerSetServiceBitsEx(NULL, // target server
|
||
Resource->Params.NetworkName, // emulated server name
|
||
transportList[i], // transport name
|
||
serviceBits, // bits of interest
|
||
0, // bits
|
||
TRUE ); // Update immediately
|
||
}
|
||
|
||
while (transportCount > 0) {
|
||
LocalFree(transportList[--transportCount]);
|
||
}
|
||
|
||
LocalFree(transportList);
|
||
}
|
||
} // NetNameOfflineNetbios
|
||
|
||
|
||
DWORD
|
||
NetNameOnlineThread(
|
||
IN PCLUS_WORKER Worker,
|
||
IN PNETNAME_RESOURCE Resource
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings a network name resource online.
|
||
|
||
Arguments:
|
||
|
||
Worker - Supplies the worker structure
|
||
|
||
Resource - A pointer to the NETNAME_RESOURCE block for this resource.
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
CLUSTER_RESOURCE_STATE finalState = ClusterResourceFailed;
|
||
LPWSTR lastName = NULL;
|
||
LPWSTR * transportList = NULL;
|
||
DWORD transportCount = 0;
|
||
PDOMAIN_ADDRESS_MAPPING domainMapList = NULL;
|
||
DWORD domainMapCount = 0;
|
||
DWORD i;
|
||
DWORD dwFlags;
|
||
PCLRTL_NET_ADAPTER_ENUM adapterEnum = NULL;
|
||
RESOURCE_STATUS resourceStatus;
|
||
DWORD serviceBits;
|
||
LPWSTR netbiosSMBDevice = L"\\Device\\NetbiosSmb";
|
||
|
||
ResUtilInitializeResourceStatus( &resourceStatus );
|
||
|
||
ASSERT(Resource->State == ClusterResourceOnlinePending);
|
||
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Bringing resource online...\n"
|
||
);
|
||
|
||
//
|
||
// If this is the first resource to be brought online then spin up the DNS
|
||
// check thread at this point
|
||
//
|
||
NetNameAcquireResourceLock();
|
||
if ( NetNameWorkerThread == NULL ) {
|
||
NetNameWorkerThread = CreateThread(NULL,
|
||
0,
|
||
NetNameWorker,
|
||
NULL,
|
||
0,
|
||
NULL);
|
||
|
||
if ( NetNameWorkerThread == NULL ) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Can't start Netname worker thread. status = %1!u!\n",
|
||
status
|
||
);
|
||
NetNameReleaseResourceLock();
|
||
goto error_exit;
|
||
}
|
||
}
|
||
NetNameReleaseResourceLock();
|
||
|
||
//
|
||
// initialize the checkpoint var that is used to communicate back to
|
||
// resmon that we're still working on bringing the resource online
|
||
//
|
||
Resource->StatusCheckpoint = 0;
|
||
|
||
//
|
||
// notify the worker thread that we're bringing a name online.
|
||
//
|
||
SetEvent( NetNameWorkerPendingResources );
|
||
|
||
//
|
||
// see if we need to create the Node Parameters section in the registry
|
||
// for this resource.
|
||
//
|
||
if ( Resource->NodeParametersKey == NULL ) {
|
||
DWORD disposition;
|
||
|
||
status = ClusterRegCreateKey(Resource->ParametersKey,
|
||
Resource->NodeId,
|
||
0,
|
||
KEY_READ | KEY_WRITE,
|
||
NULL,
|
||
&Resource->NodeParametersKey,
|
||
&disposition);
|
||
|
||
if (status != NO_ERROR) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to create node parameters key, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// This read must continue to be here as long as adminstrative
|
||
// agents (like CLUSCLI) continue to write to the registry behind the back
|
||
// of the resource dll. We need to migrate to writing all registry
|
||
// parameters via the SET_COMMON/PRIVATE_PROPERTIES control function. That
|
||
// way, resource dll's can read their parameters in the open (allowing for
|
||
// the possibility that they may fail), and then update the parameters
|
||
// whenever the SET_PRIVATE_PROPERTIES control code is delivered and
|
||
// (optionally) on the SET_COMMON_PROPERTIES as needed.
|
||
//
|
||
// Fetch our parameters from the registry.
|
||
//
|
||
status = NetNameGetParameters(
|
||
Resource->ResKey,
|
||
Resource->ParametersKey,
|
||
Resource->NodeParametersKey,
|
||
Resource->ResourceHandle,
|
||
&Resource->Params,
|
||
&Resource->RandomSize,
|
||
&lastName,
|
||
&Resource->dwFlags
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
|
||
if (lastName != NULL) {
|
||
LocalFree(lastName); // we don't use this value.
|
||
}
|
||
|
||
if ( Resource->Params.NetworkName == NULL ) {
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Ensure that the specified network name is not the same as the
|
||
// computername of this node.
|
||
//
|
||
if ( lstrcmpiW(Resource->Params.NetworkName, Resource->NodeName) == 0 ) {
|
||
ClusResLogSystemEventByKey1(Resource->ResKey,
|
||
LOG_CRITICAL,
|
||
RES_NETNAME_DUPLICATE,
|
||
Resource->Params.NetworkName);
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"The specified network name is the same as the local computername.\n"
|
||
);
|
||
status = ERROR_DUP_NAME;
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// get the adapter configuration and determine which adapters are
|
||
// participating in a DNS domain
|
||
//
|
||
|
||
adapterEnum = ClRtlEnumNetAdapters();
|
||
|
||
if ( adapterEnum == NULL ) {
|
||
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Couldn't acquire network adapter configuration, status %1!u!\n",
|
||
status
|
||
);
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Search our dependencies and return the list of NBT devices to which we
|
||
// need to bind the server. Also get the IP addresses this resource
|
||
// depends on so we can publish them in DNS.
|
||
//
|
||
status = NetNameGetLists(
|
||
Resource,
|
||
adapterEnum,
|
||
&transportList,
|
||
&transportCount,
|
||
&domainMapList,
|
||
&domainMapCount
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// transportCount could be zero in the case where NetBIOS names are turned
|
||
// off for all IP addr resources. In any case, a network name must have at
|
||
// least one IP address associated with it.
|
||
//
|
||
if (( transportCount + domainMapCount ) == 0 ) {
|
||
ClusResLogSystemEventByKey(Resource->ResKey,
|
||
LOG_CRITICAL,
|
||
RES_NETNAME_NO_IP_ADDRESS);
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"This name is configured such that it will not be registered "
|
||
L"with a name service or it could not be registered with either "
|
||
L"NetBIOS or a DNS name server at this time. This condition prevents "
|
||
L"the name from being brought online.\n"
|
||
);
|
||
status = ERROR_DEPENDENCY_NOT_FOUND;
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Write the name to the registry so we can delete it if we crash and
|
||
// restart.
|
||
//
|
||
status = ClusterRegSetValue(
|
||
Resource->NodeParametersKey,
|
||
PARAM_NAME__LASTNAME,
|
||
REG_SZ,
|
||
(LPBYTE)Resource->Params.NetworkName,
|
||
((lstrlenW(Resource->Params.NetworkName) + 1) * sizeof(WCHAR))
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to write name to registry, status %1!u!\n",
|
||
status
|
||
);
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
if ( transportCount > 0 ) {
|
||
//
|
||
// Allocate an array to hold the handles for the registered name
|
||
//
|
||
Resource->NameHandleList = LocalAlloc(
|
||
LMEM_FIXED | LMEM_ZEROINIT,
|
||
sizeof(HANDLE) * transportCount
|
||
);
|
||
|
||
if (Resource->NameHandleList == NULL) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory for name registration.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
Resource->NameHandleCount = transportCount;
|
||
|
||
//
|
||
// if we have DNS related data from a previous online, free it up now
|
||
// since AddAlternateComputerName will be reconstructing with current
|
||
// info.
|
||
//
|
||
if ( Resource->DnsLists != NULL ) {
|
||
NetNameCleanupDnsLists( Resource );
|
||
}
|
||
|
||
//
|
||
// Add the name/transport combinations.
|
||
//
|
||
status = AddAlternateComputerName(
|
||
Worker,
|
||
Resource,
|
||
transportList,
|
||
transportCount,
|
||
domainMapList,
|
||
domainMapCount
|
||
);
|
||
|
||
if (status != NERR_Success) {
|
||
ClusResLogSystemEventByKeyData(Resource->ResKey,
|
||
LOG_CRITICAL,
|
||
RES_NETNAME_CANT_ADD_NAME,
|
||
sizeof(status),
|
||
&status);
|
||
|
||
NetNameOfflineNetbios( Resource );
|
||
|
||
//
|
||
// don't need to synchronize with worker thread since it only checks
|
||
// online resources
|
||
//
|
||
NetNameCleanupDnsLists( Resource );
|
||
goto error_exit;
|
||
}
|
||
|
||
finalState = ClusterResourceOnline;
|
||
|
||
//
|
||
// set the appropriate service type bit(s) for this name. core cluster
|
||
// name resource additionally gets the cluster bit.
|
||
//
|
||
serviceBits = SV_TYPE_CLUSTER_VS_NT;
|
||
if (Resource->dwFlags & CLUS_FLAG_CORE) {
|
||
serviceBits |= SV_TYPE_CLUSTER_NT;
|
||
}
|
||
|
||
for (i=0; i<transportCount; i++) {
|
||
I_NetServerSetServiceBitsEx(NULL, // Local server serv
|
||
Resource->Params.NetworkName,
|
||
transportList[i], //transport name
|
||
serviceBits,
|
||
serviceBits,
|
||
TRUE ); // Update immediately
|
||
}
|
||
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Network Name %1!ws! is now online\n",
|
||
Resource->Params.NetworkName
|
||
);
|
||
|
||
error_exit:
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
if ( Resource->NameHandleList != NULL ) {
|
||
LocalFree(Resource->NameHandleList);
|
||
Resource->NameHandleList = NULL;
|
||
Resource->NameHandleCount = 0;
|
||
}
|
||
}
|
||
|
||
if (transportList != NULL) {
|
||
ASSERT(transportCount > 0);
|
||
|
||
while (transportCount > 0) {
|
||
LocalFree(transportList[--transportCount]);
|
||
}
|
||
|
||
LocalFree(transportList);
|
||
}
|
||
|
||
if (domainMapList != NULL) {
|
||
|
||
while (domainMapCount--) {
|
||
LocalFree( domainMapList[domainMapCount].IpAddress );
|
||
LocalFree( domainMapList[domainMapCount].DomainName );
|
||
LocalFree( domainMapList[domainMapCount].ConnectoidName );
|
||
|
||
if ( domainMapList[domainMapCount].DnsServerList != NULL ) {
|
||
LocalFree( domainMapList[domainMapCount].DnsServerList );
|
||
}
|
||
}
|
||
|
||
LocalFree(domainMapList);
|
||
}
|
||
|
||
if ( adapterEnum != NULL ) {
|
||
ClRtlFreeNetAdapterEnum( adapterEnum );
|
||
}
|
||
|
||
ASSERT(Resource->State == ClusterResourceOnlinePending);
|
||
|
||
//
|
||
// set the final state accordingly. We acquire the lock to synch with the
|
||
// worker thread
|
||
//
|
||
NetNameAcquireResourceLock();
|
||
|
||
Resource->State = finalState;
|
||
resourceStatus.ResourceState = finalState;
|
||
|
||
NetNameReleaseResourceLock();
|
||
|
||
(NetNameSetResourceStatus)( Resource->ResourceHandle, &resourceStatus );
|
||
|
||
return(status);
|
||
|
||
} // NetNameOnlineThread
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
NetNameOfflineWorker(
|
||
IN PNETNAME_RESOURCE Resource,
|
||
IN BOOL Terminate,
|
||
IN PCLUS_WORKER Worker OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal offline routine for Network Name resource. This routine is called
|
||
by both the offline and terminate routines. Terminate calls it directly
|
||
with Worker set to NULL, while Offline spins a worker thread and then has
|
||
the worker thread call it.
|
||
|
||
If terminate is true, we bag any long running operations like removing DNS
|
||
records or renaming/deleting the object. We'll figure out how to deal with
|
||
the resource's carcass the next time it is brought online.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies the resource it to be taken offline
|
||
|
||
Terminate - indicates whether call is result of NetNameTerminate or NetNameOffline
|
||
|
||
Worker - pointer to cluster work thread struct. NULL if called by Terminate
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
BOOL nameChanged = FALSE;
|
||
BOOL deleteCO = FALSE;
|
||
|
||
//
|
||
// Terminate any pending thread if it is running.
|
||
//
|
||
if ( Terminate ) {
|
||
ClusWorkerTerminate(&(Resource->PendingThread));
|
||
}
|
||
|
||
//
|
||
// Synchronize offline/terminate and worker thread
|
||
//
|
||
NetNameAcquireResourceLock();
|
||
|
||
if (Resource->State != ClusterResourceOffline) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Offline of resource continuing...\n"
|
||
);
|
||
|
||
Resource->State = ClusterResourceOfflinePending;
|
||
|
||
NetNameOfflineNetbios( Resource );
|
||
|
||
if ( Resource->RefCount > 1 ) {
|
||
//
|
||
// DNS registration is still in progress. If we don't synchronize
|
||
// with the worker thread, then it is possible to delete the
|
||
// resource while the worker routine still had a pointer to the
|
||
// freed memory. kaboom....
|
||
//
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Waiting for Worker thread operation to finish\n");
|
||
|
||
status = ERROR_IO_PENDING;
|
||
}
|
||
|
||
if ( status == ERROR_SUCCESS ) {
|
||
if ( !Terminate ) {
|
||
//
|
||
// If the name was changed or kerb was disbled while we were
|
||
// still online, do the appropriate clean up after we release
|
||
// the netname lock. We have to maintain a reference since a
|
||
// delete can be issued after the resource has gone offline.
|
||
//
|
||
if ( Resource->NameChangedWhileOnline || Resource->DeleteCOWhenOffline ) {
|
||
++Resource->RefCount;
|
||
}
|
||
|
||
if ( Resource->NameChangedWhileOnline ) {
|
||
nameChanged = TRUE;
|
||
Resource->NameChangedWhileOnline = FALSE;
|
||
}
|
||
|
||
if ( Resource->DeleteCOWhenOffline ) {
|
||
deleteCO = TRUE;
|
||
Resource->DeleteCOWhenOffline = FALSE;
|
||
}
|
||
}
|
||
|
||
Resource->State = ClusterResourceOffline;
|
||
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Resource is now offline\n");
|
||
}
|
||
}
|
||
else {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Resource is already offline.\n"
|
||
);
|
||
}
|
||
|
||
NetNameReleaseResourceLock();
|
||
|
||
if ( !Terminate ) {
|
||
RESOURCE_STATUS resourceStatus;
|
||
|
||
ResUtilInitializeResourceStatus( &resourceStatus );
|
||
resourceStatus.ResourceState = ClusterResourceOffline;
|
||
(NetNameSetResourceStatus)( Resource->ResourceHandle, &resourceStatus );
|
||
|
||
if ( nameChanged || deleteCO ) {
|
||
//
|
||
// we're not terminating the resource and we need to do some
|
||
// cleanup work. Before each major operation, check if we need to
|
||
// get out due to our Terminate routine being called.
|
||
//
|
||
if ( nameChanged ) {
|
||
if ( !ClusWorkerCheckTerminate( Worker )) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Attempting removal of DNS records\n");
|
||
|
||
RemoveDnsRecords( Resource );
|
||
}
|
||
#if RENAME_SUPPORT
|
||
//
|
||
// only rename if we're not deleting and we don't have to
|
||
// terminate
|
||
//
|
||
if ( !deleteCO && !ClusWorkerCheckTerminate( Worker )) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Attempting to rename computer account\n");
|
||
|
||
status = RenameComputerObject( Resource, NULL );
|
||
if ( status == ERROR_NO_SUCH_DOMAIN ) {
|
||
//
|
||
// no DC is available;
|
||
//
|
||
}
|
||
else if ( status != ERROR_SUCCESS ) {
|
||
//
|
||
// something else bad happened
|
||
//
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if ( deleteCO && !ClusWorkerCheckTerminate( Worker )) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Attempting to delete computer account\n");
|
||
|
||
status = NetNameDeleteComputerObject( Resource );
|
||
if ( status == ERROR_NO_SUCH_DOMAIN ) {
|
||
//
|
||
// no DC was available; deal with it
|
||
//
|
||
}
|
||
else if ( status != ERROR_SUCCESS && status != NERR_UserNotFound ) {
|
||
//
|
||
// failed for some other, significant reason
|
||
//
|
||
}
|
||
}
|
||
|
||
NetNameAcquireResourceLock();
|
||
|
||
--Resource->RefCount;
|
||
|
||
ASSERT( Resource->RefCount >= 0 );
|
||
if ( Resource->RefCount == 0 ) {
|
||
NetNameReleaseResource( Resource );
|
||
}
|
||
|
||
NetNameReleaseResourceLock();
|
||
}
|
||
}
|
||
|
||
return status;
|
||
|
||
} // NetNameOfflineWorker
|
||
|
||
DWORD
|
||
NetNameOfflineThread(
|
||
IN PCLUS_WORKER Worker,
|
||
IN PNETNAME_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
stub routine to call common offline routine used by both terminate and
|
||
offline
|
||
|
||
Arguments:
|
||
|
||
Worker - pointer to cluster work thread
|
||
|
||
Resource - pointer to netname resource context block that is going offline
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
|
||
//
|
||
// notify the worker thread that we're bringing a name offline.
|
||
//
|
||
SetEvent( NetNameWorkerPendingResources );
|
||
|
||
status = NetNameOfflineWorker( Resource, FALSE, Worker );
|
||
|
||
return status;
|
||
|
||
} // NetNameOfflineThread
|
||
|
||
DWORD
|
||
RemoveDependentIpAddress(
|
||
PNETNAME_RESOURCE Resource,
|
||
LPWSTR DependentResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A dependent IP address resource is being removed. Delete the associated
|
||
DNS records for this address and the netbt device.
|
||
|
||
Arguments:
|
||
|
||
Resource - pointer to private netname resource data
|
||
|
||
DependentResourceId - pointer to Unicode string of dependent resource's name
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
HCLUSTER clusterHandle;
|
||
HRESOURCE ipResourceHandle = NULL;
|
||
RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
|
||
DWORD status;
|
||
HKEY ipResourceKey;
|
||
HKEY parametersKey;
|
||
LPWSTR reverseName;
|
||
PDNS_LISTS dnsList;
|
||
DWORD numberOfDnsLists = Resource->NumberOfDnsLists;
|
||
LPWSTR ipAddressBuffer;
|
||
IP4_ADDRESS ipAddress;
|
||
UNICODE_STRING ipAddressStringW;
|
||
ANSI_STRING ipAddressStringA;
|
||
|
||
//
|
||
// work our way through the miriad of Cluster APIs to read the IP address
|
||
// resource's address from the registry
|
||
//
|
||
clusterHandle = OpenCluster(NULL);
|
||
if (clusterHandle != NULL) {
|
||
ipResourceHandle = OpenClusterResource( clusterHandle, DependentResourceId );
|
||
CloseCluster( clusterHandle );
|
||
|
||
if ( ipResourceHandle != NULL ) {
|
||
ipResourceKey = GetClusterResourceKey( ipResourceHandle, KEY_READ );
|
||
CloseClusterResource( ipResourceHandle );
|
||
|
||
if ( ipResourceKey != NULL ) {
|
||
status = ClusterRegOpenKey(ipResourceKey,
|
||
CLUSREG_KEYNAME_PARAMETERS,
|
||
KEY_READ,
|
||
¶metersKey);
|
||
|
||
ClusterRegCloseKey( ipResourceKey );
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
ipAddressBuffer = ResUtilGetSzValue( parametersKey, CLUSREG_NAME_IPADDR_ADDRESS );
|
||
ClusterRegCloseKey( parametersKey );
|
||
|
||
if (ipAddressBuffer == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get resource's Address value for resource "
|
||
L"'%1!ws!', status %2!u!.\n",
|
||
DependentResourceId,
|
||
status);
|
||
}
|
||
} else {
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open parameters key for resource '%1!ws!', "
|
||
L"status %2!u!.\n",
|
||
DependentResourceId,
|
||
status);
|
||
}
|
||
} else {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to obtain registry key to resource '%1!ws!', "
|
||
L"status %2!u!.\n",
|
||
DependentResourceId,
|
||
status);
|
||
}
|
||
} else {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open handle to resource '%1!ws!', status %2!u!.\n",
|
||
DependentResourceId,
|
||
status);
|
||
}
|
||
} else {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open handle to cluster, status %1!u!.\n",
|
||
status);
|
||
}
|
||
|
||
//
|
||
// argh. dependencies can be removed while the two resources are in a
|
||
// stable state, i.e., not pending. Furthermore, the remove dependency
|
||
// control is issued to all nodes in the cluster (double argh). This
|
||
// really complicates matters since we're not tracking add dependency
|
||
// which means we potentially don't have current DNS data on all nodes
|
||
// except for the one that owns the resource. Consequently, if all nodes
|
||
// handle the remove then we may use stale DNS info and remove the wrong
|
||
// records at the server.
|
||
//
|
||
// Since this is our only chance to clean up PTR records at the server
|
||
// (due to the fact that the PTR logic uses ModifyRecordSet instead of
|
||
// ReplaceRecordSet), we can only process this request on a node where the
|
||
// resource is online (along with the fact that if the resource is online,
|
||
// then its DNS lists are correct). This is sort of ok since the resource
|
||
// will either 1) go online again at which point the DNS A records will be
|
||
// corrected at the server or 2) the resource will be deleted in which
|
||
// case the last node hosting resource will clean up at the server if
|
||
// possible.
|
||
//
|
||
// In any case, if we can't delete the records, we should log it.
|
||
//
|
||
if ( Resource->State != ClusterResourceOnline || numberOfDnsLists == 0 ) {
|
||
WCHAR msgBuffer[64];
|
||
|
||
msgBuffer[( sizeof( msgBuffer ) / sizeof( WCHAR )) - 1] = UNICODE_NULL;
|
||
if ( status == ERROR_SUCCESS ) {
|
||
_snwprintf(msgBuffer,
|
||
( sizeof( msgBuffer ) / sizeof( WCHAR )) - 1,
|
||
L"IP Address %ws",
|
||
ipAddressBuffer);
|
||
|
||
} else {
|
||
_snwprintf(msgBuffer,
|
||
( sizeof( msgBuffer ) / sizeof( WCHAR )) - 1,
|
||
L"Cluster IP Address resource %ws",
|
||
DependentResourceId);
|
||
|
||
}
|
||
|
||
ClusResLogSystemEventByKey1(Resource->ResKey,
|
||
LOG_UNUSUAL,
|
||
RES_NETNAME_CANT_DELETE_DEPENDENT_RESOURCE_DNS_RECORDS,
|
||
msgBuffer);
|
||
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to delete DNS records associated with IP resource '%1!ws!'. "
|
||
L"The DNS Administrator can delete these records through the DNS "
|
||
L"management snapin.\n",
|
||
DependentResourceId);
|
||
|
||
if ( ipAddressBuffer != NULL ) {
|
||
LocalFree( ipAddressBuffer );
|
||
}
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_INFORMATION,
|
||
L"RemoveDependentIpAddress: Deleting DNS records associated with resource '%1!ws!'.\n",
|
||
DependentResourceId);
|
||
|
||
RtlInitUnicodeString( &ipAddressStringW, ipAddressBuffer );
|
||
RtlUnicodeStringToAnsiString( &ipAddressStringA,
|
||
&ipAddressStringW,
|
||
TRUE );
|
||
ipAddress = inet_addr( ipAddressStringA.Buffer );
|
||
RtlFreeAnsiString( &ipAddressStringA );
|
||
|
||
//
|
||
// finally, we know what to delete. Convert the address into reverse zone
|
||
// format and find it in the resource's DNS list structures.
|
||
//
|
||
reverseName = BuildUnicodeReverseName( ipAddressBuffer );
|
||
|
||
if ( reverseName == NULL ) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(resourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to build DNS reverse zone name for resource '%1!ws!', status %2!u!.\n",
|
||
DependentResourceId,
|
||
status);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// co-ordinate changes to DnsLists with the worker thread
|
||
//
|
||
NetNameAcquireDnsListLock( Resource );
|
||
|
||
dnsList = Resource->DnsLists;
|
||
while ( numberOfDnsLists-- ) {
|
||
PDNS_RECORD dnsRecord;
|
||
PDNS_RECORD lastDnsRecord;
|
||
PDNS_RECORD nextDnsRecord;
|
||
DNS_STATUS dnsStatus;
|
||
|
||
if ( dnsList->ForwardZoneIsDynamic ) {
|
||
dnsRecord = dnsList->A_RRSet.pFirstRR;
|
||
lastDnsRecord = NULL;
|
||
|
||
while( dnsRecord != NULL ) {
|
||
if ( dnsRecord->Data.A.IpAddress == ipAddress ) {
|
||
//
|
||
// found a match. we need to whack just that record from
|
||
// the server and from our DNS lists.
|
||
//
|
||
nextDnsRecord = dnsRecord->pNext;
|
||
dnsRecord->pNext = NULL;
|
||
|
||
dnsStatus = DnsModifyRecordsInSet_W(NULL,
|
||
dnsRecord,
|
||
DNS_UPDATE_SECURITY_USE_DEFAULT,
|
||
NULL,
|
||
dnsList->DnsServerList,
|
||
NULL);
|
||
|
||
if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Deleted DNS A record at server: name: %1!ws! IP Address: %2!ws!\n",
|
||
dnsRecord->pName,
|
||
ipAddressBuffer);
|
||
|
||
} else {
|
||
WCHAR statusBuf[ 32 ];
|
||
|
||
_snwprintf(statusBuf, ( sizeof( statusBuf ) / sizeof( WCHAR )) - 1,
|
||
L"%d",
|
||
dnsStatus );
|
||
ClusResLogSystemEventByKey3(Resource->ResKey,
|
||
LOG_UNUSUAL,
|
||
RES_NETNAME_DNS_SINGLE_A_RECORD_DELETE_FAILED,
|
||
dnsRecord->pName,
|
||
ipAddressBuffer,
|
||
statusBuf);
|
||
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to delete DNS A record at server: owner: %1!ws!, "
|
||
L"IP Address: %2!ws!. status %3!u!\n",
|
||
dnsRecord->pName,
|
||
ipAddressBuffer,
|
||
dnsStatus);
|
||
}
|
||
|
||
//
|
||
// fix up forward ptrs
|
||
//
|
||
if ( lastDnsRecord != NULL ) {
|
||
lastDnsRecord->pNext = nextDnsRecord;
|
||
} else {
|
||
dnsList->A_RRSet.pFirstRR = nextDnsRecord;
|
||
}
|
||
|
||
//
|
||
// fix up last ptr if necessary
|
||
//
|
||
if ( dnsList->A_RRSet.pLastRR == dnsRecord ) {
|
||
dnsList->A_RRSet.pLastRR = lastDnsRecord;
|
||
}
|
||
|
||
//
|
||
// have DNS clean up its allocations and free the record
|
||
DnsRecordListFree( dnsRecord, DnsFreeRecordListDeep );
|
||
break;
|
||
}
|
||
|
||
lastDnsRecord = dnsRecord;
|
||
dnsRecord = dnsRecord->pNext;
|
||
|
||
} // while dnsRecord != NULL
|
||
} // if forward zone is dynamic
|
||
|
||
if ( dnsList->ReverseZoneIsDynamic ) {
|
||
dnsRecord = dnsList->PTR_RRSet.pFirstRR;
|
||
lastDnsRecord = NULL;
|
||
|
||
while( dnsRecord != NULL ) {
|
||
if ( _wcsicmp( reverseName, dnsRecord->pName ) == 0 ) {
|
||
//
|
||
// found a match. we need to whack that record from the
|
||
// server and from our DNS lists. This also means that we
|
||
// have to fix up the RRSet struct if the record we're
|
||
// whacking is either first and/or last.
|
||
//
|
||
nextDnsRecord = dnsRecord->pNext;
|
||
dnsRecord->pNext = NULL;
|
||
|
||
dnsStatus = DnsModifyRecordsInSet_W(NULL,
|
||
dnsRecord,
|
||
DNS_UPDATE_SECURITY_USE_DEFAULT,
|
||
NULL,
|
||
dnsList->DnsServerList,
|
||
NULL);
|
||
|
||
if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Deleted DNS PTR record at server: name: %1!ws! host: %2!ws!\n",
|
||
dnsRecord->pName,
|
||
dnsRecord->Data.PTR.pNameHost
|
||
);
|
||
} else {
|
||
WCHAR statusBuf[ 32 ];
|
||
|
||
_snwprintf(statusBuf, ( sizeof( statusBuf ) / sizeof( WCHAR )) - 1,
|
||
L"%d",
|
||
dnsStatus );
|
||
ClusResLogSystemEventByKey3(Resource->ResKey,
|
||
LOG_UNUSUAL,
|
||
RES_NETNAME_DNS_PTR_RECORD_DELETE_FAILED,
|
||
dnsRecord->pName,
|
||
dnsRecord->Data.PTR.pNameHost,
|
||
statusBuf);
|
||
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to delete DNS PTR record: owner %1!ws! "
|
||
L"host: %2!ws!, status %3!u!\n",
|
||
dnsRecord->pName,
|
||
dnsRecord->Data.PTR.pNameHost,
|
||
dnsStatus
|
||
);
|
||
}
|
||
|
||
//
|
||
// fix up forward ptrs
|
||
//
|
||
if ( lastDnsRecord != NULL ) {
|
||
lastDnsRecord->pNext = nextDnsRecord;
|
||
} else {
|
||
dnsList->PTR_RRSet.pFirstRR = nextDnsRecord;
|
||
}
|
||
|
||
//
|
||
// fix up last ptr if necessary
|
||
//
|
||
if ( dnsList->PTR_RRSet.pLastRR == dnsRecord ) {
|
||
dnsList->PTR_RRSet.pLastRR = lastDnsRecord;
|
||
}
|
||
|
||
//
|
||
// have DNS clean up its allocations and free the record
|
||
DnsRecordListFree( dnsRecord, DnsFreeRecordListDeep );
|
||
break;
|
||
}
|
||
|
||
lastDnsRecord = dnsRecord;
|
||
dnsRecord = dnsRecord->pNext;
|
||
|
||
} // while dnsRecord != NULL
|
||
} // if reverse zone is dynamic
|
||
|
||
++dnsList;
|
||
|
||
} // while more dns lists to process
|
||
|
||
NetNameReleaseDnsListLock( Resource );
|
||
|
||
LocalFree( reverseName );
|
||
LocalFree( ipAddressBuffer );
|
||
|
||
return ERROR_SUCCESS;
|
||
} // RemoveDependentIpAddress
|
||
|
||
VOID
|
||
RemoveDnsRecords(
|
||
PNETNAME_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
delete all the DNS records associated with this resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - pointer to private netname resource data
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PDNS_LISTS dnsLists;
|
||
DNS_STATUS dnsStatus;
|
||
PDNS_RECORD dnsRecord;
|
||
PDNS_RECORD nextDnsRecord;
|
||
ULONG numberOfDnsLists;
|
||
|
||
if ( Resource->NumberOfDnsLists == 0 ) {
|
||
//
|
||
// nothing to cleanup; log an entry in the event log so they know what
|
||
// to do
|
||
//
|
||
ClusResLogSystemEventByKey(Resource->ResKey,
|
||
LOG_UNUSUAL,
|
||
RES_NETNAME_CANT_DELETE_DNS_RECORDS);
|
||
return;
|
||
}
|
||
|
||
NetNameAcquireDnsListLock( Resource );
|
||
|
||
dnsLists = Resource->DnsLists;
|
||
numberOfDnsLists = Resource->NumberOfDnsLists;
|
||
|
||
while ( numberOfDnsLists-- ) {
|
||
|
||
if ( dnsLists->ReverseZoneIsDynamic ) {
|
||
//
|
||
// whack the PTR records; see the write up in RegisterDnsRecords
|
||
// for this bit of funkiness
|
||
//
|
||
dnsRecord = dnsLists->PTR_RRSet.pFirstRR;
|
||
while ( dnsRecord != NULL ) {
|
||
|
||
nextDnsRecord = dnsRecord->pNext;
|
||
dnsRecord->pNext = NULL;
|
||
|
||
dnsStatus = DnsModifyRecordsInSet_W(NULL,
|
||
dnsRecord,
|
||
DNS_UPDATE_SECURITY_USE_DEFAULT,
|
||
NULL,
|
||
dnsLists->DnsServerList,
|
||
NULL);
|
||
|
||
if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Deleted DNS PTR record at server: owner: %1!ws! host: %2!ws!\n",
|
||
dnsRecord->pName,
|
||
dnsRecord->Data.PTR.pNameHost
|
||
);
|
||
} else {
|
||
WCHAR statusBuf[ 32 ];
|
||
|
||
_snwprintf(statusBuf, ( sizeof( statusBuf ) / sizeof( WCHAR )) - 1,
|
||
L"%d",
|
||
dnsStatus );
|
||
ClusResLogSystemEventByKey3(Resource->ResKey,
|
||
LOG_UNUSUAL,
|
||
RES_NETNAME_DNS_PTR_RECORD_DELETE_FAILED,
|
||
dnsRecord->pName,
|
||
dnsRecord->Data.PTR.pNameHost,
|
||
statusBuf);
|
||
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to delete DNS PTR record: owner %1!ws! host: %2!ws!, status %3!u!\n",
|
||
dnsRecord->pName,
|
||
dnsRecord->Data.PTR.pNameHost,
|
||
dnsStatus
|
||
);
|
||
}
|
||
|
||
dnsRecord->pNext = nextDnsRecord;
|
||
dnsRecord = nextDnsRecord;
|
||
}
|
||
}
|
||
|
||
//
|
||
// it's possible to remove all dependencies from the netname
|
||
// resource. In that situation, we're left with no DNS records.
|
||
//
|
||
if ( dnsLists->ForwardZoneIsDynamic && dnsLists->A_RRSet.pFirstRR != NULL ) {
|
||
//
|
||
// delete the A records from the DNS server
|
||
//
|
||
dnsStatus = DnsModifyRecordsInSet_W(NULL,
|
||
dnsLists->A_RRSet.pFirstRR,
|
||
DNS_UPDATE_SECURITY_USE_DEFAULT,
|
||
NULL,
|
||
dnsLists->DnsServerList,
|
||
NULL);
|
||
|
||
if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
|
||
|
||
dnsRecord = dnsLists->A_RRSet.pFirstRR;
|
||
while ( dnsRecord != NULL ) {
|
||
struct in_addr ipAddress;
|
||
|
||
ipAddress.s_addr = dnsRecord->Data.A.IpAddress;
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Deleted DNS A record at server: owner: %1!ws! IP Address: %2!hs!\n",
|
||
dnsRecord->pName,
|
||
inet_ntoa( ipAddress ));
|
||
|
||
dnsRecord = dnsRecord->pNext;
|
||
}
|
||
} else {
|
||
WCHAR statusBuf[ 32 ];
|
||
|
||
_snwprintf(statusBuf, ( sizeof( statusBuf ) / sizeof( WCHAR )) - 1,
|
||
L"%d",
|
||
dnsStatus );
|
||
ClusResLogSystemEventByKey2(Resource->ResKey,
|
||
LOG_UNUSUAL,
|
||
RES_NETNAME_DNS_A_RECORD_DELETE_FAILED,
|
||
dnsLists->A_RRSet.pFirstRR->pName,
|
||
statusBuf);
|
||
|
||
(NetNameLogEvent)(Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to delete DNS A record at server: owner: %1!ws!, status %2!u!\n",
|
||
dnsLists->A_RRSet.pFirstRR->pName,
|
||
dnsStatus
|
||
);
|
||
}
|
||
}
|
||
|
||
++dnsLists;
|
||
}
|
||
|
||
NetNameReleaseDnsListLock( Resource );
|
||
|
||
NetNameCleanupDnsLists( Resource );
|
||
} // RemoveDnsRecords
|
||
|
||
DWORD
|
||
NetNameGetNetworkName(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_GET_NETWORK_NAME control function
|
||
for resources of type Network Name.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
OutBuffer - Returns the output data.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by OutBuffer.
|
||
|
||
BytesReturned - The number of bytes returned in OutBuffer.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
ERROR_MORE_DATA - More data is available than can fit in OutBuffer.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD required;
|
||
|
||
//
|
||
// Calculate the required number of bytes required for
|
||
// the network name string.
|
||
//
|
||
required = (lstrlenW( ResourceEntry->Params.NetworkName ) + 1) * sizeof( WCHAR );
|
||
|
||
//
|
||
// Make sure we can return the required number of bytes.
|
||
//
|
||
if ( BytesReturned == NULL ) {
|
||
status = ERROR_INVALID_PARAMETER;
|
||
} else {
|
||
//
|
||
// Copy the required number of bytes to the output parameter.
|
||
//
|
||
*BytesReturned = required;
|
||
|
||
//
|
||
// If there is no output buffer, the call just wanted the size.
|
||
//
|
||
if ( OutBuffer == NULL ) {
|
||
status = ERROR_SUCCESS;
|
||
} else {
|
||
//
|
||
// If the output buffer is large enough, copy the data.
|
||
// Otherwise return an error.
|
||
//
|
||
if ( OutBufferSize >= required ) {
|
||
lstrcpyW( OutBuffer, ResourceEntry->Params.NetworkName );
|
||
status = ERROR_SUCCESS;
|
||
} else {
|
||
status = ERROR_MORE_DATA;
|
||
}
|
||
}
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // NetNameGetNetworkName
|
||
|
||
//
|
||
// Public Functions
|
||
//
|
||
BOOLEAN
|
||
WINAPI
|
||
NetNameDllEntryPoint(
|
||
IN HINSTANCE DllHandle,
|
||
IN DWORD Reason,
|
||
IN LPVOID Reserved
|
||
)
|
||
{
|
||
switch(Reason) {
|
||
|
||
case DLL_PROCESS_ATTACH:
|
||
return(NetNameInit( DllHandle ));
|
||
break;
|
||
|
||
case DLL_PROCESS_DETACH:
|
||
NetNameCleanup();
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return(TRUE);
|
||
|
||
} // NetNameDllEntryPoint
|
||
|
||
|
||
|
||
RESID
|
||
WINAPI
|
||
NetNameOpen(
|
||
IN LPCWSTR ResourceName,
|
||
IN HKEY ResourceKey,
|
||
IN RESOURCE_HANDLE ResourceHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Open routine for Network Name resource
|
||
|
||
Arguments:
|
||
|
||
ResourceName - supplies the resource name
|
||
|
||
ResourceKey - a registry key for access registry information for this
|
||
resource.
|
||
|
||
ResourceHandle - the resource handle to be supplied with SetResourceStatus
|
||
is called.
|
||
|
||
Return Value:
|
||
|
||
RESID of created resource
|
||
NULL on failure
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
HKEY parametersKey = NULL;
|
||
HKEY nodeParametersKey = NULL;
|
||
HKEY ResKey=NULL;
|
||
PNETNAME_RESOURCE resource = NULL;
|
||
LPWSTR nodeName = NULL;
|
||
DWORD nameSize = MAX_COMPUTERNAME_LENGTH + 1;
|
||
LPWSTR nodeId = NULL;
|
||
DWORD nodeIdSize = 6;
|
||
NETNAME_PARAMS paramBlock;
|
||
LPWSTR lastName = NULL;
|
||
DWORD dwFlags;
|
||
DWORD randomSize;
|
||
HCLUSTER clusterHandle;
|
||
HRESOURCE clusterResourceHandle = NULL;
|
||
|
||
RtlZeroMemory( ¶mBlock, sizeof( paramBlock ));
|
||
|
||
//
|
||
// Open a handle to the resource and remember it.
|
||
//
|
||
clusterHandle = OpenCluster(NULL);
|
||
|
||
if (clusterHandle == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open handle to cluster, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
clusterResourceHandle = OpenClusterResource(
|
||
clusterHandle,
|
||
ResourceName
|
||
);
|
||
|
||
CloseCluster( clusterHandle );
|
||
if (clusterResourceHandle == NULL) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open handle to resource <%1!ws!>, status %2!u!.\n",
|
||
ResourceName,
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Figure out what node we are running on.
|
||
//
|
||
nodeName = LocalAlloc(LMEM_FIXED, nameSize * sizeof(WCHAR));
|
||
|
||
if (nodeName == NULL) {
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto error_exit;
|
||
}
|
||
|
||
if ( !GetComputerNameW(nodeName, &nameSize) ) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get local node name, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
nodeId = LocalAlloc(LMEM_FIXED, nodeIdSize * sizeof(WCHAR));
|
||
|
||
if (nodeId == NULL) {
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate memory.\n"
|
||
);
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto error_exit;
|
||
}
|
||
|
||
status = GetCurrentClusterNodeId(nodeId, &nodeIdSize);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to get local node name, status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Open handles to our key, our parameters key, and our node parameters
|
||
// key in the registry
|
||
//
|
||
status = ClusterRegOpenKey(ResourceKey,
|
||
L"",
|
||
KEY_ALL_ACCESS,
|
||
&ResKey);
|
||
|
||
if (status != ERROR_SUCCESS)
|
||
{
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open the top level key,status %1!u!.\n",
|
||
status
|
||
);
|
||
goto error_exit;
|
||
}
|
||
|
||
status = ClusterRegOpenKey(ResourceKey,
|
||
CLUSREG_KEYNAME_PARAMETERS,
|
||
KEY_ALL_ACCESS,
|
||
¶metersKey);
|
||
|
||
if (status != NO_ERROR) {
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open parameters key, status %1!u!.\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
status = ClusterRegOpenKey(
|
||
parametersKey,
|
||
nodeId,
|
||
KEY_ALL_ACCESS,
|
||
&nodeParametersKey
|
||
);
|
||
|
||
if (status == NO_ERROR) {
|
||
|
||
//
|
||
// Fetch our parameters from the registry.
|
||
//
|
||
status = NetNameGetParameters(ResourceKey,
|
||
parametersKey,
|
||
nodeParametersKey,
|
||
ResourceHandle,
|
||
¶mBlock,
|
||
&randomSize,
|
||
&lastName,
|
||
&dwFlags);
|
||
|
||
if (status == ERROR_SUCCESS && lastName != NULL) {
|
||
|
||
//
|
||
// Delete the name if it is currently instantiated, making sure
|
||
// that the specified network name is not the same as the
|
||
// computername of this node.
|
||
//
|
||
if (lstrcmpiW(lastName, nodeName) != 0) {
|
||
DeleteServerName(ResourceHandle, lastName);
|
||
}
|
||
}
|
||
} else {
|
||
if ( status != ERROR_FILE_NOT_FOUND ) {
|
||
(NetNameLogEvent)(ResourceHandle,
|
||
LOG_UNUSUAL,
|
||
L"Unable to open node parameters key, status %1!u!.\n",
|
||
status);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now we're ready to create a resource.
|
||
//
|
||
resource = NetNameAllocateResource(ResourceHandle);
|
||
|
||
if (resource == NULL) {
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate resource structure.\n"
|
||
);
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto error_exit;
|
||
} else {
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
resource->RefCount = 1;
|
||
resource->NodeName = nodeName;
|
||
resource->NodeId = nodeId;
|
||
resource->State = ClusterResourceOffline;
|
||
resource->ResKey = ResKey;
|
||
resource->ParametersKey = parametersKey;
|
||
resource->NodeParametersKey = nodeParametersKey;
|
||
resource->Params = paramBlock;
|
||
resource->RandomSize = randomSize;
|
||
resource->dwFlags = dwFlags;
|
||
resource->ClusterResourceHandle = clusterResourceHandle;
|
||
resource->NameChangedWhileOnline = FALSE;
|
||
|
||
//
|
||
// initialize the mutex used to protect the DNS list data.
|
||
//
|
||
resource->DnsListMutex = CreateMutex(NULL, FALSE, NULL);
|
||
if ( resource->DnsListMutex == NULL ) {
|
||
status = GetLastError();
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to initialize DNS list mutex: %1!d!.\n",
|
||
status);
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// insert resource in list for DNS check routine
|
||
//
|
||
NetNameAcquireResourceLock();
|
||
InsertHeadList( &NetNameResourceListHead, &resource->Next );
|
||
NetNameReleaseResourceLock();
|
||
|
||
InterlockedIncrement(&NetNameOpenCount);
|
||
|
||
#ifdef COMPOBJ_SUPPORT
|
||
//
|
||
// If a computer object already exists for this name, get its object
|
||
// GUID. We can't fail the open if this doesn't succeed: while the
|
||
// resource may have its name property set, it may have never gone online,
|
||
// therefore there maybe no CO in the DS at this point in time.
|
||
//
|
||
if ( resource->Params.NetworkName != NULL ) {
|
||
GetComputerObjectGuid( resource );
|
||
}
|
||
#endif
|
||
|
||
error_exit:
|
||
if (lastName != NULL) {
|
||
LocalFree(lastName);
|
||
}
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Successful open of resid %1!u!\n",
|
||
resource
|
||
);
|
||
} else {
|
||
|
||
if (paramBlock.NetworkName != NULL) {
|
||
LocalFree(paramBlock.NetworkName);
|
||
}
|
||
|
||
if (paramBlock.NetworkRandom != NULL) {
|
||
LocalFree(paramBlock.NetworkRandom);
|
||
}
|
||
|
||
if (parametersKey != NULL) {
|
||
ClusterRegCloseKey(parametersKey);
|
||
}
|
||
|
||
if (ResKey != NULL){
|
||
ClusterRegCloseKey(ResKey);
|
||
}
|
||
if (nodeParametersKey != NULL) {
|
||
ClusterRegCloseKey(nodeParametersKey);
|
||
}
|
||
|
||
if (clusterResourceHandle != NULL) {
|
||
CloseClusterResource(clusterResourceHandle);
|
||
}
|
||
|
||
if (nodeName != NULL) {
|
||
LocalFree(nodeName);
|
||
}
|
||
|
||
if (nodeId != NULL) {
|
||
LocalFree(nodeId);
|
||
}
|
||
|
||
if (resource != NULL) {
|
||
LocalFree(resource);
|
||
}
|
||
|
||
(NetNameLogEvent)(
|
||
ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Open failed, status %1!u!\n",
|
||
status
|
||
);
|
||
|
||
SetLastError(status);
|
||
}
|
||
|
||
return resource;
|
||
} // NetNameOpen
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
NetNameOnline(
|
||
IN RESID Resource,
|
||
IN OUT PHANDLE EventHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Online routine for Network Name resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be brought online
|
||
|
||
EventHandle - supplies a pointer to a handle to signal on error.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
|
||
ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
|
||
acquire 'ownership'.
|
||
Win32 error code if other failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
|
||
DWORD threadId;
|
||
DWORD status=ERROR_SUCCESS;
|
||
|
||
|
||
if (resource == NULL) {
|
||
return(ERROR_RESOURCE_NOT_FOUND);
|
||
}
|
||
|
||
NetNameAcquireResourceLock();
|
||
|
||
resource->State = ClusterResourceOnlinePending;
|
||
|
||
status = ClusWorkerCreate(
|
||
&resource->PendingThread,
|
||
NetNameOnlineThread,
|
||
resource
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
resource->State = ClusterResourceFailed;
|
||
|
||
(NetNameLogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to start online thread, status %1!u!.\n",
|
||
status
|
||
);
|
||
}
|
||
else {
|
||
status = ERROR_IO_PENDING;
|
||
}
|
||
|
||
NetNameReleaseResourceLock();
|
||
|
||
return(status);
|
||
|
||
} // NetNameOnline
|
||
|
||
DWORD
|
||
WINAPI
|
||
NetNameOffline(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Offline routine for Network Name resource. Spin a worker thread and return
|
||
pending.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be taken offline.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
A Win32 error code otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
|
||
|
||
if (resource != NULL) {
|
||
(NetNameLogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Taking resource offline...\n"
|
||
);
|
||
|
||
status = ClusWorkerCreate(&resource->PendingThread,
|
||
NetNameOfflineThread,
|
||
resource);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
resource->State = ClusterResourceFailed;
|
||
|
||
(NetNameLogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to start offline thread, status %1!u!.\n",
|
||
status
|
||
);
|
||
}
|
||
else {
|
||
status = ERROR_IO_PENDING;
|
||
}
|
||
}
|
||
else {
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // NetNameOffline
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
NetNameTerminate(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Terminate routine for Network Name resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be terminated
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
|
||
|
||
if (resource != NULL) {
|
||
(NetNameLogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Terminating resource...\n"
|
||
);
|
||
|
||
/* Ruihu: 11/06/2000 */
|
||
NetNameAcquireResourceLock();
|
||
if ((resource->State != ClusterResourceOffline) &&
|
||
(resource->State != ClusterResourceOfflinePending))
|
||
{
|
||
//
|
||
// only call private offline routine if we haven't called it
|
||
// already
|
||
//
|
||
NetNameReleaseResourceLock();
|
||
NetNameOfflineWorker( resource, TRUE, NULL );
|
||
NetNameAcquireResourceLock();
|
||
}
|
||
resource->State = ClusterResourceOffline;
|
||
NetNameReleaseResourceLock();
|
||
/* Ruihu: 11/06/2000 */
|
||
}
|
||
|
||
return;
|
||
|
||
} // NetNameTerminate
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
NetNameLooksAlive(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
LooksAlive routine for Network Name resource.
|
||
|
||
Check that any Netbt plumbing is still intact. Then check the status of
|
||
the last DNS operation. Finally check the kerberos status and fail if
|
||
appropriate to do so.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies the resource id to be polled.
|
||
|
||
Return Value:
|
||
|
||
TRUE - Resource looks like it is alive and well
|
||
|
||
FALSE - Resource looks like it is toast.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
|
||
BOOL isHealthy = TRUE;
|
||
DWORD status;
|
||
DWORD numberOfFailures = 0;
|
||
ULONG numberOfDnsLists;
|
||
PDNS_LISTS dnsLists;
|
||
BOOL dnsFailure = FALSE;
|
||
|
||
if (resource == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
NetNameAcquireResourceLock();
|
||
|
||
//
|
||
// avoid gotos by breaking out of fake do loop
|
||
//
|
||
do {
|
||
|
||
status = NetNameCheckNbtName(resource->Params.NetworkName,
|
||
resource->NameHandleCount,
|
||
resource->NameHandleList,
|
||
resource->ResourceHandle);
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
ClusResLogSystemEventByKeyData1(resource->ResKey,
|
||
LOG_CRITICAL,
|
||
RES_NETNAME_CANT_ADD_NAME,
|
||
sizeof(status),
|
||
&status,
|
||
resource->Params.NetworkName);
|
||
|
||
(NetNameLogEvent)(resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Name %1!ws! failed IsAlive/LooksAlive check, error %2!u!.\n",
|
||
resource->Params.NetworkName,
|
||
status);
|
||
|
||
isHealthy = FALSE;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// check how many of the DNS A record registrations are correct. We
|
||
// don't acquire the resource's DNS list lock since we're only reading
|
||
// the status out of a struct. The resource can't be deleted while
|
||
// we're in this routine and we're not walking the DNS records
|
||
// associated with this list so the number of lists won't change out
|
||
// from underneath of us.
|
||
//
|
||
numberOfDnsLists = resource->NumberOfDnsLists;
|
||
dnsLists = resource->DnsLists;
|
||
|
||
while ( numberOfDnsLists-- ) {
|
||
DNS_STATUS dnsStatus;
|
||
|
||
dnsStatus = InterlockedExchange(&dnsLists->LastARecQueryStatus,
|
||
dnsLists->LastARecQueryStatus);
|
||
|
||
if (dnsStatus != DNS_ERROR_RCODE_NO_ERROR && dnsStatus != ERROR_TIMEOUT ) {
|
||
dnsFailure = TRUE;
|
||
++numberOfFailures;
|
||
}
|
||
|
||
++dnsLists;
|
||
}
|
||
|
||
//
|
||
// If DNS is required and we detected a failure other than timeout or all
|
||
// DNS name registrations failed and there are no netbt names associated
|
||
// with this name, then we need to fail the resource
|
||
//
|
||
if ( ( resource->Params.RequireDNS && dnsFailure )
|
||
||
|
||
( numberOfFailures == resource->NumberOfDnsLists
|
||
&&
|
||
resource->NameHandleCount == 0 ) )
|
||
{
|
||
isHealthy = FALSE;
|
||
break;
|
||
}
|
||
|
||
#if 0
|
||
if ( resource->DoKerberosCheck ) {
|
||
//
|
||
// ISSUE-01/03/13 charlwi - should resource fail if can't reach DS?
|
||
//
|
||
// The problem here is that we might have lost our connection to a
|
||
// DC. Does that mean we fail the name? Not sure, since we don't know
|
||
// if replication has been late. On the other hand, if the object has
|
||
// been deleted from the DS, we should take some sort of action. This
|
||
// will affect clients that do not have tickets at this point, i.e.,
|
||
// existing clients with tickets will continue to work.
|
||
//
|
||
// see if our kerb plumbing is intact by getting a handle to the
|
||
// computer object and checking its DnsHostName and
|
||
// SecurityPrincipalName attributes
|
||
//
|
||
status = InterlockedExchange( &resource->KerberosStatus, resource->KerberosStatus );
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
isHealthy = FALSE;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
} while ( FALSE );
|
||
|
||
NetNameReleaseResourceLock();
|
||
|
||
return isHealthy;
|
||
|
||
} // NetNameLooksAlive
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
NetNameIsAlive(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
IsAlive routine for Network Name resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies the resource id to be polled.
|
||
|
||
Return Value:
|
||
|
||
TRUE - Resource is alive and well
|
||
|
||
FALSE - Resource is toast.
|
||
|
||
--*/
|
||
|
||
{
|
||
return(NetNameLooksAlive(Resource));
|
||
|
||
} // NetNameIsAlive
|
||
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
NetNameClose(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Close routine for Network Name resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be closed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
|
||
PLIST_ENTRY entry;
|
||
|
||
|
||
if (resource != NULL) {
|
||
|
||
ClusWorkerTerminate( &resource->PendingThread );
|
||
if ( InterlockedDecrement(&NetNameOpenCount) == 0 ) {
|
||
// This is the last resource //
|
||
// Kill NetNameWorker //
|
||
//
|
||
// set the event to terminate the worker thread and wait for it to
|
||
// terminate.
|
||
//
|
||
if ( NetNameWorkerThread != NULL ) {
|
||
DWORD status;
|
||
SetEvent( NetNameWorkerTerminate );
|
||
status = WaitForSingleObject(NetNameWorkerThread, 3 * 60 * 1000);
|
||
if ( status == WAIT_TIMEOUT ) {
|
||
(NetNameLogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_CRITICAL,
|
||
L"Worker routine failed to stop. Terminating resrcmon.\n");
|
||
ClusResLogSystemEventByKey(resource->ResKey,
|
||
LOG_CRITICAL,
|
||
RES_NETNAME_DNS_CANNOT_STOP
|
||
);
|
||
ExitProcess(WAIT_TIMEOUT);
|
||
}
|
||
|
||
CloseHandle( NetNameWorkerThread );
|
||
NetNameWorkerThread = NULL;
|
||
}
|
||
}
|
||
|
||
NetNameAcquireResourceLock();
|
||
|
||
//
|
||
// release our reference to this block. If the DNS worker thread
|
||
// doesn't have an outstanding reference to it, then we can zap the
|
||
// block now. Otherwise the DNS check routine will detect that the ref
|
||
// count went to zero and get rid of it then. In either case, remove
|
||
// it from the resource block list to avoid the problem where an
|
||
// identical resource is recreated and both blocks are on the list.
|
||
//
|
||
RemoveEntryList(&resource->Next);
|
||
|
||
ASSERT( resource->RefCount > 0 );
|
||
if ( --resource->RefCount == 0 ) {
|
||
NetNameReleaseResource( resource );
|
||
}
|
||
|
||
NetNameReleaseResourceLock();
|
||
}
|
||
|
||
return;
|
||
|
||
} // NetNameClose
|
||
|
||
|
||
DWORD
|
||
NetNameGetRequiredDependencies(
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
|
||
for resources of type Network Name.
|
||
|
||
Arguments:
|
||
|
||
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the available space
|
||
pointed to by OutBuffer.
|
||
|
||
BytesReturned - Returns the number of bytes of OutBuffer actually
|
||
filled in by the resource. If OutBuffer is too small, BytesReturned
|
||
contains the total number of bytes for the operation to succeed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_MORE_DATA - The output buffer is too small to return the data.
|
||
BytesReturned contains the required size.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
typedef struct DEP_DATA {
|
||
CLUSPROP_SZ_DECLARE( ipaddrEntry, sizeof(IP_ADDRESS_RESOURCETYPE_NAME) / sizeof(WCHAR) );
|
||
CLUSPROP_SYNTAX endmark;
|
||
} DEP_DATA, *PDEP_DATA;
|
||
PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
|
||
DWORD status;
|
||
|
||
*BytesReturned = sizeof(DEP_DATA);
|
||
if ( OutBufferSize < sizeof(DEP_DATA) ) {
|
||
if ( OutBuffer == NULL ) {
|
||
status = ERROR_SUCCESS;
|
||
} else {
|
||
status = ERROR_MORE_DATA;
|
||
}
|
||
} else {
|
||
ZeroMemory( pdepdata, sizeof(DEP_DATA) );
|
||
pdepdata->ipaddrEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
|
||
pdepdata->ipaddrEntry.cbLength = sizeof(IP_ADDRESS_RESOURCETYPE_NAME);
|
||
lstrcpyW( pdepdata->ipaddrEntry.sz, IP_ADDRESS_RESOURCETYPE_NAME );
|
||
pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
|
||
return status;
|
||
|
||
} // NetNameGetRequiredDependencies
|
||
|
||
DWORD
|
||
NetNameResourceControl(
|
||
IN RESID Resource,
|
||
IN DWORD ControlCode,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ResourceControl routine for Network Name resources.
|
||
|
||
Perform the control request specified by ControlCode on the specified
|
||
resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - Supplies the resource id for the specific resource.
|
||
|
||
ControlCode - Supplies the control code that defines the action
|
||
to be performed.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the available space
|
||
pointed to by OutBuffer.
|
||
|
||
BytesReturned - Returns the number of bytes of OutBuffer actually
|
||
filled in by the resource. If OutBuffer is too small, BytesReturned
|
||
contains the total number of bytes for the operation to succeed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_FUNCTION - The requested control code is not supported.
|
||
In some cases, this allows the cluster software to perform the work.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
PNETNAME_RESOURCE resourceEntry = (PNETNAME_RESOURCE)Resource;
|
||
DWORD required;
|
||
BOOL readOnly = FALSE;
|
||
BOOL nameHasChanged;
|
||
|
||
switch ( ControlCode ) {
|
||
|
||
case CLUSCTL_RESOURCE_UNKNOWN:
|
||
*BytesReturned = 0;
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
|
||
status = ResUtilGetPropertyFormats( NetNameResourcePrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
if ( status == ERROR_MORE_DATA ) {
|
||
*BytesReturned = required;
|
||
}
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
|
||
status = NetNameGetRequiredDependencies( OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned
|
||
);
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
|
||
status = ResUtilEnumProperties( NetNameResourcePrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
if ( status == ERROR_MORE_DATA ) {
|
||
*BytesReturned = required;
|
||
}
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES:
|
||
//
|
||
// NOTE: fallthrough is the required behavior here.
|
||
//
|
||
readOnly = TRUE;
|
||
|
||
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
|
||
status = NetNameGetPrivateResProperties( resourceEntry,
|
||
readOnly,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
|
||
status = NetNameValidatePrivateResProperties( resourceEntry,
|
||
InBuffer,
|
||
InBufferSize,
|
||
NULL,
|
||
&nameHasChanged);
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
|
||
status = NetNameSetPrivateResProperties( resourceEntry,
|
||
InBuffer,
|
||
InBufferSize );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_CLUSTER_NAME_CHANGED:
|
||
//fm has changed the cluster name, this resource should read its
|
||
//private name property from the registry if it is a core resource
|
||
status = NetNameClusterNameChanged(resourceEntry);
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_GET_NETWORK_NAME:
|
||
status = NetNameGetNetworkName( resourceEntry,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_DELETE:
|
||
RemoveDnsRecords( resourceEntry );
|
||
|
||
#ifdef COMPOBJ_SUPPORT
|
||
//
|
||
// if resource was created but has no properities, then
|
||
// NetworkName can be NULL
|
||
//
|
||
if ( resourceEntry->Params.NetworkName != NULL ) {
|
||
NetNameDeleteComputerObject( resourceEntry );
|
||
}
|
||
#endif
|
||
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_REMOVE_DEPENDENCY:
|
||
//
|
||
// argh! resource dependencies can be removed without any veto
|
||
// power by the resource DLL. We could be deleting the last
|
||
// dependent resource which leaves netname with nothing.
|
||
//
|
||
RemoveDependentIpAddress( resourceEntry, InBuffer );
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
status = ERROR_INVALID_FUNCTION;
|
||
break;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // NetNameResourceControl
|
||
|
||
DWORD
|
||
NetNameResourceTypeControl(
|
||
IN LPCWSTR ResourceTypeName,
|
||
IN DWORD ControlCode,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ResourceTypeControl routine for Network Name resources.
|
||
|
||
Perform the control request specified by ControlCode.
|
||
|
||
Arguments:
|
||
|
||
ResourceTypeName - Supplies the name of the resource type.
|
||
|
||
ControlCode - Supplies the control code that defines the action
|
||
to be performed.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the available space
|
||
pointed to by OutBuffer.
|
||
|
||
BytesReturned - Returns the number of bytes of OutBuffer actually
|
||
filled in by the resource. If OutBuffer is too small, BytesReturned
|
||
contains the total number of bytes for the operation to succeed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_FUNCTION - The requested control code is not supported.
|
||
In some cases, this allows the cluster software to perform the work.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD required;
|
||
|
||
switch ( ControlCode ) {
|
||
|
||
case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
|
||
*BytesReturned = 0;
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
|
||
status = ResUtilGetPropertyFormats( NetNameResourcePrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
if ( status == ERROR_MORE_DATA ) {
|
||
*BytesReturned = required;
|
||
}
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
|
||
status = NetNameGetRequiredDependencies( OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned
|
||
);
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
|
||
status = ResUtilEnumProperties( NetNameResourcePrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
if ( status == ERROR_MORE_DATA ) {
|
||
*BytesReturned = required;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
status = ERROR_INVALID_FUNCTION;
|
||
break;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // NetNameResourceTypeControl
|
||
|
||
DWORD
|
||
NetNameGetPrivateResProperties(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
IN BOOL ReadOnly,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
|
||
for resources of type Network Name.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
ReadOnly - true if we're selecting read only property table
|
||
|
||
OutBuffer - Returns the output data.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by OutBuffer.
|
||
|
||
BytesReturned - The number of bytes returned in OutBuffer.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD required;
|
||
|
||
//
|
||
// The resutil routines don't support resources with r/w, r/o, and unknown
|
||
// props very well. There is no easy way to get just the unknown
|
||
// properties. For the r/o request, the props are separated out into a
|
||
// separate table. For the r/w case, if we call RUGetAllProperties using
|
||
// the r/w table, we get the r/o props back since they weren't in the
|
||
// table. If we combine the two tables into one, then the r/o case is
|
||
// broken, i.e., it returns the r/w props as well as the r/o ones.
|
||
//
|
||
// The current (yucky) solution is to have 3 tables: r/w, r/o, and
|
||
// combined. Combined is used to get any unknown props that are associated
|
||
// with the resource. It would be nice to have a resutils routine that
|
||
// gathers the unknown props using a list of prop list tables as input.
|
||
//
|
||
if ( ReadOnly ) {
|
||
status = ResUtilGetProperties(ResourceEntry->ParametersKey,
|
||
NetNameResourceROPrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
} else {
|
||
//
|
||
// get the r/w props first; after the call, required will be non-zero
|
||
// if the buffer wasn't large enough. Regardless, we have to continue
|
||
// to get the amount of space for any unknown props
|
||
//
|
||
status = ResUtilGetProperties(ResourceEntry->ParametersKey,
|
||
NetNameResourcePrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
|
||
//
|
||
// Add unknown properties to the property list.
|
||
//
|
||
if ( status == ERROR_SUCCESS || status == ERROR_MORE_DATA ) {
|
||
status = ResUtilAddUnknownProperties(ResourceEntry->ParametersKey,
|
||
NetNameResourceCombinedPrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required);
|
||
}
|
||
} // end of if getting r/w props
|
||
|
||
//
|
||
// This is kinda wierd: if null is passed in for the input buffer, the
|
||
// return status is success and required reflects how many bytes are
|
||
// needed. If a buffer was specified but it was too small, then more data
|
||
// is returned. It appears that the thing to watch is required indicating
|
||
// that more space is needed regardless of whether a buffer was specified
|
||
// or not.
|
||
//
|
||
if ( required > 0 && ( status == ERROR_SUCCESS || status == ERROR_MORE_DATA )) {
|
||
*BytesReturned = required;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // NetNameGetPrivateResProperties
|
||
|
||
DWORD
|
||
NetNameValidatePrivateResProperties(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PNETNAME_PARAMS Params,
|
||
OUT PBOOL NewNameIsDifferent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
|
||
function for resources of type Network Name.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
Params - Supplies the parameter block to fill in.
|
||
|
||
NewNameIsDifferent - TRUE if the new name is different than the current name
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_DATA - No input data.
|
||
|
||
ERROR_INVALID_NETNAME - The specified network name has invalid characters.
|
||
|
||
RPC_S_STRING_TOO_LONG - The specified network name is too long.
|
||
|
||
ERROR_BUSY - The specified network name is already in use.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
CLRTL_NAME_STATUS netnameStatus;
|
||
NETNAME_PARAMS currentProps;
|
||
NETNAME_PARAMS newProps;
|
||
PNETNAME_PARAMS pParams;
|
||
LPWSTR nameOfPropInError;
|
||
|
||
//
|
||
// Check if there is input data.
|
||
//
|
||
if ( (InBuffer == NULL) ||
|
||
(InBufferSize < sizeof(DWORD)) ) {
|
||
return(ERROR_INVALID_DATA);
|
||
}
|
||
|
||
//
|
||
// Retrieve the current set of private properties from the cluster
|
||
// database. This may be different from what is stored in ResourceEntry
|
||
// since the name could be online at this point in time.
|
||
//
|
||
ZeroMemory( ¤tProps, sizeof(currentProps) );
|
||
|
||
status = ResUtilGetPropertiesToParameterBlock(
|
||
ResourceEntry->ParametersKey,
|
||
NetNameResourcePrivateProperties,
|
||
(LPBYTE) ¤tProps,
|
||
FALSE, /*CheckForRequiredProperties*/
|
||
&nameOfPropInError
|
||
);
|
||
|
||
if ( status != ERROR_SUCCESS ) {
|
||
(NetNameLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to read the '%1' property. Error: %2!u!.\n",
|
||
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
|
||
status );
|
||
goto FnExit;
|
||
}
|
||
|
||
//
|
||
// Duplicate the resource parameter block.
|
||
//
|
||
if ( Params == NULL ) {
|
||
pParams = &newProps;
|
||
} else {
|
||
pParams = Params;
|
||
}
|
||
ZeroMemory( pParams, sizeof(NETNAME_PARAMS) );
|
||
status = ResUtilDupParameterBlock( (LPBYTE) pParams,
|
||
(LPBYTE) ¤tProps,
|
||
NetNameResourcePrivateProperties );
|
||
if ( status != ERROR_SUCCESS ) {
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Parse and validate the properties.
|
||
//
|
||
status = ResUtilVerifyPropertyTable( NetNameResourcePrivateProperties,
|
||
NULL,
|
||
TRUE, // Allow unknowns
|
||
InBuffer,
|
||
InBufferSize,
|
||
(LPBYTE) pParams );
|
||
|
||
if ( status == ERROR_SUCCESS ) {
|
||
|
||
*NewNameIsDifferent = FALSE;
|
||
|
||
//
|
||
// check the new name if:
|
||
// the name has never been set (ResourceEntry value is null)
|
||
// OR
|
||
// ( it is different from the future name (currentProps).
|
||
// AND
|
||
// it is different from the name currently online (ResourceEntry)
|
||
// )
|
||
//
|
||
// ClRtlIsNetNameValid will fail if the name hasn't changed and the name
|
||
// is online. currentProps value is NULL only when the name is first
|
||
// created and hasn't been online at all, i.e., no data in the
|
||
// registry. Once brought online, the currentProps value is always
|
||
// non-NULL hence no need to test if the pointer is valid.
|
||
//
|
||
if (ResourceEntry->Params.NetworkName == NULL
|
||
||
|
||
(
|
||
_wcsicmp( pParams->NetworkName, currentProps.NetworkName ) != 0
|
||
&&
|
||
_wcsicmp( pParams->NetworkName, ResourceEntry->Params.NetworkName ) != 0
|
||
)
|
||
)
|
||
{
|
||
//
|
||
// Validate the parameter values.
|
||
//
|
||
if ( !ClRtlIsNetNameValid( pParams->NetworkName, &netnameStatus, TRUE /* CheckIfExists */ ) ) {
|
||
switch ( netnameStatus ) {
|
||
case NetNameTooLong:
|
||
status = RPC_S_STRING_TOO_LONG;
|
||
break;
|
||
case NetNameInUse:
|
||
status = ERROR_DUP_NAME;
|
||
break;
|
||
case NetNameDNSNonRFCChars:
|
||
//
|
||
// we leave it up to the calling application to do the
|
||
// validation and ask the user if non-RFC chars
|
||
// (underscores) are acceptable.
|
||
//
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
case NetNameInvalidChars:
|
||
default:
|
||
status = ERROR_INVALID_NETNAME;
|
||
break;
|
||
}
|
||
}
|
||
|
||
#ifdef COMPOBJ_SUPPORT
|
||
//
|
||
// The NewNameIsDifferent flag drives the offline cleanup
|
||
// routine. If the name has truly changed while it was online,
|
||
// then we want to do the appropriate cleanup when it goes
|
||
// offline. The problem is that the name can change many times
|
||
// while it is online; it could return to its current value so the
|
||
// overall appearance is that it never changed. In that case, we
|
||
// want to avoid cleanup.
|
||
//
|
||
// If we're here because we're creating the name for the first
|
||
// time and the properties haven't been read from the registry,
|
||
// (ResourceEntry->Params.NetworkName equals NULL), then don't
|
||
// consider the name to be changed. Otherwise, we consider it
|
||
// changed if it is different from the currently stored name
|
||
// (currentProps) or the current "online" name
|
||
// (ResourceEntry->...).
|
||
//
|
||
if ( status == ERROR_SUCCESS && ResourceEntry->Params.NetworkName != NULL ) {
|
||
|
||
if ( _wcsicmp( pParams->NetworkName, currentProps.NetworkName ) != 0
|
||
&&
|
||
_wcsicmp( pParams->NetworkName, ResourceEntry->Params.NetworkName ) != 0
|
||
)
|
||
{
|
||
BOOL objectExists;
|
||
|
||
//
|
||
// a CO for the new name can't already exist in the DS if
|
||
// we're renaming a netname that has been online at least
|
||
// once. Renaming would require deleting the existing
|
||
// object which is a bad decision for netname to be
|
||
// making.
|
||
//
|
||
status = IsComputerObjectInDS(ResourceEntry->NodeName,
|
||
pParams->NetworkName,
|
||
&objectExists);
|
||
|
||
if ( status == ERROR_SUCCESS && objectExists ) {
|
||
status = E_ADS_OBJECT_EXISTS;
|
||
}
|
||
|
||
*NewNameIsDifferent = TRUE;
|
||
}
|
||
}
|
||
#else
|
||
*NewNameIsDifferent = TRUE;
|
||
#endif // COMPOBJ_SUPPORT
|
||
}
|
||
|
||
if ( status == ERROR_SUCCESS ) {
|
||
//
|
||
// passed the valid check. now check that RequireDns must be set
|
||
// if RequireKerberos is set
|
||
//
|
||
if ( !pParams->RequireDNS && pParams->RequireKerberos ) {
|
||
status = ERROR_CLUSTER_PARAMETER_MISMATCH;
|
||
}
|
||
}
|
||
} // end if ResUtilVerifyPropertyTable was successful
|
||
|
||
FnExit:
|
||
//
|
||
// Cleanup our parameter block.
|
||
//
|
||
if (( status != ERROR_SUCCESS && pParams != NULL )
|
||
||
|
||
pParams == &newProps
|
||
)
|
||
{
|
||
ResUtilFreeParameterBlock( (LPBYTE) pParams,
|
||
(LPBYTE) ¤tProps,
|
||
NetNameResourcePrivateProperties );
|
||
}
|
||
|
||
ResUtilFreeParameterBlock(
|
||
(LPBYTE) ¤tProps,
|
||
NULL,
|
||
NetNameResourcePrivateProperties
|
||
);
|
||
|
||
return(status);
|
||
|
||
} // NetNameValidatePrivateResProperties
|
||
|
||
DWORD
|
||
NetNameSetPrivateResProperties(
|
||
IN OUT PNETNAME_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
|
||
for resources of type Network Name.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
BOOL newNameIsDifferent;
|
||
BOOL disablingKerberos;
|
||
|
||
NETNAME_PARAMS params;
|
||
|
||
ZeroMemory( ¶ms, sizeof(NETNAME_PARAMS) );
|
||
|
||
//
|
||
// Parse the properties so they can be validated together.
|
||
// This routine does individual property validation.
|
||
//
|
||
status = NetNameValidatePrivateResProperties( ResourceEntry,
|
||
InBuffer,
|
||
InBufferSize,
|
||
¶ms,
|
||
&newNameIsDifferent);
|
||
if ( status != ERROR_SUCCESS ) {
|
||
return(status);
|
||
}
|
||
|
||
|
||
//
|
||
// If network name is one of the parameters to be set, convert the name
|
||
// to uppercase.
|
||
//
|
||
if ( params.NetworkName != NULL ) {
|
||
_wcsupr( params.NetworkName );
|
||
}
|
||
|
||
//
|
||
// if kerb is currently required and we're turning it off, then note that
|
||
// now.
|
||
//
|
||
disablingKerberos = ( ResourceEntry->Params.RequireKerberos && !params.RequireKerberos );
|
||
|
||
if ( ResourceEntry->State == ClusterResourceOnline ||
|
||
ResourceEntry->State == ClusterResourceOnlinePending )
|
||
{
|
||
//
|
||
// If the resource is online, remember that the name property has
|
||
// truly changed (it can change and then be set back to its original
|
||
// value while online) and whether we need to delete the CO because is
|
||
// no longer required.
|
||
//
|
||
ResourceEntry->NameChangedWhileOnline = newNameIsDifferent;
|
||
ResourceEntry->DeleteCOWhenOffline = disablingKerberos;
|
||
|
||
status = ERROR_RESOURCE_PROPERTIES_STORED;
|
||
}
|
||
else {
|
||
if ( newNameIsDifferent ) {
|
||
//
|
||
// name change; try to cleanup the old name's DNS records
|
||
//
|
||
RemoveDnsRecords( ResourceEntry );
|
||
|
||
#if RENAME_SUPPORT
|
||
//
|
||
// ISSUE-01/04/05 charlwi - changes required if object renaming is supported
|
||
//
|
||
// Renaming the object adds another wrinkle at this point in that
|
||
// we always need to make sure that the name of the object in the
|
||
// DS is the same as the netname name property. So if we change
|
||
// the name, we change the object name. If we change the name back
|
||
// to its original name (without necessarily bringing it online),
|
||
// then we have to change the object name as well.
|
||
//
|
||
// The previous strategy worked since all that was cleaned up
|
||
// during a name change were the DNS records. If a name was
|
||
// changed and then changed back to its original name, the most
|
||
// damage done was the deletion of the DNS records which would
|
||
// have been re-registered the next time the name went
|
||
// online. With object renaming, we will probably need to track
|
||
// the renaming events separately from whether the name has
|
||
// changed from what is stored in the registry (the current
|
||
// property value).
|
||
//
|
||
if ( !disablingKerberos ) {
|
||
status = RenameComputerObject( ResourceEntry, params.NetworkName );
|
||
|
||
if ( status == ERROR_NO_SUCH_DOMAIN ) {
|
||
//
|
||
// no DC is available; remember this so we can rename
|
||
// when we bring the name back online.
|
||
//
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
else if ( status != ERROR_SUCCESS ) {
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if ( disablingKerberos ) {
|
||
status = NetNameDeleteComputerObject( ResourceEntry );
|
||
if ( status == NERR_UserNotFound ) {
|
||
//
|
||
// it's not an error if the CO is already gone
|
||
//
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
else if ( status == ERROR_NO_SUCH_DOMAIN ) {
|
||
//
|
||
// can't contact a DC right now. Remember that and the old
|
||
// name so we can try to rename when brought online again.
|
||
//
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( status == ERROR_SUCCESS || status == ERROR_RESOURCE_PROPERTIES_STORED ) {
|
||
//
|
||
// Save the parameter values.
|
||
//
|
||
status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
|
||
NetNameResourcePrivateProperties,
|
||
NULL,
|
||
(LPBYTE) ¶ms,
|
||
InBuffer,
|
||
InBufferSize,
|
||
NULL );
|
||
}
|
||
|
||
ResUtilFreeParameterBlock( (LPBYTE) ¶ms,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
NetNameResourcePrivateProperties );
|
||
|
||
return status;
|
||
|
||
} // NetNameSetPrivateResProperties
|
||
|
||
|
||
/****
|
||
@func BOOL | NetNameClusterNameChanged| Called when FM notifies the
|
||
core network resource dll that the cluster name and the private
|
||
name property of the resource has been changed.
|
||
|
||
@parm PNETNAME_RESOURCE | pResource | Pointer to the netname
|
||
resource whose name is being changed.
|
||
|
||
@comm A core network resource updates its inmemory structure by reading the
|
||
registry.
|
||
@xref
|
||
****/
|
||
DWORD
|
||
NetNameClusterNameChanged(
|
||
IN PNETNAME_RESOURCE Resource
|
||
)
|
||
{
|
||
|
||
LPWSTR NetworkName;
|
||
DWORD dwError = ERROR_SUCCESS;
|
||
|
||
if (Resource->dwFlags & CLUS_FLAG_CORE)
|
||
{
|
||
//
|
||
// Read the private parameters.
|
||
//
|
||
NetworkName = ResUtilGetSzValue(
|
||
Resource->ParametersKey,
|
||
PARAM_NAME__NAME
|
||
);
|
||
|
||
if (NetworkName == NULL) {
|
||
(NetNameLogEvent)(
|
||
Resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"NameChanged - unable to read network name parameter.\n"
|
||
);
|
||
goto error_exit;
|
||
}
|
||
if (Resource->Params.NetworkName) {
|
||
LocalFree(Resource->Params.NetworkName);
|
||
}
|
||
|
||
Resource->Params.NetworkName = NetworkName;
|
||
}
|
||
error_exit:
|
||
return(dwError);
|
||
} // NetNameClusterNameChanged
|
||
|
||
|
||
|
||
//***********************************************************
|
||
//
|
||
// Define Function Table
|
||
//
|
||
//***********************************************************
|
||
|
||
CLRES_V1_FUNCTION_TABLE( NetNameFunctionTable, // Name
|
||
CLRES_VERSION_V1_00, // Version
|
||
NetName, // Prefix
|
||
NULL, // Arbitrate
|
||
NULL, // Release
|
||
NetNameResourceControl, // ResControl
|
||
NetNameResourceTypeControl ); // ResTypeControl
|