Source code of Windows XP (NT5)
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.

5184 lines
160 KiB

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