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.

1992 lines
64 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name:
  4. nameutil.c
  5. Abstract:
  6. Routines for manipulating LM workstation and server names.
  7. Author:
  8. Mike Massa (mikemas) 29-Dec-1995
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusres.h"
  13. #include "clusrtl.h"
  14. #include <tdi.h>
  15. #include <lm.h>
  16. #include <stdlib.h>
  17. #include "netname.h"
  18. #include "nameutil.h"
  19. #include <dnsapi.h>
  20. #include <dnslib.h>
  21. //
  22. // Constants
  23. //
  24. #define LOG_CURRENT_MODULE LOG_MODULE_NETNAME
  25. //
  26. // forward declarations
  27. //
  28. VOID
  29. LogDnsFailureToEventLog(
  30. IN HKEY ResourceKey,
  31. IN LPWSTR DnsName,
  32. IN LPWSTR ResourceName,
  33. IN DWORD Status,
  34. IN LPWSTR ConnectoidName
  35. );
  36. //
  37. // Local Utility Routines
  38. //
  39. NET_API_STATUS
  40. CheckForServerName(
  41. IN RESOURCE_HANDLE ResourceHandle,
  42. IN LPWSTR ServerName,
  43. IN POEM_STRING OemServerNameString,
  44. OUT PBOOLEAN IsNameRegistered
  45. )
  46. {
  47. PSERVER_TRANSPORT_INFO_0 psti0 = NULL;
  48. DWORD entriesRead = 0;
  49. DWORD totalEntries = 0;
  50. DWORD resumeHandle = 0;
  51. NET_API_STATUS status;
  52. DWORD i;
  53. *IsNameRegistered = FALSE;
  54. status = NetServerTransportEnum(
  55. NULL,
  56. 0,
  57. (LPBYTE *) &psti0,
  58. (DWORD) -1,
  59. &entriesRead,
  60. &totalEntries,
  61. &resumeHandle
  62. );
  63. if (status != NERR_Success) {
  64. (NetNameLogEvent)(
  65. ResourceHandle,
  66. LOG_WARNING,
  67. L"Unable to enumerate server tranports, error %1!u!.\n",
  68. status
  69. );
  70. return(status);
  71. }
  72. for ( i=0; i < entriesRead; i++ ) {
  73. if ( ( psti0[i].svti0_transportaddresslength ==
  74. OemServerNameString->Length
  75. )
  76. &&
  77. ( RtlCompareMemory(
  78. psti0[i].svti0_transportaddress,
  79. OemServerNameString->Buffer,
  80. OemServerNameString->Length
  81. ) == OemServerNameString->Length
  82. )
  83. )
  84. {
  85. *IsNameRegistered = TRUE;
  86. break;
  87. }
  88. }
  89. if (psti0 != NULL) {
  90. LocalFree(psti0);
  91. }
  92. return(status);
  93. } // CheckForServerName
  94. NET_API_STATUS
  95. pDeleteServerName(
  96. IN RESOURCE_HANDLE ResourceHandle,
  97. IN LPWSTR ServerName,
  98. IN POEM_STRING OemServerNameString
  99. )
  100. {
  101. NET_API_STATUS status;
  102. BOOLEAN isNameRegistered;
  103. DWORD count;
  104. //
  105. // Delete the name
  106. //
  107. status = NetServerComputerNameDel(NULL, ServerName);
  108. if (status != NERR_Success) {
  109. if (status != ERROR_BAD_NET_NAME) {
  110. (NetNameLogEvent)(
  111. ResourceHandle,
  112. LOG_WARNING,
  113. L"Failed to delete server name %1!ws!, status %2!u!.\n",
  114. ServerName,
  115. status
  116. );
  117. }
  118. return(status);
  119. }
  120. //
  121. // Check to make sure the name was really deleted. We'll wait up
  122. // to 2 seconds.
  123. //
  124. for (count = 0; count < 8; count++) {
  125. status = CheckForServerName(
  126. ResourceHandle,
  127. ServerName,
  128. OemServerNameString,
  129. &isNameRegistered
  130. );
  131. if (status != NERR_Success) {
  132. (NetNameLogEvent)(
  133. ResourceHandle,
  134. LOG_WARNING,
  135. L"Unable to verify that server name %1!ws! was deleted, status %2!u!.\n",
  136. ServerName,
  137. status
  138. );
  139. return(NERR_Success);
  140. }
  141. if (isNameRegistered == FALSE) {
  142. (NetNameLogEvent)(
  143. ResourceHandle,
  144. LOG_INFORMATION,
  145. L"Deleted server name %1!ws! from all transports.\n",
  146. ServerName
  147. );
  148. return(NERR_Success);
  149. }
  150. Sleep(250);
  151. }
  152. (NetNameLogEvent)(
  153. ResourceHandle,
  154. LOG_WARNING,
  155. L"Delete of server name %1!ws! succeeded, but name still has not gone away. "
  156. L"Giving up.\n",
  157. ServerName
  158. );
  159. return(ERROR_IO_PENDING);
  160. } // pDeleteServerName
  161. NET_API_STATUS
  162. AddServerName(
  163. IN RESOURCE_HANDLE ResourceHandle,
  164. IN LPWSTR ServerName,
  165. IN BOOL RemapPipeNames,
  166. IN LPWSTR TransportName,
  167. IN BOOLEAN CheckNameFirst,
  168. IN PWCHAR MachinePwd
  169. )
  170. {
  171. SERVER_TRANSPORT_INFO_2 sti2;
  172. SERVER_TRANSPORT_INFO_3 sti3;
  173. UCHAR netBiosName[ NETBIOS_NAME_LEN ];
  174. OEM_STRING netBiosNameString;
  175. UNICODE_STRING unicodeName;
  176. NET_API_STATUS status;
  177. NTSTATUS ntStatus;
  178. //
  179. // Convert the ServerName to an OEM string
  180. //
  181. RtlInitUnicodeString( &unicodeName, ServerName );
  182. netBiosNameString.Buffer = (PCHAR)netBiosName;
  183. netBiosNameString.MaximumLength = sizeof( netBiosName );
  184. ntStatus = RtlUpcaseUnicodeStringToOemString(
  185. &netBiosNameString,
  186. &unicodeName,
  187. FALSE
  188. );
  189. if (ntStatus != STATUS_SUCCESS) {
  190. status = RtlNtStatusToDosError(ntStatus);
  191. (NetNameLogEvent)(
  192. ResourceHandle,
  193. LOG_ERROR,
  194. L"Unable to convert name %1!ws! to an OEM string, status %2!u!\n",
  195. ServerName,
  196. status
  197. );
  198. return(status);
  199. }
  200. if (CheckNameFirst) {
  201. BOOLEAN isNameRegistered;
  202. //
  203. // Check to see if the name is already registered.
  204. //
  205. status = CheckForServerName(
  206. ResourceHandle,
  207. ServerName,
  208. &netBiosNameString,
  209. &isNameRegistered
  210. );
  211. if (status != NERR_Success) {
  212. (NetNameLogEvent)(
  213. ResourceHandle,
  214. LOG_WARNING,
  215. L"Unable to verify that server name %1!ws! does not already exist.\n",
  216. ServerName
  217. );
  218. isNameRegistered = TRUE; // just to be safe
  219. }
  220. if (isNameRegistered) {
  221. (NetNameLogEvent)(
  222. ResourceHandle,
  223. LOG_INFORMATION,
  224. L"Deleting old registration for server name %1!ws!.\n",
  225. ServerName
  226. );
  227. status = pDeleteServerName(
  228. ResourceHandle,
  229. ServerName,
  230. &netBiosNameString
  231. );
  232. if (status != NERR_Success) {
  233. if (status == ERROR_IO_PENDING) {
  234. status = ERROR_GEN_FAILURE;
  235. }
  236. return(status);
  237. }
  238. }
  239. }
  240. //
  241. // Register the name on the specified transport. If we have a password,
  242. // then kerb was enabled. If no password, bring the name online without
  243. // any credentials. This will cause RDR to fall back to NTLM for
  244. // authentication.
  245. //
  246. if ( MachinePwd != NULL ) {
  247. RtlZeroMemory( &sti3, sizeof(sti3) );
  248. sti3.svti3_transportname = TransportName;
  249. sti3.svti3_transportaddress = netBiosName;
  250. sti3.svti3_transportaddresslength = strlen(netBiosName);
  251. if (RemapPipeNames) {
  252. sti3.svti3_flags = SVTI2_REMAP_PIPE_NAMES;
  253. }
  254. wcscpy( (PWCHAR)sti3.svti3_password, MachinePwd );
  255. sti3.svti3_passwordlength = wcslen( MachinePwd ) * sizeof(WCHAR);
  256. status = NetServerTransportAddEx( NULL, 3, (LPBYTE)&sti3 );
  257. }
  258. else {
  259. RtlZeroMemory( &sti2, sizeof(sti2) );
  260. sti2.svti2_transportname = TransportName;
  261. sti2.svti2_transportaddress = netBiosName;
  262. sti2.svti2_transportaddresslength = strlen(netBiosName);
  263. if (RemapPipeNames) {
  264. sti2.svti2_flags = SVTI2_REMAP_PIPE_NAMES;
  265. }
  266. status = NetServerTransportAddEx( NULL, 2, (LPBYTE)&sti2 );
  267. }
  268. if (status != NERR_Success) {
  269. (NetNameLogEvent)(
  270. ResourceHandle,
  271. LOG_ERROR,
  272. L"Unable to add server name %1!ws! to transport %2!ws!, status %3!u!.\n",
  273. ServerName,
  274. TransportName,
  275. status
  276. );
  277. }
  278. else {
  279. (NetNameLogEvent)(
  280. ResourceHandle,
  281. LOG_INFORMATION,
  282. L"Registered server name %1!ws! on transport %2!ws!.\n",
  283. ServerName,
  284. TransportName
  285. );
  286. }
  287. return(status);
  288. } // AddServerName
  289. NET_API_STATUS
  290. DeleteServerName(
  291. IN RESOURCE_HANDLE ResourceHandle,
  292. IN LPWSTR ServerName
  293. )
  294. {
  295. NET_API_STATUS status;
  296. NTSTATUS ntStatus;
  297. UCHAR netBiosName[ NETBIOS_NAME_LEN ];
  298. OEM_STRING netBiosNameString;
  299. UNICODE_STRING unicodeName;
  300. BOOLEAN isNameRegistered;
  301. DWORD count;
  302. //
  303. // Convert the ServerName to an OEM string
  304. //
  305. RtlInitUnicodeString( &unicodeName, ServerName );
  306. netBiosNameString.Buffer = (PCHAR)netBiosName;
  307. netBiosNameString.MaximumLength = sizeof( netBiosName );
  308. ntStatus = RtlUpcaseUnicodeStringToOemString(
  309. &netBiosNameString,
  310. &unicodeName,
  311. FALSE
  312. );
  313. if (ntStatus != STATUS_SUCCESS) {
  314. status = RtlNtStatusToDosError(ntStatus);
  315. (NetNameLogEvent)(
  316. ResourceHandle,
  317. LOG_ERROR,
  318. L"Unable to convert name %1!ws! to an OEM string, status %2!u!\n",
  319. ServerName,
  320. status
  321. );
  322. return(status);
  323. }
  324. //
  325. // Delete the name
  326. //
  327. status = pDeleteServerName(
  328. ResourceHandle,
  329. ServerName,
  330. &netBiosNameString
  331. );
  332. if (status == ERROR_IO_PENDING) {
  333. status = NERR_Success;
  334. }
  335. return(status);
  336. } // DeleteServerName
  337. DWORD
  338. AddWorkstationName(
  339. IN LPWSTR WorkstationName,
  340. IN LPWSTR TransportName,
  341. IN RESOURCE_HANDLE ResourceHandle,
  342. OUT HANDLE * WorkstationNameHandle
  343. )
  344. /*++
  345. Routine Description:
  346. This function adds an alternate workstation ( <0> ) name on a netbios
  347. transport by opening a TDI address object. The name remains registered
  348. as long as the address object is open.
  349. Arguments:
  350. WorkstationName - Alternate computer name to add.
  351. TransportName - Transport to add the computer name on.
  352. Return Value:
  353. Status - The status of the operation.
  354. --*/
  355. {
  356. DWORD status;
  357. PFILE_FULL_EA_INFORMATION eaBuffer;
  358. DWORD eaLength;
  359. OBJECT_ATTRIBUTES objectAttributes;
  360. IO_STATUS_BLOCK ioStatusBlock;
  361. UNICODE_STRING transportString;
  362. DWORD i;
  363. PTA_NETBIOS_ADDRESS taAddress;
  364. UNICODE_STRING unicodeName;
  365. OEM_STRING oemName;
  366. PUCHAR nameBuffer;
  367. *WorkstationNameHandle = NULL;
  368. //
  369. // Allocate an extended attribute to hold the TDI address
  370. //
  371. eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  372. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  373. sizeof(TA_NETBIOS_ADDRESS);
  374. eaBuffer = LocalAlloc(LMEM_FIXED, eaLength);
  375. if (eaBuffer == NULL) {
  376. (NetNameLogEvent)(
  377. ResourceHandle,
  378. LOG_ERROR,
  379. L"Unable to allocate memory for name registration.\n"
  380. );
  381. return(ERROR_NOT_ENOUGH_MEMORY);
  382. }
  383. eaBuffer->NextEntryOffset = 0;
  384. eaBuffer->Flags = 0;
  385. eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  386. eaBuffer->EaValueLength = sizeof(TA_NETBIOS_ADDRESS);
  387. CopyMemory(
  388. eaBuffer->EaName,
  389. TdiTransportAddress,
  390. eaBuffer->EaNameLength+1
  391. );
  392. //
  393. // Build the TDI NetBIOS Address structure
  394. //
  395. taAddress = (PTA_NETBIOS_ADDRESS) (eaBuffer->EaName +
  396. TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  397. taAddress->TAAddressCount = 1;
  398. taAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  399. taAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  400. taAddress->Address[0].Address[0].NetbiosNameType =
  401. TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  402. //
  403. // Canonicalize the name by converting to an upper case OEM string,
  404. // padding with spaces, and ending with a 0x0.
  405. //
  406. nameBuffer = &(taAddress->Address[0].Address[0].NetbiosName[0]);
  407. oemName.Buffer = nameBuffer;
  408. oemName.Length = 0;
  409. oemName.MaximumLength = NETBIOS_NAME_LEN;
  410. RtlInitUnicodeString(&unicodeName, WorkstationName);
  411. status = RtlUpcaseUnicodeStringToOemString(
  412. &oemName,
  413. &unicodeName,
  414. FALSE
  415. );
  416. if (status != STATUS_SUCCESS) {
  417. (NetNameLogEvent)(
  418. ResourceHandle,
  419. LOG_ERROR,
  420. L"Unable to convert name %1!ws! to an OEM string, status %2!u!\n",
  421. WorkstationName,
  422. status
  423. );
  424. LocalFree(eaBuffer);
  425. return(RtlNtStatusToDosError(status));
  426. }
  427. for (i=oemName.Length; i < (NETBIOS_NAME_LEN - 1); i++) {
  428. nameBuffer[i] = 0x20;
  429. }
  430. nameBuffer[NETBIOS_NAME_LEN-1] = 0;
  431. //
  432. // Open an address object handle.
  433. //
  434. RtlInitUnicodeString(&transportString, TransportName);
  435. InitializeObjectAttributes(
  436. &objectAttributes,
  437. &transportString,
  438. OBJ_CASE_INSENSITIVE,
  439. (HANDLE) NULL,
  440. (PSECURITY_DESCRIPTOR) NULL
  441. );
  442. status = NtCreateFile(
  443. WorkstationNameHandle,
  444. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  445. &objectAttributes,
  446. &ioStatusBlock,
  447. NULL,
  448. FILE_ATTRIBUTE_NORMAL,
  449. FILE_SHARE_READ | FILE_SHARE_WRITE,
  450. FILE_OPEN_IF,
  451. 0,
  452. eaBuffer,
  453. eaLength
  454. );
  455. if (status == STATUS_SUCCESS) {
  456. status = ioStatusBlock.Status;
  457. }
  458. LocalFree(eaBuffer);
  459. status = RtlNtStatusToDosError(status);
  460. if (status != ERROR_SUCCESS) {
  461. (NetNameLogEvent)(
  462. ResourceHandle,
  463. LOG_ERROR,
  464. L"Failed to register workstation name %1!ws! on transport %2!ws!, "
  465. L"error %3!u!.\n",
  466. WorkstationName,
  467. TransportName,
  468. status
  469. );
  470. }
  471. else {
  472. (NetNameLogEvent)(
  473. ResourceHandle,
  474. LOG_INFORMATION,
  475. L"Registered workstation name %1!ws! on transport %2!ws!.\n",
  476. WorkstationName,
  477. TransportName
  478. );
  479. }
  480. return(status);
  481. } // AddWorkstationName
  482. DNS_STATUS
  483. AddDnsNames(
  484. IN PCLUS_WORKER Worker,
  485. IN LPWSTR AlternateComputerName,
  486. IN HKEY ResourceKey,
  487. IN RESOURCE_HANDLE ResourceHandle,
  488. IN PDOMAIN_ADDRESS_MAPPING DomainMapList,
  489. IN DWORD DomainMapCount,
  490. IN BOOL FailOnAnyError,
  491. OUT PULONG NumberOfDnsLists,
  492. OUT PDNS_LISTS * DnsLists,
  493. OUT PULONG NumberOfRegisteredNames
  494. )
  495. /*++
  496. Routine Description:
  497. For the given set of IP addresses and their corresponding DNS domains,
  498. build DNS records that will register the network name in the domain(s)
  499. associated with the IP address. Lists of A and PTR records are built which
  500. are used by RegisterDnsRecords to publish the name/address associations at
  501. the DNS server. If the names can't be registered now,
  502. NetNameUpdateDnsServer will attempt to register them. This is the only
  503. shot at building the lists; if this portion fails, then the resource is
  504. failed.
  505. This routine also checks for whether a DNS zone accepts dynamic
  506. updates. DnsUpdateTest will tell us if the zone is dynamic or not, and if
  507. dynamic and integrated with the DS as a secure zone, whether the caller
  508. has sufficient permission to modify the entry.
  509. For non-dynamic zones, Netbios ends up being the only mechanism by which a
  510. name gets registered and therefore, DNS registration failures are not
  511. fatal unless the RequireDNS property is set to true.
  512. If the zone is dynamic but the caller lacks sufficient permission, we view
  513. that as DNS having precedence over Netbios. In that case, the resource is
  514. failed.
  515. Arguments:
  516. Worker - used to check if we should terminate early
  517. AlternateComputerName - NetBIOS network name to be registered
  518. ResourceKey - used to log events to the system event log
  519. ResourceHandle - for logging to the cluster log
  520. DomainMapList - list of IP address domain names pairs for registration
  521. DomainMapCount - # of entries in DomainMapList
  522. NumberOfDnsLists - pointer to location of final count of entries in DnsLists
  523. DnsLists - array of lists that contain A and PTR listheads
  524. NumberOfRegisteredNames - pointer to location of final count of names that
  525. actually got registered
  526. Return Value:
  527. DNS_STATUS indicating whether it worked or not. If the DNS lists couldn't
  528. be built, always return an error.
  529. --*/
  530. {
  531. LPWSTR fqNameARec = NULL;
  532. LPWSTR fqNamePTRRec = NULL;
  533. DWORD fqNameLength;
  534. DWORD listheadFreeEntries = 0;
  535. DWORD listheadCount = 0;
  536. PDNS_LISTS dnsLists = NULL;
  537. DWORD mapIndex;
  538. DWORD index;
  539. DNS_STATUS dnsStatus;
  540. DNS_STATUS ptrRecStatus;
  541. PDNS_RECORD PTRRecord;
  542. PDNS_RECORD ARecord;
  543. LPWSTR PTRName = NULL;
  544. BOOL ARecTimeout;
  545. BOOL PTRRecTimeout;
  546. //
  547. // run through the list of domain map structs and register the names where
  548. // appopriate
  549. //
  550. for ( mapIndex = 0; mapIndex < DomainMapCount; ++mapIndex ) {
  551. if ( ClusWorkerCheckTerminate( Worker )) {
  552. dnsStatus = ERROR_OPERATION_ABORTED;
  553. goto error_exit;
  554. }
  555. ASSERT( DomainMapList[ mapIndex ].DomainName != NULL );
  556. //
  557. // create the fully qualified DNS name and make a copy for the PTR
  558. // records. DnsRecordListFree operates in a way that makes it
  559. // difficult to use the same buffer multiple times. It is easier to
  560. // allocate separate buffers for everything and let DnsRecordListFree
  561. // clean up.
  562. //
  563. fqNameLength = (wcslen( DomainMapList[ mapIndex ].DomainName ) +
  564. wcslen( AlternateComputerName ) +
  565. 2 // one for "." and one for null
  566. )
  567. * sizeof( WCHAR );
  568. fqNameARec = LocalAlloc( LMEM_FIXED, fqNameLength );
  569. fqNamePTRRec = LocalAlloc( LMEM_FIXED, fqNameLength );
  570. if ( fqNameARec == NULL || fqNamePTRRec == NULL ) {
  571. dnsStatus = GetLastError();
  572. (NetNameLogEvent)(ResourceHandle,
  573. LOG_ERROR,
  574. L"Can't allocate memory for DNS name for address %1!ws!, "
  575. L"status %2!u!.\n",
  576. DomainMapList[ mapIndex ].IpAddress,
  577. dnsStatus);
  578. goto error_exit;
  579. }
  580. wcscpy( fqNameARec, AlternateComputerName );
  581. wcscat( fqNameARec, L"." );
  582. wcscat( fqNameARec, DomainMapList[ mapIndex ].DomainName );
  583. _wcslwr( fqNameARec );
  584. wcscpy( fqNamePTRRec, fqNameARec );
  585. //
  586. // see if this domain is updatable.
  587. //
  588. ARecTimeout = FALSE;
  589. dnsStatus = DnsUpdateTest(NULL,
  590. fqNameARec,
  591. 0,
  592. DomainMapList[ mapIndex ].DnsServerList);
  593. #if DBG_DNSLIST
  594. {
  595. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  596. struct in_addr addr;
  597. addr.s_addr = DomainMapList[ mapIndex ].DnsServerList->AddrArray[0];
  598. _snwprintf(buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
  599. L"AddDnsNames UPDATETEST: %ws on %.32ws (%hs) returned %u\n",
  600. fqNameARec,
  601. DomainMapList[ mapIndex ].ConnectoidName,
  602. inet_ntoa( addr ),
  603. dnsStatus);
  604. OutputDebugStringW( buf );
  605. }
  606. #endif
  607. if ( dnsStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  608. //
  609. // zone does not accept dynamic updates.
  610. //
  611. (NetNameLogEvent)(ResourceHandle,
  612. LOG_INFORMATION,
  613. L"%1!ws! does not accept dynamic DNS registration updates over "
  614. L"adapter '%2!ws!'.\n",
  615. DomainMapList[ mapIndex ].DomainName,
  616. DomainMapList[ mapIndex ].ConnectoidName);
  617. //
  618. // by freeing the name storage, we'll never to be able to register
  619. // the name. On the other hand, if the zone was changed to be
  620. // dynamic while the name was online, the admin would have to wait
  621. // 20 minutes before we would retry the registration. I suspect
  622. // that cycling the name would be preferred.
  623. //
  624. LocalFree( fqNameARec );
  625. LocalFree( fqNamePTRRec );
  626. fqNameARec = NULL;
  627. fqNamePTRRec = NULL;
  628. if ( FailOnAnyError ) {
  629. goto error_exit;
  630. } else {
  631. continue;
  632. }
  633. } else if ( dnsStatus == DNS_ERROR_RCODE_REFUSED ) {
  634. //
  635. // secure zone and we don't have credentials to change the
  636. // name. fail the resource.
  637. //
  638. (NetNameLogEvent)(ResourceHandle,
  639. LOG_WARNING,
  640. L"%1!ws! is a secure zone and has refused the registration of "
  641. L"%2!ws! over adapter '%3!ws!'.\n",
  642. DomainMapList[ mapIndex ].DomainName,
  643. fqNameARec,
  644. DomainMapList[ mapIndex ].ConnectoidName);
  645. LogDnsFailureToEventLog(ResourceKey,
  646. fqNameARec,
  647. AlternateComputerName,
  648. dnsStatus,
  649. DomainMapList[ mapIndex ].ConnectoidName);
  650. if ( FailOnAnyError ) {
  651. goto error_exit;
  652. } else {
  653. continue;
  654. }
  655. } else if ( dnsStatus == ERROR_TIMEOUT ) {
  656. //
  657. // couldn't contact a server so we're not sure if it allows
  658. // updates or not. build the records anyway and we'll deal with it
  659. // during the query period
  660. //
  661. if ( FailOnAnyError ) {
  662. goto error_exit;
  663. } else {
  664. ARecTimeout = TRUE;
  665. }
  666. } else if ( dnsStatus == DNS_ERROR_RCODE_YXDOMAIN ) {
  667. //
  668. // the record we asked about in DnsUpdateTest is not there but it
  669. // can be dynamically registered.
  670. //
  671. } else if ( dnsStatus != ERROR_SUCCESS ) {
  672. //
  673. // bad juju but only fail to bring the name online if DNS is
  674. // required. If any one of the registrations is successful, then
  675. // we consider that goodness.
  676. //
  677. (NetNameLogEvent)(ResourceHandle,
  678. LOG_WARNING,
  679. L"Testing %1!ws! for dynamic updates failed over adapter "
  680. L"'%3!ws!', status %2!u!.\n",
  681. fqNameARec,
  682. dnsStatus,
  683. DomainMapList[ mapIndex ].ConnectoidName);
  684. LogDnsFailureToEventLog(ResourceKey,
  685. fqNameARec,
  686. AlternateComputerName,
  687. dnsStatus,
  688. DomainMapList[ mapIndex ].ConnectoidName);
  689. if ( FailOnAnyError ) {
  690. goto error_exit;
  691. } else {
  692. continue;
  693. }
  694. }
  695. //
  696. // allocate memory to hold an array of DNS list data for the A and PTR
  697. // records. Separate lists are maintained for the different record types.
  698. //
  699. if (listheadFreeEntries == 0) {
  700. dnsStatus = GrowBlock((PCHAR *)&dnsLists,
  701. listheadCount,
  702. sizeof( *dnsLists ),
  703. &listheadFreeEntries);
  704. if ( dnsStatus != ERROR_SUCCESS) {
  705. (NetNameLogEvent)(ResourceHandle,
  706. LOG_ERROR,
  707. L"Unable to allocate memory (1).\n");
  708. goto error_exit;
  709. }
  710. }
  711. //
  712. // if the FQDN is already in use in another DNS record and the
  713. // connectoid names for the two FQDNs we're adding are the same, then
  714. // we have to add this new IP address entry to the existing DNS list.
  715. //
  716. for ( index = 0; index < listheadCount; ++index ) {
  717. if ( _wcsicmp( dnsLists[index].A_RRSet.pFirstRR->pName,
  718. fqNameARec
  719. ) == 0 )
  720. {
  721. #if DBG_DNSLIST
  722. {
  723. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 50];
  724. _snwprintf( buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
  725. L"DNS NAME MATCH w/ index %d: %ws\n",
  726. index, fqNameARec );
  727. OutputDebugStringW(buf);
  728. }
  729. #endif
  730. //
  731. // FQDNs are equal; how about the connectoids?
  732. //
  733. if (_wcsicmp(DomainMapList[ mapIndex ].ConnectoidName,
  734. dnsLists[index].ConnectoidName )
  735. ==
  736. 0 )
  737. {
  738. break;
  739. }
  740. }
  741. }
  742. #if DBG_DNSLIST
  743. {
  744. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 80];
  745. _snwprintf(buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
  746. L"ADDING (%ws, %ws, %.32ws) to dnsList[%d], lhCount = %d, DomMapList index = %d\n",
  747. fqNameARec,
  748. DomainMapList[mapIndex].IpAddress,
  749. DomainMapList[mapIndex].ConnectoidName,
  750. index,
  751. listheadCount,
  752. mapIndex );
  753. OutputDebugStringW(buf);
  754. }
  755. #endif
  756. if ( index == listheadCount ) {
  757. //
  758. // it's not, so init a new pair of listheads and adjust the
  759. // distinct listhead count
  760. //
  761. DNS_RRSET_INIT( dnsLists[ index ].A_RRSet );
  762. DNS_RRSET_INIT( dnsLists[ index ].PTR_RRSet );
  763. ++listheadCount;
  764. --listheadFreeEntries;
  765. }
  766. dnsLists[ index ].UpdateTestTimeout = ARecTimeout;
  767. if ( ClusWorkerCheckTerminate( Worker )) {
  768. dnsStatus = ERROR_OPERATION_ABORTED;
  769. goto error_exit;
  770. }
  771. //
  772. // build the PTR records. Per DNS dev, this should be considered a
  773. // warning instead of a failure. We note the failures and bring the
  774. // name online.
  775. //
  776. PTRName = BuildUnicodeReverseName( DomainMapList[ mapIndex ].IpAddress );
  777. if ( PTRName != NULL ) {
  778. PTRRecTimeout = FALSE;
  779. ptrRecStatus = DnsUpdateTest(NULL,
  780. PTRName,
  781. 0,
  782. DomainMapList[ mapIndex ].DnsServerList);
  783. #if DBG_DNSLIST
  784. {
  785. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  786. struct in_addr addr;
  787. addr.s_addr = DomainMapList[ mapIndex ].DnsServerList->AddrArray[0];
  788. _snwprintf(buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
  789. L"AddDnsNames UPDATETEST: %ws on %.32ws (%hs) returned %u\n",
  790. PTRName,
  791. DomainMapList[ mapIndex ].ConnectoidName,
  792. inet_ntoa( addr ),
  793. ptrRecStatus);
  794. OutputDebugStringW( buf );
  795. }
  796. #endif
  797. if ( ptrRecStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  798. //
  799. // zone does not accept dynamic updates.
  800. //
  801. (NetNameLogEvent)(ResourceHandle,
  802. LOG_INFORMATION,
  803. L"The zone for %1!ws! does not accept dynamic DNS "
  804. L"registration updates over adapter '%2!ws!'.\n",
  805. PTRName,
  806. DomainMapList[ mapIndex ].ConnectoidName);
  807. LocalFree( PTRName );
  808. LocalFree( fqNamePTRRec );
  809. PTRName = NULL;
  810. fqNamePTRRec = NULL;
  811. } else if ( ptrRecStatus == DNS_ERROR_RCODE_REFUSED ) {
  812. //
  813. // secure zone and we don't have credentials to change the
  814. // name. fail the resource.
  815. //
  816. (NetNameLogEvent)(ResourceHandle,
  817. LOG_WARNING,
  818. L"%1!ws! is a secure zone and has refused the registration of "
  819. L"%2!ws! over adapter '%3!ws!'.\n",
  820. DomainMapList[ mapIndex ].DomainName,
  821. PTRName,
  822. DomainMapList[ mapIndex ].ConnectoidName);
  823. } else if ( ptrRecStatus == ERROR_TIMEOUT ) {
  824. //
  825. // couldn't contact a server so we're not sure if it allows
  826. // updates or not. build the records anyway and we'll deal
  827. // with it during the query period
  828. //
  829. (NetNameLogEvent)(ResourceHandle,
  830. LOG_WARNING,
  831. L"The server for %1!ws! could not be contacted over adapter '%2!ws!' "
  832. L"to determine whether it accepts DNS registration updates. "
  833. L"Retrying at a later time.\n",
  834. PTRName,
  835. DomainMapList[ mapIndex ].ConnectoidName);
  836. PTRRecTimeout = TRUE;
  837. ptrRecStatus = ERROR_SUCCESS;
  838. } else if ( ptrRecStatus == DNS_ERROR_RCODE_YXDOMAIN ) {
  839. //
  840. // the record we asked about in DnsUpdateTest is not there but
  841. // it can be dynamically registered.
  842. //
  843. ptrRecStatus = ERROR_SUCCESS;
  844. } else if ( ptrRecStatus != ERROR_SUCCESS ) {
  845. //
  846. // bad juju - log the error but don't fail the name since
  847. // these are just lowly PTR records.
  848. //
  849. (NetNameLogEvent)(ResourceHandle,
  850. LOG_WARNING,
  851. L"Testing %1!ws! for dynamic updates over adapter '%3!ws!' "
  852. L"failed, status %2!u!.\n",
  853. PTRName,
  854. ptrRecStatus,
  855. DomainMapList[ mapIndex ].ConnectoidName);
  856. }
  857. if ( ptrRecStatus == ERROR_SUCCESS ) {
  858. //
  859. // build the PTR rec
  860. //
  861. PTRRecord = DnsRecordBuild_W(&dnsLists[ index ].PTR_RRSet,
  862. PTRName,
  863. DNS_TYPE_PTR,
  864. TRUE,
  865. 0,
  866. 1,
  867. &fqNamePTRRec);
  868. if (PTRRecord != NULL) {
  869. //
  870. // BUGBUG - DNS doesn't free the owner and data fields for
  871. // us in DnsRecordListFree. Set these flags until we sort
  872. // out what is happening
  873. //
  874. SET_FREE_OWNER( PTRRecord );
  875. SET_FREE_DATA( PTRRecord );
  876. //
  877. // set the time to live so clients don't beat up the
  878. // server
  879. //
  880. PTRRecord->dwTtl = 20 * 60; // 20 minutes
  881. //
  882. // "consume" the pointers to name strings. If we got this
  883. // far, then these pointers have been captured in the DNS
  884. // record and will be freed when the record is freed by
  885. // DnsRecordListFree.
  886. //
  887. PTRName = NULL;
  888. fqNamePTRRec = NULL;
  889. }
  890. else {
  891. (NetNameLogEvent)(ResourceHandle,
  892. LOG_WARNING,
  893. L"Error building PTR record for owner %1!ws!, addr %2!ws!, status %3!u!\n",
  894. fqNameARec,
  895. DomainMapList[ mapIndex ].IpAddress,
  896. ptrRecStatus = GetLastError());
  897. LocalFree( PTRName );
  898. LocalFree( fqNamePTRRec );
  899. PTRName = NULL;
  900. fqNamePTRRec = NULL;
  901. }
  902. } // if ptrRecStatus == ERROR_SUCCESS
  903. } // if PTRName != NULL
  904. else {
  905. ptrRecStatus = GetLastError();
  906. (NetNameLogEvent)(ResourceHandle,
  907. LOG_ERROR,
  908. L"Error building PTR name for owner %1!ws!, addr %2!ws!, status %3!u!\n",
  909. fqNameARec,
  910. DomainMapList[ mapIndex ].IpAddress,
  911. ptrRecStatus);
  912. LocalFree( fqNamePTRRec );
  913. fqNamePTRRec = NULL;
  914. }
  915. //
  916. // build the A rec
  917. //
  918. ARecord = DnsRecordBuild_W(&dnsLists[ index ].A_RRSet,
  919. fqNameARec,
  920. DNS_TYPE_A,
  921. TRUE,
  922. 0,
  923. 1,
  924. &DomainMapList[ mapIndex ].IpAddress);
  925. if ( ARecord == NULL ) {
  926. (NetNameLogEvent)(ResourceHandle,
  927. LOG_ERROR,
  928. L"Error building A rec for owner %1!ws!, addr %2!ws!, status %3!u!\n",
  929. fqNameARec,
  930. DomainMapList[ mapIndex ].IpAddress,
  931. dnsStatus = GetLastError());
  932. goto error_exit;
  933. }
  934. //
  935. // set the time to live so clients don't beat up the server
  936. //
  937. ARecord->dwTtl = 20 * 60; // 20 minutes
  938. //
  939. // BUGBUG - DNS doesn't free the owner and data fields for us in
  940. // DnsRecordListFree. Set these flags until we sort out what is
  941. // happening
  942. //
  943. SET_FREE_OWNER( ARecord );
  944. SET_FREE_DATA( ARecord );
  945. //
  946. // "consume" this pointer as well
  947. //
  948. fqNameARec = NULL;
  949. //
  950. // capture the DNS server list and connectoid name for this entry
  951. //
  952. dnsLists[ index ].DnsServerList = DomainMapList[ mapIndex ].DnsServerList;
  953. DomainMapList[ mapIndex ].DnsServerList = NULL;
  954. dnsLists[ index ].ConnectoidName = ResUtilDupString( DomainMapList[ mapIndex ].ConnectoidName );
  955. if ( dnsLists[ index ].ConnectoidName == NULL ) {
  956. (NetNameLogEvent)(ResourceHandle,
  957. LOG_ERROR,
  958. L"Unable to allocate memory .\n");
  959. goto error_exit;
  960. }
  961. } // end of for each entry in DomainMapCount
  962. //
  963. // update the DNS server with the records that were just created
  964. //
  965. *NumberOfRegisteredNames = 0;
  966. for( index = 0; index < listheadCount; ++index ) {
  967. if ( ClusWorkerCheckTerminate( Worker )) {
  968. dnsStatus = ERROR_OPERATION_ABORTED;
  969. goto error_exit;
  970. }
  971. //
  972. // if we made it this far, we know that the server is dynamic or we
  973. // timed out trying to figure that out. For the timeout case, we'll
  974. // assume that the servers are dynamic and let NetNameUpdateDnsServer
  975. // discover otherwise.
  976. //
  977. dnsLists[ index ].ForwardZoneIsDynamic = TRUE;
  978. dnsLists[ index ].ReverseZoneIsDynamic = TRUE;
  979. dnsStatus = RegisterDnsRecords(&dnsLists[ index ],
  980. AlternateComputerName,
  981. ResourceKey,
  982. ResourceHandle,
  983. TRUE, /* LogRegistration */
  984. NumberOfRegisteredNames);
  985. if ( dnsStatus != ERROR_SUCCESS && FailOnAnyError ) {
  986. goto error_exit;
  987. }
  988. }
  989. *NumberOfDnsLists = listheadCount;
  990. *DnsLists = dnsLists;
  991. return dnsStatus;
  992. error_exit:
  993. if ( dnsLists != NULL ) {
  994. while ( listheadCount-- ) {
  995. DnsRecordListFree(
  996. dnsLists[listheadCount].PTR_RRSet.pFirstRR,
  997. DnsFreeRecordListDeep );
  998. DnsRecordListFree(
  999. dnsLists[listheadCount].A_RRSet.pFirstRR,
  1000. DnsFreeRecordListDeep );
  1001. if ( dnsLists[listheadCount].DnsServerList != NULL ) {
  1002. LocalFree( dnsLists[listheadCount].DnsServerList );
  1003. }
  1004. if ( dnsLists[listheadCount].ConnectoidName != NULL ) {
  1005. LocalFree( dnsLists[listheadCount].ConnectoidName );
  1006. }
  1007. }
  1008. LocalFree( dnsLists );
  1009. }
  1010. if ( PTRName != NULL ) {
  1011. LocalFree( PTRName );
  1012. }
  1013. if ( fqNamePTRRec != NULL ) {
  1014. LocalFree( fqNamePTRRec );
  1015. }
  1016. if ( fqNameARec != NULL ) {
  1017. LocalFree( fqNameARec );
  1018. }
  1019. *NumberOfDnsLists = 0;
  1020. *NumberOfRegisteredNames = 0;
  1021. *DnsLists = NULL;
  1022. return dnsStatus;
  1023. } // AddDnsNames
  1024. VOID
  1025. LogDnsFailureToEventLog(
  1026. IN HKEY ResourceKey,
  1027. IN LPWSTR DnsName,
  1028. IN LPWSTR ResourceName,
  1029. IN DWORD Status,
  1030. IN LPWSTR ConnectoidName
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Log dns name failures to the event log
  1035. Arguments:
  1036. DnsName - FQ DNS name that failed to be registered
  1037. ResourceName - associated resource
  1038. Status - status returned by DNSAPI
  1039. Return Value:
  1040. NONE
  1041. --*/
  1042. {
  1043. LPWSTR msgBuff;
  1044. DWORD msgBytes;
  1045. msgBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1046. FORMAT_MESSAGE_FROM_SYSTEM,
  1047. NULL,
  1048. Status,
  1049. 0,
  1050. (LPWSTR)&msgBuff,
  1051. 0,
  1052. NULL);
  1053. if ( msgBytes > 0 ) {
  1054. ClusResLogSystemEventByKeyData3(ResourceKey,
  1055. LOG_UNUSUAL,
  1056. RES_NETNAME_DNS_REGISTRATION_MISSING,
  1057. sizeof( Status ),
  1058. &Status,
  1059. DnsName,
  1060. msgBuff,
  1061. ConnectoidName);
  1062. LocalFree( msgBuff );
  1063. }
  1064. } // LogDnsFailureToEventLog
  1065. //
  1066. // Exported Routines
  1067. //
  1068. LPWSTR
  1069. BuildUnicodeReverseName(
  1070. IN LPWSTR IpAddress
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. Given an Ip address, build a reverse DNS name for publishing as
  1075. a PTR record
  1076. Arguments:
  1077. IpAddress - unicode version of dotted decimal IP address
  1078. Return Value:
  1079. address of pointer to buffer with reverse name. Null if an error occured
  1080. --*/
  1081. {
  1082. ULONG ipAddress;
  1083. PCHAR ansiReverseName;
  1084. PCHAR pAnsi;
  1085. ULONG ansiNameLength;
  1086. PWCHAR unicodeReverseName;
  1087. PWCHAR pUni;
  1088. CHAR ansiIpAddress[ 64 ];
  1089. //
  1090. // convert to ansi, have DNS create the name, and then convert back to
  1091. // unicode
  1092. //
  1093. wcstombs( ansiIpAddress, IpAddress, sizeof( ansiIpAddress ));
  1094. ipAddress = inet_addr( ansiIpAddress );
  1095. ansiReverseName = DnsCreateReverseNameStringForIpAddress(
  1096. (IP4_ADDRESS)ipAddress
  1097. );
  1098. if ( ansiReverseName == NULL ) {
  1099. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1100. return NULL;
  1101. }
  1102. ansiNameLength = strlen( ansiReverseName ) + 1;
  1103. unicodeReverseName = LocalAlloc(LMEM_FIXED,
  1104. ansiNameLength * sizeof(WCHAR));
  1105. if ( unicodeReverseName == NULL ) {
  1106. LocalFree( ansiReverseName );
  1107. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1108. return NULL;
  1109. }
  1110. //
  1111. // convert to Unicode
  1112. //
  1113. mbstowcs( unicodeReverseName, ansiReverseName, ansiNameLength );
  1114. LocalFree( ansiReverseName );
  1115. return unicodeReverseName;
  1116. } // BuildUnicodeReverseName
  1117. DWORD
  1118. RegisterDnsRecords(
  1119. IN PDNS_LISTS DnsLists,
  1120. IN LPWSTR NetworkName,
  1121. IN HKEY ResourceKey,
  1122. IN RESOURCE_HANDLE ResourceHandle,
  1123. IN BOOL LogRegistration,
  1124. OUT PULONG NumberOfRegisteredNames
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Register the A and PTR records specified in DnsLists with the DNS server.
  1129. Arguments:
  1130. DnsLists - pointer to the list of structs holding the record sets to
  1131. be registered
  1132. NetworkName - host name portion of name being registered
  1133. ResourceKey - used to log events to the event viewer
  1134. ResourceHandle - used to log messages in the cluster log
  1135. LogRegistration - TRUE if the successful registration should be logged to the cluster log
  1136. NumberOfRegisteredNames - pointer that receives count of successful registrations
  1137. Return Value:
  1138. None
  1139. --*/
  1140. {
  1141. DNS_STATUS ARecStatus;
  1142. DNS_STATUS PTRRecStatus;
  1143. DNS_STATUS dnsStatus;
  1144. PDNS_RECORD dnsRecord;
  1145. PDNS_RECORD nextDnsRecord;
  1146. ULONG registeredCount = 0;
  1147. //
  1148. // check the status of DnsUpdateTest on this name. If we've previously
  1149. // timed out, then try again.
  1150. //
  1151. if ( DnsLists->UpdateTestTimeout ) {
  1152. DnsLists->UpdateTestTimeout = FALSE;
  1153. dnsStatus = DnsUpdateTest(NULL,
  1154. DnsLists->A_RRSet.pFirstRR->pName,
  1155. 0,
  1156. DnsLists->DnsServerList);
  1157. #if DBG_DNSLIST
  1158. {
  1159. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  1160. struct in_addr addr;
  1161. addr.s_addr = DnsLists->DnsServerList->AddrArray[0];
  1162. _snwprintf(buf, (sizeof( buf ) / sizeof( WCHAR )) - 1,
  1163. L"RegisterDnsRecords UPDATETEST: %ws on %.32ws (%hs) returned %u\n",
  1164. DnsLists->A_RRSet.pFirstRR->pName,
  1165. DnsLists->ConnectoidName,
  1166. inet_ntoa( addr ),
  1167. dnsStatus);
  1168. OutputDebugStringW( buf );
  1169. }
  1170. #endif
  1171. if ( dnsStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  1172. //
  1173. // zone does not accept dynamic updates. Invalidate this entry
  1174. //
  1175. (NetNameLogEvent)(ResourceHandle,
  1176. LOG_INFORMATION,
  1177. L"%1!ws! does not accept dynamic DNS registration updates over "
  1178. L"adapter '%2!ws!'.\n",
  1179. DnsLists->A_RRSet.pFirstRR->pName,
  1180. DnsLists->ConnectoidName);
  1181. DnsLists->ForwardZoneIsDynamic = FALSE;
  1182. return dnsStatus;
  1183. } else if ( dnsStatus == DNS_ERROR_RCODE_REFUSED ) {
  1184. //
  1185. // secure zone and we don't have credentials to change the
  1186. // name. fail the resource.
  1187. //
  1188. (NetNameLogEvent)(ResourceHandle,
  1189. LOG_WARNING,
  1190. L"The registration of %1!ws! in a secure zone was refused "
  1191. L"because the record was already registered but owned by a "
  1192. L"different user.\n",
  1193. DnsLists->A_RRSet.pFirstRR->pName);
  1194. if (!DnsLists->AErrorLogged ||
  1195. dnsStatus != DnsLists->LastARecQueryStatus ) {
  1196. LogDnsFailureToEventLog(ResourceKey,
  1197. DnsLists->A_RRSet.pFirstRR->pName,
  1198. NetworkName,
  1199. dnsStatus,
  1200. DnsLists->ConnectoidName);
  1201. DnsLists->AErrorLogged = TRUE;
  1202. }
  1203. DnsLists->LastARecQueryStatus = dnsStatus;
  1204. return dnsStatus;
  1205. } else if ( dnsStatus == ERROR_TIMEOUT ) {
  1206. //
  1207. // couldn't contact a server so we're not sure if it allows
  1208. // updates or not.
  1209. //
  1210. (NetNameLogEvent)(ResourceHandle,
  1211. LOG_WARNING,
  1212. L"The server for %1!ws! could not be contacted over adapter "
  1213. L"'%2!ws!' to determine whether it accepts DNS registration "
  1214. L"updates. Retrying at a later time.\n",
  1215. DnsLists->A_RRSet.pFirstRR->pName,
  1216. DnsLists->ConnectoidName);
  1217. if (!DnsLists->AErrorLogged ) {
  1218. LogDnsFailureToEventLog(ResourceKey,
  1219. DnsLists->A_RRSet.pFirstRR->pName,
  1220. NetworkName,
  1221. dnsStatus,
  1222. DnsLists->ConnectoidName);
  1223. DnsLists->AErrorLogged = TRUE;
  1224. }
  1225. DnsLists->UpdateTestTimeout = TRUE;
  1226. return dnsStatus;
  1227. } else if ( dnsStatus == DNS_ERROR_RCODE_YXDOMAIN ) {
  1228. //
  1229. // the record we asked about in DnsUpdateTest is not there but it
  1230. // can be dynamically registered.
  1231. //
  1232. } else if ( dnsStatus != ERROR_SUCCESS ) {
  1233. //
  1234. // bad juju
  1235. //
  1236. (NetNameLogEvent)(ResourceHandle,
  1237. LOG_WARNING,
  1238. L"Testing %1!ws! for dynamic updates failed over adapter "
  1239. L"'%3!ws!', status %2!u!.\n",
  1240. DnsLists->A_RRSet.pFirstRR->pName,
  1241. dnsStatus,
  1242. DnsLists->ConnectoidName);
  1243. if (!DnsLists->AErrorLogged ||
  1244. dnsStatus != DnsLists->LastARecQueryStatus ) {
  1245. LogDnsFailureToEventLog(ResourceKey,
  1246. DnsLists->A_RRSet.pFirstRR->pName,
  1247. NetworkName,
  1248. dnsStatus,
  1249. DnsLists->ConnectoidName);
  1250. DnsLists->AErrorLogged = TRUE;
  1251. }
  1252. DnsLists->LastARecQueryStatus = dnsStatus;
  1253. return dnsStatus;
  1254. }
  1255. //
  1256. // since we previously timed out but (at this point) are going to
  1257. // register the records, adjust the logging flag so we get this time
  1258. // recorded.
  1259. //
  1260. LogRegistration = TRUE;
  1261. } // end if the update test had previously timed out
  1262. #if DBG
  1263. (NetNameLogEvent)(ResourceHandle,
  1264. LOG_INFORMATION,
  1265. L"Registering %1!ws! over '%2!ws!'\n",
  1266. DnsLists->A_RRSet.pFirstRR->pName,
  1267. DnsLists->ConnectoidName);
  1268. #endif
  1269. //
  1270. // register the A Recs
  1271. //
  1272. ARecStatus = DnsReplaceRecordSetW(DnsLists->A_RRSet.pFirstRR,
  1273. DNS_UPDATE_SECURITY_USE_DEFAULT,
  1274. NULL,
  1275. DnsLists->DnsServerList,
  1276. NULL);
  1277. if ( ARecStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  1278. ++registeredCount;
  1279. DnsLists->AErrorLogged = FALSE;
  1280. if ( LogRegistration ) {
  1281. PDNS_RECORD dnsRecord;
  1282. dnsRecord = DnsLists->A_RRSet.pFirstRR;
  1283. while ( dnsRecord != NULL ) {
  1284. struct in_addr ipAddress;
  1285. ipAddress.s_addr = dnsRecord->Data.A.IpAddress;
  1286. (NetNameLogEvent)(ResourceHandle,
  1287. LOG_INFORMATION,
  1288. L"Registered DNS name %1!ws! with IP Address %2!hs! "
  1289. L"over adapter '%3!ws!'.\n",
  1290. dnsRecord->pName,
  1291. inet_ntoa( ipAddress ),
  1292. DnsLists->ConnectoidName);
  1293. dnsRecord = dnsRecord->pNext;
  1294. }
  1295. }
  1296. } else {
  1297. //
  1298. // it failed. log an error to the cluster log and change the worker
  1299. // thread polling period. If we haven't logged an event before or the
  1300. // error is different from the previous error, log it in the event log
  1301. //
  1302. if ( ARecStatus == ERROR_TIMEOUT ) {
  1303. (NetNameLogEvent)(ResourceHandle,
  1304. LOG_WARNING,
  1305. L"The DNS server couldn't be contacted to update the registration "
  1306. L"for %1!ws!. Retrying at a later time.\n",
  1307. DnsLists->A_RRSet.pFirstRR->pName);
  1308. }
  1309. else {
  1310. (NetNameLogEvent)(ResourceHandle,
  1311. LOG_ERROR,
  1312. L"Failed to register DNS A records for owner %1!ws! over "
  1313. L"adapter '%3!ws!', status %2!u!\n",
  1314. DnsLists->A_RRSet.pFirstRR->pName,
  1315. ARecStatus,
  1316. DnsLists->ConnectoidName);
  1317. }
  1318. NetNameWorkerCheckPeriod = NETNAME_WORKER_PROBLEM_CHECK_PERIOD;
  1319. if (!DnsLists->AErrorLogged ||
  1320. ARecStatus != DnsLists->LastARecQueryStatus ) {
  1321. LogDnsFailureToEventLog(ResourceKey,
  1322. DnsLists->A_RRSet.pFirstRR->pName,
  1323. NetworkName,
  1324. ARecStatus,
  1325. DnsLists->ConnectoidName);
  1326. DnsLists->AErrorLogged = TRUE;
  1327. }
  1328. }
  1329. //
  1330. // Record the status of the registration in the list for this
  1331. // owner. NetnameLooksAlive will check this value to determine the health
  1332. // of this set of registrations. Use interlocked to co-ordinate with
  1333. // Is/LooksAlive.
  1334. //
  1335. InterlockedExchange( &DnsLists->LastARecQueryStatus, ARecStatus );
  1336. //
  1337. // don't bother with PTR recs if bad juju happened with the A recs. we'll
  1338. // try to register them the next time the DNS check thread runs
  1339. //
  1340. if ( ARecStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  1341. //
  1342. // dynamic DNS requires that the pName must be the same for a given
  1343. // set of records in an RRSET. The pName for a set of PTR records will
  1344. // always be different. Maintaining a huge pile of RRSets, one per PTR
  1345. // record is ridiculous (or at least I thought so when I orginally
  1346. // wrote this; in hind sight, this was a bad decision - charlwi).
  1347. //
  1348. // AddDnsNames linked all these recs together. Now we have to register
  1349. // them one at time by remembering the link, breaking it, registering,
  1350. // restoring the link and moving on to the next record.
  1351. //
  1352. // The ErrorLogged logic is broken since we don't keep the status for
  1353. // each (separate) registration. It's an approximation at best.
  1354. //
  1355. // In addition, it is possible for the server to accept A records
  1356. // dynamically but disallow PTR records hence the check to see if we
  1357. // have records to register is up front.
  1358. //
  1359. // Finally, we use ModifyRecordsInSet instead of ReplaceRecordSet due
  1360. // to the organization of the PTR RRSET. When two names map to the
  1361. // same IP address, we have identical reverse addr strings in more
  1362. // than one DNS_LIST entry. If ReplaceRecordSet were used instead, it
  1363. // would delete all but one of the reverse address mappings. In hind
  1364. // sight, each DNS_LIST entry should have hosted either an A or PTR
  1365. // RRSet but not both.
  1366. //
  1367. dnsRecord = DnsLists->PTR_RRSet.pFirstRR;
  1368. while ( dnsRecord != NULL ) {
  1369. nextDnsRecord = dnsRecord->pNext;
  1370. dnsRecord->pNext = NULL;
  1371. PTRRecStatus = DnsModifyRecordsInSet_W(dnsRecord,
  1372. NULL,
  1373. DNS_UPDATE_SECURITY_USE_DEFAULT,
  1374. NULL,
  1375. DnsLists->DnsServerList,
  1376. NULL);
  1377. if ( PTRRecStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  1378. DnsLists->PTRErrorLogged = FALSE;
  1379. if ( LogRegistration ) {
  1380. (NetNameLogEvent)(ResourceHandle,
  1381. LOG_INFORMATION,
  1382. L"Registered DNS PTR record %1!ws! for host %2!ws! "
  1383. L"over adapter '%3!ws!'\n",
  1384. dnsRecord->pName,
  1385. DnsLists->A_RRSet.pFirstRR->pName,
  1386. DnsLists->ConnectoidName);
  1387. }
  1388. } else {
  1389. (NetNameLogEvent)(ResourceHandle,
  1390. LOG_ERROR,
  1391. L"Failed to register DNS PTR record %1!ws! for host "
  1392. L"%2!ws! over adapter '%4!ws!', status %3!u!\n",
  1393. dnsRecord->pName,
  1394. DnsLists->A_RRSet.pFirstRR->pName,
  1395. PTRRecStatus,
  1396. DnsLists->ConnectoidName);
  1397. if (!DnsLists->PTRErrorLogged ||
  1398. PTRRecStatus != DnsLists->LastPTRRecQueryStatus )
  1399. {
  1400. DnsLists->PTRErrorLogged = TRUE;
  1401. }
  1402. }
  1403. InterlockedExchange(&DnsLists->LastPTRRecQueryStatus,
  1404. PTRRecStatus);
  1405. dnsRecord->pNext = nextDnsRecord;
  1406. dnsRecord = nextDnsRecord;
  1407. }
  1408. } // end if A rec registration was successful
  1409. else {
  1410. //
  1411. // since we don't end up trying the PTR records because of the A rec
  1412. // failure, we'll propagate the A rec error code in the PTR status.
  1413. //
  1414. InterlockedExchange(&DnsLists->LastPTRRecQueryStatus,
  1415. ARecStatus);
  1416. }
  1417. *NumberOfRegisteredNames = registeredCount;
  1418. return ARecStatus;
  1419. } // RegisterDnsRecords
  1420. VOID
  1421. DeleteAlternateComputerName(
  1422. IN LPWSTR AlternateComputerName,
  1423. IN HANDLE * NameHandleList,
  1424. IN DWORD NameHandleCount,
  1425. IN RESOURCE_HANDLE ResourceHandle
  1426. )
  1427. {
  1428. NET_API_STATUS status;
  1429. if ( NameHandleCount > 0 ) {
  1430. status = DeleteServerName(ResourceHandle, AlternateComputerName);
  1431. if (status != ERROR_SUCCESS) {
  1432. (NetNameLogEvent)(ResourceHandle,
  1433. LOG_WARNING,
  1434. L"Failed to delete server name %1!ws!, status %2!u!.\n",
  1435. AlternateComputerName,
  1436. status);
  1437. }
  1438. }
  1439. while ( NameHandleCount-- ) {
  1440. CloseHandle(NameHandleList[NameHandleCount]);
  1441. NameHandleList[NameHandleCount] = NULL;
  1442. (NetNameLogEvent)(ResourceHandle,
  1443. LOG_INFORMATION,
  1444. L"Deleted workstation name %1!ws! from transport %2!u!.\n",
  1445. AlternateComputerName,
  1446. NameHandleCount
  1447. );
  1448. }
  1449. } // DeleteAlternateComputerName
  1450. DWORD
  1451. AddAlternateComputerName(
  1452. IN PCLUS_WORKER Worker,
  1453. IN PNETNAME_RESOURCE Resource,
  1454. IN LPWSTR * TransportList,
  1455. IN DWORD TransportCount,
  1456. IN PDOMAIN_ADDRESS_MAPPING DomainMapList,
  1457. IN DWORD DomainMapCount
  1458. )
  1459. {
  1460. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  1461. LPWSTR alternateComputerName = Resource->Params.NetworkName;
  1462. DWORD status = ERROR_SUCCESS;
  1463. DWORD setValueStatus;
  1464. DWORD i;
  1465. DWORD handleCount = 0;
  1466. LONG numberOfDnsNamesRegistered = 0;
  1467. PWCHAR machinePwd = NULL;
  1468. //
  1469. // clear all the status values so we don't show left over crud if we fail
  1470. // early on.
  1471. //
  1472. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1473. PARAM_NAME__STATUS_NETBIOS,
  1474. 0,
  1475. NULL);
  1476. ASSERT( setValueStatus == ERROR_SUCCESS );
  1477. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1478. PARAM_NAME__STATUS_DNS,
  1479. 0,
  1480. NULL);
  1481. ASSERT( setValueStatus == ERROR_SUCCESS );
  1482. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1483. PARAM_NAME__STATUS_KERBEROS,
  1484. 0,
  1485. NULL);
  1486. ASSERT( setValueStatus == ERROR_SUCCESS );
  1487. //
  1488. // register DNS name(s) with server
  1489. //
  1490. status = AddDnsNames(Worker,
  1491. alternateComputerName,
  1492. Resource->ResKey,
  1493. resourceHandle,
  1494. DomainMapList,
  1495. DomainMapCount,
  1496. Resource->Params.RequireDNS, // FailOnAnyError
  1497. &Resource->NumberOfDnsLists,
  1498. &Resource->DnsLists,
  1499. &numberOfDnsNamesRegistered);
  1500. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1501. PARAM_NAME__STATUS_DNS,
  1502. status,
  1503. NULL);
  1504. ASSERT( setValueStatus == ERROR_SUCCESS );
  1505. if ( status == ERROR_OPERATION_ABORTED ||
  1506. ( status != ERROR_SUCCESS && Resource->Params.RequireDNS ))
  1507. {
  1508. if ( status != ERROR_OPERATION_ABORTED && Resource->Params.RequireDNS ) {
  1509. LPWSTR msgBuff;
  1510. DWORD msgBytes;
  1511. msgBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1512. FORMAT_MESSAGE_FROM_SYSTEM,
  1513. NULL,
  1514. status,
  1515. 0,
  1516. (LPWSTR)&msgBuff,
  1517. 0,
  1518. NULL);
  1519. if ( msgBytes > 0 ) {
  1520. ClusResLogSystemEventByKey1(Resource->ResKey,
  1521. LOG_CRITICAL,
  1522. RES_NETNAME_DNS_REGISTRATION_FAILED,
  1523. msgBuff);
  1524. LocalFree( msgBuff );
  1525. } else {
  1526. ClusResLogSystemEventByKeyData(Resource->ResKey,
  1527. LOG_CRITICAL,
  1528. RES_NETNAME_DNS_REGISTRATION_FAILED_STATUS,
  1529. sizeof( status ),
  1530. &status);
  1531. }
  1532. }
  1533. return status;
  1534. }
  1535. #ifdef COMPOBJ_SUPPORT
  1536. if ( Resource->Params.RequireKerberos ) {
  1537. //
  1538. // create the backing computer account in the DS for kerb. authentication
  1539. //
  1540. status = NetNameAddComputerObject( Worker, Resource, &machinePwd );
  1541. Resource->KerberosStatus = status;
  1542. Resource->DoKerberosCheck = ( status == ERROR_SUCCESS );
  1543. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1544. PARAM_NAME__STATUS_KERBEROS,
  1545. status,
  1546. NULL);
  1547. ASSERT( setValueStatus == ERROR_SUCCESS );
  1548. if ( status != ERROR_SUCCESS ) {
  1549. return status;
  1550. }
  1551. } else {
  1552. //
  1553. // we need some cluster wide mechanism (a property?) to indicate that
  1554. // we need to delete the CO before online completes.
  1555. //
  1556. if ( Resource->ObjectGUID != NULL ) {
  1557. status = NetNameDeleteComputerObject( Resource );
  1558. //
  1559. // ISSUE: check for comm error and post warning that we're
  1560. // bringing the name online but that authentication may fail due
  1561. // to a residual CO we can't detect.
  1562. //
  1563. if ( status == ERROR_NO_SUCH_DOMAIN ) {
  1564. }
  1565. else if ( status != ERROR_SUCCESS && status != NERR_UserNotFound ) {
  1566. (NetNameLogEvent)(Resource->ResourceHandle,
  1567. LOG_ERROR,
  1568. L"Kerberos is disabled for this resource but a computer account "
  1569. L"exists in the directory service and it can't be deleted by the cluster "
  1570. L"service. The computer account must be deleted before the resource "
  1571. L"can be brought online. error %1!u!\n",
  1572. status);
  1573. return status;
  1574. }
  1575. }
  1576. Resource->DoKerberosCheck = FALSE;
  1577. }
  1578. #else
  1579. Resource->DoKerberosCheck = FALSE;
  1580. #endif
  1581. //
  1582. // bring NetBT names online
  1583. //
  1584. status = ERROR_SUCCESS;
  1585. for (i=0; i<TransportCount; i++) {
  1586. if ( ClusWorkerCheckTerminate( Worker )) {
  1587. status = ERROR_OPERATION_ABORTED;
  1588. goto cleanup;
  1589. }
  1590. status = AddServerName(resourceHandle,
  1591. alternateComputerName,
  1592. Resource->Params.NetworkRemap,
  1593. TransportList[i],
  1594. (BOOLEAN) ((i == 0) ? TRUE : FALSE), // CheckNameFirst
  1595. machinePwd);
  1596. if ( status == NERR_ServerNotStarted ) {
  1597. status = ERROR_SUCCESS;
  1598. }
  1599. if ( status != ERROR_SUCCESS ) {
  1600. goto cleanup;
  1601. }
  1602. if ( ClusWorkerCheckTerminate( Worker )) {
  1603. status = ERROR_OPERATION_ABORTED;
  1604. goto cleanup;
  1605. }
  1606. status = AddWorkstationName(
  1607. alternateComputerName,
  1608. TransportList[i],
  1609. resourceHandle,
  1610. &(Resource->NameHandleList[i])
  1611. );
  1612. if (status != ERROR_SUCCESS) {
  1613. goto cleanup;
  1614. }
  1615. handleCount++;
  1616. }
  1617. //
  1618. // if didn't register any NetBt or DNS names, then fail the netname.
  1619. //
  1620. if ( TransportCount == 0 && numberOfDnsNamesRegistered == 0 ) {
  1621. ClusResLogSystemEvent1(LOG_CRITICAL,
  1622. RES_NETNAME_NOT_REGISTERED,
  1623. alternateComputerName);
  1624. status = ERROR_RESOURCE_FAILED;
  1625. }
  1626. cleanup:
  1627. if ( machinePwd != NULL ) {
  1628. PWCHAR p = machinePwd;
  1629. while ( *p != UNICODE_NULL ) {
  1630. *p++ = UNICODE_NULL;
  1631. }
  1632. HeapFree( GetProcessHeap(), 0, machinePwd );
  1633. }
  1634. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1635. PARAM_NAME__STATUS_NETBIOS,
  1636. status,
  1637. NULL);
  1638. ASSERT( setValueStatus == ERROR_SUCCESS );
  1639. return status;
  1640. } // AddAlternateComputerName