Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5844 lines
199 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. netname.c
  5. Abstract:
  6. Resource DLL for a network name.
  7. Author:
  8. Mike Massa (mikemas) 29-Dec-1995
  9. Revision History:
  10. Severely whacked on by Charlie Wickham (charlwi)
  11. --*/
  12. #define UNICODE 1
  13. #include "clusres.h"
  14. #include "clusrtl.h"
  15. #include <lm.h>
  16. #include <srvann.h>
  17. #include <dsgetdc.h>
  18. #include <dsgetdcp.h>
  19. #include <adserr.h>
  20. #include "netname.h"
  21. #include "nameutil.h"
  22. #include "namechk.h"
  23. #include "clusudef.h"
  24. #include "clusstrs.h"
  25. //
  26. // Constants
  27. //
  28. #define LOG_CURRENT_MODULE LOG_MODULE_NETNAME
  29. #define IP_ADDRESS_RESOURCETYPE_NAME CLUS_RESTYPE_NAME_IPADDR
  30. //
  31. // Macros
  32. //
  33. #ifndef ARGUMENT_PRESENT
  34. #define ARGUMENT_PRESENT( ArgumentPointer ) (\
  35. (CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
  36. #endif
  37. //
  38. // turn on _INSTRUMENTED_LOCKS if you're trying to figure out where the lock
  39. // is getting orphaned
  40. //
  41. //#define _INSTRUMENTED_LOCKS
  42. #ifdef _INSTRUMENTED_LOCKS
  43. #define NetNameAcquireResourceLock() \
  44. { \
  45. DWORD status; \
  46. status = WaitForSingleObject(NetNameResourceMutex, INFINITE); \
  47. if ( status == WAIT_ABANDONED ) { \
  48. OutputDebugStringW( L"Resource List Mutex Abandoned!\n" ); \
  49. DebugBreak(); \
  50. } \
  51. (NetNameLogEvent)(L"rtNetwork Name", \
  52. LOG_INFORMATION, \
  53. L"++NNMutex (line %1!u!)\n", \
  54. __LINE__); \
  55. }
  56. #define NetNameReleaseResourceLock() \
  57. { \
  58. BOOL released; \
  59. (NetNameLogEvent)(L"rtNetwork Name", \
  60. LOG_INFORMATION, \
  61. L"--NNMutex (line %1!u!)\n", \
  62. __LINE__); \
  63. released = ReleaseMutex(NetNameResourceMutex); \
  64. }
  65. #define NetNameAcquireDnsListLock( _res_ ) \
  66. { \
  67. DWORD status; \
  68. status = WaitForSingleObject((_res_)->DnsListMutex, INFINITE); \
  69. if ( status == WAIT_ABANDONED ) { \
  70. OutputDebugStringW( L"DNS List Mutex Abandoned!\n" ); \
  71. DebugBreak(); \
  72. } \
  73. (NetNameLogEvent)(L"rtNetwork Name", \
  74. LOG_INFORMATION, \
  75. L"++DNSMutex (res %1!X! line %2!u!)\n", \
  76. _res_, __LINE__); \
  77. }
  78. #define NetNameReleaseDnsListLock( _res_ ) \
  79. { \
  80. BOOL released; \
  81. (NetNameLogEvent)(L"rtNetwork Name", \
  82. LOG_INFORMATION, \
  83. L"--DNSMutex (res %1!X! line %2!u!)\n", \
  84. _res_, __LINE__); \
  85. released = ReleaseMutex((_res_)->DnsListMutex); \
  86. if ( !released ) { \
  87. (NetNameLogEvent)(L"rtNetwork Name", \
  88. LOG_INFORMATION, \
  89. L"ERROR %1!d! releasing DNS mutex (res %2!X! line %3!u!)\n", \
  90. GetLastError(), _res_, __LINE__); \
  91. } \
  92. }
  93. #else // _INSTRUMENTED_LOCKS
  94. #define NetNameAcquireResourceLock() \
  95. { \
  96. DWORD status; \
  97. status = WaitForSingleObject(NetNameResourceMutex, INFINITE); \
  98. }
  99. #define NetNameReleaseResourceLock() \
  100. { \
  101. BOOL released; \
  102. released = ReleaseMutex(NetNameResourceMutex); \
  103. }
  104. #define NetNameAcquireDnsListLock( _res_ ) \
  105. { \
  106. DWORD status; \
  107. status = WaitForSingleObject((_res_)->DnsListMutex, INFINITE); \
  108. }
  109. #define NetNameReleaseDnsListLock( _res_ ) \
  110. { \
  111. BOOL released; \
  112. released = ReleaseMutex((_res_)->DnsListMutex); \
  113. }
  114. #endif // _INSTRUMENTED_LOCKS
  115. //
  116. // Local Variables
  117. //
  118. // Mutex for sync'ing access to the list of resources as well as each resource
  119. // block
  120. //
  121. HANDLE NetNameResourceMutex = NULL;
  122. //
  123. // The checking of DNS names requires talking to a DNS server, hence this work
  124. // is spun off to a separate thread. The resource context blocks are linked
  125. // together on a doubly linked list and are ref counted to make sure that a
  126. // block isn't changed during offline processing while its DNS name records
  127. // are being checked.
  128. //
  129. // The NetNameWorkerTerminate event signals the worker routine to exit.
  130. //
  131. HANDLE NetNameWorkerTerminate;
  132. //
  133. // NetNameWorkerPendingResources is used to signal the worker thread that a
  134. // name is moving through a pending state. It is possible for an online
  135. // operation to time out when lots of names go online
  136. // simultaneously. Similarly, an offline might require communication with a DC
  137. // which could take a while. The worker thread will periodically report back
  138. // to resmon that we're making progress.
  139. //
  140. HANDLE NetNameWorkerPendingResources;
  141. //
  142. // list head for resource context block linkage
  143. //
  144. LIST_ENTRY NetNameResourceListHead;
  145. //
  146. // the amount of seconds the worker thread waits before doing something. This
  147. // includes querying the DNS server to make sure registrations are correct and
  148. // reporting back to resmon when names are going online. This value gets
  149. // smaller when server communication is suspect.
  150. //
  151. ULONG NetNameWorkerCheckPeriod;
  152. //
  153. // ladies and gentlemen, the worker thread
  154. //
  155. HANDLE NetNameWorkerThread;
  156. //
  157. // Count of opened NetName resources.
  158. // Incremented in NetNameOpen
  159. // Decremented in NetNameClose
  160. //
  161. DWORD NetNameOpenCount = 0;
  162. //
  163. // account description string used for computer objects
  164. //
  165. LPWSTR NetNameCompObjAccountDesc;
  166. //
  167. // argh. If you have r/w and r/o props, you have to combine them into a
  168. // combined prop table in order to support unknown properties correctly. For
  169. // this reason, we use #defines to keep only one list of properties.
  170. //
  171. #define NETNAME_RW_PROPERTIES \
  172. { \
  173. PARAM_NAME__NAME, \
  174. NULL, \
  175. CLUSPROP_FORMAT_SZ, \
  176. 0, 0, 0, \
  177. RESUTIL_PROPITEM_REQUIRED, \
  178. FIELD_OFFSET(NETNAME_PARAMS,NetworkName) \
  179. }, \
  180. { \
  181. PARAM_NAME__REMAP, \
  182. NULL, \
  183. CLUSPROP_FORMAT_DWORD, \
  184. PARAM_DEFAULT__REMAP, \
  185. 0, 1, 0, \
  186. FIELD_OFFSET(NETNAME_PARAMS,NetworkRemap) \
  187. }, \
  188. { \
  189. PARAM_NAME__REQUIRE_DNS, \
  190. NULL, \
  191. CLUSPROP_FORMAT_DWORD, \
  192. PARAM_DEFAULT__REQUIRE_DNS, \
  193. 0, 1, 0, \
  194. FIELD_OFFSET(NETNAME_PARAMS,RequireDNS) \
  195. }, \
  196. { \
  197. PARAM_NAME__REQUIRE_KERBEROS, \
  198. NULL, \
  199. CLUSPROP_FORMAT_DWORD, \
  200. PARAM_DEFAULT__REQUIRE_KERBEROS, \
  201. 0, 1, 0, \
  202. FIELD_OFFSET(NETNAME_PARAMS,RequireKerberos) \
  203. }
  204. #define NETNAME_RO_PROPERTIES \
  205. { \
  206. PARAM_NAME__RESOURCE_DATA, \
  207. NULL, \
  208. CLUSPROP_FORMAT_BINARY, \
  209. 0, 0, 0, \
  210. RESUTIL_PROPITEM_READ_ONLY, \
  211. FIELD_OFFSET(NETNAME_PARAMS,ResourceData) \
  212. }, \
  213. { \
  214. PARAM_NAME__STATUS_NETBIOS, \
  215. NULL, \
  216. CLUSPROP_FORMAT_DWORD, \
  217. 0, 0, 0xFFFFFFFF, \
  218. RESUTIL_PROPITEM_READ_ONLY, \
  219. FIELD_OFFSET(NETNAME_PARAMS,StatusNetBIOS) \
  220. }, \
  221. { \
  222. PARAM_NAME__STATUS_DNS, \
  223. NULL, \
  224. CLUSPROP_FORMAT_DWORD, \
  225. 0, 0, 0xFFFFFFFF, \
  226. RESUTIL_PROPITEM_READ_ONLY, \
  227. FIELD_OFFSET(NETNAME_PARAMS,StatusDNS) \
  228. }, \
  229. { \
  230. PARAM_NAME__STATUS_KERBEROS, \
  231. NULL, \
  232. CLUSPROP_FORMAT_DWORD, \
  233. 0, 0, 0xFFFFFFFF, \
  234. RESUTIL_PROPITEM_READ_ONLY, \
  235. FIELD_OFFSET(NETNAME_PARAMS,StatusKerberos) \
  236. }, \
  237. { \
  238. PARAM_NAME__CREATING_DC, \
  239. NULL, \
  240. CLUSPROP_FORMAT_SZ, \
  241. 0, 0, 0, \
  242. RESUTIL_PROPITEM_READ_ONLY, \
  243. FIELD_OFFSET(NETNAME_PARAMS,CreatingDC) \
  244. }
  245. /*
  246. #ifdef PASSWORD_ROTATION
  247. // r/w
  248. { \
  249. PARAM_NAME__UPDATE_INTERVAL, \
  250. NULL, \
  251. CLUSPROP_FORMAT_DWORD, \
  252. PARAM_DEFAULT__UPDATE_INTERVAL, \
  253. PARAM_MINIMUM__UPDATE_INTERVAL, \
  254. PARAM_MAXIMUM__UPDATE_INTERVAL, \
  255. 0, \
  256. FIELD_OFFSET(NETNAME_PARAMS,UpdateInterval) \
  257. }
  258. // read-only
  259. { \
  260. PARAM_NAME__NEXT_UPDATE, \
  261. NULL, \
  262. CLUSPROP_FORMAT_BINARY, \
  263. 0, 0, 0, \
  264. RESUTIL_PROPITEM_READ_ONLY, \
  265. FIELD_OFFSET(NETNAME_PARAMS,NextUpdate) \
  266. }, \
  267. #endif // PASSWORD_ROTATION
  268. */
  269. //
  270. // Network Name resource read-write private properties.
  271. //
  272. // DON'T ADD PROPERTIES DIRECTLY TO THIS TABLE. ADD TO THE APPROPRIATE MACRO
  273. // DEFINED ABOVE.
  274. //
  275. RESUTIL_PROPERTY_ITEM
  276. NetNameResourcePrivateProperties[] = {
  277. NETNAME_RW_PROPERTIES,
  278. { NULL, NULL, 0, 0, 0, 0 }
  279. };
  280. //
  281. // Network Name resource read-only private properties.
  282. //
  283. // DON'T ADD PROPERTIES DIRECTLY TO THIS TABLE. ADD TO THE APPROPRIATE MACRO
  284. // DEFINED ABOVE.
  285. //
  286. RESUTIL_PROPERTY_ITEM
  287. NetNameResourceROPrivateProperties[] = {
  288. NETNAME_RO_PROPERTIES,
  289. { NULL, NULL, 0, 0, 0, 0 }
  290. };
  291. //
  292. // Network Name resource combined private properties.
  293. //
  294. // DON'T ADD PROPERTIES DIRECTLY TO THIS TABLE. ADD TO THE APPROPRIATE MACRO
  295. // DEFINED ABOVE.
  296. //
  297. RESUTIL_PROPERTY_ITEM
  298. NetNameResourceCombinedPrivateProperties[] = {
  299. NETNAME_RW_PROPERTIES,
  300. NETNAME_RO_PROPERTIES,
  301. { NULL, NULL, 0, 0, 0, 0 }
  302. };
  303. //
  304. // static variables
  305. //
  306. //
  307. // after an upgrade, this var will be true if MSMQ dependent netnames should
  308. // be upgraded to kerberos support.
  309. //
  310. static BOOL CheckForKerberosUpgrade = FALSE;
  311. //
  312. // forward declarations
  313. //
  314. CLRES_FUNCTION_TABLE NetNameFunctionTable;
  315. //
  316. // Forward references
  317. //
  318. DWORD
  319. NetNameGetPrivateResProperties(
  320. IN OUT PNETNAME_RESOURCE ResourceEntry,
  321. IN BOOL ReadOnly,
  322. OUT PVOID OutBuffer,
  323. IN DWORD OutBufferSize,
  324. OUT LPDWORD BytesReturned
  325. );
  326. DWORD
  327. NetNameValidatePrivateResProperties(
  328. IN OUT PNETNAME_RESOURCE ResourceEntry,
  329. IN PVOID InBuffer,
  330. IN DWORD InBufferSize,
  331. OUT PNETNAME_PARAMS Params,
  332. OUT PBOOL NetnameHasChanged,
  333. OUT PBOOL CompObjRenameIsRequired
  334. );
  335. DWORD
  336. NetNameSetPrivateResProperties(
  337. IN OUT PNETNAME_RESOURCE ResourceEntry,
  338. IN PVOID InBuffer,
  339. IN DWORD InBufferSize
  340. );
  341. DWORD
  342. NetNameClusterNameChanged(
  343. IN PNETNAME_RESOURCE Resource
  344. );
  345. DWORD
  346. NetNameGetNetworkName(
  347. IN OUT PNETNAME_RESOURCE ResourceEntry,
  348. OUT PVOID OutBuffer,
  349. IN DWORD OutBufferSize,
  350. OUT LPDWORD BytesReturned
  351. );
  352. VOID
  353. NetNameCleanupDnsLists(
  354. IN PNETNAME_RESOURCE Resource
  355. );
  356. VOID
  357. RemoveDnsRecords(
  358. PNETNAME_RESOURCE Resource
  359. );
  360. //
  361. // Local utility functions
  362. //
  363. VOID
  364. WINAPI
  365. NetNameReleaseResource(
  366. IN RESID Resource
  367. )
  368. /*++
  369. Routine Description:
  370. Cleanup all handles and memory allocations in the netname context block
  371. Arguments:
  372. Resource - supplies resource id to be cleaned up.
  373. Return Value:
  374. None.
  375. --*/
  376. {
  377. PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
  378. PLIST_ENTRY entry;
  379. if ( resource == NULL ) {
  380. return;
  381. }
  382. if (resource->Params.NetworkName != NULL) {
  383. LocalFree( resource->Params.NetworkName );
  384. }
  385. if (resource->Params.ResourceData != NULL) {
  386. LocalFree( resource->Params.ResourceData );
  387. }
  388. if (resource->Params.CreatingDC != NULL) {
  389. LocalFree( resource->Params.CreatingDC );
  390. }
  391. if (resource->NodeName != NULL) {
  392. LocalFree( resource->NodeName );
  393. }
  394. if (resource->NodeId != NULL) {
  395. LocalFree( resource->NodeId );
  396. }
  397. if (resource->ParametersKey != NULL) {
  398. ClusterRegCloseKey(resource->ParametersKey);
  399. }
  400. if (resource->ResKey != NULL){
  401. ClusterRegCloseKey(resource->ResKey);
  402. }
  403. if (resource->ClusterResourceHandle != NULL){
  404. CloseClusterResource(resource->ClusterResourceHandle);
  405. }
  406. if (resource->ObjectGUID != NULL) {
  407. LocalFree( resource->ObjectGUID );
  408. }
  409. if ( resource->DnsLists != NULL ) {
  410. NetNameCleanupDnsLists( resource );
  411. }
  412. if ( resource->DnsListMutex != NULL ) {
  413. #if DBG
  414. {
  415. DWORD status;
  416. status = WaitForSingleObject( resource->DnsListMutex, 0 );
  417. if ( status == WAIT_TIMEOUT ) {
  418. WCHAR buf[64];
  419. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  420. _snwprintf(buf, COUNT_OF( buf ) - 1,
  421. L"res %08X DNS list mutex still signalled at delete!\n",
  422. (DWORD_PTR)resource);
  423. OutputDebugStringW( buf );
  424. DebugBreak();
  425. } else {
  426. ReleaseMutex( resource->DnsListMutex );
  427. }
  428. }
  429. #endif
  430. CloseHandle( resource->DnsListMutex );
  431. }
  432. (NetNameLogEvent)(resource->ResourceHandle,
  433. LOG_INFORMATION,
  434. L"ResID %1!u! closed.\n",
  435. Resource
  436. );
  437. LocalFree( resource );
  438. } // NetNameReleaseResource
  439. VOID
  440. NetNameUpdateDnsServer(
  441. PNETNAME_RESOURCE Resource
  442. )
  443. /*++
  444. Routine Description:
  445. Update this resource's A and PTR records at its DNS server
  446. Arguments:
  447. Resource - pointer to netname resource context block
  448. Return Value:
  449. None
  450. --*/
  451. {
  452. PDNS_LISTS dnsLists;
  453. DWORD numberOfDnsLists;
  454. ULONG numberOfRegisteredNames;
  455. NetNameAcquireDnsListLock( Resource );
  456. numberOfDnsLists = Resource->NumberOfDnsLists;
  457. dnsLists = Resource->DnsLists;
  458. while ( numberOfDnsLists-- ) {
  459. if ( dnsLists->ForwardZoneIsDynamic ) {
  460. #if DBG_DNSLIST
  461. {
  462. PDNS_RECORD dnsRec = dnsLists->A_RRSet.pFirstRR;
  463. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  464. struct in_addr addr;
  465. if ( dnsRec != NULL ) {
  466. addr.s_addr = dnsLists->DnsServerList->AddrArray[0];
  467. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  468. _snwprintf(buf, COUNT_OF( buf ) - 1,
  469. L"REGISTERING ON adapter %.32ws (%hs)\n",
  470. dnsLists->ConnectoidName,
  471. inet_ntoa( addr ) );
  472. OutputDebugStringW( buf );
  473. do {
  474. addr.s_addr = dnsRec->Data.A.IpAddress;
  475. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  476. _snwprintf(buf, COUNT_OF( buf ) - 1,
  477. L"\t(%ws, %hs)\n",
  478. dnsRec->pName, inet_ntoa( addr ));
  479. OutputDebugStringW( buf );
  480. dnsRec = dnsRec->pNext;
  481. } while ( dnsRec != NULL );
  482. }
  483. }
  484. #endif
  485. //
  486. // resource went or is going offline; no point in
  487. // continueing. don't need to grab resource lock since we have a
  488. // refcount on the resource block
  489. //
  490. if (Resource->State != ClusterResourceOnline) {
  491. break;
  492. }
  493. //
  494. // register the records to update their timestamp (if there is
  495. // something to register). Before we used to query but eventually
  496. // the records would time out and be scavenged (deleted). This can
  497. // cause lots of grief (or in Exchange's case, lots of undelivered
  498. // mail).
  499. //
  500. // we don't worry about logging errors or update the
  501. // LastARecQueryStatus since all of that is done in
  502. // RegisterDnsRecords.
  503. //
  504. if ( dnsLists->A_RRSet.pFirstRR != NULL ) {
  505. RegisterDnsRecords(dnsLists,
  506. Resource->Params.NetworkName,
  507. Resource->ResKey,
  508. Resource->ResourceHandle,
  509. FALSE, /* LogRegistration */
  510. &numberOfRegisteredNames);
  511. }
  512. } // Is Forward zone dynamic?
  513. ++dnsLists;
  514. } // while numberOfDnsLists != 0
  515. NetNameReleaseDnsListLock( Resource );
  516. } // NetNameUpdateDnsServer
  517. DWORD WINAPI
  518. NetNameWorker(
  519. IN LPVOID NotUsed
  520. )
  521. /*++
  522. Routine Description:
  523. background worker thread. Checks on the health of the DNS registrations
  524. and reports back to resmon while names are in the online pending
  525. state. The netname Is/LooksAlive checks are too frequent such that they
  526. would cause alot of DNS traffic on the network. This routine runs through
  527. the linked list of netname resource blocks and queries the server for the
  528. records that should be registered. Any discrepancies will cause the
  529. records to be registered again. The success of each operation is left in
  530. the DNS_LIST area for the particular record type.
  531. In addition, when prompted, it will run down the list of resources and
  532. report back the resource's status to resmon. Name registration is
  533. serialized through srv.sys causing some names to time out before they get
  534. registered.
  535. Arguments:
  536. NotUsed - not used...
  537. Return Value:
  538. ERROR_SUCCESS
  539. --*/
  540. {
  541. DWORD status = ERROR_SUCCESS;
  542. PLIST_ENTRY entry;
  543. PNETNAME_RESOURCE resource;
  544. DNS_STATUS dnsStatus;
  545. BOOL reportPending;
  546. DWORD oldCheckPeriod = NetNameWorkerCheckPeriod;
  547. DWORD pendingResourceCount;
  548. RESOURCE_STATUS resourceStatus;
  549. HANDLE waitHandles[ 2 ] = { NetNameWorkerTerminate,
  550. NetNameWorkerPendingResources };
  551. ResUtilInitializeResourceStatus( &resourceStatus );
  552. do {
  553. status = WaitForMultipleObjects(2,
  554. waitHandles,
  555. FALSE,
  556. NetNameWorkerCheckPeriod * 1000);
  557. if ( status == WAIT_OBJECT_0 ) {
  558. return ERROR_SUCCESS;
  559. }
  560. if ( status == ( WAIT_OBJECT_0 + 1 )) {
  561. reportPending = TRUE;
  562. #if DBG
  563. (NetNameLogEvent)(L"rtNetwork Name",
  564. LOG_INFORMATION,
  565. L"Start of pending resource reporting\n");
  566. #endif
  567. }
  568. //
  569. // reset check frequency back to normal. if something goes wrong,
  570. // other code will set it back to the problem check period.
  571. //
  572. NetNameWorkerCheckPeriod = NETNAME_WORKER_NORMAL_CHECK_PERIOD;
  573. pendingResourceCount = 0;
  574. NetNameAcquireResourceLock();
  575. entry = NetNameResourceListHead.Flink;
  576. while ( entry != &NetNameResourceListHead ) {
  577. //
  578. // get a pointer to the resource block
  579. //
  580. resource = CONTAINING_RECORD( entry, NETNAME_RESOURCE, Next );
  581. if ( resource->State > ClusterResourcePending ) {
  582. //
  583. // bringing lots (40) of names online simultaneously caused
  584. // some names to hit their pending timeouts. Each time a name
  585. // enters a pending state, the NetNameWorkerPendingResources
  586. // event is set to wake up this thread. The timeout is changed
  587. // so we can report back to resmon that the operation is
  588. // continuing. This should prevent resmon from timing out the
  589. // resource and causing much thrashing. No other checking (DNS
  590. // or Kerb) is done while this is happening.
  591. //
  592. #if DBG
  593. (NetNameLogEvent)(resource->ResourceHandle,
  594. LOG_INFORMATION,
  595. L"Reporting resource pending\n");
  596. #endif
  597. oldCheckPeriod = NetNameWorkerCheckPeriod;
  598. NetNameWorkerCheckPeriod = NETNAME_WORKER_PENDING_PERIOD;
  599. resourceStatus.CheckPoint = ++resource->StatusCheckpoint;
  600. resourceStatus.ResourceState = resource->State;
  601. //
  602. // never hold the resource lock when calling
  603. // SetResourceStatus. You'll end up with deadlocks when resmon
  604. // calls back in to the Looks/IsAlive routines. However, the
  605. // resource state is always synch'ed by this lock. No need to
  606. // bump refcount since this resource is still in a Pending
  607. // state and resmon won't allow the resource delete cluster
  608. // control to be issued.
  609. //
  610. NetNameReleaseResourceLock();
  611. (NetNameSetResourceStatus)(resource->ResourceHandle,
  612. &resourceStatus);
  613. NetNameAcquireResourceLock();
  614. ++pendingResourceCount;
  615. }
  616. else if ( resource->State == ClusterResourceOnline && !reportPending ) {
  617. //
  618. // up the ref count so this resource doesn't go away while we
  619. // re-register the records with the DNS server. This keeps
  620. // them from getting scavenged (deleted).
  621. //
  622. ++resource->RefCount;
  623. NetNameReleaseResourceLock();
  624. NetNameUpdateDnsServer( resource );
  625. //
  626. // check the status of the computer object and see if it is
  627. // time to generate a new password.
  628. //
  629. if ( resource->DoKerberosCheck ) {
  630. FILETIME currentFileTime;
  631. if ( resource->ObjectGUID == NULL ) {
  632. //
  633. // wasn't able to get the GUID during online; let's try now
  634. //
  635. GetComputerObjectGuid( resource, NULL );
  636. }
  637. if ( resource->ObjectGUID != NULL ) {
  638. status = CheckComputerObjectAttributes( resource, NULL );
  639. InterlockedExchange( &resource->KerberosStatus, status );
  640. }
  641. #ifdef PASSWORD_ROTATION
  642. GetSystemTimeAsFileTime( &currentFileTime );
  643. if ( CompareFileTime( &currentFileTime, &resource->Params.NextUpdate ) == 1 ) {
  644. ULARGE_INTEGER updateTime;
  645. DWORD setValueStatus;
  646. status = UpdateCompObjPassword( resource );
  647. updateTime.LowPart = currentFileTime.dwLowDateTime;
  648. updateTime.HighPart = currentFileTime.dwHighDateTime;
  649. updateTime.QuadPart += ( resource->Params.UpdateInterval * 60 * 1000 * 100 );
  650. currentFileTime.dwLowDateTime = updateTime.LowPart;
  651. currentFileTime.dwHighDateTime = updateTime.HighPart;
  652. setValueStatus = ResUtilSetBinaryValue(resource->ParametersKey,
  653. PARAM_NAME__NEXT_UPDATE,
  654. (const LPBYTE)&updateTime,
  655. sizeof( updateTime ),
  656. NULL,
  657. NULL);
  658. //
  659. // not sure how we should handle an error here; any
  660. // type of error generally indicates that the cluster
  661. // service has croaked. Since this is our worker
  662. // thread, there isn't much we can do until we've been
  663. // asked to terminate.
  664. //
  665. // ASSERT( setValueStatus == ERROR_SUCCESS );
  666. }
  667. #endif // PASSWORD_ROTATION
  668. }
  669. //
  670. // reacquire the mutex so we can release our reference. If the
  671. // resource went offline and was deleted during the
  672. // registration, then perform "last ref" cleanup. If the
  673. // resource just went offline, we need to inform resmon that
  674. // we're finally going offline. This is synchronized with the
  675. // resource delete code by not having the DNS lists in use
  676. // when a delete resource control is sent.
  677. //
  678. NetNameAcquireResourceLock();
  679. ASSERT( resource->RefCount > 0 ); /* Ruihu: 11/04/2000 */
  680. if (resource->RefCount == 1) {
  681. //
  682. // we hold the last reference to this resource so it must
  683. // have been deleted while the registration was taking
  684. // place. Clean up and free our context block for this
  685. // resource. Restart the loop since we don't know if the
  686. // flink for this entry is still valid.
  687. //
  688. NetNameReleaseResource( resource );
  689. entry = NetNameResourceListHead.Flink; /* start over */
  690. continue;
  691. }
  692. else
  693. {
  694. if ( resource->State == ClusterResourceOfflinePending ) {
  695. BOOL nameChanged;
  696. //
  697. // The resource state was changed while we were
  698. // dealing with DNS. Set the state to offline.
  699. //
  700. resourceStatus.ResourceState = ClusterResourceOffline;
  701. resource->State = ClusterResourceOffline;
  702. //
  703. // note whatever cleanup we need to do while we hold the lock
  704. //
  705. nameChanged = resource->NameChangedWhileOnline;
  706. resource->NameChangedWhileOnline = FALSE;
  707. //
  708. // ok to release lock since we haven't released our
  709. // reference to this block
  710. //
  711. NetNameReleaseResourceLock();
  712. //
  713. // if appropriate, do cleanup processing
  714. //
  715. if ( nameChanged ) {
  716. RemoveDnsRecords( resource );
  717. resource->NameChangedWhileOnline = FALSE;
  718. }
  719. (NetNameSetResourceStatus)(resource->ResourceHandle,
  720. &resourceStatus);
  721. (NetNameLogEvent)(resource->ResourceHandle,
  722. LOG_INFORMATION,
  723. L"Resource is now offline\n");
  724. NetNameAcquireResourceLock();
  725. } // ( resource->State == ClusterResourceOfflinePending )
  726. /* Ruihu: 11/04/2000 */
  727. --resource->RefCount;
  728. ASSERT(resource->RefCount >=0 );
  729. if (resource->RefCount == 0) {
  730. NetNameReleaseResource( resource );
  731. entry = NetNameResourceListHead.Flink; /* start over */
  732. continue;
  733. }
  734. /* Ruihu: 11/04/2000 */
  735. } // end if resource count != 1
  736. } // resource is online
  737. entry = entry->Flink;
  738. } // while entries in the resource block list
  739. NetNameReleaseResourceLock();
  740. if ( reportPending && pendingResourceCount == 0 ) {
  741. //
  742. // no resources are left in a pending state so revert back to
  743. // checking DNS registrations
  744. //
  745. NetNameWorkerCheckPeriod = oldCheckPeriod;
  746. reportPending = FALSE;
  747. #if DBG
  748. (NetNameLogEvent)(L"rtNetwork Name",
  749. LOG_INFORMATION,
  750. L"End of pending resource reporting\n");
  751. #endif
  752. }
  753. } while ( TRUE );
  754. } // NetNameWorker
  755. BOOLEAN
  756. NetNameInit(
  757. IN HINSTANCE DllHandle
  758. )
  759. /*++
  760. Routine Description:
  761. Process attach initialization routine.
  762. Arguments:
  763. DllHandle - handle to clusres module
  764. Return Value:
  765. TRUE if initialization succeeded. FALSE otherwise.
  766. --*/
  767. {
  768. DWORD status;
  769. DWORD charsCopied;
  770. DWORD charsAllocated = 0;
  771. NetNameResourceMutex = CreateMutex(NULL, FALSE, NULL);
  772. if (NetNameResourceMutex == NULL) {
  773. return(FALSE);
  774. }
  775. //
  776. // create worker thread terminate event with no special security,
  777. // auto-reset, initially nonsignalled, and no name
  778. //
  779. NetNameWorkerTerminate = CreateEvent( NULL, FALSE, FALSE, NULL );
  780. if ( NetNameWorkerTerminate == NULL ) {
  781. CloseHandle( NetNameResourceMutex );
  782. return FALSE;
  783. }
  784. //
  785. // create worker thread online pending event with no special security,
  786. // auto-reset, initially nonsignalled, and no name
  787. //
  788. NetNameWorkerPendingResources = CreateEvent( NULL, FALSE, FALSE, NULL );
  789. if ( NetNameWorkerPendingResources == NULL ) {
  790. CloseHandle( NetNameWorkerTerminate );
  791. CloseHandle( NetNameResourceMutex );
  792. return FALSE;
  793. }
  794. //
  795. // init the list head of the list of resources to check for DNS
  796. // registrations
  797. //
  798. InitializeListHead( &NetNameResourceListHead );
  799. //
  800. // lookup the account description string resource; start with 64 char
  801. // buffer and double until we fail or we get all of the string. Not
  802. // considered fatal if we can't load the string
  803. //
  804. charsAllocated = 64;
  805. realloc:
  806. charsCopied = 0;
  807. NetNameCompObjAccountDesc = LocalAlloc( LMEM_FIXED, charsAllocated * sizeof( WCHAR ));
  808. if ( NetNameCompObjAccountDesc ) {
  809. charsCopied = LoadString(DllHandle,
  810. RES_NETNAME_COMPUTER_ACCOUNT_DESCRIPTION,
  811. NetNameCompObjAccountDesc,
  812. charsAllocated);
  813. if ( charsCopied != 0 && charsCopied == ( charsAllocated - 1 )) {
  814. LocalFree( NetNameCompObjAccountDesc );
  815. charsAllocated *= 2;
  816. goto realloc;
  817. }
  818. }
  819. if ( charsCopied == 0 && NetNameCompObjAccountDesc != NULL ) {
  820. LocalFree( NetNameCompObjAccountDesc );
  821. NetNameCompObjAccountDesc = NULL;
  822. }
  823. return(TRUE);
  824. } // NetNameInit
  825. VOID
  826. NetNameCleanup(
  827. VOID
  828. )
  829. /*++
  830. Routine Description:
  831. Process detach cleanup routine.
  832. Arguments:
  833. None.
  834. Return Value:
  835. None.
  836. --*/
  837. {
  838. if (NetNameResourceMutex != NULL) {
  839. CloseHandle(NetNameResourceMutex);
  840. NetNameResourceMutex = NULL;
  841. }
  842. if ( NetNameWorkerTerminate ) {
  843. CloseHandle( NetNameWorkerTerminate );
  844. NetNameWorkerTerminate = NULL;
  845. }
  846. if ( NetNameWorkerPendingResources ) {
  847. CloseHandle( NetNameWorkerPendingResources );
  848. NetNameWorkerPendingResources = NULL;
  849. }
  850. } // NetNameCleanup
  851. PNETNAME_RESOURCE
  852. NetNameAllocateResource(
  853. IN RESOURCE_HANDLE ResourceHandle
  854. )
  855. /*++
  856. Routine Description:
  857. Allocates a resource object.
  858. Arguments:
  859. ResourceHandle - A pointer to the Resource Monitor handle to be associated
  860. with this resource.
  861. Return Value:
  862. A pointer to the new resource if successful. NULL otherwise.
  863. --*/
  864. {
  865. PNETNAME_RESOURCE resource = NULL;
  866. resource = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(NETNAME_RESOURCE) );
  867. if (resource == NULL) {
  868. (NetNameLogEvent)(ResourceHandle,
  869. LOG_ERROR,
  870. L"Resource allocation failed\n");
  871. return(NULL);
  872. }
  873. resource->ResourceHandle = ResourceHandle;
  874. return(resource);
  875. } // NetNameAllocateResource
  876. DWORD
  877. NetNameCheckForCompObjRenameRecovery(
  878. IN PNETNAME_RESOURCE Resource
  879. )
  880. /*++
  881. Routine Description:
  882. Using the Rename keys in the resource's GUID registry area, determine if a
  883. rename operation was interrupted. All operations in this function center
  884. around the Creating DC. If it is not available, we don't know the state of
  885. the rename since the name could have been changed but the change hasn't
  886. replicated to other DCs just yet. Consequently, the name will not go
  887. online until netname can resolve the outcome of the rename.
  888. If the object was renamed but the Name property wasn't updated, then the
  889. object is renamed to be consistent with the current value of the Name
  890. property.
  891. Arguments:
  892. Resource - pointer to netname resource context block/structure...
  893. Return Value:
  894. ERROR_SUCCESS if everything worked as expected.
  895. --*/
  896. {
  897. LPWSTR originalName;
  898. LPWSTR newName;
  899. DWORD status;
  900. DWORD functionStatus = ERROR_SUCCESS;
  901. DWORD errorTextID;
  902. WCHAR originalDollarName[ DNS_MAX_LABEL_BUFFER_LENGTH ];
  903. WCHAR newDollarName[ DNS_MAX_LABEL_BUFFER_LENGTH ];
  904. DWORD paramInError;
  905. BOOL renameObject = FALSE;
  906. USER_INFO_0 netUI0;
  907. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  908. //
  909. // read the rename keys from the regsitry
  910. //
  911. originalName = ResUtilGetSzValue( Resource->ResKey, PARAM_NAME__RENAMEORIGINALNAME );
  912. if ( originalName == NULL ) {
  913. status = GetLastError();
  914. if ( status != ERROR_FILE_NOT_FOUND ) {
  915. return status;
  916. } else {
  917. status = ERROR_SUCCESS;
  918. }
  919. }
  920. newName = ResUtilGetSzValue( Resource->ResKey, PARAM_NAME__RENAMENEWNAME );
  921. if ( newName == NULL ) {
  922. status = GetLastError();
  923. if ( status != ERROR_FILE_NOT_FOUND ) {
  924. return status;
  925. } else {
  926. status = ERROR_SUCCESS;
  927. }
  928. }
  929. if ( newName == NULL ) {
  930. //
  931. // never got far enough to do the rename. Clean up, if necessary, and
  932. // return success
  933. //
  934. if ( originalName ) {
  935. status = ClusterRegDeleteValue( Resource->ResKey, PARAM_NAME__RENAMEORIGINALNAME );
  936. if ( status != ERROR_SUCCESS ) {
  937. (NetNameLogEvent)(resourceHandle,
  938. LOG_WARNING,
  939. L"Failed to delete "
  940. PARAM_NAME__RENAMEORIGINALNAME
  941. L" from registry - status %1!u!\n",
  942. status);
  943. }
  944. LocalFree( originalName );
  945. }
  946. return status;
  947. }
  948. (NetNameLogEvent)(resourceHandle,
  949. LOG_INFORMATION,
  950. L"Previous rename operation interrupted; attempting recovery.\n");
  951. if ( originalName && newName ) {
  952. HRESULT hr;
  953. BOOL originalNameObjectExists;
  954. BOOL newNameObjectExists;
  955. //
  956. // have to find which version of the object is in the DS to determine
  957. // which name we're going to keep. Try the original name first
  958. //
  959. hr = IsComputerObjectInDS( resourceHandle,
  960. Resource->NodeName,
  961. originalName,
  962. Resource->Params.CreatingDC,
  963. &originalNameObjectExists,
  964. NULL, // don't need FQDN
  965. NULL); // don't need HostingDCName
  966. if ( SUCCEEDED( hr )) {
  967. if ( originalNameObjectExists ) {
  968. //
  969. // this means resmon croaked after writing the new name to the
  970. // registry but before the rename was issued. We do nothing in
  971. // this case.
  972. //
  973. (NetNameLogEvent)(Resource->ResourceHandle,
  974. LOG_INFORMATION,
  975. L"The computer account (%1!ws!) for this resource is correct.\n",
  976. originalName);
  977. }
  978. else {
  979. //
  980. // couldn't find an object with the original (old) name; try
  981. // with the new name.
  982. //
  983. hr = IsComputerObjectInDS( resourceHandle,
  984. Resource->NodeName,
  985. newName,
  986. Resource->Params.CreatingDC,
  987. &newNameObjectExists,
  988. NULL, // don't need FQDN
  989. NULL); // don't need HostingDCName
  990. if ( SUCCEEDED( hr )) {
  991. if ( newNameObjectExists) {
  992. //
  993. // found the object with the new name so that means we
  994. // renamed the object but resmon died before the Name
  995. // property was updated. Make object name consistent
  996. // with Name property
  997. //
  998. (NetNameLogEvent)(resourceHandle,
  999. LOG_INFORMATION,
  1000. L"The computer account is currently %1!ws!. It will be"
  1001. L"renamed back to its original name (%2!ws!)\n",
  1002. newName,
  1003. originalName);
  1004. renameObject = TRUE;
  1005. }
  1006. else {
  1007. //
  1008. // this is bad; no object could be found for either
  1009. // the original or new name. Have to assume the admin
  1010. // deleted it.
  1011. //
  1012. (NetNameLogEvent)(resourceHandle,
  1013. LOG_ERROR,
  1014. L"The computer account for this resource cannot be found on DC "
  1015. L"%1!ws! during rename recovery. The original name (%2!ws!) was "
  1016. L"being renamed to %3!ws! and neither computer account "
  1017. L"could be found. The resource cannot go online until the "
  1018. L"object is recreated. This can be accomplished by disabling and "
  1019. L"re-enabling Kerberos Authentication for this resource.\n",
  1020. Resource->Params.CreatingDC,
  1021. originalName,
  1022. newName);
  1023. ClusResLogSystemEventByKey3(Resource->ResKey,
  1024. LOG_CRITICAL,
  1025. RES_NETNAME_ONLINE_RENAME_RECOVERY_MISSING_ACCOUNT,
  1026. Resource->Params.CreatingDC,
  1027. originalName,
  1028. newName);
  1029. functionStatus = ERROR_DS_OBJ_NOT_FOUND;
  1030. }
  1031. }
  1032. else {
  1033. (NetNameLogEvent)(resourceHandle,
  1034. LOG_ERROR,
  1035. L"The AD search to find computer account %1!ws! on DC %2!ws! failed - "
  1036. L"status %3!08X!. The computer account for this resource was in the "
  1037. L"process of being renamed which did not complete. The account "
  1038. L"was being renamed on DC %2!ws! which appears to be unavailable "
  1039. L"or is preventing access in order to find the account. This DC must "
  1040. L"be made available before this resource can go online in order "
  1041. L"to reconcile the rename operation.\n",
  1042. newName,
  1043. Resource->Params.CreatingDC,
  1044. hr);
  1045. ClusResLogSystemEventByKeyData2(Resource->ResKey,
  1046. LOG_CRITICAL,
  1047. RES_NETNAME_ONLINE_RENAME_DC_NOT_FOUND,
  1048. sizeof( hr ),
  1049. &hr,
  1050. newName,
  1051. Resource->Params.CreatingDC);
  1052. functionStatus = hr;
  1053. }
  1054. }
  1055. }
  1056. else {
  1057. (NetNameLogEvent)(resourceHandle,
  1058. LOG_ERROR,
  1059. L"The AD search to find computer account %1!ws! on DC %2!ws! failed - "
  1060. L"status %3!08X!. The computer account for this resource was in the "
  1061. L"process of being renamed which did not complete. The account was "
  1062. L"being renamed on DC %2!ws! which appears to be unavailable or is "
  1063. L"preventing access in order to find the account. This DC must be "
  1064. L"made available before this resource can go online in order to "
  1065. L"reconcile the rename operation.\n",
  1066. originalName,
  1067. Resource->Params.CreatingDC,
  1068. hr);
  1069. ClusResLogSystemEventByKeyData2(Resource->ResKey,
  1070. LOG_CRITICAL,
  1071. RES_NETNAME_ONLINE_RENAME_DC_NOT_FOUND,
  1072. sizeof( hr ),
  1073. &hr,
  1074. originalName,
  1075. Resource->Params.CreatingDC);
  1076. functionStatus = hr;
  1077. }
  1078. }
  1079. else if ( originalName == NULL && newName ) {
  1080. if ( ClRtlStrICmp( newName, Resource->Params.NetworkName ) != 0 ) {
  1081. //
  1082. // made it through RenameComputerObject but crashed before Name
  1083. // property got stored. Change name of object back to Name
  1084. // property
  1085. //
  1086. renameObject = TRUE;
  1087. }
  1088. }
  1089. if ( renameObject ) {
  1090. //
  1091. // don't call RenameComputerObject to do the rename. In order to call
  1092. // it, we'd need to delete the Rename keys prior to the call. If
  1093. // resmon failed in between the delete and create of the keys, our
  1094. // Rename state would be lost. We don't try to fix up the DnsHostName
  1095. // attribute. It will be detected in Online that it is wrong and will
  1096. // be fixed up there.
  1097. //
  1098. //
  1099. // build the dollar sign names
  1100. //
  1101. originalDollarName[ COUNT_OF( originalDollarName ) - 1 ] = UNICODE_NULL;
  1102. _snwprintf( originalDollarName, COUNT_OF( originalDollarName ) - 1, L"%ws$", newName );
  1103. newDollarName[ COUNT_OF( newDollarName ) - 1 ] = UNICODE_NULL;
  1104. _snwprintf( newDollarName, COUNT_OF( newDollarName ) - 1, L"%ws$", Resource->Params.NetworkName );
  1105. (NetNameLogEvent)(resourceHandle,
  1106. LOG_INFORMATION,
  1107. L"Attempting rename of computer account %1!ws! to %2!ws! with DC %3!ws!.\n",
  1108. newName,
  1109. Resource->Params.NetworkName,
  1110. Resource->Params.CreatingDC);
  1111. netUI0.usri0_name = newDollarName;
  1112. status = NetUserSetInfo( Resource->Params.CreatingDC,
  1113. originalDollarName,
  1114. 0,
  1115. (LPBYTE)&netUI0,
  1116. &paramInError);
  1117. if ( status == NERR_Success ) {
  1118. (NetNameLogEvent)(resourceHandle,
  1119. LOG_INFORMATION,
  1120. L"Renamed computer account from %1!ws! to %2!ws!.\n",
  1121. newName,
  1122. Resource->Params.NetworkName);
  1123. } else {
  1124. //
  1125. // "now this is fine situation you've gotten us into, Ollie."
  1126. //
  1127. // Failed to rename. Bail out of routine, leaving the Rename keys
  1128. // intact so it might work the next time once the problem
  1129. // (probably access to the object) is fixed.
  1130. //
  1131. (NetNameLogEvent)(resourceHandle,
  1132. LOG_ERROR,
  1133. L"Failed to rename computer account %1!ws! to %2!ws! using DC %3!ws! "
  1134. L"(status %4!08X!).\n",
  1135. newName,
  1136. Resource->Params.NetworkName,
  1137. Resource->Params.CreatingDC,
  1138. status);
  1139. ClusResLogSystemEventByKeyData3(Resource->ResKey,
  1140. LOG_CRITICAL,
  1141. RES_NETNAME_ONLINE_RENAME_RECOVERY_FAILED,
  1142. sizeof( status ),
  1143. &status,
  1144. newName,
  1145. Resource->Params.NetworkName,
  1146. Resource->Params.CreatingDC);
  1147. functionStatus = status;
  1148. goto cleanup;
  1149. }
  1150. }
  1151. //
  1152. // clean up Rename keys from registry
  1153. //
  1154. status = ClusterRegDeleteValue( Resource->ResKey, PARAM_NAME__RENAMEORIGINALNAME );
  1155. if ( status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND ) {
  1156. (NetNameLogEvent)(resourceHandle,
  1157. LOG_WARNING,
  1158. L"Failed to delete "
  1159. PARAM_NAME__RENAMEORIGINALNAME
  1160. L" from registry - status %1!u!\n",
  1161. status);
  1162. }
  1163. status = ClusterRegDeleteValue( Resource->ResKey, PARAM_NAME__RENAMENEWNAME );
  1164. if ( status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND ) {
  1165. (NetNameLogEvent)(resourceHandle,
  1166. LOG_WARNING,
  1167. L"Failed to delete "
  1168. PARAM_NAME__RENAMENEWNAME
  1169. L" from registry - status %1!u!\n",
  1170. status);
  1171. }
  1172. cleanup:
  1173. if ( newName != NULL ) {
  1174. LocalFree( newName );
  1175. }
  1176. if ( originalName != NULL ) {
  1177. LocalFree( originalName );
  1178. }
  1179. return functionStatus;
  1180. } // NetNameCheckForCompObjRenameRecovery
  1181. DWORD
  1182. NetNameGetParameters(
  1183. IN HKEY ResourceKey,
  1184. IN HKEY ParametersKey,
  1185. IN RESOURCE_HANDLE ResourceHandle,
  1186. OUT PNETNAME_PARAMS ParamBlock,
  1187. OUT DWORD * ResDataSize,
  1188. OUT DWORD * pdwFlags
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Reads the registry parameters for a netname resource.
  1193. Arguments:
  1194. ParametersKey - An open handle to the resource's parameters key.
  1195. ResourceHandle - The Resource Monitor handle associated with this resource.
  1196. ParamBlock - A pointer to a buffer into which to place the private properties read
  1197. from the registry
  1198. ResDataSize - A pointer to a buffer into which to place the number of bytes
  1199. pointed to by ParamBlock->ResourceData
  1200. pdwFlags - a pointer to a DWORD that receives the flags data. Used to store the
  1201. core resource flag.
  1202. Return Value:
  1203. ERROR_SUCCESS if the routine is successful.
  1204. A Win32 error code otherwise.
  1205. --*/
  1206. {
  1207. DWORD status;
  1208. DWORD bytesReturned;
  1209. //
  1210. // get the Flags parameter; hold core resource flag for cluster name
  1211. //
  1212. status = ResUtilGetDwordValue(ResourceKey,
  1213. PARAM_NAME__FLAGS,
  1214. pdwFlags,
  1215. 0);
  1216. if ( status != ERROR_SUCCESS) {
  1217. (NetNameLogEvent)(ResourceHandle,
  1218. LOG_ERROR,
  1219. L"Unable to read Flags parameter, error=%1!u!\n",
  1220. status);
  1221. *pdwFlags = 0;
  1222. }
  1223. //
  1224. // Read the private parameters. always free the existing storage areas
  1225. //
  1226. if ( ParamBlock->NetworkName != NULL ) {
  1227. LocalFree( ParamBlock->NetworkName );
  1228. ParamBlock->NetworkName = NULL;
  1229. }
  1230. ParamBlock->NetworkName = ResUtilGetSzValue( ParametersKey, PARAM_NAME__NAME );
  1231. if (ParamBlock->NetworkName == NULL) {
  1232. status = GetLastError();
  1233. (NetNameLogEvent)(ResourceHandle,
  1234. LOG_WARNING,
  1235. L"Unable to read NetworkName parameter, error=%1!u!\n",
  1236. status);
  1237. goto error_exit;
  1238. }
  1239. status = ResUtilGetDwordValue(ParametersKey,
  1240. PARAM_NAME__REMAP,
  1241. &ParamBlock->NetworkRemap,
  1242. PARAM_DEFAULT__REMAP);
  1243. if ( status != ERROR_SUCCESS) {
  1244. (NetNameLogEvent)(ResourceHandle,
  1245. LOG_WARNING,
  1246. L"Unable to read NetworkRemap parameter, error=%1!u!\n",
  1247. status);
  1248. goto error_exit;
  1249. }
  1250. if ( ParamBlock->ResourceData != NULL ) {
  1251. LocalFree( ParamBlock->ResourceData );
  1252. ParamBlock->ResourceData = NULL;
  1253. }
  1254. //
  1255. // it is not fatal if this resource isn't in the registry. It will only
  1256. // have a value if RequireKerberos is set to one
  1257. //
  1258. status = ResUtilGetBinaryValue(ParametersKey,
  1259. PARAM_NAME__RESOURCE_DATA,
  1260. &ParamBlock->ResourceData,
  1261. ResDataSize);
  1262. if ( status != ERROR_SUCCESS ) {
  1263. (NetNameLogEvent)(ResourceHandle,
  1264. LOG_WARNING,
  1265. L"Unable to read ResourceData parameter, error=%1!u!\n",
  1266. status);
  1267. }
  1268. status = ResUtilGetDwordValue(ParametersKey,
  1269. PARAM_NAME__REQUIRE_DNS,
  1270. &ParamBlock->RequireDNS,
  1271. PARAM_DEFAULT__REQUIRE_DNS);
  1272. if ( status != ERROR_SUCCESS) {
  1273. (NetNameLogEvent)(ResourceHandle,
  1274. LOG_ERROR,
  1275. L"Unable to read RequireDNS parameter, error=%1!u!\n",
  1276. status);
  1277. goto error_exit;
  1278. }
  1279. status = ResUtilGetDwordValue(ParametersKey,
  1280. PARAM_NAME__REQUIRE_KERBEROS,
  1281. &ParamBlock->RequireKerberos,
  1282. PARAM_DEFAULT__REQUIRE_KERBEROS);
  1283. if ( status != ERROR_SUCCESS) {
  1284. (NetNameLogEvent)(ResourceHandle,
  1285. LOG_ERROR,
  1286. L"Unable to read RequireKerberos parameter, error=%1!u!\n",
  1287. status);
  1288. goto error_exit;
  1289. }
  1290. #ifdef PASSWORD_ROTATION
  1291. status = ResUtilGetBinaryValue(ParametersKey,
  1292. PARAM_NAME__NEXT_UPDATE,
  1293. (LPBYTE *)&ParamBlock->NextUpdate,
  1294. &bytesReturned);
  1295. if ( status != ERROR_SUCCESS ) {
  1296. (NetNameLogEvent)(ResourceHandle,
  1297. LOG_WARNING,
  1298. L"Unable to read NextUpdate parameter, error=%1!u!\n",
  1299. status);
  1300. }
  1301. status = ResUtilGetDwordValue(ParametersKey,
  1302. PARAM_NAME__UPDATE_INTERVAL,
  1303. &ParamBlock->UpdateInterval,
  1304. PARAM_DEFAULT__UPDATE_INTERVAL);
  1305. if ( status != ERROR_SUCCESS) {
  1306. (NetNameLogEvent)(ResourceHandle,
  1307. LOG_ERROR,
  1308. L"Unable to read UpdateInterval parameter, error=%1!u!\n",
  1309. status);
  1310. goto error_exit;
  1311. }
  1312. #endif // PASSWORD_ROTATION
  1313. if ( ParamBlock->CreatingDC != NULL ) {
  1314. LocalFree( ParamBlock->CreatingDC );
  1315. ParamBlock->CreatingDC = NULL;
  1316. }
  1317. //
  1318. // it is not fatal if this resource isn't in the registry. It will only
  1319. // have a value if RequireKerberos is set to one
  1320. //
  1321. ParamBlock->CreatingDC = ResUtilGetSzValue( ParametersKey, PARAM_NAME__CREATING_DC );
  1322. if (ParamBlock->CreatingDC == NULL) {
  1323. status = GetLastError();
  1324. (NetNameLogEvent)(ResourceHandle,
  1325. LOG_WARNING,
  1326. L"Unable to read CreatingDC parameter, error=%1!u!\n",
  1327. status);
  1328. status = ERROR_SUCCESS;
  1329. }
  1330. error_exit:
  1331. if (status != ERROR_SUCCESS) {
  1332. if (ParamBlock->NetworkName != NULL) {
  1333. LocalFree( ParamBlock->NetworkName );
  1334. ParamBlock->NetworkName = NULL;
  1335. }
  1336. if (ParamBlock->ResourceData != NULL) {
  1337. LocalFree( ParamBlock->ResourceData );
  1338. ParamBlock->ResourceData = NULL;
  1339. }
  1340. if ( ParamBlock->CreatingDC != NULL ) {
  1341. LocalFree( ParamBlock->CreatingDC );
  1342. ParamBlock->CreatingDC = NULL;
  1343. }
  1344. }
  1345. return(status);
  1346. } // NetNameGetParameters
  1347. #define TRANSPORT_BLOCK_SIZE 4
  1348. DWORD
  1349. GrowBlock(
  1350. PCHAR * Block,
  1351. DWORD UsedEntries,
  1352. DWORD BlockSize,
  1353. PDWORD FreeEntries
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Grow the specified block to hold more entries. Block might end up pointing
  1358. to different chunk of memory as a result
  1359. Arguments:
  1360. None
  1361. Return Value:
  1362. None
  1363. --*/
  1364. {
  1365. PVOID tmp;
  1366. tmp = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  1367. (UsedEntries + TRANSPORT_BLOCK_SIZE) * BlockSize);
  1368. if (tmp == NULL) {
  1369. return ERROR_NOT_ENOUGH_MEMORY;
  1370. }
  1371. if (*Block != NULL) {
  1372. CopyMemory( tmp, *Block, UsedEntries * BlockSize );
  1373. LocalFree( *Block );
  1374. }
  1375. *Block = tmp;
  1376. *FreeEntries = TRANSPORT_BLOCK_SIZE;
  1377. return ERROR_SUCCESS;
  1378. } // GrowBlock
  1379. DWORD
  1380. UpdateDomainMapEntry(
  1381. PDOMAIN_ADDRESS_MAPPING DomainEntry,
  1382. LPWSTR IpAddress,
  1383. LPWSTR DomainName,
  1384. LPWSTR ConnectoidName,
  1385. DWORD DnsServerCount,
  1386. PDWORD DnsServerList
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. Update the specified DomainMap entry by making copies of the supplied
  1391. parameters
  1392. Arguments:
  1393. None
  1394. Return Value:
  1395. None
  1396. --*/
  1397. {
  1398. //
  1399. // make copies of the address and domain and connectoid names
  1400. //
  1401. DomainEntry->IpAddress = ResUtilDupString ( IpAddress );
  1402. DomainEntry->DomainName = ResUtilDupString( DomainName );
  1403. DomainEntry->ConnectoidName = ResUtilDupString( ConnectoidName );
  1404. if ( DomainEntry->IpAddress == NULL
  1405. ||
  1406. DomainEntry->DomainName == NULL
  1407. ||
  1408. DomainEntry->ConnectoidName == NULL )
  1409. {
  1410. if ( DomainEntry->IpAddress != NULL ) {
  1411. LocalFree( DomainEntry->IpAddress );
  1412. }
  1413. if ( DomainEntry->DomainName != NULL ) {
  1414. LocalFree( DomainEntry->DomainName );
  1415. }
  1416. if ( DomainEntry->ConnectoidName != NULL ) {
  1417. LocalFree( DomainEntry->ConnectoidName );
  1418. }
  1419. return ERROR_NOT_ENOUGH_MEMORY;
  1420. }
  1421. //
  1422. // make a copy of the DNS server addresses to use when registering
  1423. //
  1424. if ( DnsServerCount > 0 ) {
  1425. DomainEntry->DnsServerList = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1426. sizeof( IP4_ARRAY ) +
  1427. (sizeof(IP4_ADDRESS) * (DnsServerCount - 1)));
  1428. if ( DomainEntry->DnsServerList == NULL ) {
  1429. LocalFree( DomainEntry->IpAddress );
  1430. LocalFree( DomainEntry->DomainName );
  1431. LocalFree( DomainEntry->ConnectoidName );
  1432. return ERROR_NOT_ENOUGH_MEMORY;
  1433. }
  1434. DomainEntry->DnsServerList->AddrCount = DnsServerCount;
  1435. RtlCopyMemory(DomainEntry->DnsServerList->AddrArray,
  1436. DnsServerList,
  1437. DnsServerCount * sizeof( IP4_ADDRESS ));
  1438. } else {
  1439. DomainEntry->DnsServerList = NULL;
  1440. }
  1441. return ERROR_SUCCESS;
  1442. } // UpdateDomainMapEntry
  1443. DWORD
  1444. NetNameGetLists(
  1445. IN PNETNAME_RESOURCE Resource,
  1446. IN PCLRTL_NET_ADAPTER_ENUM AdapterEnum OPTIONAL,
  1447. OUT LPWSTR ** TransportList,
  1448. OUT LPDWORD TransportCount,
  1449. OUT PDOMAIN_ADDRESS_MAPPING * DomainMapList OPTIONAL,
  1450. OUT LPDWORD DomainMapCount OPTIONAL
  1451. )
  1452. /*++
  1453. Build a list of NetBT transports, IP addresses, and Domain names on which
  1454. this name is dependent. The transport devices are used to register NETBios
  1455. names while the IP addresses and Domain Names are used if the adapter
  1456. associated with the IP address is the member of a DNS domain. Each IP
  1457. address can have a different domain name associated with it hence the need
  1458. to maintain a separate list.
  1459. --*/
  1460. {
  1461. DWORD status;
  1462. HRESOURCE providerHandle = NULL;
  1463. HKEY providerKey = NULL;
  1464. HRESENUM resEnumHandle = NULL;
  1465. DWORD i;
  1466. DWORD objectType;
  1467. DWORD providerNameSize = 0;
  1468. LPWSTR providerName = NULL;
  1469. LPWSTR providerType = NULL;
  1470. DWORD transportFreeEntries = 0;
  1471. LPWSTR * transportList = NULL;
  1472. DWORD transportCount = 0;
  1473. LPWSTR transportName = NULL;
  1474. HCLUSTER clusterHandle = NULL;
  1475. DWORD enableNetbios;
  1476. PDOMAIN_ADDRESS_MAPPING domainMapList = NULL;
  1477. DWORD domainMapCount = 0;
  1478. DWORD domainMapFreeEntries = 0;
  1479. LPWSTR ipAddress;
  1480. PCLRTL_NET_ADAPTER_INFO adapterInfo;
  1481. PCLRTL_NET_INTERFACE_INFO interfaceInfo;
  1482. WCHAR primaryDomain[ DNS_MAX_NAME_BUFFER_LENGTH ] = { 0 };
  1483. DWORD primaryDomainSize = DNS_MAX_NAME_BUFFER_LENGTH;
  1484. //
  1485. // get the node's primary domain name, if any. Domains with only NT4 DCs
  1486. // won't necessarily have a PDN
  1487. //
  1488. if ( !GetComputerNameEx(ComputerNamePhysicalDnsDomain,
  1489. primaryDomain,
  1490. &primaryDomainSize))
  1491. {
  1492. status = GetLastError();
  1493. (NetNameLogEvent)(
  1494. Resource->ResourceHandle,
  1495. LOG_WARNING,
  1496. L"Unable to get primary domain name, status %1!u!.\n",
  1497. status
  1498. );
  1499. primaryDomainSize = 0;
  1500. }
  1501. //
  1502. // Open a handle to the cluster.
  1503. //
  1504. clusterHandle = OpenCluster(NULL);
  1505. if (clusterHandle == NULL) {
  1506. status = GetLastError();
  1507. (NetNameLogEvent)(
  1508. Resource->ResourceHandle,
  1509. LOG_ERROR,
  1510. L"Unable to open handle to cluster, status %1!u!.\n",
  1511. status
  1512. );
  1513. goto error_exit;
  1514. }
  1515. //
  1516. // Enumerate the dependencies to find the IP Addresses
  1517. //
  1518. resEnumHandle = ClusterResourceOpenEnum(
  1519. Resource->ClusterResourceHandle,
  1520. CLUSTER_RESOURCE_ENUM_DEPENDS
  1521. );
  1522. if (resEnumHandle == NULL) {
  1523. status = GetLastError();
  1524. (NetNameLogEvent)(
  1525. Resource->ResourceHandle,
  1526. LOG_ERROR,
  1527. L"Unable to open enum handle for this resource, status %1!u!.\n",
  1528. status
  1529. );
  1530. goto error_exit;
  1531. }
  1532. //
  1533. // enum all the dependent resources for this netname resource
  1534. //
  1535. for (i=0; ;i++) {
  1536. status = ClusterResourceEnum(
  1537. resEnumHandle,
  1538. i,
  1539. &objectType,
  1540. providerName,
  1541. &providerNameSize
  1542. );
  1543. if (status == ERROR_NO_MORE_ITEMS) {
  1544. break;
  1545. }
  1546. if ((status == ERROR_MORE_DATA) ||
  1547. ((status == ERROR_SUCCESS) && (providerName == NULL))) {
  1548. if (providerName != NULL) {
  1549. LocalFree( providerName );
  1550. }
  1551. providerNameSize++;
  1552. providerName = LocalAlloc( LMEM_FIXED, providerNameSize * sizeof(WCHAR) );
  1553. if (providerName == NULL) {
  1554. (NetNameLogEvent)(
  1555. Resource->ResourceHandle,
  1556. LOG_ERROR,
  1557. L"Unable to allocate memory.\n"
  1558. );
  1559. status = ERROR_NOT_ENOUGH_MEMORY;
  1560. goto error_exit;
  1561. }
  1562. status = ClusterResourceEnum(
  1563. resEnumHandle,
  1564. i,
  1565. &objectType,
  1566. providerName,
  1567. &providerNameSize
  1568. );
  1569. ASSERT(status != ERROR_MORE_DATA);
  1570. }
  1571. if (status != ERROR_SUCCESS) {
  1572. (NetNameLogEvent)(
  1573. Resource->ResourceHandle,
  1574. LOG_ERROR,
  1575. L"Unable to enumerate resource dependencies, status %1!u!.\n",
  1576. status
  1577. );
  1578. goto error_exit;
  1579. }
  1580. //
  1581. // Open the resource
  1582. //
  1583. providerHandle = OpenClusterResource(clusterHandle, providerName);
  1584. if (providerHandle == NULL) {
  1585. status = GetLastError();
  1586. (NetNameLogEvent)(
  1587. Resource->ResourceHandle,
  1588. LOG_ERROR,
  1589. L"Unable to open handle to provider resource %1!ws!, status %2!u!.\n",
  1590. providerName,
  1591. status
  1592. );
  1593. goto error_exit;
  1594. }
  1595. //
  1596. // Figure out what type it is.
  1597. //
  1598. providerKey = GetClusterResourceKey(providerHandle, KEY_READ);
  1599. status = GetLastError();
  1600. CloseClusterResource(providerHandle);
  1601. if (providerKey == NULL) {
  1602. (NetNameLogEvent)(
  1603. Resource->ResourceHandle,
  1604. LOG_ERROR,
  1605. L"Unable to open provider resource key, status %1!u!.\n",
  1606. status
  1607. );
  1608. goto error_exit;
  1609. }
  1610. providerType = ResUtilGetSzValue(providerKey, CLUSREG_NAME_RES_TYPE);
  1611. if (providerType == NULL) {
  1612. status = GetLastError();
  1613. (NetNameLogEvent)(
  1614. Resource->ResourceHandle,
  1615. LOG_ERROR,
  1616. L"Unable to get provider resource type, status %1!u!.\n",
  1617. status
  1618. );
  1619. goto error_exit;
  1620. }
  1621. //
  1622. // make sure it's an IP address resource
  1623. //
  1624. if (wcscmp(providerType, IP_ADDRESS_RESOURCETYPE_NAME) == 0) {
  1625. HKEY parametersKey;
  1626. //
  1627. // Open the provider's parameters key.
  1628. //
  1629. status = ClusterRegOpenKey(
  1630. providerKey,
  1631. CLUSREG_KEYNAME_PARAMETERS,
  1632. KEY_READ,
  1633. &parametersKey
  1634. );
  1635. if (status != ERROR_SUCCESS) {
  1636. (NetNameLogEvent)(
  1637. Resource->ResourceHandle,
  1638. LOG_ERROR,
  1639. L"Unable to open provider's parameters key, status %1!u!.\n",
  1640. status
  1641. );
  1642. goto error_exit;
  1643. }
  1644. if ( ARGUMENT_PRESENT( DomainMapList )) {
  1645. ASSERT( ARGUMENT_PRESENT( DomainMapCount ));
  1646. ASSERT( ARGUMENT_PRESENT( AdapterEnum ));
  1647. //
  1648. // build a list of IP address strings that we can use for
  1649. // building the appropriate DNS records
  1650. //
  1651. ipAddress = ResUtilGetSzValue( parametersKey, CLUSREG_NAME_IPADDR_ADDRESS );
  1652. if (ipAddress == NULL) {
  1653. status = GetLastError();
  1654. ClusterRegCloseKey(parametersKey);
  1655. (NetNameLogEvent)(
  1656. Resource->ResourceHandle,
  1657. LOG_ERROR,
  1658. L"Unable to get provider's Address value, status %1!u!.\n",
  1659. status
  1660. );
  1661. goto error_exit;
  1662. }
  1663. //
  1664. // find the corresponding adapter/interface over which packets
  1665. // for this IP address would be sent. Get the domain name (if
  1666. // any) from the adapter info.
  1667. //
  1668. adapterInfo = ClRtlFindNetAdapterByInterfaceAddress(
  1669. AdapterEnum,
  1670. ipAddress,
  1671. &interfaceInfo);
  1672. if ( adapterInfo != NULL ) {
  1673. LPWSTR deviceGuid;
  1674. DWORD guidLength;
  1675. //
  1676. // argh. DeviceGuid is not bracketed by braces which the
  1677. // following Dns routines require. Dup the string and make
  1678. // it all nice and pretty for DNS.
  1679. //
  1680. guidLength = wcslen( adapterInfo->DeviceGuid );
  1681. deviceGuid = LocalAlloc( LMEM_FIXED, (guidLength + 3) * sizeof(WCHAR) );
  1682. if ( deviceGuid == NULL ) {
  1683. status = GetLastError();
  1684. (NetNameLogEvent)(
  1685. Resource->ResourceHandle,
  1686. LOG_ERROR,
  1687. L"Unable to allocate memory.\n"
  1688. );
  1689. goto error_exit;
  1690. }
  1691. deviceGuid[0] = L'{';
  1692. wcscpy( &deviceGuid[1], adapterInfo->DeviceGuid );
  1693. wcscpy( &deviceGuid[ guidLength + 1 ], L"}" );
  1694. //
  1695. // see if dynamic DNS is enabled for this adapter and that
  1696. // they are DNS servers associated with this adapter. Bail
  1697. // if not. This check corresponds to the "register this
  1698. // connection's addresses in DNS" checkbox in the DNS
  1699. // proppage in the advanced TCP properties
  1700. //
  1701. if ( DnsIsDynamicRegistrationEnabled( deviceGuid ) &&
  1702. adapterInfo->DnsServerCount > 0)
  1703. {
  1704. //
  1705. // set up a mapping with the Primary Domain Name if
  1706. // apropriate
  1707. //
  1708. if ( primaryDomainSize != 0 ) {
  1709. if (domainMapFreeEntries == 0) {
  1710. status = GrowBlock((PCHAR *)&domainMapList,
  1711. domainMapCount,
  1712. sizeof( *domainMapList ),
  1713. &domainMapFreeEntries);
  1714. if ( status != ERROR_SUCCESS) {
  1715. (NetNameLogEvent)(
  1716. Resource->ResourceHandle,
  1717. LOG_ERROR,
  1718. L"Unable to allocate memory.\n"
  1719. );
  1720. goto error_exit;
  1721. }
  1722. }
  1723. //
  1724. // make copies of the address and name
  1725. //
  1726. status = UpdateDomainMapEntry(&domainMapList[ domainMapCount ],
  1727. ipAddress,
  1728. primaryDomain,
  1729. adapterInfo->ConnectoidName,
  1730. adapterInfo->DnsServerCount,
  1731. adapterInfo->DnsServerList);
  1732. if ( status != ERROR_SUCCESS ) {
  1733. (NetNameLogEvent)(
  1734. Resource->ResourceHandle,
  1735. LOG_ERROR,
  1736. L"Unable to allocate memory.\n"
  1737. );
  1738. goto error_exit;
  1739. }
  1740. domainMapCount++;
  1741. domainMapFreeEntries--;
  1742. }
  1743. //
  1744. // now check if we should care about the adapter
  1745. // specific name. It must be different from the
  1746. // primary domain name and have the "use this
  1747. // connection's DNS suffix" checkbox checked.
  1748. //
  1749. if ( DnsIsAdapterDomainNameRegistrationEnabled( deviceGuid ) &&
  1750. adapterInfo->AdapterDomainName != NULL &&
  1751. ClRtlStrICmp(adapterInfo->AdapterDomainName, primaryDomain) != 0)
  1752. {
  1753. if (domainMapFreeEntries == 0) {
  1754. status = GrowBlock((PCHAR *)&domainMapList,
  1755. domainMapCount,
  1756. sizeof( *domainMapList ),
  1757. &domainMapFreeEntries);
  1758. if ( status != ERROR_SUCCESS) {
  1759. (NetNameLogEvent)(
  1760. Resource->ResourceHandle,
  1761. LOG_ERROR,
  1762. L"Unable to allocate memory.\n"
  1763. );
  1764. goto error_exit;
  1765. }
  1766. }
  1767. //
  1768. // make copies of the address and name
  1769. //
  1770. status = UpdateDomainMapEntry(&domainMapList[ domainMapCount ],
  1771. ipAddress,
  1772. adapterInfo->AdapterDomainName,
  1773. adapterInfo->ConnectoidName,
  1774. adapterInfo->DnsServerCount,
  1775. adapterInfo->DnsServerList);
  1776. if ( status != ERROR_SUCCESS ) {
  1777. (NetNameLogEvent)(
  1778. Resource->ResourceHandle,
  1779. LOG_ERROR,
  1780. L"Unable to allocate memory.\n"
  1781. );
  1782. goto error_exit;
  1783. }
  1784. domainMapCount++;
  1785. domainMapFreeEntries--;
  1786. } // if register adapter domain is true and one has been specified
  1787. } // if dynamic DNS is enabled for this adapter
  1788. LocalFree( deviceGuid );
  1789. } // if we found the matching adapter in our adapter info
  1790. LocalFree( ipAddress );
  1791. } // if DomainMapList present
  1792. //
  1793. // Figure out if this resource supports NetBios.
  1794. //
  1795. status = ResUtilGetDwordValue(
  1796. parametersKey,
  1797. CLUSREG_NAME_IPADDR_ENABLE_NETBIOS,
  1798. &enableNetbios,
  1799. 1
  1800. );
  1801. if (status != ERROR_SUCCESS) {
  1802. ClusterRegCloseKey(parametersKey);
  1803. (NetNameLogEvent)(
  1804. Resource->ResourceHandle,
  1805. LOG_ERROR,
  1806. L"Unable to get provider's EnableNetbios value, status %1!u!.\n",
  1807. status
  1808. );
  1809. goto error_exit;
  1810. }
  1811. if (enableNetbios) {
  1812. HKEY nodeParametersKey;
  1813. //
  1814. // Open the provider's node-specific parameters key.
  1815. //
  1816. status = ClusterRegOpenKey(
  1817. parametersKey,
  1818. Resource->NodeId,
  1819. KEY_READ,
  1820. &nodeParametersKey
  1821. );
  1822. ClusterRegCloseKey(parametersKey);
  1823. if (status != ERROR_SUCCESS) {
  1824. (NetNameLogEvent)(
  1825. Resource->ResourceHandle,
  1826. LOG_ERROR,
  1827. L"Unable to open provider's node parameters key, status %1!u!.\n",
  1828. status
  1829. );
  1830. goto error_exit;
  1831. }
  1832. transportName = ResUtilGetSzValue(
  1833. nodeParametersKey,
  1834. L"NbtDeviceName"
  1835. );
  1836. status = GetLastError();
  1837. ClusterRegCloseKey(nodeParametersKey);
  1838. if (transportName == NULL) {
  1839. (NetNameLogEvent)(
  1840. Resource->ResourceHandle,
  1841. LOG_ERROR,
  1842. L"Unable to get provider's transport name, status %1!u!.\n",
  1843. status
  1844. );
  1845. goto error_exit;
  1846. }
  1847. if (transportFreeEntries == 0) {
  1848. status = GrowBlock((PCHAR *)&transportList,
  1849. transportCount,
  1850. sizeof( *transportList ),
  1851. &transportFreeEntries);
  1852. if ( status != ERROR_SUCCESS) {
  1853. (NetNameLogEvent)(
  1854. Resource->ResourceHandle,
  1855. LOG_ERROR,
  1856. L"Unable to allocate memory.\n"
  1857. );
  1858. goto error_exit;
  1859. }
  1860. }
  1861. transportList[transportCount] = transportName;
  1862. transportName = NULL;
  1863. transportCount++;
  1864. transportFreeEntries--;
  1865. }
  1866. else {
  1867. ClusterRegCloseKey(parametersKey);
  1868. }
  1869. }
  1870. ClusterRegCloseKey(providerKey);
  1871. providerKey = NULL;
  1872. LocalFree( providerType );
  1873. providerType = NULL;
  1874. }
  1875. if (providerName != NULL) {
  1876. LocalFree( providerName );
  1877. providerName = NULL;
  1878. }
  1879. CloseCluster(clusterHandle);
  1880. ClusterResourceCloseEnum(resEnumHandle);
  1881. *TransportList = transportList;
  1882. *TransportCount = transportCount;
  1883. if ( ARGUMENT_PRESENT( DomainMapList )) {
  1884. *DomainMapList = domainMapList;
  1885. *DomainMapCount = domainMapCount;
  1886. }
  1887. return(ERROR_SUCCESS);
  1888. error_exit:
  1889. if (transportList != NULL) {
  1890. ASSERT(transportCount > 0);
  1891. while (transportCount > 0) {
  1892. LocalFree( transportList[--transportCount] );
  1893. }
  1894. LocalFree( transportList );
  1895. }
  1896. if ( domainMapList != NULL ) {
  1897. while (domainMapCount--) {
  1898. if ( domainMapList[ domainMapCount ].IpAddress != NULL ) {
  1899. LocalFree( domainMapList[ domainMapCount ].IpAddress );
  1900. }
  1901. if ( domainMapList[ domainMapCount ].DomainName != NULL ) {
  1902. LocalFree( domainMapList[ domainMapCount ].DomainName );
  1903. }
  1904. if ( domainMapList[ domainMapCount ].DnsServerList != NULL ) {
  1905. LocalFree( domainMapList[ domainMapCount ].DnsServerList );
  1906. }
  1907. }
  1908. LocalFree( domainMapList );
  1909. }
  1910. if (clusterHandle != NULL) {
  1911. CloseCluster(clusterHandle);
  1912. }
  1913. if (resEnumHandle != NULL) {
  1914. ClusterResourceCloseEnum(resEnumHandle);
  1915. }
  1916. if (providerName != NULL) {
  1917. LocalFree( providerName );
  1918. }
  1919. if (providerKey != NULL) {
  1920. ClusterRegCloseKey(providerKey);
  1921. }
  1922. if (providerType != NULL) {
  1923. LocalFree( providerType );
  1924. }
  1925. if (transportName != NULL) {
  1926. LocalFree( transportName );
  1927. }
  1928. return(status);
  1929. } // NetNameGetLists
  1930. void
  1931. FreeDNSRecordpName(PDNS_RECORDW DnsRecord)
  1932. {
  1933. PDNS_RECORDW Next;
  1934. //
  1935. // Rui: 02/24/2002
  1936. // BUG: 553148. DnsRecord->pName is allocated using LocalAlloc(),
  1937. // (DnsRecordBuild_W()). While DnsRecordListFree() uses HeapFree().
  1938. // This fix is a work around. MSDN suggests using DnsQuery(), instead of
  1939. // unpublished DnsRecordBuild_W().
  1940. //
  1941. Next = DnsRecord;
  1942. while (Next != NULL)
  1943. {
  1944. if (Next->pName != NULL)
  1945. {
  1946. LocalFree(Next->pName);
  1947. }
  1948. Next->pName = NULL;
  1949. Next = Next->pNext;
  1950. }
  1951. }
  1952. void
  1953. FreeDNSRecordPTRpNameHost(PDNS_RECORDW DnsRecord)
  1954. {
  1955. PDNS_RECORDW Next;
  1956. //
  1957. // Rui: 02/24/2002
  1958. // BUG: 553148. DnsRecord->Data.PTR.pNameHost is allocated using LocalAlloc(),
  1959. // (DnsRecordBuild_W()). While DnsRecordListFree() uses HeapFree().
  1960. // This fix is a work around. MSDN suggests using DnsQuery(), instead of
  1961. // unpublished DnsRecordBuild_W().
  1962. //
  1963. Next = DnsRecord;
  1964. while (Next != NULL)
  1965. {
  1966. if ( Next->Data.PTR.pNameHost != NULL )
  1967. {
  1968. LocalFree( Next->Data.PTR.pNameHost );
  1969. }
  1970. Next->Data.PTR.pNameHost = NULL;
  1971. Next = Next->pNext;
  1972. }
  1973. }
  1974. VOID
  1975. NetNameCleanupDnsLists(
  1976. IN PNETNAME_RESOURCE Resource
  1977. )
  1978. /*++
  1979. Routine Description:
  1980. Clean up the DNS list structures associated with the resource.
  1981. Arguments:
  1982. Resource - pointer to internal resource struct
  1983. Return Value:
  1984. None
  1985. --*/
  1986. {
  1987. PDNS_LISTS dnsLists;
  1988. DNS_STATUS dnsStatus;
  1989. PDNS_RECORD dnsRecord;
  1990. dnsLists = Resource->DnsLists;
  1991. while ( Resource->NumberOfDnsLists-- ) {
  1992. #if 0
  1993. //
  1994. // we have to free the args we handed to the DNS record build routines
  1995. //
  1996. dnsRecord = dnsLists->A_RRSet.pFirstRR;
  1997. while ( dnsRecord != NULL ) {
  1998. LocalFree( dnsRecord->pName );
  1999. dnsRecord->pName = NULL;
  2000. dnsRecord = dnsRecord->pNext;
  2001. }
  2002. dnsRecord = dnsLists->PTR_RRSet.pFirstRR;
  2003. while ( dnsRecord != NULL ) {
  2004. LocalFree( dnsRecord->Data.PTR.pNameHost );
  2005. dnsRecord->Data.PTR.pNameHost = NULL;
  2006. dnsRecord = dnsRecord->pNext;
  2007. }
  2008. #endif
  2009. //
  2010. // have DNSAPI clean up its structs
  2011. //
  2012. //
  2013. // BUG: 553148. Rui, 02/24/2002.
  2014. //
  2015. FreeDNSRecordpName(dnsLists->PTR_RRSet.pFirstRR);
  2016. FreeDNSRecordPTRpNameHost(dnsLists->PTR_RRSet.pFirstRR);
  2017. DnsRecordListFree( dnsLists->PTR_RRSet.pFirstRR, DnsFreeRecordListDeep );
  2018. FreeDNSRecordpName(dnsLists->A_RRSet.pFirstRR);
  2019. DnsRecordListFree( dnsLists->A_RRSet.pFirstRR, DnsFreeRecordListDeep );
  2020. //
  2021. // free server address info and connectoid name string
  2022. //
  2023. if ( dnsLists->DnsServerList != NULL ) {
  2024. LocalFree( dnsLists->DnsServerList );
  2025. }
  2026. if ( dnsLists->ConnectoidName != NULL ) {
  2027. LocalFree( dnsLists->ConnectoidName );
  2028. }
  2029. ++dnsLists;
  2030. }
  2031. Resource->NumberOfDnsLists = 0;
  2032. if ( Resource->DnsLists != NULL ) {
  2033. LocalFree( Resource->DnsLists );
  2034. Resource->DnsLists = NULL;
  2035. }
  2036. } // NetNameCleanupDnsLists
  2037. VOID
  2038. NetNameOfflineNetbios(
  2039. IN PNETNAME_RESOURCE Resource
  2040. )
  2041. /*++
  2042. Routine Description:
  2043. do final clean up when taking this resource offline.
  2044. Arguments:
  2045. Resource - A pointer to the NETNAME_RESOURCE block for this resource.
  2046. Returns:
  2047. None.
  2048. --*/
  2049. {
  2050. DWORD status;
  2051. DWORD i;
  2052. LPWSTR * transportList = NULL;
  2053. DWORD transportCount = 0;
  2054. LPWSTR domainName = NULL;
  2055. //
  2056. // Now we can finally do the real work of taking the netbios name
  2057. // offline. Get the domain name so we can deregister the extra credentials
  2058. // with kerberos
  2059. //
  2060. if ( Resource->Params.CreatingDC ) {
  2061. domainName = wcschr( Resource->Params.CreatingDC, L'.' );
  2062. if ( domainName != NULL ) {
  2063. ++domainName;
  2064. }
  2065. }
  2066. DeleteAlternateComputerName(Resource->Params.NetworkName,
  2067. domainName,
  2068. Resource->NameHandleList,
  2069. Resource->NameHandleCount,
  2070. Resource->ResourceHandle);
  2071. if (Resource->NameHandleList != NULL) {
  2072. LocalFree( Resource->NameHandleList );
  2073. Resource->NameHandleList = NULL;
  2074. Resource->NameHandleCount = 0;
  2075. }
  2076. //
  2077. // Remove the cluster service type bits
  2078. //
  2079. status = NetNameGetLists(Resource,
  2080. NULL,
  2081. &transportList,
  2082. &transportCount,
  2083. NULL,
  2084. NULL);
  2085. if (status == ERROR_SUCCESS) {
  2086. DWORD serviceBits;
  2087. serviceBits = SV_TYPE_CLUSTER_VS_NT | SV_TYPE_CLUSTER_NT;
  2088. for (i=0; i<transportCount; i++) {
  2089. I_NetServerSetServiceBitsEx(NULL, // target server
  2090. Resource->Params.NetworkName, // emulated server name
  2091. transportList[i], // transport name
  2092. serviceBits, // bits of interest
  2093. 0, // bits
  2094. TRUE ); // Update immediately
  2095. }
  2096. while (transportCount > 0) {
  2097. LocalFree( transportList[--transportCount] );
  2098. }
  2099. LocalFree( transportList );
  2100. }
  2101. } // NetNameOfflineNetbios
  2102. DWORD
  2103. NetNameOnlineThread(
  2104. IN PCLUS_WORKER Worker,
  2105. IN PNETNAME_RESOURCE Resource
  2106. )
  2107. /*++
  2108. Routine Description:
  2109. Brings a network name resource online.
  2110. Arguments:
  2111. Worker - Supplies the worker structure
  2112. Resource - A pointer to the NETNAME_RESOURCE block for this resource.
  2113. Returns:
  2114. ERROR_SUCCESS if successful.
  2115. Win32 error code on failure.
  2116. --*/
  2117. {
  2118. DWORD status;
  2119. CLUSTER_RESOURCE_STATE finalState = ClusterResourceFailed;
  2120. LPWSTR * transportList = NULL;
  2121. DWORD transportCount = 0;
  2122. PDOMAIN_ADDRESS_MAPPING domainMapList = NULL;
  2123. DWORD domainMapCount = 0;
  2124. DWORD i;
  2125. DWORD dwFlags;
  2126. PCLRTL_NET_ADAPTER_ENUM adapterEnum = NULL;
  2127. RESOURCE_STATUS resourceStatus;
  2128. DWORD serviceBits;
  2129. ResUtilInitializeResourceStatus( &resourceStatus );
  2130. ASSERT(Resource->State == ClusterResourceOnlinePending);
  2131. (NetNameLogEvent)(
  2132. Resource->ResourceHandle,
  2133. LOG_INFORMATION,
  2134. L"Bringing resource online...\n"
  2135. );
  2136. //
  2137. // If this is the first resource to be brought online then spin up the DNS
  2138. // check thread at this point
  2139. //
  2140. NetNameAcquireResourceLock();
  2141. if ( NetNameWorkerThread == NULL ) {
  2142. NetNameWorkerThread = CreateThread(NULL,
  2143. 0,
  2144. NetNameWorker,
  2145. NULL,
  2146. 0,
  2147. NULL);
  2148. if ( NetNameWorkerThread == NULL ) {
  2149. status = GetLastError();
  2150. (NetNameLogEvent)(
  2151. Resource->ResourceHandle,
  2152. LOG_ERROR,
  2153. L"Can't start Netname worker thread. status = %1!u!\n",
  2154. status
  2155. );
  2156. NetNameReleaseResourceLock();
  2157. goto error_exit;
  2158. }
  2159. }
  2160. NetNameReleaseResourceLock();
  2161. //
  2162. // initialize the checkpoint var that is used to communicate back to
  2163. // resmon that we're still working on bringing the resource online
  2164. //
  2165. Resource->StatusCheckpoint = 0;
  2166. //
  2167. // notify the worker thread that we're bringing a name online.
  2168. //
  2169. SetEvent( NetNameWorkerPendingResources );
  2170. //
  2171. // This is an old comment but I'm leaving it in. Netname does handle set
  2172. // private props but there are other issues.
  2173. //
  2174. // This read must continue to be here as long as adminstrative agents
  2175. // (like cluster.exe) continue to write to the registry behind the back of
  2176. // the resource dll. We need to migrate to writing all registry parameters
  2177. // via the SET_COMMON/PRIVATE_PROPERTIES control function. That way,
  2178. // resource dll's can read their parameters in the open (allowing for the
  2179. // possibility that they may fail), and then update the parameters
  2180. // whenever the SET_PRIVATE_PROPERTIES control code is delivered and
  2181. // (optionally) on the SET_COMMON_PROPERTIES as needed.
  2182. //
  2183. // Fetch our parameters from the registry.
  2184. //
  2185. status = NetNameGetParameters(
  2186. Resource->ResKey,
  2187. Resource->ParametersKey,
  2188. Resource->ResourceHandle,
  2189. &Resource->Params,
  2190. &Resource->ResDataSize,
  2191. &Resource->dwFlags
  2192. );
  2193. if (status != ERROR_SUCCESS) {
  2194. goto error_exit;
  2195. }
  2196. if ( Resource->Params.NetworkName == NULL ) {
  2197. status = ERROR_RESOURCE_NOT_FOUND;
  2198. goto error_exit;
  2199. }
  2200. //
  2201. // if we just went through an upgrade and this resource is a provider for
  2202. // an MSMQ resource, then we need to force kerb support
  2203. //
  2204. if ( Resource->CheckForKerberosUpgrade ) {
  2205. Resource->CheckForKerberosUpgrade = FALSE;
  2206. status = UpgradeMSMQDependentNetnameToKerberos( Resource );
  2207. if ( status != ERROR_SUCCESS ) {
  2208. (NetNameLogEvent)( Resource->ResourceHandle,
  2209. LOG_ERROR,
  2210. L"Unable to set RequireKerberos property after an upgrade - status %1!u!. "
  2211. L"This resource requires that the RequireKerberos property be set to "
  2212. L"one in order for its dependent MSMQ resource to be successfully "
  2213. L"brought online.\n",
  2214. status);
  2215. ClusResLogSystemEventByKeyData(Resource->ResKey,
  2216. LOG_CRITICAL,
  2217. RES_NETNAME_UPGRADE_TO_KERBEROS_SUPPORT_FAILED,
  2218. sizeof( status ),
  2219. &status);
  2220. goto error_exit;
  2221. }
  2222. }
  2223. //
  2224. // check to see if recovery from a half-baked rename is needed
  2225. //
  2226. if ( Resource->Params.CreatingDC ) {
  2227. status = NetNameCheckForCompObjRenameRecovery( Resource );
  2228. if ( status != ERROR_SUCCESS ) {
  2229. goto error_exit;
  2230. }
  2231. }
  2232. //
  2233. // Ensure that the specified network name is not the same as the
  2234. // computername of this node.
  2235. //
  2236. if ( lstrcmpiW(Resource->Params.NetworkName, Resource->NodeName) == 0 ) {
  2237. ClusResLogSystemEventByKey1(Resource->ResKey,
  2238. LOG_CRITICAL,
  2239. RES_NETNAME_DUPLICATE,
  2240. Resource->Params.NetworkName);
  2241. (NetNameLogEvent)(
  2242. Resource->ResourceHandle,
  2243. LOG_ERROR,
  2244. L"The specified network name is the same as the local computername.\n"
  2245. );
  2246. status = ERROR_DUP_NAME;
  2247. goto error_exit;
  2248. }
  2249. //
  2250. // get the adapter configuration and determine which adapters are
  2251. // participating in a DNS domain
  2252. //
  2253. adapterEnum = ClRtlEnumNetAdapters();
  2254. if ( adapterEnum == NULL ) {
  2255. status = GetLastError();
  2256. (NetNameLogEvent)(
  2257. Resource->ResourceHandle,
  2258. LOG_ERROR,
  2259. L"Couldn't acquire network adapter configuration, status %1!u!\n",
  2260. status
  2261. );
  2262. goto error_exit;
  2263. }
  2264. //
  2265. // Search our dependencies and return the list of NBT devices to which we
  2266. // need to bind the server. Also get the IP addresses this resource
  2267. // depends on so we can publish them in DNS.
  2268. //
  2269. status = NetNameGetLists(
  2270. Resource,
  2271. adapterEnum,
  2272. &transportList,
  2273. &transportCount,
  2274. &domainMapList,
  2275. &domainMapCount
  2276. );
  2277. if (status != ERROR_SUCCESS) {
  2278. goto error_exit;
  2279. }
  2280. //
  2281. // transportCount could be zero in the case where NetBIOS names are turned
  2282. // off for all IP addr resources. In any case, a network name must have at
  2283. // least one IP address associated with it.
  2284. //
  2285. if (( transportCount + domainMapCount ) == 0 ) {
  2286. ClusResLogSystemEventByKey(Resource->ResKey,
  2287. LOG_CRITICAL,
  2288. RES_NETNAME_NO_IP_ADDRESS);
  2289. (NetNameLogEvent)(
  2290. Resource->ResourceHandle,
  2291. LOG_ERROR,
  2292. L"This resource is configured such that its name will not be registered "
  2293. L"with a name service or it could not be registered with either "
  2294. L"NetBIOS or a DNS name server at this time. This condition prevents "
  2295. L"the resource from changing its state to online.\n"
  2296. );
  2297. status = ERROR_DEPENDENCY_NOT_FOUND;
  2298. goto error_exit;
  2299. }
  2300. if ( transportCount > 0 ) {
  2301. //
  2302. // Allocate an array to hold the handles for the registered name
  2303. //
  2304. Resource->NameHandleList = LocalAlloc(
  2305. LMEM_FIXED | LMEM_ZEROINIT,
  2306. sizeof(HANDLE) * transportCount
  2307. );
  2308. if (Resource->NameHandleList == NULL) {
  2309. (NetNameLogEvent)(
  2310. Resource->ResourceHandle,
  2311. LOG_ERROR,
  2312. L"Unable to allocate memory for name registration.\n"
  2313. );
  2314. goto error_exit;
  2315. }
  2316. }
  2317. Resource->NameHandleCount = transportCount;
  2318. //
  2319. // if we have DNS related data from a previous online, free it up now
  2320. // since AddAlternateComputerName will be reconstructing with current
  2321. // info. DnsLists is synchronized with offline worker thread since
  2322. // offline doesn't report offline complete until RemoveDnsRecords has
  2323. // completed.
  2324. //
  2325. if ( Resource->DnsLists != NULL ) {
  2326. NetNameCleanupDnsLists( Resource );
  2327. }
  2328. //
  2329. // Add the name/transport combinations.
  2330. //
  2331. status = AddAlternateComputerName(
  2332. Worker,
  2333. Resource,
  2334. transportList,
  2335. transportCount,
  2336. domainMapList,
  2337. domainMapCount
  2338. );
  2339. if (status != NERR_Success) {
  2340. NetNameOfflineNetbios( Resource );
  2341. //
  2342. // don't need to synchronize with worker thread since it only checks
  2343. // online resources
  2344. //
  2345. NetNameCleanupDnsLists( Resource );
  2346. goto error_exit;
  2347. }
  2348. finalState = ClusterResourceOnline;
  2349. //
  2350. // set the appropriate service type bit(s) for this name. core cluster
  2351. // name resource additionally gets the cluster bit.
  2352. //
  2353. serviceBits = SV_TYPE_CLUSTER_VS_NT;
  2354. if (Resource->dwFlags & CLUS_FLAG_CORE) {
  2355. serviceBits |= SV_TYPE_CLUSTER_NT;
  2356. }
  2357. for (i=0; i<transportCount; i++) {
  2358. I_NetServerSetServiceBitsEx(NULL, // Local server serv
  2359. Resource->Params.NetworkName,
  2360. transportList[i], //transport name
  2361. serviceBits,
  2362. serviceBits,
  2363. TRUE ); // Update immediately
  2364. }
  2365. (NetNameLogEvent)(
  2366. Resource->ResourceHandle,
  2367. LOG_INFORMATION,
  2368. L"Network Name %1!ws! is now online\n",
  2369. Resource->Params.NetworkName
  2370. );
  2371. error_exit:
  2372. if ( status != ERROR_SUCCESS ) {
  2373. if ( Resource->NameHandleList != NULL ) {
  2374. LocalFree( Resource->NameHandleList );
  2375. Resource->NameHandleList = NULL;
  2376. Resource->NameHandleCount = 0;
  2377. }
  2378. }
  2379. if (transportList != NULL) {
  2380. ASSERT(transportCount > 0);
  2381. while (transportCount > 0) {
  2382. LocalFree( transportList[--transportCount] );
  2383. }
  2384. LocalFree( transportList );
  2385. }
  2386. if (domainMapList != NULL) {
  2387. while (domainMapCount--) {
  2388. LocalFree( domainMapList[domainMapCount].IpAddress );
  2389. LocalFree( domainMapList[domainMapCount].DomainName );
  2390. LocalFree( domainMapList[domainMapCount].ConnectoidName );
  2391. if ( domainMapList[domainMapCount].DnsServerList != NULL ) {
  2392. LocalFree( domainMapList[domainMapCount].DnsServerList );
  2393. }
  2394. }
  2395. LocalFree( domainMapList );
  2396. }
  2397. if ( adapterEnum != NULL ) {
  2398. ClRtlFreeNetAdapterEnum( adapterEnum );
  2399. }
  2400. ASSERT(Resource->State == ClusterResourceOnlinePending);
  2401. //
  2402. // set the final state accordingly. We acquire the lock to synch with the
  2403. // worker thread
  2404. //
  2405. NetNameAcquireResourceLock();
  2406. Resource->State = finalState;
  2407. resourceStatus.ResourceState = finalState;
  2408. NetNameReleaseResourceLock();
  2409. (NetNameSetResourceStatus)( Resource->ResourceHandle, &resourceStatus );
  2410. return(status);
  2411. } // NetNameOnlineThread
  2412. DWORD
  2413. WINAPI
  2414. NetNameOfflineWorker(
  2415. IN PNETNAME_RESOURCE Resource,
  2416. IN BOOL Terminate,
  2417. IN PCLUS_WORKER Worker OPTIONAL
  2418. )
  2419. /*++
  2420. Routine Description:
  2421. Internal offline routine for Network Name resource. This routine is called
  2422. by both the offline and terminate routines. Terminate calls it directly
  2423. with Worker set to NULL, while Offline spins a worker thread and then has
  2424. the worker thread call it.
  2425. If terminate is true, we bag any long running operations like removing DNS
  2426. records. We'll figure out how to deal with the resource's carcass the next
  2427. time it is brought online.
  2428. Arguments:
  2429. Resource - supplies the resource it to be taken offline
  2430. Terminate - indicates whether call is result of NetNameTerminate or NetNameOffline
  2431. Worker - pointer to cluster work thread struct. NULL if called by Terminate
  2432. Return Value:
  2433. None.
  2434. --*/
  2435. {
  2436. DWORD status = ERROR_SUCCESS;
  2437. BOOL nameChanged = FALSE;
  2438. //
  2439. // Terminate any pending thread if it is running.
  2440. //
  2441. if ( Terminate ) {
  2442. ClusWorkerTerminate(&(Resource->PendingThread));
  2443. }
  2444. //
  2445. // Synchronize offline/terminate and worker thread
  2446. //
  2447. NetNameAcquireResourceLock();
  2448. if (Resource->State != ClusterResourceOffline) {
  2449. (NetNameLogEvent)(
  2450. Resource->ResourceHandle,
  2451. LOG_INFORMATION,
  2452. L"Offline of resource continuing...\n"
  2453. );
  2454. Resource->State = ClusterResourceOfflinePending;
  2455. NetNameOfflineNetbios( Resource );
  2456. if ( Resource->RefCount > 1 ) {
  2457. //
  2458. // DNS registration is still in progress. If we don't synchronize
  2459. // with the worker thread, then it is possible to delete the
  2460. // resource while the worker routine still had a pointer to the
  2461. // freed memory. kaboom....
  2462. //
  2463. (NetNameLogEvent)(Resource->ResourceHandle,
  2464. LOG_INFORMATION,
  2465. L"Waiting for Worker thread operation to finish\n");
  2466. status = ERROR_IO_PENDING;
  2467. }
  2468. if ( status == ERROR_SUCCESS ) {
  2469. if ( !Terminate ) {
  2470. //
  2471. // If the name was changed while we were still online, do the
  2472. // appropriate clean up after we release the netname lock. We
  2473. // have to maintain a reference since a delete can be issued
  2474. // after the resource has gone offline.
  2475. //
  2476. if ( Resource->NameChangedWhileOnline ) {
  2477. ++Resource->RefCount;
  2478. nameChanged = TRUE;
  2479. Resource->NameChangedWhileOnline = FALSE;
  2480. }
  2481. }
  2482. Resource->State = ClusterResourceOffline;
  2483. }
  2484. }
  2485. else {
  2486. (NetNameLogEvent)(
  2487. Resource->ResourceHandle,
  2488. LOG_INFORMATION,
  2489. L"Resource is already offline.\n"
  2490. );
  2491. }
  2492. //
  2493. // release VS token
  2494. //
  2495. if ( Resource->VSToken ) {
  2496. CloseHandle( Resource->VSToken );
  2497. Resource->VSToken = NULL;
  2498. }
  2499. NetNameReleaseResourceLock();
  2500. if ( !Terminate ) {
  2501. RESOURCE_STATUS resourceStatus;
  2502. if ( nameChanged ) {
  2503. //
  2504. // we're not terminating the resource and we need to do some
  2505. // cleanup work. Before each major operation, check if we need to
  2506. // get out due to our Terminate routine being called.
  2507. //
  2508. if ( !ClusWorkerCheckTerminate( Worker )) {
  2509. (NetNameLogEvent)(Resource->ResourceHandle,
  2510. LOG_INFORMATION,
  2511. L"Attempting removal of DNS records\n");
  2512. RemoveDnsRecords( Resource );
  2513. }
  2514. NetNameAcquireResourceLock();
  2515. --Resource->RefCount;
  2516. ASSERT( Resource->RefCount >= 0 );
  2517. if ( Resource->RefCount == 0 ) {
  2518. NetNameReleaseResource( Resource );
  2519. }
  2520. NetNameReleaseResourceLock();
  2521. }
  2522. //
  2523. // report we're offline here; any sooner and RemoveDnsRecords and the
  2524. // online thread could collide and cause bad things to happen
  2525. //
  2526. ResUtilInitializeResourceStatus( &resourceStatus );
  2527. resourceStatus.ResourceState = ClusterResourceOffline;
  2528. (NetNameSetResourceStatus)( Resource->ResourceHandle, &resourceStatus );
  2529. (NetNameLogEvent)(Resource->ResourceHandle,
  2530. LOG_INFORMATION,
  2531. L"Resource is now offline\n");
  2532. }
  2533. return status;
  2534. } // NetNameOfflineWorker
  2535. DWORD
  2536. NetNameOfflineThread(
  2537. IN PCLUS_WORKER Worker,
  2538. IN PNETNAME_RESOURCE Resource
  2539. )
  2540. /*++
  2541. Routine Description:
  2542. stub routine to call common offline routine used by both terminate and
  2543. offline
  2544. Arguments:
  2545. Worker - pointer to cluster work thread
  2546. Resource - pointer to netname resource context block that is going offline
  2547. Return Value:
  2548. None
  2549. --*/
  2550. {
  2551. DWORD status;
  2552. //
  2553. // notify the worker thread that we're bringing a name offline.
  2554. //
  2555. SetEvent( NetNameWorkerPendingResources );
  2556. status = NetNameOfflineWorker( Resource, FALSE, Worker );
  2557. return status;
  2558. } // NetNameOfflineThread
  2559. DWORD
  2560. RemoveDependentIpAddress(
  2561. PNETNAME_RESOURCE Resource,
  2562. LPWSTR DependentResourceId
  2563. )
  2564. /*++
  2565. Routine Description:
  2566. A dependent IP address resource is being removed. Delete the associated
  2567. DNS records for this address and the netbt device.
  2568. Arguments:
  2569. Resource - pointer to private netname resource data
  2570. DependentResourceId - pointer to Unicode string of dependent resource's name
  2571. Return Value:
  2572. None
  2573. --*/
  2574. {
  2575. HCLUSTER clusterHandle;
  2576. HRESOURCE ipResourceHandle = NULL;
  2577. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  2578. DWORD status;
  2579. HKEY ipResourceKey;
  2580. HKEY parametersKey;
  2581. LPWSTR reverseName;
  2582. PDNS_LISTS dnsList;
  2583. DWORD numberOfDnsLists = Resource->NumberOfDnsLists;
  2584. LPWSTR ipAddressBuffer;
  2585. IP4_ADDRESS ipAddress;
  2586. UNICODE_STRING ipAddressStringW;
  2587. ANSI_STRING ipAddressStringA;
  2588. //
  2589. // work our way through the miriad of Cluster APIs to read the IP address
  2590. // resource's address from the registry
  2591. //
  2592. clusterHandle = OpenCluster(NULL);
  2593. if (clusterHandle != NULL) {
  2594. ipResourceHandle = OpenClusterResource( clusterHandle, DependentResourceId );
  2595. CloseCluster( clusterHandle );
  2596. if ( ipResourceHandle != NULL ) {
  2597. ipResourceKey = GetClusterResourceKey( ipResourceHandle, KEY_READ );
  2598. CloseClusterResource( ipResourceHandle );
  2599. if ( ipResourceKey != NULL ) {
  2600. status = ClusterRegOpenKey(ipResourceKey,
  2601. CLUSREG_KEYNAME_PARAMETERS,
  2602. KEY_READ,
  2603. &parametersKey);
  2604. ClusterRegCloseKey( ipResourceKey );
  2605. if (status == ERROR_SUCCESS) {
  2606. ipAddressBuffer = ResUtilGetSzValue( parametersKey, CLUSREG_NAME_IPADDR_ADDRESS );
  2607. ClusterRegCloseKey( parametersKey );
  2608. if (ipAddressBuffer == NULL) {
  2609. status = GetLastError();
  2610. (NetNameLogEvent)(resourceHandle,
  2611. LOG_ERROR,
  2612. L"Unable to get resource's Address value for resource "
  2613. L"'%1!ws!', status %2!u!.\n",
  2614. DependentResourceId,
  2615. status);
  2616. return status;
  2617. }
  2618. } else {
  2619. (NetNameLogEvent)(resourceHandle,
  2620. LOG_ERROR,
  2621. L"Unable to open parameters key for resource '%1!ws!', "
  2622. L"status %2!u!.\n",
  2623. DependentResourceId,
  2624. status);
  2625. return status;
  2626. }
  2627. } else {
  2628. status = GetLastError();
  2629. (NetNameLogEvent)(resourceHandle,
  2630. LOG_ERROR,
  2631. L"Unable to obtain registry key to resource '%1!ws!', "
  2632. L"status %2!u!.\n",
  2633. DependentResourceId,
  2634. status);
  2635. return status;
  2636. }
  2637. } else {
  2638. status = GetLastError();
  2639. (NetNameLogEvent)(resourceHandle,
  2640. LOG_ERROR,
  2641. L"Unable to open handle to resource '%1!ws!', status %2!u!.\n",
  2642. DependentResourceId,
  2643. status);
  2644. return status;
  2645. }
  2646. } else {
  2647. status = GetLastError();
  2648. (NetNameLogEvent)(resourceHandle,
  2649. LOG_ERROR,
  2650. L"Unable to open handle to cluster, status %1!u!.\n",
  2651. status);
  2652. return status;
  2653. }
  2654. //
  2655. // argh. dependencies can be removed while the two resources are in a
  2656. // stable state, i.e., not pending. Furthermore, the remove dependency
  2657. // control is issued to all nodes in the cluster (double argh). This
  2658. // really complicates matters since we're not tracking add dependency
  2659. // which means we potentially don't have current DNS data on all nodes
  2660. // except for the one that owns the resource. Consequently, if all nodes
  2661. // handle the remove then we may use stale DNS info and remove the wrong
  2662. // records at the server.
  2663. //
  2664. // Since this is our only chance to clean up PTR records at the server
  2665. // (due to the fact that the PTR logic uses ModifyRecordSet instead of
  2666. // ReplaceRecordSet), we can only process this request on a node where the
  2667. // resource is online (along with the fact that if the resource is online,
  2668. // then its DNS lists are correct). This is sort of ok since the resource
  2669. // will either 1) go online again at which point the DNS A records will be
  2670. // corrected at the server or 2) the resource will be deleted in which
  2671. // case the last node hosting resource will clean up at the server if
  2672. // possible.
  2673. //
  2674. // In any case, if we can't delete the records, we should log it.
  2675. //
  2676. if ( Resource->State != ClusterResourceOnline || numberOfDnsLists == 0 ) {
  2677. WCHAR msgBuffer[64];
  2678. msgBuffer[ COUNT_OF( msgBuffer ) - 1] = UNICODE_NULL;
  2679. if ( status == ERROR_SUCCESS ) {
  2680. _snwprintf(msgBuffer,
  2681. COUNT_OF( msgBuffer ) - 1,
  2682. L"IP Address %ws",
  2683. ipAddressBuffer);
  2684. } else {
  2685. _snwprintf(msgBuffer,
  2686. COUNT_OF( msgBuffer ) - 1,
  2687. L"Cluster IP Address resource %ws",
  2688. DependentResourceId);
  2689. }
  2690. ClusResLogSystemEventByKey1(Resource->ResKey,
  2691. LOG_UNUSUAL,
  2692. RES_NETNAME_CANT_DELETE_DEPENDENT_RESOURCE_DNS_RECORDS,
  2693. msgBuffer);
  2694. (NetNameLogEvent)(resourceHandle,
  2695. LOG_ERROR,
  2696. L"Unable to delete DNS records associated with IP resource '%1!ws!'. "
  2697. L"The DNS Administrator can delete these records through the DNS "
  2698. L"management snapin.\n",
  2699. DependentResourceId);
  2700. if ( ipAddressBuffer != NULL ) {
  2701. LocalFree( ipAddressBuffer );
  2702. }
  2703. return ERROR_SUCCESS;
  2704. }
  2705. (NetNameLogEvent)(resourceHandle,
  2706. LOG_INFORMATION,
  2707. L"RemoveDependentIpAddress: Deleting DNS records associated with resource '%1!ws!'.\n",
  2708. DependentResourceId);
  2709. RtlInitUnicodeString( &ipAddressStringW, ipAddressBuffer );
  2710. RtlUnicodeStringToAnsiString( &ipAddressStringA,
  2711. &ipAddressStringW,
  2712. TRUE );
  2713. ipAddress = inet_addr( ipAddressStringA.Buffer );
  2714. RtlFreeAnsiString( &ipAddressStringA );
  2715. //
  2716. // finally, we know what to delete. Convert the address into reverse zone
  2717. // format and find it in the resource's DNS list structures.
  2718. //
  2719. reverseName = BuildUnicodeReverseName( ipAddressBuffer );
  2720. if ( reverseName == NULL ) {
  2721. status = GetLastError();
  2722. (NetNameLogEvent)(resourceHandle,
  2723. LOG_ERROR,
  2724. L"Unable to build DNS reverse zone name for resource '%1!ws!', status %2!u!.\n",
  2725. DependentResourceId,
  2726. status);
  2727. return status;
  2728. }
  2729. //
  2730. // co-ordinate changes to DnsLists with the worker thread
  2731. //
  2732. NetNameAcquireDnsListLock( Resource );
  2733. dnsList = Resource->DnsLists;
  2734. while ( numberOfDnsLists-- ) {
  2735. PDNS_RECORD dnsRecord;
  2736. PDNS_RECORD lastDnsRecord;
  2737. PDNS_RECORD nextDnsRecord;
  2738. DNS_STATUS dnsStatus;
  2739. if ( dnsList->ForwardZoneIsDynamic ) {
  2740. dnsRecord = dnsList->A_RRSet.pFirstRR;
  2741. lastDnsRecord = NULL;
  2742. while( dnsRecord != NULL ) {
  2743. if ( dnsRecord->Data.A.IpAddress == ipAddress ) {
  2744. //
  2745. // found a match. we need to whack just that record from
  2746. // the server and from our DNS lists.
  2747. //
  2748. nextDnsRecord = dnsRecord->pNext;
  2749. dnsRecord->pNext = NULL;
  2750. dnsStatus = DnsModifyRecordsInSet_W(NULL,
  2751. dnsRecord,
  2752. DNS_UPDATE_SECURITY_USE_DEFAULT,
  2753. NULL,
  2754. dnsList->DnsServerList,
  2755. NULL);
  2756. if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  2757. (NetNameLogEvent)(Resource->ResourceHandle,
  2758. LOG_INFORMATION,
  2759. L"Deleted DNS A record at server: name: %1!ws! IP Address: %2!ws!\n",
  2760. dnsRecord->pName,
  2761. ipAddressBuffer);
  2762. } else {
  2763. WCHAR statusBuf[ 32 ];
  2764. statusBuf[ COUNT_OF( statusBuf ) - 1 ] = UNICODE_NULL;
  2765. _snwprintf(statusBuf, COUNT_OF( statusBuf ) - 1,
  2766. L"%d",
  2767. dnsStatus );
  2768. ClusResLogSystemEventByKey3(Resource->ResKey,
  2769. LOG_UNUSUAL,
  2770. RES_NETNAME_DNS_SINGLE_A_RECORD_DELETE_FAILED,
  2771. dnsRecord->pName,
  2772. ipAddressBuffer,
  2773. statusBuf);
  2774. (NetNameLogEvent)(Resource->ResourceHandle,
  2775. LOG_ERROR,
  2776. L"Failed to delete DNS A record at server: owner: %1!ws!, "
  2777. L"IP Address: %2!ws!. status %3!u!\n",
  2778. dnsRecord->pName,
  2779. ipAddressBuffer,
  2780. dnsStatus);
  2781. }
  2782. //
  2783. // fix up forward ptrs
  2784. //
  2785. if ( lastDnsRecord != NULL ) {
  2786. lastDnsRecord->pNext = nextDnsRecord;
  2787. } else {
  2788. dnsList->A_RRSet.pFirstRR = nextDnsRecord;
  2789. }
  2790. //
  2791. // fix up last ptr if necessary
  2792. //
  2793. if ( dnsList->A_RRSet.pLastRR == dnsRecord ) {
  2794. dnsList->A_RRSet.pLastRR = lastDnsRecord;
  2795. }
  2796. //
  2797. // have DNS clean up its allocations and free the record
  2798. DnsRecordListFree( dnsRecord, DnsFreeRecordListDeep );
  2799. break;
  2800. }
  2801. lastDnsRecord = dnsRecord;
  2802. dnsRecord = dnsRecord->pNext;
  2803. } // while dnsRecord != NULL
  2804. } // if forward zone is dynamic
  2805. if ( dnsList->ReverseZoneIsDynamic ) {
  2806. dnsRecord = dnsList->PTR_RRSet.pFirstRR;
  2807. lastDnsRecord = NULL;
  2808. while( dnsRecord != NULL ) {
  2809. if ( ClRtlStrICmp( reverseName, dnsRecord->pName ) == 0 ) {
  2810. //
  2811. // found a match. we need to whack that record from the
  2812. // server and from our DNS lists. This also means that we
  2813. // have to fix up the RRSet struct if the record we're
  2814. // whacking is either first and/or last.
  2815. //
  2816. nextDnsRecord = dnsRecord->pNext;
  2817. dnsRecord->pNext = NULL;
  2818. dnsStatus = DnsModifyRecordsInSet_W(NULL,
  2819. dnsRecord,
  2820. DNS_UPDATE_SECURITY_USE_DEFAULT,
  2821. NULL,
  2822. dnsList->DnsServerList,
  2823. NULL);
  2824. if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  2825. (NetNameLogEvent)(Resource->ResourceHandle,
  2826. LOG_INFORMATION,
  2827. L"Deleted DNS PTR record at server: name: %1!ws! host: %2!ws!\n",
  2828. dnsRecord->pName,
  2829. dnsRecord->Data.PTR.pNameHost
  2830. );
  2831. } else {
  2832. WCHAR statusBuf[ 32 ];
  2833. statusBuf[ COUNT_OF( statusBuf ) - 1 ] = UNICODE_NULL;
  2834. _snwprintf(statusBuf, COUNT_OF( statusBuf ) - 1,
  2835. L"%d",
  2836. dnsStatus );
  2837. ClusResLogSystemEventByKey3(Resource->ResKey,
  2838. LOG_UNUSUAL,
  2839. RES_NETNAME_DNS_PTR_RECORD_DELETE_FAILED,
  2840. dnsRecord->pName,
  2841. dnsRecord->Data.PTR.pNameHost,
  2842. statusBuf);
  2843. (NetNameLogEvent)(Resource->ResourceHandle,
  2844. LOG_ERROR,
  2845. L"Failed to delete DNS PTR record: owner %1!ws! "
  2846. L"host: %2!ws!, status %3!u!\n",
  2847. dnsRecord->pName,
  2848. dnsRecord->Data.PTR.pNameHost,
  2849. dnsStatus
  2850. );
  2851. }
  2852. //
  2853. // fix up forward ptrs
  2854. //
  2855. if ( lastDnsRecord != NULL ) {
  2856. lastDnsRecord->pNext = nextDnsRecord;
  2857. } else {
  2858. dnsList->PTR_RRSet.pFirstRR = nextDnsRecord;
  2859. }
  2860. //
  2861. // fix up last ptr if necessary
  2862. //
  2863. if ( dnsList->PTR_RRSet.pLastRR == dnsRecord ) {
  2864. dnsList->PTR_RRSet.pLastRR = lastDnsRecord;
  2865. }
  2866. //
  2867. // have DNS clean up its allocations and free the record
  2868. DnsRecordListFree( dnsRecord, DnsFreeRecordListDeep );
  2869. break;
  2870. }
  2871. lastDnsRecord = dnsRecord;
  2872. dnsRecord = dnsRecord->pNext;
  2873. } // while dnsRecord != NULL
  2874. } // if reverse zone is dynamic
  2875. ++dnsList;
  2876. } // while more dns lists to process
  2877. NetNameReleaseDnsListLock( Resource );
  2878. LocalFree( reverseName );
  2879. LocalFree( ipAddressBuffer );
  2880. return ERROR_SUCCESS;
  2881. } // RemoveDependentIpAddress
  2882. VOID
  2883. RemoveDnsRecords(
  2884. PNETNAME_RESOURCE Resource
  2885. )
  2886. /*++
  2887. Routine Description:
  2888. delete all the DNS records associated with this resource.
  2889. Arguments:
  2890. Resource - pointer to private netname resource data
  2891. Return Value:
  2892. None
  2893. --*/
  2894. {
  2895. PDNS_LISTS dnsLists;
  2896. DNS_STATUS dnsStatus;
  2897. PDNS_RECORD dnsRecord;
  2898. PDNS_RECORD nextDnsRecord;
  2899. ULONG numberOfDnsLists;
  2900. if ( Resource->NumberOfDnsLists == 0 ) {
  2901. //
  2902. // nothing to cleanup; log an entry in the event log so they know what
  2903. // to do
  2904. //
  2905. ClusResLogSystemEventByKey(Resource->ResKey,
  2906. LOG_UNUSUAL,
  2907. RES_NETNAME_CANT_DELETE_DNS_RECORDS);
  2908. return;
  2909. }
  2910. NetNameAcquireDnsListLock( Resource );
  2911. dnsLists = Resource->DnsLists;
  2912. numberOfDnsLists = Resource->NumberOfDnsLists;
  2913. while ( numberOfDnsLists-- ) {
  2914. if ( dnsLists->ReverseZoneIsDynamic ) {
  2915. //
  2916. // whack the PTR records; see the write up in RegisterDnsRecords
  2917. // for this bit of funkiness
  2918. //
  2919. dnsRecord = dnsLists->PTR_RRSet.pFirstRR;
  2920. while ( dnsRecord != NULL ) {
  2921. nextDnsRecord = dnsRecord->pNext;
  2922. dnsRecord->pNext = NULL;
  2923. dnsStatus = DnsModifyRecordsInSet_W(NULL,
  2924. dnsRecord,
  2925. DNS_UPDATE_SECURITY_USE_DEFAULT,
  2926. NULL,
  2927. dnsLists->DnsServerList,
  2928. NULL);
  2929. if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  2930. (NetNameLogEvent)(Resource->ResourceHandle,
  2931. LOG_INFORMATION,
  2932. L"Deleted DNS PTR record at server: owner: %1!ws! host: %2!ws!\n",
  2933. dnsRecord->pName,
  2934. dnsRecord->Data.PTR.pNameHost
  2935. );
  2936. } else {
  2937. WCHAR statusBuf[ 32 ];
  2938. statusBuf[ COUNT_OF( statusBuf ) - 1 ] = UNICODE_NULL;
  2939. _snwprintf(statusBuf, COUNT_OF( statusBuf ) - 1,
  2940. L"%d",
  2941. dnsStatus );
  2942. ClusResLogSystemEventByKey3(Resource->ResKey,
  2943. LOG_UNUSUAL,
  2944. RES_NETNAME_DNS_PTR_RECORD_DELETE_FAILED,
  2945. dnsRecord->pName,
  2946. dnsRecord->Data.PTR.pNameHost,
  2947. statusBuf);
  2948. (NetNameLogEvent)(Resource->ResourceHandle,
  2949. LOG_ERROR,
  2950. L"Failed to delete DNS PTR record: owner %1!ws! host: %2!ws!, status %3!u!\n",
  2951. dnsRecord->pName,
  2952. dnsRecord->Data.PTR.pNameHost,
  2953. dnsStatus
  2954. );
  2955. }
  2956. dnsRecord->pNext = nextDnsRecord;
  2957. dnsRecord = nextDnsRecord;
  2958. }
  2959. }
  2960. //
  2961. // it's possible to remove all dependencies from the netname
  2962. // resource. In that situation, we're left with no DNS records.
  2963. //
  2964. if ( dnsLists->ForwardZoneIsDynamic && dnsLists->A_RRSet.pFirstRR != NULL ) {
  2965. //
  2966. // delete the A records from the DNS server
  2967. //
  2968. dnsStatus = DnsModifyRecordsInSet_W(NULL,
  2969. dnsLists->A_RRSet.pFirstRR,
  2970. DNS_UPDATE_SECURITY_USE_DEFAULT,
  2971. NULL,
  2972. dnsLists->DnsServerList,
  2973. NULL);
  2974. if ( dnsStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  2975. dnsRecord = dnsLists->A_RRSet.pFirstRR;
  2976. while ( dnsRecord != NULL ) {
  2977. struct in_addr ipAddress;
  2978. ipAddress.s_addr = dnsRecord->Data.A.IpAddress;
  2979. (NetNameLogEvent)(Resource->ResourceHandle,
  2980. LOG_INFORMATION,
  2981. L"Deleted DNS A record at server: owner: %1!ws! IP Address: %2!hs!\n",
  2982. dnsRecord->pName,
  2983. inet_ntoa( ipAddress ));
  2984. dnsRecord = dnsRecord->pNext;
  2985. }
  2986. } else {
  2987. WCHAR statusBuf[ 32 ];
  2988. statusBuf[ COUNT_OF( statusBuf ) - 1 ] = UNICODE_NULL;
  2989. _snwprintf(statusBuf, COUNT_OF( statusBuf ) - 1,
  2990. L"%d",
  2991. dnsStatus );
  2992. ClusResLogSystemEventByKey2(Resource->ResKey,
  2993. LOG_UNUSUAL,
  2994. RES_NETNAME_DNS_A_RECORD_DELETE_FAILED,
  2995. dnsLists->A_RRSet.pFirstRR->pName,
  2996. statusBuf);
  2997. (NetNameLogEvent)(Resource->ResourceHandle,
  2998. LOG_ERROR,
  2999. L"Failed to delete DNS A record at server: owner: %1!ws!, status %2!u!\n",
  3000. dnsLists->A_RRSet.pFirstRR->pName,
  3001. dnsStatus
  3002. );
  3003. }
  3004. }
  3005. ++dnsLists;
  3006. }
  3007. NetNameCleanupDnsLists( Resource );
  3008. NetNameReleaseDnsListLock( Resource );
  3009. } // RemoveDnsRecords
  3010. DWORD
  3011. NetNameGetNetworkName(
  3012. IN OUT PNETNAME_RESOURCE ResourceEntry,
  3013. OUT PVOID OutBuffer,
  3014. IN DWORD OutBufferSize,
  3015. OUT LPDWORD BytesReturned
  3016. )
  3017. /*++
  3018. Routine Description:
  3019. Processes the CLUSCTL_RESOURCE_GET_NETWORK_NAME control function
  3020. for resources of type Network Name.
  3021. Arguments:
  3022. ResourceEntry - Supplies the resource entry on which to operate.
  3023. OutBuffer - Returns the output data.
  3024. OutBufferSize - Supplies the size, in bytes, of the data pointed
  3025. to by OutBuffer.
  3026. BytesReturned - The number of bytes returned in OutBuffer.
  3027. Return Value:
  3028. ERROR_SUCCESS - The function completed successfully.
  3029. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  3030. ERROR_MORE_DATA - More data is available than can fit in OutBuffer.
  3031. Win32 error code - The function failed.
  3032. --*/
  3033. {
  3034. DWORD status;
  3035. DWORD required;
  3036. //
  3037. // Calculate the required number of bytes required for
  3038. // the network name string.
  3039. //
  3040. required = (lstrlenW( ResourceEntry->Params.NetworkName ) + 1) * sizeof( WCHAR );
  3041. //
  3042. // Make sure we can return the required number of bytes.
  3043. //
  3044. if ( BytesReturned == NULL ) {
  3045. status = ERROR_INVALID_PARAMETER;
  3046. } else {
  3047. //
  3048. // Copy the required number of bytes to the output parameter.
  3049. //
  3050. *BytesReturned = required;
  3051. //
  3052. // If there is no output buffer, the call just wanted the size.
  3053. //
  3054. if ( OutBuffer == NULL ) {
  3055. status = ERROR_SUCCESS;
  3056. } else {
  3057. //
  3058. // If the output buffer is large enough, copy the data.
  3059. // Otherwise return an error.
  3060. //
  3061. if ( OutBufferSize >= required ) {
  3062. lstrcpyW( OutBuffer, ResourceEntry->Params.NetworkName );
  3063. status = ERROR_SUCCESS;
  3064. } else {
  3065. status = ERROR_MORE_DATA;
  3066. }
  3067. }
  3068. }
  3069. return(status);
  3070. } // NetNameGetNetworkName
  3071. //
  3072. // Public Functions
  3073. //
  3074. BOOLEAN
  3075. WINAPI
  3076. NetNameDllEntryPoint(
  3077. IN HINSTANCE DllHandle,
  3078. IN DWORD Reason,
  3079. IN LPVOID Reserved
  3080. )
  3081. {
  3082. switch(Reason) {
  3083. case DLL_PROCESS_ATTACH:
  3084. return(NetNameInit( DllHandle ));
  3085. break;
  3086. case DLL_PROCESS_DETACH:
  3087. NetNameCleanup();
  3088. break;
  3089. default:
  3090. break;
  3091. }
  3092. return(TRUE);
  3093. } // NetNameDllEntryPoint
  3094. RESID
  3095. WINAPI
  3096. NetNameOpen(
  3097. IN LPCWSTR ResourceName,
  3098. IN HKEY ResourceKey,
  3099. IN RESOURCE_HANDLE ResourceHandle
  3100. )
  3101. /*++
  3102. Routine Description:
  3103. Open routine for Network Name resource
  3104. Arguments:
  3105. ResourceName - supplies the resource name
  3106. ResourceKey - a registry key for access registry information for this
  3107. resource.
  3108. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  3109. is called.
  3110. Return Value:
  3111. RESID of created resource
  3112. NULL on failure
  3113. --*/
  3114. {
  3115. DWORD status;
  3116. HKEY parametersKey = NULL;
  3117. HKEY ResKey=NULL;
  3118. PNETNAME_RESOURCE resource = NULL;
  3119. LPWSTR nodeName = NULL;
  3120. DWORD nameSize = MAX_COMPUTERNAME_LENGTH + 1;
  3121. LPWSTR nodeId = NULL;
  3122. DWORD nodeIdSize = 6;
  3123. NETNAME_PARAMS paramBlock;
  3124. DWORD dwFlags;
  3125. DWORD resDataSize;
  3126. HCLUSTER clusterHandle;
  3127. HRESOURCE clusterResourceHandle = NULL;
  3128. RtlZeroMemory( &paramBlock, sizeof( paramBlock ));
  3129. //
  3130. // Open a handle to the resource and remember it.
  3131. //
  3132. clusterHandle = OpenCluster(NULL);
  3133. if (clusterHandle == NULL) {
  3134. status = GetLastError();
  3135. (NetNameLogEvent)(
  3136. ResourceHandle,
  3137. LOG_ERROR,
  3138. L"Unable to open handle to cluster, status %1!u!.\n",
  3139. status
  3140. );
  3141. goto error_exit;
  3142. }
  3143. clusterResourceHandle = OpenClusterResource(
  3144. clusterHandle,
  3145. ResourceName
  3146. );
  3147. CloseCluster( clusterHandle );
  3148. if (clusterResourceHandle == NULL) {
  3149. status = GetLastError();
  3150. (NetNameLogEvent)(
  3151. ResourceHandle,
  3152. LOG_ERROR,
  3153. L"Unable to open handle to resource <%1!ws!>, status %2!u!.\n",
  3154. ResourceName,
  3155. status
  3156. );
  3157. goto error_exit;
  3158. }
  3159. //
  3160. // Figure out what node we are running on.
  3161. //
  3162. nodeName = LocalAlloc( LMEM_FIXED, nameSize * sizeof(WCHAR));
  3163. if (nodeName == NULL) {
  3164. (NetNameLogEvent)(
  3165. ResourceHandle,
  3166. LOG_ERROR,
  3167. L"Unable to allocate memory.\n"
  3168. );
  3169. status = ERROR_NOT_ENOUGH_MEMORY;
  3170. goto error_exit;
  3171. }
  3172. if ( !GetComputerNameW(nodeName, &nameSize) ) {
  3173. status = GetLastError();
  3174. (NetNameLogEvent)(
  3175. ResourceHandle,
  3176. LOG_ERROR,
  3177. L"Unable to get local node name, status %1!u!.\n",
  3178. status
  3179. );
  3180. goto error_exit;
  3181. }
  3182. nodeId = LocalAlloc( LMEM_FIXED, nodeIdSize * sizeof(WCHAR));
  3183. if (nodeId == NULL) {
  3184. (NetNameLogEvent)(
  3185. ResourceHandle,
  3186. LOG_ERROR,
  3187. L"Unable to allocate memory.\n"
  3188. );
  3189. status = ERROR_NOT_ENOUGH_MEMORY;
  3190. goto error_exit;
  3191. }
  3192. status = GetCurrentClusterNodeId(nodeId, &nodeIdSize);
  3193. if (status != ERROR_SUCCESS) {
  3194. (NetNameLogEvent)(
  3195. ResourceHandle,
  3196. LOG_ERROR,
  3197. L"Unable to get local node name, status %1!u!.\n",
  3198. status
  3199. );
  3200. goto error_exit;
  3201. }
  3202. //
  3203. // Open handles to our key, our parameters key, and our node parameters
  3204. // key in the registry
  3205. //
  3206. status = ClusterRegOpenKey(ResourceKey,
  3207. L"",
  3208. KEY_ALL_ACCESS,
  3209. &ResKey);
  3210. if (status != ERROR_SUCCESS)
  3211. {
  3212. (NetNameLogEvent)(
  3213. ResourceHandle,
  3214. LOG_ERROR,
  3215. L"Unable to open the top level key,status %1!u!.\n",
  3216. status
  3217. );
  3218. goto error_exit;
  3219. }
  3220. status = ClusterRegOpenKey(ResourceKey,
  3221. CLUSREG_KEYNAME_PARAMETERS,
  3222. KEY_ALL_ACCESS,
  3223. &parametersKey);
  3224. if (status != NO_ERROR) {
  3225. (NetNameLogEvent)(
  3226. ResourceHandle,
  3227. LOG_ERROR,
  3228. L"Unable to open parameters key, status %1!u!.\n",
  3229. status);
  3230. goto error_exit;
  3231. }
  3232. //
  3233. // Fetch our parameters from the registry.
  3234. //
  3235. status = NetNameGetParameters(ResourceKey,
  3236. parametersKey,
  3237. ResourceHandle,
  3238. &paramBlock,
  3239. &resDataSize,
  3240. &dwFlags);
  3241. //
  3242. // Now we're ready to create a resource.
  3243. //
  3244. resource = NetNameAllocateResource(ResourceHandle);
  3245. if (resource == NULL) {
  3246. (NetNameLogEvent)(
  3247. ResourceHandle,
  3248. LOG_ERROR,
  3249. L"Unable to allocate resource structure.\n"
  3250. );
  3251. status = ERROR_NOT_ENOUGH_MEMORY;
  3252. goto error_exit;
  3253. } else {
  3254. status = ERROR_SUCCESS;
  3255. }
  3256. resource->RefCount = 1;
  3257. resource->NodeName = nodeName;
  3258. resource->NodeId = nodeId;
  3259. resource->State = ClusterResourceOffline;
  3260. resource->ResKey = ResKey;
  3261. resource->ParametersKey = parametersKey;
  3262. resource->Params = paramBlock;
  3263. resource->ResDataSize = resDataSize;
  3264. resource->dwFlags = dwFlags;
  3265. resource->ClusterResourceHandle = clusterResourceHandle;
  3266. resource->NameChangedWhileOnline = FALSE;
  3267. if ( resource->dwFlags & CLUS_FLAG_CORE ) {
  3268. LPWSTR currentName;
  3269. //
  3270. // for the core resource, we have to remember the current name in a
  3271. // separate location: FM will clobber the Name property directly in
  3272. // order to perserve the updating of the cluster name in a
  3273. // transaction. To that end, the CurrentName registry entry is used
  3274. // to store the current name.
  3275. //
  3276. // This entry is written in NetnameSetPrivateResProperties whenever
  3277. // the name changes. It is possible for that update to fail hence this
  3278. // update. We also have to write if this is the first time this name
  3279. // is opened since an upgrade from W2K.
  3280. //
  3281. currentName = ResUtilGetSzValue( resource->ResKey, PARAM_NAME__CORECURRENTNAME );
  3282. if ( currentName == NULL ) {
  3283. status = ClusterRegSetValue(resource->ResKey,
  3284. PARAM_NAME__CORECURRENTNAME,
  3285. REG_SZ,
  3286. (LPBYTE)resource->Params.NetworkName,
  3287. ( wcslen(resource->Params.NetworkName) + 1 ) * sizeof(WCHAR)
  3288. );
  3289. if (status != ERROR_SUCCESS) {
  3290. (NetNameLogEvent)(resource->ResourceHandle,
  3291. LOG_ERROR,
  3292. L"Failed to write CurrentName to registry, status %1!u!\n",
  3293. status
  3294. );
  3295. goto error_exit;
  3296. }
  3297. } else {
  3298. LocalFree( currentName );
  3299. }
  3300. }
  3301. //
  3302. // initialize the mutex used to protect the DNS list data.
  3303. //
  3304. resource->DnsListMutex = CreateMutex(NULL, FALSE, NULL);
  3305. if ( resource->DnsListMutex == NULL ) {
  3306. status = GetLastError();
  3307. (NetNameLogEvent)(
  3308. ResourceHandle,
  3309. LOG_ERROR,
  3310. L"Unable to initialize DNS list mutex: %1!d!.\n",
  3311. status);
  3312. goto error_exit;
  3313. }
  3314. //
  3315. // insert resource in list for DNS check routine
  3316. //
  3317. NetNameAcquireResourceLock();
  3318. InsertHeadList( &NetNameResourceListHead, &resource->Next );
  3319. NetNameReleaseResourceLock();
  3320. InterlockedIncrement(&NetNameOpenCount);
  3321. #if 0
  3322. //
  3323. // If a computer object already exists for this name, get its object
  3324. // GUID. We can't fail the open if this doesn't succeed: while the
  3325. // resource may have its name property set, it may have never gone online,
  3326. // therefore there maybe no CO in the DS at this point in time.
  3327. //
  3328. // turned off for now until we figure out what to do with the GUID. It is
  3329. // only valid while the resource is online (assuming the CO doesn't get
  3330. // whacked) and we don't do any kind of health check for the CO right
  3331. // now. Besides, Open is probably not the best place to do this due to
  3332. // latency related to contacting the DS.
  3333. //
  3334. if ( resource->Params.NetworkName != NULL ) {
  3335. GetComputerObjectGuid( resource );
  3336. }
  3337. #endif
  3338. error_exit:
  3339. if (status == ERROR_SUCCESS) {
  3340. (NetNameLogEvent)(
  3341. ResourceHandle,
  3342. LOG_INFORMATION,
  3343. L"Successful open of resid %1!u!\n",
  3344. resource
  3345. );
  3346. } else {
  3347. if (paramBlock.NetworkName != NULL) {
  3348. LocalFree( paramBlock.NetworkName );
  3349. }
  3350. if (paramBlock.ResourceData != NULL) {
  3351. LocalFree( paramBlock.ResourceData );
  3352. }
  3353. if (paramBlock.CreatingDC != NULL) {
  3354. LocalFree( paramBlock.CreatingDC );
  3355. }
  3356. if (parametersKey != NULL) {
  3357. ClusterRegCloseKey(parametersKey);
  3358. }
  3359. if (ResKey != NULL){
  3360. ClusterRegCloseKey(ResKey);
  3361. }
  3362. if (clusterResourceHandle != NULL) {
  3363. CloseClusterResource(clusterResourceHandle);
  3364. }
  3365. if (nodeName != NULL) {
  3366. LocalFree( nodeName );
  3367. }
  3368. if (nodeId != NULL) {
  3369. LocalFree( nodeId );
  3370. }
  3371. if (resource != NULL) {
  3372. LocalFree( resource );
  3373. resource = NULL;
  3374. }
  3375. (NetNameLogEvent)(
  3376. ResourceHandle,
  3377. LOG_INFORMATION,
  3378. L"Open failed, status %1!u!\n",
  3379. status
  3380. );
  3381. SetLastError(status);
  3382. }
  3383. return resource;
  3384. } // NetNameOpen
  3385. DWORD
  3386. WINAPI
  3387. NetNameOnline(
  3388. IN RESID Resource,
  3389. IN OUT PHANDLE EventHandle
  3390. )
  3391. /*++
  3392. Routine Description:
  3393. Online routine for Network Name resource.
  3394. Arguments:
  3395. Resource - supplies resource id to be brought online
  3396. EventHandle - supplies a pointer to a handle to signal on error.
  3397. Return Value:
  3398. ERROR_SUCCESS if successful.
  3399. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  3400. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  3401. acquire 'ownership'.
  3402. Win32 error code if other failure.
  3403. --*/
  3404. {
  3405. PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
  3406. DWORD threadId;
  3407. DWORD status=ERROR_SUCCESS;
  3408. if (resource == NULL) {
  3409. return(ERROR_RESOURCE_NOT_FOUND);
  3410. }
  3411. NetNameAcquireResourceLock();
  3412. resource->State = ClusterResourceOnlinePending;
  3413. status = ClusWorkerCreate(
  3414. &resource->PendingThread,
  3415. NetNameOnlineThread,
  3416. resource
  3417. );
  3418. if (status != ERROR_SUCCESS) {
  3419. resource->State = ClusterResourceFailed;
  3420. (NetNameLogEvent)(
  3421. resource->ResourceHandle,
  3422. LOG_ERROR,
  3423. L"Unable to start online thread, status %1!u!.\n",
  3424. status
  3425. );
  3426. }
  3427. else {
  3428. status = ERROR_IO_PENDING;
  3429. }
  3430. NetNameReleaseResourceLock();
  3431. return(status);
  3432. } // NetNameOnline
  3433. DWORD
  3434. WINAPI
  3435. NetNameOffline(
  3436. IN RESID Resource
  3437. )
  3438. /*++
  3439. Routine Description:
  3440. Offline routine for Network Name resource. Spin a worker thread and return
  3441. pending.
  3442. Arguments:
  3443. Resource - supplies resource id to be taken offline.
  3444. Return Value:
  3445. ERROR_SUCCESS if successful.
  3446. A Win32 error code otherwise.
  3447. --*/
  3448. {
  3449. DWORD status;
  3450. PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
  3451. if (resource != NULL) {
  3452. (NetNameLogEvent)(
  3453. resource->ResourceHandle,
  3454. LOG_INFORMATION,
  3455. L"Taking resource offline...\n"
  3456. );
  3457. status = ClusWorkerCreate(&resource->PendingThread,
  3458. NetNameOfflineThread,
  3459. resource);
  3460. if (status != ERROR_SUCCESS) {
  3461. resource->State = ClusterResourceFailed;
  3462. (NetNameLogEvent)(
  3463. resource->ResourceHandle,
  3464. LOG_ERROR,
  3465. L"Unable to start offline thread, status %1!u!.\n",
  3466. status
  3467. );
  3468. }
  3469. else {
  3470. status = ERROR_IO_PENDING;
  3471. }
  3472. }
  3473. else {
  3474. status = ERROR_RESOURCE_NOT_FOUND;
  3475. }
  3476. return(status);
  3477. } // NetNameOffline
  3478. VOID
  3479. WINAPI
  3480. NetNameTerminate(
  3481. IN RESID Resource
  3482. )
  3483. /*++
  3484. Routine Description:
  3485. Terminate routine for Network Name resource.
  3486. Arguments:
  3487. Resource - supplies resource id to be terminated
  3488. Return Value:
  3489. None.
  3490. --*/
  3491. {
  3492. PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
  3493. if (resource != NULL) {
  3494. (NetNameLogEvent)(
  3495. resource->ResourceHandle,
  3496. LOG_INFORMATION,
  3497. L"Terminating resource...\n"
  3498. );
  3499. /* Ruihu: 11/06/2000 */
  3500. NetNameAcquireResourceLock();
  3501. if ((resource->State != ClusterResourceOffline) &&
  3502. (resource->State != ClusterResourceOfflinePending))
  3503. {
  3504. //
  3505. // only call private offline routine if we haven't called it
  3506. // already
  3507. //
  3508. NetNameReleaseResourceLock();
  3509. NetNameOfflineWorker( resource, TRUE, NULL );
  3510. NetNameAcquireResourceLock();
  3511. }
  3512. resource->State = ClusterResourceOffline;
  3513. NetNameReleaseResourceLock();
  3514. /* Ruihu: 11/06/2000 */
  3515. }
  3516. return;
  3517. } // NetNameTerminate
  3518. BOOL
  3519. WINAPI
  3520. NetNameLooksAlive(
  3521. IN RESID Resource
  3522. )
  3523. /*++
  3524. Routine Description:
  3525. LooksAlive routine for Network Name resource.
  3526. Check that any Netbt plumbing is still intact. Then check the status of
  3527. the last DNS operation. Finally check the kerberos status and fail if
  3528. appropriate to do so.
  3529. Arguments:
  3530. Resource - supplies the resource id to be polled.
  3531. Return Value:
  3532. TRUE - Resource looks like it is alive and well
  3533. FALSE - Resource looks like it is toast.
  3534. --*/
  3535. {
  3536. PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
  3537. BOOL isHealthy = TRUE;
  3538. DWORD status;
  3539. DWORD numberOfFailures = 0;
  3540. ULONG numberOfDnsLists;
  3541. PDNS_LISTS dnsLists;
  3542. BOOL dnsFailure = FALSE;
  3543. if (resource == NULL) {
  3544. return(FALSE);
  3545. }
  3546. NetNameAcquireResourceLock();
  3547. //
  3548. // avoid gotos by breaking out of fake do loop
  3549. //
  3550. do {
  3551. status = NetNameCheckNbtName(resource->Params.NetworkName,
  3552. resource->NameHandleCount,
  3553. resource->NameHandleList,
  3554. resource->ResourceHandle);
  3555. if ( status != ERROR_SUCCESS ) {
  3556. ClusResLogSystemEventByKey1(resource->ResKey,
  3557. LOG_CRITICAL,
  3558. RES_NETNAME_NOT_REGISTERED_WITH_RDR,
  3559. resource->Params.NetworkName);
  3560. (NetNameLogEvent)(resource->ResourceHandle,
  3561. LOG_INFORMATION,
  3562. L"Name %1!ws! failed IsAlive/LooksAlive check, error %2!u!.\n",
  3563. resource->Params.NetworkName,
  3564. status);
  3565. isHealthy = FALSE;
  3566. break;
  3567. }
  3568. //
  3569. // check how many of the DNS A record registrations are correct. We
  3570. // don't acquire the resource's DNS list lock since we're only reading
  3571. // the status out of a struct. The resource can't be deleted while
  3572. // we're in this routine and we're not walking the DNS records
  3573. // associated with this list so the number of lists won't change out
  3574. // from underneath of us.
  3575. //
  3576. numberOfDnsLists = resource->NumberOfDnsLists;
  3577. dnsLists = resource->DnsLists;
  3578. while ( numberOfDnsLists-- ) {
  3579. if (dnsLists->LastARecQueryStatus != DNS_ERROR_RCODE_NO_ERROR
  3580. &&
  3581. dnsLists->LastARecQueryStatus != ERROR_TIMEOUT )
  3582. {
  3583. dnsFailure = TRUE;
  3584. ++numberOfFailures;
  3585. }
  3586. ++dnsLists;
  3587. }
  3588. //
  3589. // If DNS is required and we detected a failure other than timeout or all
  3590. // DNS name registrations failed and there are no netbt names associated
  3591. // with this name, then we need to fail the resource
  3592. //
  3593. if ( ( resource->Params.RequireDNS && dnsFailure )
  3594. ||
  3595. ( numberOfFailures == resource->NumberOfDnsLists
  3596. &&
  3597. resource->NameHandleCount == 0 ) )
  3598. {
  3599. isHealthy = FALSE;
  3600. break;
  3601. }
  3602. #if 0
  3603. if ( resource->DoKerberosCheck ) {
  3604. //
  3605. // ISSUE-01/03/13 charlwi - should resource fail if can't reach DS?
  3606. //
  3607. // The problem here is that we might have lost our connection to a
  3608. // DC. Does that mean we fail the name? Not sure, since we don't know
  3609. // if replication has been late. On the other hand, if the object has
  3610. // been deleted from the DS, we should take some sort of action. This
  3611. // will affect clients that do not have tickets at this point, i.e.,
  3612. // existing clients with tickets will continue to work.
  3613. //
  3614. // see if our kerb plumbing is intact by getting a handle to the
  3615. // computer object and checking its DnsHostName and
  3616. // SecurityPrincipalName attributes
  3617. //
  3618. if ( resource->KerberosStatus != ERROR_SUCCESS ) {
  3619. isHealthy = FALSE;
  3620. }
  3621. }
  3622. #endif
  3623. } while ( FALSE );
  3624. NetNameReleaseResourceLock();
  3625. return isHealthy;
  3626. } // NetNameLooksAlive
  3627. BOOL
  3628. WINAPI
  3629. NetNameIsAlive(
  3630. IN RESID Resource
  3631. )
  3632. /*++
  3633. Routine Description:
  3634. IsAlive routine for Network Name resource.
  3635. Arguments:
  3636. Resource - supplies the resource id to be polled.
  3637. Return Value:
  3638. TRUE - Resource is alive and well
  3639. FALSE - Resource is toast.
  3640. --*/
  3641. {
  3642. return(NetNameLooksAlive(Resource));
  3643. } // NetNameIsAlive
  3644. VOID
  3645. WINAPI
  3646. NetNameClose(
  3647. IN RESID Resource
  3648. )
  3649. /*++
  3650. Routine Description:
  3651. Close routine for Network Name resource.
  3652. Arguments:
  3653. Resource - supplies resource id to be closed.
  3654. Return Value:
  3655. None.
  3656. --*/
  3657. {
  3658. PNETNAME_RESOURCE resource = (PNETNAME_RESOURCE) Resource;
  3659. PLIST_ENTRY entry;
  3660. if (resource != NULL) {
  3661. ClusWorkerTerminate( &resource->PendingThread );
  3662. if ( InterlockedDecrement(&NetNameOpenCount) == 0 ) {
  3663. // This is the last resource //
  3664. // Kill NetNameWorker //
  3665. //
  3666. // set the event to terminate the worker thread and wait for it to
  3667. // terminate.
  3668. //
  3669. if ( NetNameWorkerThread != NULL ) {
  3670. DWORD status;
  3671. SetEvent( NetNameWorkerTerminate );
  3672. status = WaitForSingleObject(NetNameWorkerThread, 3 * 60 * 1000);
  3673. if ( status == WAIT_TIMEOUT ) {
  3674. (NetNameLogEvent)(
  3675. resource->ResourceHandle,
  3676. LOG_ERROR,
  3677. L"Worker routine failed to stop. Terminating resrcmon.\n");
  3678. ClusResLogSystemEventByKey(resource->ResKey,
  3679. LOG_CRITICAL,
  3680. RES_NETNAME_DNS_CANNOT_STOP
  3681. );
  3682. ExitProcess(WAIT_TIMEOUT);
  3683. }
  3684. CloseHandle( NetNameWorkerThread );
  3685. NetNameWorkerThread = NULL;
  3686. }
  3687. }
  3688. NetNameAcquireResourceLock();
  3689. //
  3690. // release our reference to this block. If the DNS worker thread
  3691. // doesn't have an outstanding reference to it, then we can zap the
  3692. // block now. Otherwise the DNS check routine will detect that the ref
  3693. // count went to zero and get rid of it then. In either case, remove
  3694. // it from the resource block list to avoid the problem where an
  3695. // identical resource is recreated and both blocks are on the list.
  3696. //
  3697. RemoveEntryList(&resource->Next);
  3698. ASSERT( resource->RefCount > 0 );
  3699. if ( --resource->RefCount == 0 ) {
  3700. NetNameReleaseResource( resource );
  3701. }
  3702. NetNameReleaseResourceLock();
  3703. }
  3704. return;
  3705. } // NetNameClose
  3706. DWORD
  3707. NetNameGetRequiredDependencies(
  3708. OUT PVOID OutBuffer,
  3709. IN DWORD OutBufferSize,
  3710. OUT LPDWORD BytesReturned
  3711. )
  3712. /*++
  3713. Routine Description:
  3714. Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
  3715. for resources of type Network Name.
  3716. Arguments:
  3717. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  3718. OutBufferSize - Supplies the size, in bytes, of the available space
  3719. pointed to by OutBuffer.
  3720. BytesReturned - Returns the number of bytes of OutBuffer actually
  3721. filled in by the resource. If OutBuffer is too small, BytesReturned
  3722. contains the total number of bytes for the operation to succeed.
  3723. Return Value:
  3724. ERROR_SUCCESS - The function completed successfully.
  3725. ERROR_MORE_DATA - The output buffer is too small to return the data.
  3726. BytesReturned contains the required size.
  3727. Win32 error code - The function failed.
  3728. --*/
  3729. {
  3730. typedef struct DEP_DATA {
  3731. CLUSPROP_SZ_DECLARE( ipaddrEntry, sizeof(IP_ADDRESS_RESOURCETYPE_NAME) / sizeof(WCHAR) );
  3732. CLUSPROP_SYNTAX endmark;
  3733. } DEP_DATA, *PDEP_DATA;
  3734. PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
  3735. DWORD status;
  3736. *BytesReturned = sizeof(DEP_DATA);
  3737. if ( OutBufferSize < sizeof(DEP_DATA) ) {
  3738. if ( OutBuffer == NULL ) {
  3739. status = ERROR_SUCCESS;
  3740. } else {
  3741. status = ERROR_MORE_DATA;
  3742. }
  3743. } else {
  3744. ZeroMemory( pdepdata, sizeof(DEP_DATA) );
  3745. pdepdata->ipaddrEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
  3746. pdepdata->ipaddrEntry.cbLength = sizeof(IP_ADDRESS_RESOURCETYPE_NAME);
  3747. lstrcpyW( pdepdata->ipaddrEntry.sz, IP_ADDRESS_RESOURCETYPE_NAME );
  3748. pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
  3749. status = ERROR_SUCCESS;
  3750. }
  3751. return status;
  3752. } // NetNameGetRequiredDependencies
  3753. DWORD
  3754. NetNameResourceControl(
  3755. IN RESID Resource,
  3756. IN DWORD ControlCode,
  3757. IN PVOID InBuffer,
  3758. IN DWORD InBufferSize,
  3759. OUT PVOID OutBuffer,
  3760. IN DWORD OutBufferSize,
  3761. OUT LPDWORD BytesReturned
  3762. )
  3763. /*++
  3764. Routine Description:
  3765. ResourceControl routine for Network Name resources.
  3766. Perform the control request specified by ControlCode on the specified
  3767. resource.
  3768. Arguments:
  3769. ResourceId - Supplies the resource id for the specific resource.
  3770. ControlCode - Supplies the control code that defines the action
  3771. to be performed.
  3772. InBuffer - Supplies a pointer to a buffer containing input data.
  3773. InBufferSize - Supplies the size, in bytes, of the data pointed
  3774. to by InBuffer.
  3775. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  3776. OutBufferSize - Supplies the size, in bytes, of the available space
  3777. pointed to by OutBuffer.
  3778. BytesReturned - Returns the number of bytes of OutBuffer actually
  3779. filled in by the resource. If OutBuffer is too small, BytesReturned
  3780. contains the total number of bytes for the operation to succeed.
  3781. Return Value:
  3782. ERROR_SUCCESS - The function completed successfully.
  3783. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  3784. In some cases, this allows the cluster software to perform the work.
  3785. Win32 error code - The function failed.
  3786. --*/
  3787. {
  3788. DWORD status;
  3789. PNETNAME_RESOURCE resourceEntry = (PNETNAME_RESOURCE)Resource;
  3790. DWORD required;
  3791. BOOL readOnly = FALSE;
  3792. BOOL nameHasChanged;
  3793. BOOL compObjNeedsRenaming;
  3794. switch ( ControlCode ) {
  3795. case CLUSCTL_RESOURCE_UNKNOWN:
  3796. *BytesReturned = 0;
  3797. status = ERROR_SUCCESS;
  3798. break;
  3799. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  3800. status = ResUtilGetPropertyFormats( NetNameResourcePrivateProperties,
  3801. OutBuffer,
  3802. OutBufferSize,
  3803. BytesReturned,
  3804. &required );
  3805. if ( status == ERROR_MORE_DATA ) {
  3806. *BytesReturned = required;
  3807. }
  3808. break;
  3809. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  3810. status = NetNameGetRequiredDependencies( OutBuffer,
  3811. OutBufferSize,
  3812. BytesReturned
  3813. );
  3814. break;
  3815. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  3816. status = ResUtilEnumProperties( NetNameResourcePrivateProperties,
  3817. OutBuffer,
  3818. OutBufferSize,
  3819. BytesReturned,
  3820. &required );
  3821. if ( status == ERROR_MORE_DATA ) {
  3822. *BytesReturned = required;
  3823. }
  3824. break;
  3825. case CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES:
  3826. //
  3827. // NOTE: fallthrough is the required behavior here.
  3828. //
  3829. readOnly = TRUE;
  3830. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  3831. status = NetNameGetPrivateResProperties( resourceEntry,
  3832. readOnly,
  3833. OutBuffer,
  3834. OutBufferSize,
  3835. BytesReturned );
  3836. break;
  3837. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  3838. status = NetNameValidatePrivateResProperties( resourceEntry,
  3839. InBuffer,
  3840. InBufferSize,
  3841. NULL,
  3842. &nameHasChanged,
  3843. &compObjNeedsRenaming);
  3844. break;
  3845. case CLUSCTL_RESOURCE_CLUSTER_NAME_CHANGED:
  3846. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  3847. status = NetNameSetPrivateResProperties( resourceEntry,
  3848. InBuffer,
  3849. InBufferSize );
  3850. break;
  3851. case CLUSCTL_RESOURCE_GET_NETWORK_NAME:
  3852. status = NetNameGetNetworkName( resourceEntry,
  3853. OutBuffer,
  3854. OutBufferSize,
  3855. BytesReturned );
  3856. break;
  3857. case CLUSCTL_RESOURCE_DELETE:
  3858. RemoveDnsRecords( resourceEntry );
  3859. //
  3860. // if resource was created but has no properities, then
  3861. // NetworkName can be NULL. Otherwise, try to disable the object
  3862. // and remove any crypto checkpoints that may have been created
  3863. //
  3864. if ( resourceEntry->Params.NetworkName != NULL ) {
  3865. DisableComputerObject( resourceEntry );
  3866. RemoveNNCryptoCheckpoint( resourceEntry );
  3867. }
  3868. status = ERROR_SUCCESS;
  3869. break;
  3870. case CLUSCTL_RESOURCE_REMOVE_DEPENDENCY:
  3871. //
  3872. // argh! resource dependencies can be removed without any veto
  3873. // power by the resource DLL. We could be deleting the last
  3874. // dependent resource which leaves netname with nothing.
  3875. //
  3876. RemoveDependentIpAddress( resourceEntry, InBuffer );
  3877. status = ERROR_SUCCESS;
  3878. break;
  3879. case CLUSCTL_RESOURCE_NETNAME_GET_VIRTUAL_SERVER_TOKEN:
  3880. //
  3881. // dup an impersonation token of the virtual computer account for
  3882. // the caller.
  3883. //
  3884. // caller provides a structure indicating their process ID,
  3885. // desired access and whether the handle should be
  3886. // inheritable. This process must have PROCESS_DUP_HANDLE access
  3887. // to the target process.
  3888. //
  3889. if ( InBufferSize >= sizeof( CLUS_NETNAME_VS_TOKEN_INFO )) {
  3890. if ( OutBufferSize >= sizeof( HANDLE )) {
  3891. PCLUS_NETNAME_VS_TOKEN_INFO tokenInfo = (PCLUS_NETNAME_VS_TOKEN_INFO)InBuffer;
  3892. PHANDLE dupVSToken = (PHANDLE)OutBuffer;
  3893. if ( resourceEntry->State == ClusterResourceOnline ) {
  3894. status = DuplicateVSToken( resourceEntry, tokenInfo, dupVSToken );
  3895. if ( status == ERROR_SUCCESS ) {
  3896. *BytesReturned = sizeof( HANDLE );
  3897. } else {
  3898. *BytesReturned = 0;
  3899. }
  3900. } else {
  3901. return ERROR_INVALID_STATE;
  3902. }
  3903. }
  3904. else {
  3905. status = ERROR_MORE_DATA;
  3906. *BytesReturned = sizeof( HANDLE );
  3907. }
  3908. }
  3909. else {
  3910. status = ERROR_INVALID_PARAMETER;
  3911. }
  3912. break;
  3913. case CLUSCTL_RESOURCE_CLUSTER_VERSION_CHANGED:
  3914. //
  3915. // global flag was set during restype control. If appropriate, set
  3916. // it on existing resources so that during their first online,
  3917. // they do the upgrade check.
  3918. //
  3919. if ( CheckForKerberosUpgrade ) {
  3920. resourceEntry->CheckForKerberosUpgrade = TRUE;
  3921. }
  3922. status = ERROR_SUCCESS;
  3923. break;
  3924. default:
  3925. status = ERROR_INVALID_FUNCTION;
  3926. break;
  3927. }
  3928. return(status);
  3929. } // NetNameResourceControl
  3930. DWORD
  3931. NetNameResourceTypeControl(
  3932. IN LPCWSTR ResourceTypeName,
  3933. IN DWORD ControlCode,
  3934. IN PVOID InBuffer,
  3935. IN DWORD InBufferSize,
  3936. OUT PVOID OutBuffer,
  3937. IN DWORD OutBufferSize,
  3938. OUT LPDWORD BytesReturned
  3939. )
  3940. /*++
  3941. Routine Description:
  3942. ResourceTypeControl routine for Network Name resources.
  3943. Perform the control request specified by ControlCode.
  3944. Arguments:
  3945. ResourceTypeName - Supplies the name of the resource type.
  3946. ControlCode - Supplies the control code that defines the action
  3947. to be performed.
  3948. InBuffer - Supplies a pointer to a buffer containing input data.
  3949. InBufferSize - Supplies the size, in bytes, of the data pointed
  3950. to by InBuffer.
  3951. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  3952. OutBufferSize - Supplies the size, in bytes, of the available space
  3953. pointed to by OutBuffer.
  3954. BytesReturned - Returns the number of bytes of OutBuffer actually
  3955. filled in by the resource. If OutBuffer is too small, BytesReturned
  3956. contains the total number of bytes for the operation to succeed.
  3957. Return Value:
  3958. ERROR_SUCCESS - The function completed successfully.
  3959. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  3960. In some cases, this allows the cluster software to perform the work.
  3961. Win32 error code - The function failed.
  3962. --*/
  3963. {
  3964. DWORD status;
  3965. DWORD required;
  3966. switch ( ControlCode ) {
  3967. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  3968. *BytesReturned = 0;
  3969. status = ERROR_SUCCESS;
  3970. break;
  3971. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  3972. status = ResUtilGetPropertyFormats( NetNameResourcePrivateProperties,
  3973. OutBuffer,
  3974. OutBufferSize,
  3975. BytesReturned,
  3976. &required );
  3977. if ( status == ERROR_MORE_DATA ) {
  3978. *BytesReturned = required;
  3979. }
  3980. break;
  3981. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  3982. status = NetNameGetRequiredDependencies( OutBuffer,
  3983. OutBufferSize,
  3984. BytesReturned
  3985. );
  3986. break;
  3987. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  3988. status = ResUtilEnumProperties( NetNameResourcePrivateProperties,
  3989. OutBuffer,
  3990. OutBufferSize,
  3991. BytesReturned,
  3992. &required );
  3993. if ( status == ERROR_MORE_DATA ) {
  3994. *BytesReturned = required;
  3995. }
  3996. break;
  3997. case CLUSCTL_RESOURCE_TYPE_CLUSTER_VERSION_CHANGED:
  3998. {
  3999. PDOMAIN_CONTROLLER_INFO dcInfo = NULL;
  4000. //
  4001. // if there is no DS based DC, don't add a computer object
  4002. // even if MSMQ dependent resources exist. Here we use
  4003. // DsGetDcName as opposed to DsGetDcNameWithAccount since the
  4004. // former API is documented to be successful even if all the
  4005. // DCs are down. That is the semantics we want here.
  4006. //
  4007. status = DsGetDcName( NULL, // Use local computer
  4008. NULL, // Use primary domain of this node
  4009. NULL, // Domain GUID
  4010. NULL, // Site name
  4011. DS_DIRECTORY_SERVICE_REQUIRED, // Needs W2k or higher DC
  4012. &dcInfo ); // Output DC info
  4013. if ( status == ERROR_SUCCESS ) {
  4014. //
  4015. // if MSMQ is in workgroup mode, then don't bother with
  4016. // individual resource upgrade checks
  4017. //
  4018. CheckForKerberosUpgrade = DoesMsmqNeedComputerObject();
  4019. (NetNameLogEvent)( L"rtNetwork Name",
  4020. LOG_INFORMATION,
  4021. L"Upgrade detected - Network Name resources will %1!ws!be checked "
  4022. L"for dependent MSMQ resources.\n",
  4023. CheckForKerberosUpgrade ? L"" : L"not " );
  4024. NetApiBufferFree ( dcInfo );
  4025. }
  4026. else {
  4027. (NetNameLogEvent)( L"rtNetwork Name",
  4028. LOG_WARNING,
  4029. L"Upgrade detected: Active Directory is not available in this "
  4030. L"domain. No Kerberos support upgrade check will be done. status %1!u!\n",
  4031. status);
  4032. }
  4033. }
  4034. status = ERROR_SUCCESS;
  4035. break;
  4036. default:
  4037. status = ERROR_INVALID_FUNCTION;
  4038. break;
  4039. }
  4040. return(status);
  4041. } // NetNameResourceTypeControl
  4042. DWORD
  4043. NetNameGetPrivateResProperties(
  4044. IN OUT PNETNAME_RESOURCE ResourceEntry,
  4045. IN BOOL ReadOnly,
  4046. OUT PVOID OutBuffer,
  4047. IN DWORD OutBufferSize,
  4048. OUT LPDWORD BytesReturned
  4049. )
  4050. /*++
  4051. Routine Description:
  4052. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  4053. for resources of type Network Name.
  4054. Arguments:
  4055. ResourceEntry - Supplies the resource entry on which to operate.
  4056. ReadOnly - true if we're selecting read only property table
  4057. OutBuffer - Returns the output data.
  4058. OutBufferSize - Supplies the size, in bytes, of the data pointed
  4059. to by OutBuffer.
  4060. BytesReturned - The number of bytes returned in OutBuffer.
  4061. Return Value:
  4062. ERROR_SUCCESS - The function completed successfully.
  4063. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  4064. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  4065. Win32 error code - The function failed.
  4066. --*/
  4067. {
  4068. DWORD status;
  4069. DWORD required;
  4070. //
  4071. // The resutil routines don't support resources with r/w, r/o, and unknown
  4072. // props very well. There is no easy way to get just the unknown
  4073. // properties. For the r/o request, the props are separated out into a
  4074. // separate table. For the r/w case, if we call RUGetAllProperties using
  4075. // the r/w table, we get the r/o props back since they weren't in the
  4076. // table. If we combine the two tables into one, then the r/o case is
  4077. // broken, i.e., it returns the r/w props as well as the r/o ones.
  4078. //
  4079. // The current (yucky) solution is to have 3 tables: r/w, r/o, and
  4080. // combined. Combined is used to get any unknown props that are associated
  4081. // with the resource. It would be nice to have a resutils routine that
  4082. // gathers the unknown props using a list of prop list tables as input.
  4083. //
  4084. if ( ReadOnly ) {
  4085. status = ResUtilGetProperties(ResourceEntry->ParametersKey,
  4086. NetNameResourceROPrivateProperties,
  4087. OutBuffer,
  4088. OutBufferSize,
  4089. BytesReturned,
  4090. &required );
  4091. } else {
  4092. //
  4093. // get the r/w props first; after the call, required will be non-zero
  4094. // if the buffer wasn't large enough. Regardless, we have to continue
  4095. // to get the amount of space for any unknown props
  4096. //
  4097. status = ResUtilGetProperties(ResourceEntry->ParametersKey,
  4098. NetNameResourcePrivateProperties,
  4099. OutBuffer,
  4100. OutBufferSize,
  4101. BytesReturned,
  4102. &required );
  4103. //
  4104. // Add unknown properties to the property list.
  4105. //
  4106. if ( status == ERROR_SUCCESS || status == ERROR_MORE_DATA ) {
  4107. status = ResUtilAddUnknownProperties(ResourceEntry->ParametersKey,
  4108. NetNameResourceCombinedPrivateProperties,
  4109. OutBuffer,
  4110. OutBufferSize,
  4111. BytesReturned,
  4112. &required);
  4113. }
  4114. } // end of if getting r/w props
  4115. //
  4116. // This is kinda wierd: if null is passed in for the input buffer, the
  4117. // return status is success and required reflects how many bytes are
  4118. // needed. If a buffer was specified but it was too small, then more data
  4119. // is returned. It appears that the thing to watch is required indicating
  4120. // that more space is needed regardless of whether a buffer was specified
  4121. // or not.
  4122. //
  4123. if ( required > 0 && ( status == ERROR_SUCCESS || status == ERROR_MORE_DATA )) {
  4124. *BytesReturned = required;
  4125. }
  4126. return(status);
  4127. } // NetNameGetPrivateResProperties
  4128. DWORD
  4129. NetNameValidatePrivateResProperties(
  4130. IN OUT PNETNAME_RESOURCE ResourceEntry,
  4131. IN PVOID InBuffer,
  4132. IN DWORD InBufferSize,
  4133. OUT PNETNAME_PARAMS Params OPTIONAL,
  4134. OUT PBOOL NewNameIsDifferent,
  4135. OUT PBOOL CompObjRenameIsRequired
  4136. )
  4137. /*++
  4138. Routine Description:
  4139. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  4140. function for resources of type Network Name.
  4141. This routine imposes a set of rules on when netname's properties can be
  4142. changed. Currently, this is limited to:
  4143. 1) changing RequireKerberos requires the resource to be offline and
  4144. 2) changing the Name property when RequireKerberos equals one requires the
  4145. resource to be offline
  4146. These restrictions are in place in order to simplify the coding of
  4147. netname. Both of these properties have direct implication for
  4148. communicating with the domain's DS. Consequently, limiting property
  4149. changes to when the resource is offline provides immediate feedback on the
  4150. success or failure of the requested change.
  4151. Changing the Name property when the resource is offline is a little tricky
  4152. due to qualfication issues. Since the name can change and then change back
  4153. to its original value, we have to detect and act on that.
  4154. Arguments:
  4155. ResourceEntry - Supplies the resource entry on which to operate.
  4156. InBuffer - Supplies a pointer to a buffer containing the property list of
  4157. changed property values to validate.
  4158. InBufferSize - Supplies the size, in bytes, of the data pointed
  4159. to by InBuffer.
  4160. Params - Supplies a pointer to an optional parameter block to fill in.
  4161. NewNameIsDifferent - TRUE if the new name is different than the current name
  4162. CompObjRenameIsRequired - TRUE if the new name is different from the stored
  4163. name and a corresponding CO needs to be renamed
  4164. Return Value:
  4165. ERROR_SUCCESS - The function completed successfully.
  4166. ERROR_INVALID_DATA - No input data.
  4167. ERROR_INVALID_NETNAME - The specified network name has invalid characters.
  4168. RPC_S_STRING_TOO_LONG - The specified network name is too long.
  4169. ERROR_BUSY - The specified network name is already in use.
  4170. Win32 error code - The function failed.
  4171. --*/
  4172. {
  4173. DWORD status;
  4174. CLRTL_NAME_STATUS netnameStatus;
  4175. NETNAME_PARAMS currentProps; // as stored in the registry
  4176. NETNAME_PARAMS newProps; // storage for updated props if Params is null
  4177. PNETNAME_PARAMS pParams; // pointer to the block of updated props
  4178. LPWSTR nameOfPropInError;
  4179. //
  4180. // The NewNameIsDifferent flag can (eventually) drive the offline cleanup
  4181. // routine. If the name has truly changed while it was online, then we
  4182. // want to do the appropriate cleanup when it goes offline. The problem is
  4183. // that the name can change many times while it is online; it could return
  4184. // to its current value so the overall appearance is that it never
  4185. // changed. In that case, we want to avoid cleanup.
  4186. //
  4187. *NewNameIsDifferent = FALSE;
  4188. //
  4189. // Check if there is input data.
  4190. //
  4191. if ( (InBuffer == NULL) ||
  4192. (InBufferSize < sizeof(DWORD)) ) {
  4193. return(ERROR_INVALID_DATA);
  4194. }
  4195. //
  4196. // Retrieve the current set of private read/write properties from the
  4197. // cluster database. This may be different from what is stored in
  4198. // ResourceEntry since the name could be online at this point in time.
  4199. //
  4200. ZeroMemory( &currentProps, sizeof(currentProps) );
  4201. status = ResUtilGetPropertiesToParameterBlock(
  4202. ResourceEntry->ParametersKey,
  4203. NetNameResourcePrivateProperties,
  4204. (LPBYTE) &currentProps,
  4205. FALSE, /*CheckForRequiredProperties*/
  4206. &nameOfPropInError
  4207. );
  4208. if ( status != ERROR_SUCCESS ) {
  4209. (NetNameLogEvent)(
  4210. ResourceEntry->ResourceHandle,
  4211. LOG_ERROR,
  4212. L"Unable to read the '%1' property. Error: %2!u!.\n",
  4213. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  4214. status );
  4215. goto FnExit;
  4216. }
  4217. //
  4218. // Duplicate the resource parameter block.
  4219. //
  4220. if ( Params == NULL ) {
  4221. pParams = &newProps;
  4222. } else {
  4223. pParams = Params;
  4224. }
  4225. ZeroMemory( pParams, sizeof(NETNAME_PARAMS) );
  4226. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  4227. (LPBYTE) &currentProps,
  4228. NetNameResourcePrivateProperties );
  4229. if ( status != ERROR_SUCCESS ) {
  4230. return(status);
  4231. }
  4232. //
  4233. // Parse and validate the properties that are changing.
  4234. //
  4235. status = ResUtilVerifyPropertyTable( NetNameResourcePrivateProperties,
  4236. NULL,
  4237. TRUE, // Allow unknowns
  4238. InBuffer,
  4239. InBufferSize,
  4240. (LPBYTE) pParams );
  4241. //
  4242. // now make validation checks
  4243. //
  4244. if ( status == ERROR_SUCCESS ) {
  4245. //
  4246. // can't change RequireKerberos while we're online
  4247. //
  4248. if ( ResourceEntry->State == ClusterResourceOnline
  4249. &&
  4250. ResourceEntry->Params.RequireKerberos != pParams->RequireKerberos
  4251. )
  4252. {
  4253. status = ERROR_INVALID_STATE;
  4254. }
  4255. }
  4256. if ( status == ERROR_SUCCESS ) {
  4257. //
  4258. // if Kerb is on, we have to be offline to change the name
  4259. //
  4260. if ( ResourceEntry->State == ClusterResourceOnline
  4261. &&
  4262. ResourceEntry->Params.RequireKerberos
  4263. &&
  4264. pParams->NetworkName != NULL
  4265. )
  4266. {
  4267. if ( ClRtlStrICmp( pParams->NetworkName, ResourceEntry->Params.NetworkName ) != 0 ) {
  4268. status = ERROR_INVALID_STATE;
  4269. }
  4270. }
  4271. }
  4272. if ( status == ERROR_SUCCESS && pParams->NetworkName != NULL ) {
  4273. BOOL validateName = FALSE;
  4274. LPWSTR currentName;
  4275. //
  4276. // got a request to change the network name property. if this is the
  4277. // core resource, then it is possible our name has already been
  4278. // changed by FM. Look it up in the registry. Otherwise, use the one
  4279. // stored as the Name property.
  4280. //
  4281. if ( ResourceEntry->dwFlags & CLUS_FLAG_CORE ) {
  4282. currentName = ResUtilGetSzValue( ResourceEntry->ResKey, PARAM_NAME__CORECURRENTNAME );
  4283. if ( currentName == NULL ) {
  4284. //
  4285. // this is bad; we've lost track of the old name for the core
  4286. // resource so we can't rename it
  4287. //
  4288. status = GetLastError();
  4289. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4290. LOG_ERROR,
  4291. L"Unable to find core resource's current name. status %1!u!\n",
  4292. status );
  4293. }
  4294. } else {
  4295. currentName = currentProps.NetworkName;
  4296. }
  4297. if ( currentName != NULL ) {
  4298. //
  4299. // a name has been specified. validate the new name if:
  4300. // the name has never been set (ResourceEntry and currentProps value is null)
  4301. // OR
  4302. // resource hasn't been online yet (RE is null) but the new name is different
  4303. // from the stored name (currentProps)
  4304. // OR
  4305. // ( the new name is different from the future name (currentProps).
  4306. // AND
  4307. // the new name is different from the name currently online (ResourceEntry)
  4308. // )
  4309. //
  4310. // ClRtlIsNetNameValid will fail if the name hasn't changed and
  4311. // the name is online.
  4312. //
  4313. // currentProps value is NULL only when the name is created and
  4314. // hasn't had its Name property set, i.e., no data in the
  4315. // registry. Once brought online, the currentProps value is always
  4316. // non-NULL hence no need to test if the pointer is valid.
  4317. //
  4318. if ( ResourceEntry->Params.NetworkName == NULL ) {
  4319. if ( currentName == NULL ) {
  4320. validateName = TRUE;
  4321. } else if ( ClRtlStrICmp( pParams->NetworkName, currentName ) != 0 ) {
  4322. validateName = TRUE;
  4323. }
  4324. }
  4325. else if ( ClRtlStrICmp( pParams->NetworkName, currentName ) != 0
  4326. &&
  4327. ClRtlStrICmp( pParams->NetworkName, ResourceEntry->Params.NetworkName ) != 0
  4328. )
  4329. {
  4330. validateName = TRUE;
  4331. }
  4332. if ( validateName ) {
  4333. *NewNameIsDifferent = TRUE;
  4334. //
  4335. // Validate the syntax of the new name
  4336. //
  4337. if ( !ClRtlIsNetNameValid( pParams->NetworkName, &netnameStatus, TRUE /* CheckIfExists */ ) ) {
  4338. switch ( netnameStatus ) {
  4339. case NetNameTooLong:
  4340. status = RPC_S_STRING_TOO_LONG;
  4341. break;
  4342. case NetNameInUse:
  4343. status = ERROR_DUP_NAME;
  4344. break;
  4345. case NetNameDNSNonRFCChars:
  4346. //
  4347. // we leave it up to the calling application to do the
  4348. // validation and ask the user if non-RFC chars
  4349. // (underscores) are acceptable.
  4350. //
  4351. status = ERROR_SUCCESS;
  4352. break;
  4353. case NetNameInvalidChars:
  4354. default:
  4355. status = ERROR_INVALID_NETNAME;
  4356. break;
  4357. }
  4358. }
  4359. } // end if validateName
  4360. if ( status == ERROR_SUCCESS // everything is ok so far
  4361. &&
  4362. ResourceEntry->Params.CreatingDC != NULL // we have a CO
  4363. &&
  4364. pParams->RequireKerberos != 0 // and we're not disabling kerb
  4365. )
  4366. {
  4367. //
  4368. // check if the new name is different from the stored name. If
  4369. // so, inform the caller that the CO needs to be renamed.
  4370. //
  4371. *CompObjRenameIsRequired = ClRtlStrICmp( pParams->NetworkName, currentName );
  4372. }
  4373. #if 0
  4374. //
  4375. // ISSUE: not sure how to handle this. Under some circumstances,
  4376. // we want the resource to hijack the object but under others we
  4377. // don't. Most of the problem stems from having two resources with
  4378. // the same Name property and they are both offline. One
  4379. // possibility is to run the list of resources on this cluster and
  4380. // see if there are any dups but that isn't always effective since
  4381. // the NetworkName field in ResourceEntry->Params might be
  4382. // NULL. This still wouldn't work for a cluster in the same domain
  4383. // using the same name and it was offline.
  4384. //
  4385. // for now, we'll avoid this check to avoid causing a situation
  4386. // where it is valid to set the Name property but it would be
  4387. // disallowed by this check.
  4388. //
  4389. if ( status == ERROR_SUCCESS // everything is ok so far
  4390. &&
  4391. pParams->RequireKerberos // RK is set to one
  4392. &&
  4393. *NewNameIsDifferent // and we're changing the name
  4394. )
  4395. {
  4396. BOOL objectExists;
  4397. HRESULT hr;
  4398. //
  4399. // check if the new name has a corresponding computer object
  4400. // and fail it it does. We allow hijacking of a CO only if
  4401. // RequireKerberos was zero and is now one or if the resource
  4402. // has never created a CO.
  4403. //
  4404. hr = IsComputerObjectInDS(ResourceEntry->ResourceHandle,
  4405. ResourceEntry->NodeName,
  4406. pParams->NetworkName,
  4407. NULL,
  4408. &objectExists,
  4409. NULL, // don't need FQDN
  4410. NULL); // don't need HostingDCName
  4411. if ( SUCCEEDED( hr ) && objectExists ) {
  4412. status = E_ADS_OBJECT_EXISTS;
  4413. }
  4414. else {
  4415. //
  4416. // check if the new name is different from the stored
  4417. // name. If so, inform the caller that the CO needs to be
  4418. // renamed. This handles the case where the name was
  4419. // changed and then changed back to what it originally
  4420. // was. The first rename caused a CO rename so we have to
  4421. // undo that operation.
  4422. //
  4423. if ( currentProps.NetworkName != NULL ) {
  4424. *CompObjRenameIsRequired = ClRtlStrICmp( pParams->NetworkName, currentProps.NetworkName );
  4425. }
  4426. } // end of there is no existing object
  4427. } // end of if successful so far and RK is set to one and new name is different
  4428. #endif // 0
  4429. if ( currentName != currentProps.NetworkName ) {
  4430. LocalFree( currentName );
  4431. }
  4432. } // end of if currentName != NULL
  4433. } // end of if successful so far and new name is specified
  4434. FnExit:
  4435. //
  4436. // Cleanup our parameter block.
  4437. //
  4438. if (( status != ERROR_SUCCESS && pParams != NULL )
  4439. ||
  4440. pParams == &newProps
  4441. )
  4442. {
  4443. ResUtilFreeParameterBlock( (LPBYTE) pParams,
  4444. (LPBYTE) &currentProps,
  4445. NetNameResourcePrivateProperties );
  4446. }
  4447. ResUtilFreeParameterBlock(
  4448. (LPBYTE) &currentProps,
  4449. NULL,
  4450. NetNameResourcePrivateProperties
  4451. );
  4452. return(status);
  4453. } // NetNameValidatePrivateResProperties
  4454. DWORD
  4455. NetNameSetPrivateResProperties(
  4456. IN OUT PNETNAME_RESOURCE ResourceEntry,
  4457. IN PVOID InBuffer,
  4458. IN DWORD InBufferSize
  4459. )
  4460. /*++
  4461. Routine Description:
  4462. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  4463. for resources of type Network Name.
  4464. Arguments:
  4465. ResourceEntry - Supplies the resource entry on which to operate.
  4466. InBuffer - Supplies a pointer to a buffer containing the property list of
  4467. changed property values to set.
  4468. InBufferSize - Supplies the size, in bytes, of the data pointed
  4469. to by InBuffer.
  4470. Return Value:
  4471. ERROR_SUCCESS - The function completed successfully.
  4472. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  4473. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  4474. Win32 error code - The function failed.
  4475. --*/
  4476. {
  4477. DWORD status = ERROR_SUCCESS;
  4478. BOOL newNameIsDifferent = FALSE;
  4479. BOOL disablingKerberos;
  4480. BOOL compObjNeedsRenaming = FALSE;
  4481. LPWSTR creatingDC = NULL;
  4482. BOOL coreName = ResourceEntry->dwFlags & CLUS_FLAG_CORE;
  4483. NETNAME_PARAMS params;
  4484. ZeroMemory( &params, sizeof(NETNAME_PARAMS) );
  4485. //
  4486. // Parse the properties so they can be validated together.
  4487. // This routine does individual property validation.
  4488. //
  4489. status = NetNameValidatePrivateResProperties( ResourceEntry,
  4490. InBuffer,
  4491. InBufferSize,
  4492. &params,
  4493. &newNameIsDifferent,
  4494. &compObjNeedsRenaming);
  4495. if ( status != ERROR_SUCCESS ) {
  4496. return(status);
  4497. }
  4498. //
  4499. // If network name is one of the parameters to be set, convert the name
  4500. // to uppercase.
  4501. //
  4502. if ( params.NetworkName != NULL ) {
  4503. _wcsupr( params.NetworkName );
  4504. }
  4505. //
  4506. // if kerb is currently required and we're turning it off, then note that
  4507. // now.
  4508. //
  4509. disablingKerberos = ( ResourceEntry->Params.RequireKerberos && !params.RequireKerberos );
  4510. if ( ResourceEntry->State == ClusterResourceOnline ||
  4511. ResourceEntry->State == ClusterResourceOnlinePending )
  4512. {
  4513. //
  4514. // If the resource is online, remember that the name property has
  4515. // truly changed (it can change and then be set back to its original
  4516. // value while online). When the resource goes offline, this flag is
  4517. // used to cleanup stuff with the old name.
  4518. //
  4519. ResourceEntry->NameChangedWhileOnline = newNameIsDifferent;
  4520. status = ERROR_RESOURCE_PROPERTIES_STORED;
  4521. }
  4522. else {
  4523. //
  4524. // read the CreatingDC parameter. If it is NULL, then that indicates
  4525. // that no CO has been created for this name.
  4526. //
  4527. creatingDC = ResUtilGetSzValue( ResourceEntry->ParametersKey, PARAM_NAME__CREATING_DC );
  4528. if ( creatingDC == NULL ) {
  4529. status = GetLastError();
  4530. if ( status != ERROR_FILE_NOT_FOUND ) {
  4531. goto cleanup;
  4532. }
  4533. status = ERROR_SUCCESS;
  4534. }
  4535. if ( newNameIsDifferent ) {
  4536. //
  4537. // name change; try to cleanup the old name's DNS records
  4538. //
  4539. RemoveDnsRecords( ResourceEntry );
  4540. }
  4541. //
  4542. // do renaming first before disabling the CO: you can't rename a
  4543. // disabled CO via NetUserSetInfo
  4544. //
  4545. if ( compObjNeedsRenaming && creatingDC ) {
  4546. LPWSTR currentName;
  4547. if ( coreName ) {
  4548. currentName = ResUtilGetSzValue( ResourceEntry->ResKey, PARAM_NAME__CORECURRENTNAME );
  4549. if ( currentName == NULL ) {
  4550. //
  4551. // this is bad; we've lost track of the old name for the
  4552. // core resource so we can't rename it
  4553. //
  4554. status = GetLastError();
  4555. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4556. LOG_ERROR,
  4557. L"Unable to find core resource's current name. status %1!u!\n",
  4558. status );
  4559. }
  4560. }
  4561. else {
  4562. //
  4563. // get the name parameter out of the registry since it
  4564. // represents the current setting, i.e., if the name is
  4565. // changed multiple times while the resource is offline, the
  4566. // registry holds the last value.
  4567. //
  4568. currentName = ResUtilGetSzValue( ResourceEntry->ParametersKey, PARAM_NAME__NAME );
  4569. if (currentName == NULL) {
  4570. status = GetLastError();
  4571. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4572. LOG_ERROR,
  4573. L"Unable to read NetworkName parameter to rename computer "
  4574. L"account, status %1!u!\n",
  4575. status);
  4576. }
  4577. }
  4578. if ( currentName != NULL ) {
  4579. status = RenameComputerObject( ResourceEntry, currentName, params.NetworkName );
  4580. LocalFree( currentName );
  4581. }
  4582. }
  4583. if ( status == ERROR_SUCCESS && disablingKerberos ) {
  4584. if ( creatingDC ) {
  4585. status = DisableComputerObject( ResourceEntry );
  4586. if ( status == NERR_UserNotFound ) {
  4587. //
  4588. // it's not an error if the CO is already gone
  4589. //
  4590. status = ERROR_SUCCESS;
  4591. }
  4592. else if ( status != NERR_Success ) {
  4593. //
  4594. // failed for some reason (probably access denied).
  4595. //
  4596. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4597. LOG_WARNING,
  4598. L"Unable to disable computer account for %1!ws!. Kerberos authentication "
  4599. L"to this name will fail. Set RequireKerberos back to one or, if "
  4600. L"appropriate, delete the CO from Active Directory. status %2!u!\n",
  4601. ResourceEntry->Params.NetworkName,
  4602. status );
  4603. }
  4604. } // end of if creatingDC != NULL
  4605. //
  4606. // clean up the resource's param block; delete the creating DC
  4607. // property so we don't think that we still have a CO. Do the
  4608. // cluster registry stuff first to make sure the resource will
  4609. // work the next time it goes online.
  4610. //
  4611. status = ClusterRegDeleteValue(ResourceEntry->ParametersKey,
  4612. PARAM_NAME__CREATING_DC);
  4613. if ( status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND ) {
  4614. status = ClusterRegDeleteValue(ResourceEntry->ParametersKey,
  4615. PARAM_NAME__RESOURCE_DATA);
  4616. if ( status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND ) {
  4617. ResourceEntry->Params.RequireKerberos = 0;
  4618. if ( ResourceEntry->Params.CreatingDC != NULL ) {
  4619. LocalFree( ResourceEntry->Params.CreatingDC );
  4620. ResourceEntry->Params.CreatingDC = NULL;
  4621. }
  4622. if ( ResourceEntry->Params.ResourceData != NULL ) {
  4623. LocalFree( ResourceEntry->Params.ResourceData );
  4624. ResourceEntry->Params.ResourceData = NULL;
  4625. }
  4626. RemoveNNCryptoCheckpoint( ResourceEntry );
  4627. } else {
  4628. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4629. LOG_ERROR,
  4630. L"Unable to clear the "
  4631. PARAM_NAME__RESOURCE_DATA
  4632. L" property for %1!ws!. status %2!u!\n",
  4633. ResourceEntry->Params.NetworkName,
  4634. status );
  4635. }
  4636. } else {
  4637. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4638. LOG_ERROR,
  4639. L"Unable to clear the "
  4640. PARAM_NAME__CREATING_DC
  4641. L" property for %1!ws!. status %2!u!\n",
  4642. ResourceEntry->Params.NetworkName,
  4643. status );
  4644. }
  4645. //
  4646. // all this can fail due to lack of access rights; don't make it a
  4647. // fatal error for the routine
  4648. //
  4649. status = ERROR_SUCCESS;
  4650. } // end of if disabling Kerberos
  4651. if ( creatingDC ) {
  4652. //
  4653. // free but don't clear the pointer; it is used as a flag later on
  4654. // to indicate that we did a rename on a CO
  4655. //
  4656. LocalFree( creatingDC );
  4657. }
  4658. } // end if resource state is not online or online pending
  4659. if ( coreName && ( status == ERROR_SUCCESS || status == ERROR_RESOURCE_PROPERTIES_STORED )) {
  4660. DWORD regStatus;
  4661. //
  4662. // Remember the name of the core resource in a different area to deal with
  4663. // FM changing the Name property as a result of calling SetClusterName.
  4664. //
  4665. regStatus = ClusterRegSetValue(ResourceEntry->ResKey,
  4666. PARAM_NAME__CORECURRENTNAME,
  4667. REG_SZ,
  4668. (LPBYTE)params.NetworkName,
  4669. ( wcslen(params.NetworkName) + 1 ) * sizeof(WCHAR) );
  4670. if ( regStatus != ERROR_SUCCESS ) {
  4671. status = regStatus;
  4672. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4673. LOG_ERROR,
  4674. L"Failed to write "
  4675. PARAM_NAME__CORECURRENTNAME,
  4676. L" to registry, status %1!u!\n",
  4677. status
  4678. );
  4679. }
  4680. }
  4681. if ( status == ERROR_SUCCESS || status == ERROR_RESOURCE_PROPERTIES_STORED ) {
  4682. DWORD resUtilStatus;
  4683. //
  4684. // Save the parameter values.
  4685. //
  4686. resUtilStatus = ResUtilSetPropertyParameterBlock(ResourceEntry->ParametersKey,
  4687. NetNameResourcePrivateProperties,
  4688. NULL,
  4689. (LPBYTE) &params,
  4690. InBuffer,
  4691. InBufferSize,
  4692. NULL );
  4693. if ( resUtilStatus == ERROR_SUCCESS && newNameIsDifferent ) {
  4694. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4695. LOG_INFORMATION,
  4696. L"Name property changed from %1!ws! to %2!ws!\n",
  4697. ResourceEntry->Params.NetworkName,
  4698. params.NetworkName);
  4699. ClusResLogSystemEventByKey2( ResourceEntry->ResKey,
  4700. LOG_NOISE,
  4701. RES_NETNAME_RENAME,
  4702. ResourceEntry->Params.NetworkName,
  4703. params.NetworkName);
  4704. } else {
  4705. status = resUtilStatus;
  4706. }
  4707. }
  4708. if ( compObjNeedsRenaming && creatingDC ) {
  4709. DWORD deleteStatus;
  4710. //
  4711. // ok to whack RenameNewName from the registry
  4712. //
  4713. deleteStatus = ClusterRegDeleteValue( ResourceEntry->ResKey, PARAM_NAME__RENAMENEWNAME );
  4714. if ( deleteStatus != ERROR_SUCCESS && deleteStatus != ERROR_FILE_NOT_FOUND ) {
  4715. (NetNameLogEvent)(ResourceEntry->ResourceHandle,
  4716. LOG_WARNING,
  4717. L"Failed to delete "
  4718. PARAM_NAME__RENAMENEWNAME
  4719. L" from registry - status %1!u!\n",
  4720. deleteStatus);
  4721. }
  4722. }
  4723. cleanup:
  4724. ResUtilFreeParameterBlock( (LPBYTE) &params,
  4725. (LPBYTE) &ResourceEntry->Params,
  4726. NetNameResourcePrivateProperties );
  4727. return status;
  4728. } // NetNameSetPrivateResProperties
  4729. //***********************************************************
  4730. //
  4731. // Define Function Table
  4732. //
  4733. //***********************************************************
  4734. CLRES_V1_FUNCTION_TABLE( NetNameFunctionTable, // Name
  4735. CLRES_VERSION_V1_00, // Version
  4736. NetName, // Prefix
  4737. NULL, // Arbitrate
  4738. NULL, // Release
  4739. NetNameResourceControl, // ResControl
  4740. NetNameResourceTypeControl ); // ResTypeControl