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

2456 lines
84 KiB

  1. /*++
  2. Copyright (c) 1995-2001 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. #include <adserr.h>
  22. #include <kerberos.h>
  23. //
  24. // Constants
  25. //
  26. #define LOG_CURRENT_MODULE LOG_MODULE_NETNAME
  27. //
  28. // Local types
  29. //
  30. typedef enum _NETNAME_CREDENTIAL_OPERATION {
  31. NNAddCredential = 1,
  32. NNRemoveCredential
  33. } NETNAME_CREDENTIAL_OPERATION;
  34. //
  35. // forward declarations
  36. //
  37. VOID
  38. LogDnsFailureToEventLog(
  39. IN HKEY ResourceKey,
  40. IN LPWSTR DnsName,
  41. IN LPWSTR ResourceName,
  42. IN DWORD Status,
  43. IN LPWSTR ConnectoidName
  44. );
  45. //
  46. // Local Utility Routines
  47. //
  48. NET_API_STATUS
  49. CheckForServerName(
  50. IN RESOURCE_HANDLE ResourceHandle,
  51. IN LPWSTR ServerName,
  52. IN POEM_STRING OemServerNameString,
  53. OUT PBOOLEAN IsNameRegistered
  54. )
  55. {
  56. PSERVER_TRANSPORT_INFO_0 psti0 = NULL;
  57. DWORD entriesRead = 0;
  58. DWORD totalEntries = 0;
  59. DWORD resumeHandle = 0;
  60. NET_API_STATUS status;
  61. DWORD i;
  62. *IsNameRegistered = FALSE;
  63. status = NetServerTransportEnum(
  64. NULL,
  65. 0,
  66. (LPBYTE *) &psti0,
  67. (DWORD) -1,
  68. &entriesRead,
  69. &totalEntries,
  70. &resumeHandle
  71. );
  72. if (status != NERR_Success) {
  73. (NetNameLogEvent)(
  74. ResourceHandle,
  75. LOG_WARNING,
  76. L"Unable to enumerate server tranports, error %1!u!.\n",
  77. status
  78. );
  79. return(status);
  80. }
  81. for ( i=0; i < entriesRead; i++ ) {
  82. if ( ( psti0[i].svti0_transportaddresslength ==
  83. OemServerNameString->Length
  84. )
  85. &&
  86. ( RtlCompareMemory(
  87. psti0[i].svti0_transportaddress,
  88. OemServerNameString->Buffer,
  89. OemServerNameString->Length
  90. ) == OemServerNameString->Length
  91. )
  92. )
  93. {
  94. *IsNameRegistered = TRUE;
  95. break;
  96. }
  97. }
  98. if (psti0 != NULL) {
  99. LocalFree(psti0);
  100. }
  101. return(status);
  102. } // CheckForServerName
  103. NET_API_STATUS
  104. pDeleteServerName(
  105. IN RESOURCE_HANDLE ResourceHandle,
  106. IN LPWSTR ServerName,
  107. IN POEM_STRING OemServerNameString
  108. )
  109. {
  110. NET_API_STATUS status;
  111. BOOLEAN isNameRegistered;
  112. DWORD count;
  113. //
  114. // Delete the name
  115. //
  116. status = NetServerComputerNameDel(NULL, ServerName);
  117. if (status != NERR_Success) {
  118. if (status != ERROR_BAD_NET_NAME) {
  119. (NetNameLogEvent)(
  120. ResourceHandle,
  121. LOG_WARNING,
  122. L"Failed to delete server name %1!ws!, status %2!u!.\n",
  123. ServerName,
  124. status
  125. );
  126. }
  127. return(status);
  128. }
  129. //
  130. // Check to make sure the name was really deleted. We'll wait up
  131. // to 2 seconds.
  132. //
  133. for (count = 0; count < 8; count++) {
  134. status = CheckForServerName(
  135. ResourceHandle,
  136. ServerName,
  137. OemServerNameString,
  138. &isNameRegistered
  139. );
  140. if (status != NERR_Success) {
  141. (NetNameLogEvent)(
  142. ResourceHandle,
  143. LOG_WARNING,
  144. L"Unable to verify that server name %1!ws! was deleted, status %2!u!.\n",
  145. ServerName,
  146. status
  147. );
  148. return(NERR_Success);
  149. }
  150. if (isNameRegistered == FALSE) {
  151. (NetNameLogEvent)(
  152. ResourceHandle,
  153. LOG_INFORMATION,
  154. L"Deleted server name %1!ws! from all transports.\n",
  155. ServerName
  156. );
  157. return(NERR_Success);
  158. }
  159. Sleep(250);
  160. }
  161. (NetNameLogEvent)(
  162. ResourceHandle,
  163. LOG_WARNING,
  164. L"Delete of server name %1!ws! succeeded, but name still has not gone away. "
  165. L"Giving up.\n",
  166. ServerName
  167. );
  168. return(ERROR_IO_PENDING);
  169. } // pDeleteServerName
  170. DWORD
  171. NNCredentialOperation(
  172. RESOURCE_HANDLE ResourceHandle,
  173. LPWSTR ComputerName,
  174. LPWSTR DomainName,
  175. LPWSTR Password OPTIONAL,
  176. NETNAME_CREDENTIAL_OPERATION CredOp
  177. )
  178. /*++
  179. Routine Description:
  180. Add or remove the specified credentials as alternates for the LocalSystem
  181. and NetworkService accounts.
  182. Remove will remove all passwords associated with the account. Repeated
  183. Adds will move the current password into the old password, obliterating
  184. it, and make the supplied password the new one. The password cache is 2
  185. deep FIFO.
  186. Arguments:
  187. ResourceHandle - for logging to cluster log
  188. ComputerName - pointer to the computer account principal name
  189. DomainName - FQDN of domain associated with ComputerName
  190. Password - the password associated with this account. Not used for remove
  191. CredOp - indicates whether to add or remove credential
  192. Return Value:
  193. ERROR_SUCCESS if ok, otherwise Win32 error
  194. --*/
  195. {
  196. HANDLE lsaHandle;
  197. ULONG packageId;
  198. LUID networkServiceLuid = NETWORKSERVICE_LUID;
  199. LUID localSystemLuid = SYSTEM_LUID;
  200. PWCHAR opTypeString;
  201. BOOLEAN tcbWasEnabled;
  202. DWORD requestSize;
  203. NTSTATUS ntStatus;
  204. NTSTATUS subStatus;
  205. LSA_STRING packageName;
  206. PKERB_ADD_CREDENTIALS_REQUEST addCredsRequest;
  207. //
  208. // compute the total size of the request buffer and allocate that space
  209. //
  210. requestSize = sizeof( KERB_ADD_CREDENTIALS_REQUEST )
  211. +
  212. ( wcslen( ComputerName ) + 2 // 2 for dollar sign and null
  213. +
  214. wcslen( DomainName ) + 1
  215. )
  216. * sizeof( WCHAR );
  217. if ( ARGUMENT_PRESENT( Password )) {
  218. requestSize += ( wcslen( Password ) + 1 ) * sizeof( WCHAR );
  219. }
  220. addCredsRequest = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, requestSize );
  221. if ( addCredsRequest == NULL ) {
  222. (NetNameLogEvent)(ResourceHandle,
  223. LOG_ERROR,
  224. L"Unable to allocate memory for LSA credential operation.\n");
  225. return GetLastError();
  226. }
  227. //
  228. // validate type of operation
  229. //
  230. if ( CredOp == NNAddCredential ) {
  231. opTypeString = L"add";
  232. addCredsRequest->Flags = KERB_REQUEST_ADD_CREDENTIAL;
  233. }
  234. else if ( CredOp == NNRemoveCredential ) {
  235. opTypeString = L"remove";
  236. addCredsRequest->Flags = KERB_REQUEST_REMOVE_CREDENTIAL;
  237. } else {
  238. LocalFree( addCredsRequest );
  239. return ERROR_INVALID_PARAMETER;
  240. }
  241. //
  242. // enable TCB for this thread
  243. //
  244. ntStatus = ClRtlEnableThreadPrivilege( SE_TCB_PRIVILEGE, &tcbWasEnabled );
  245. if ( NT_SUCCESS( ntStatus )) {
  246. NTSTATUS privStatus;
  247. //
  248. // get handle to LSA
  249. //
  250. ntStatus = LsaConnectUntrusted( &lsaHandle );
  251. if ( NT_SUCCESS( ntStatus )) {
  252. //
  253. // get kerb package ID
  254. //
  255. RtlInitString( &packageName, MICROSOFT_KERBEROS_NAME_A );
  256. ntStatus = LsaLookupAuthenticationPackage( lsaHandle, &packageName, &packageId );
  257. if ( NT_SUCCESS( ntStatus )) {
  258. PCHAR response = NULL;
  259. ULONG responseSize;
  260. PWCHAR credStrings = (PWCHAR)( addCredsRequest + 1 );
  261. addCredsRequest->MessageType = KerbAddExtraCredentialsMessage;
  262. //
  263. // build the request by appending the strings after the
  264. // request structure and initializing the UNICODE_STRING
  265. // structs to the strings in that area.
  266. //
  267. wcscpy( credStrings, ComputerName );
  268. wcscat( credStrings, L"$" );
  269. RtlInitUnicodeString( &addCredsRequest->UserName, credStrings );
  270. credStrings = credStrings + wcslen( credStrings ) + 1;
  271. wcscpy( credStrings, DomainName );
  272. RtlInitUnicodeString( &addCredsRequest->DomainName, credStrings );
  273. if ( CredOp == NNAddCredential ) {
  274. credStrings = credStrings + wcslen( credStrings ) + 1;
  275. wcscpy( credStrings, Password );
  276. RtlInitUnicodeString( &addCredsRequest->Password, credStrings );
  277. } else {
  278. addCredsRequest->Password.Length = 0;
  279. addCredsRequest->Password.MaximumLength = 0;
  280. addCredsRequest->Password.Buffer = NULL;
  281. }
  282. //
  283. // add creds to LocalSystem
  284. //
  285. addCredsRequest->LogonId = localSystemLuid;
  286. ntStatus = LsaCallAuthenticationPackage(lsaHandle,
  287. packageId,
  288. addCredsRequest,
  289. requestSize,
  290. (PVOID *) &response,
  291. &responseSize,
  292. &subStatus);
  293. if ( NT_SUCCESS( ntStatus ) && NT_SUCCESS( subStatus )) {
  294. if ( response != NULL ) {
  295. LsaFreeReturnBuffer( response );
  296. response = NULL;
  297. }
  298. //
  299. // now add them for the NetworkService account
  300. //
  301. addCredsRequest->LogonId = networkServiceLuid;
  302. ntStatus = LsaCallAuthenticationPackage(lsaHandle,
  303. packageId,
  304. addCredsRequest,
  305. requestSize,
  306. (PVOID *) &response,
  307. &responseSize,
  308. &subStatus);
  309. if ( NT_SUCCESS( ntStatus ) && NT_SUCCESS( subStatus )) {
  310. if ( response != NULL ) {
  311. LsaFreeReturnBuffer( response );
  312. }
  313. } else {
  314. if ( NT_SUCCESS( ntStatus )) {
  315. ntStatus = subStatus;
  316. }
  317. (NetNameLogEvent)(ResourceHandle,
  318. LOG_ERROR,
  319. L"Unable to %1!ws! credentials for NetworkService "
  320. L"- status %2!08X!\n",
  321. opTypeString,
  322. ntStatus);
  323. }
  324. } // if credentials were added to LocalSystem
  325. else {
  326. if ( NT_SUCCESS( ntStatus )) {
  327. ntStatus = subStatus;
  328. }
  329. (NetNameLogEvent)(ResourceHandle,
  330. LOG_ERROR,
  331. L"Unable to %1!ws! credentials for LocalSystem "
  332. L"- status %2!08X!\n",
  333. opTypeString,
  334. ntStatus);
  335. }
  336. } // if we found the kerb package in LSA
  337. else {
  338. (NetNameLogEvent)(ResourceHandle,
  339. LOG_ERROR,
  340. L"Unable to get package ID of Kerberos package from LSA - status %1!08X!\n",
  341. ntStatus);
  342. }
  343. LsaDeregisterLogonProcess( lsaHandle );
  344. } // if an untrusted handle to LSA was obtained
  345. else {
  346. (NetNameLogEvent)(ResourceHandle,
  347. LOG_ERROR,
  348. L"Unable to get an untrusted handle to LSA - status %1!08X!\n",
  349. ntStatus);
  350. }
  351. privStatus = ClRtlRestoreThreadPrivilege( SE_TCB_PRIVILEGE, tcbWasEnabled );
  352. if ( !NT_SUCCESS( privStatus )) {
  353. (NetNameLogEvent)(ResourceHandle,
  354. LOG_ERROR,
  355. L"Failed to disable TCB privilege, "
  356. L"status %1!08X!.\n",
  357. privStatus);
  358. }
  359. } // if TCB was enabled
  360. else {
  361. (NetNameLogEvent)(ResourceHandle,
  362. LOG_ERROR,
  363. L"Failed to enable TCB privilege, status %1!08X!.\n",
  364. ntStatus);
  365. }
  366. LocalFree( addCredsRequest );
  367. return LsaNtStatusToWinError( ntStatus );
  368. } // NNCredentialOperation
  369. NET_API_STATUS
  370. AddServerName(
  371. IN RESOURCE_HANDLE ResourceHandle,
  372. IN LPWSTR ServerName,
  373. IN BOOL RemapPipeNames,
  374. IN LPWSTR TransportName,
  375. IN BOOLEAN CheckNameFirst
  376. )
  377. {
  378. SERVER_TRANSPORT_INFO_2 sti2;
  379. UCHAR netBiosName[ NETBIOS_NAME_LEN ];
  380. OEM_STRING netBiosNameString;
  381. UNICODE_STRING unicodeName;
  382. NET_API_STATUS status;
  383. NTSTATUS ntStatus;
  384. //
  385. // Convert the ServerName to an OEM string
  386. //
  387. RtlInitUnicodeString( &unicodeName, ServerName );
  388. netBiosNameString.Buffer = (PCHAR)netBiosName;
  389. netBiosNameString.MaximumLength = sizeof( netBiosName );
  390. ntStatus = RtlUpcaseUnicodeStringToOemString(
  391. &netBiosNameString,
  392. &unicodeName,
  393. FALSE
  394. );
  395. if (ntStatus != STATUS_SUCCESS) {
  396. status = RtlNtStatusToDosError(ntStatus);
  397. (NetNameLogEvent)(
  398. ResourceHandle,
  399. LOG_ERROR,
  400. L"Unable to convert name %1!ws! to an OEM string, status %2!u!\n",
  401. ServerName,
  402. status
  403. );
  404. return(status);
  405. }
  406. if (CheckNameFirst) {
  407. BOOLEAN isNameRegistered;
  408. //
  409. // Check to see if the name is already registered.
  410. //
  411. status = CheckForServerName(
  412. ResourceHandle,
  413. ServerName,
  414. &netBiosNameString,
  415. &isNameRegistered
  416. );
  417. if (status != NERR_Success) {
  418. (NetNameLogEvent)(
  419. ResourceHandle,
  420. LOG_WARNING,
  421. L"Unable to verify that server name %1!ws! does not already exist.\n",
  422. ServerName
  423. );
  424. isNameRegistered = TRUE; // just to be safe
  425. }
  426. if (isNameRegistered) {
  427. (NetNameLogEvent)(
  428. ResourceHandle,
  429. LOG_INFORMATION,
  430. L"Deleting old registration for server name %1!ws!.\n",
  431. ServerName
  432. );
  433. status = pDeleteServerName(
  434. ResourceHandle,
  435. ServerName,
  436. &netBiosNameString
  437. );
  438. if (status != NERR_Success) {
  439. if (status == ERROR_IO_PENDING) {
  440. status = ERROR_GEN_FAILURE;
  441. }
  442. return(status);
  443. }
  444. }
  445. }
  446. //
  447. // Register the name on the specified transport.
  448. //
  449. RtlZeroMemory( &sti2, sizeof(sti2) );
  450. sti2.svti2_transportname = TransportName;
  451. sti2.svti2_transportaddress = netBiosName;
  452. sti2.svti2_transportaddresslength = strlen(netBiosName);
  453. if (RemapPipeNames) {
  454. sti2.svti2_flags = SVTI2_REMAP_PIPE_NAMES;
  455. }
  456. status = NetServerTransportAddEx( NULL, 2, (LPBYTE)&sti2 );
  457. if (status != NERR_Success) {
  458. (NetNameLogEvent)(
  459. ResourceHandle,
  460. LOG_ERROR,
  461. L"Unable to add server name %1!ws! to transport %2!ws!, status %3!u!.\n",
  462. ServerName,
  463. TransportName,
  464. status
  465. );
  466. }
  467. else {
  468. (NetNameLogEvent)(
  469. ResourceHandle,
  470. LOG_INFORMATION,
  471. L"Registered server name %1!ws! on transport %2!ws!.\n",
  472. ServerName,
  473. TransportName
  474. );
  475. }
  476. return(status);
  477. } // AddServerName
  478. NET_API_STATUS
  479. DeleteServerName(
  480. IN RESOURCE_HANDLE ResourceHandle,
  481. IN LPWSTR ServerName
  482. )
  483. {
  484. NET_API_STATUS status;
  485. NTSTATUS ntStatus;
  486. UCHAR netBiosName[ NETBIOS_NAME_LEN ];
  487. OEM_STRING netBiosNameString;
  488. UNICODE_STRING unicodeName;
  489. BOOLEAN isNameRegistered;
  490. DWORD count;
  491. //
  492. // Convert the ServerName to an OEM string
  493. //
  494. RtlInitUnicodeString( &unicodeName, ServerName );
  495. netBiosNameString.Buffer = (PCHAR)netBiosName;
  496. netBiosNameString.MaximumLength = sizeof( netBiosName );
  497. ntStatus = RtlUpcaseUnicodeStringToOemString(
  498. &netBiosNameString,
  499. &unicodeName,
  500. FALSE
  501. );
  502. if (ntStatus != STATUS_SUCCESS) {
  503. status = RtlNtStatusToDosError(ntStatus);
  504. (NetNameLogEvent)(
  505. ResourceHandle,
  506. LOG_ERROR,
  507. L"Unable to convert name %1!ws! to an OEM string, status %2!u!\n",
  508. ServerName,
  509. status
  510. );
  511. return(status);
  512. }
  513. //
  514. // Delete the name
  515. //
  516. status = pDeleteServerName(
  517. ResourceHandle,
  518. ServerName,
  519. &netBiosNameString
  520. );
  521. if (status == ERROR_IO_PENDING) {
  522. status = NERR_Success;
  523. }
  524. return(status);
  525. } // DeleteServerName
  526. DWORD
  527. AddWorkstationName(
  528. IN LPWSTR WorkstationName,
  529. IN LPWSTR TransportName,
  530. IN RESOURCE_HANDLE ResourceHandle,
  531. OUT HANDLE * WorkstationNameHandle
  532. )
  533. /*++
  534. Routine Description:
  535. This function adds an alternate workstation ( <0> ) name on a netbios
  536. transport by opening a TDI address object. The name remains registered
  537. as long as the address object is open.
  538. Arguments:
  539. WorkstationName - Alternate computer name to add.
  540. TransportName - Transport to add the computer name on.
  541. Return Value:
  542. Status - The status of the operation.
  543. --*/
  544. {
  545. DWORD status;
  546. PFILE_FULL_EA_INFORMATION eaBuffer;
  547. DWORD eaLength;
  548. OBJECT_ATTRIBUTES objectAttributes;
  549. IO_STATUS_BLOCK ioStatusBlock;
  550. UNICODE_STRING transportString;
  551. DWORD i;
  552. PTA_NETBIOS_ADDRESS taAddress;
  553. UNICODE_STRING unicodeName;
  554. OEM_STRING oemName;
  555. PUCHAR nameBuffer;
  556. *WorkstationNameHandle = NULL;
  557. //
  558. // Allocate an extended attribute to hold the TDI address
  559. //
  560. eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  561. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  562. sizeof(TA_NETBIOS_ADDRESS);
  563. eaBuffer = LocalAlloc( LMEM_FIXED, eaLength);
  564. if (eaBuffer == NULL) {
  565. (NetNameLogEvent)(
  566. ResourceHandle,
  567. LOG_ERROR,
  568. L"Unable to allocate memory for name registration.\n"
  569. );
  570. return(ERROR_NOT_ENOUGH_MEMORY);
  571. }
  572. eaBuffer->NextEntryOffset = 0;
  573. eaBuffer->Flags = 0;
  574. eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  575. eaBuffer->EaValueLength = sizeof(TA_NETBIOS_ADDRESS);
  576. CopyMemory(
  577. eaBuffer->EaName,
  578. TdiTransportAddress,
  579. eaBuffer->EaNameLength+1
  580. );
  581. //
  582. // Build the TDI NetBIOS Address structure
  583. //
  584. taAddress = (PTA_NETBIOS_ADDRESS) (eaBuffer->EaName +
  585. TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  586. taAddress->TAAddressCount = 1;
  587. taAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  588. taAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  589. taAddress->Address[0].Address[0].NetbiosNameType =
  590. TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  591. //
  592. // Canonicalize the name by converting to an upper case OEM string,
  593. // padding with spaces, and ending with a 0x0.
  594. //
  595. nameBuffer = &(taAddress->Address[0].Address[0].NetbiosName[0]);
  596. oemName.Buffer = nameBuffer;
  597. oemName.Length = 0;
  598. oemName.MaximumLength = NETBIOS_NAME_LEN;
  599. RtlInitUnicodeString(&unicodeName, WorkstationName);
  600. status = RtlUpcaseUnicodeStringToOemString(
  601. &oemName,
  602. &unicodeName,
  603. FALSE
  604. );
  605. if (status != STATUS_SUCCESS) {
  606. (NetNameLogEvent)(
  607. ResourceHandle,
  608. LOG_ERROR,
  609. L"Unable to convert name %1!ws! to an OEM string, status %2!u!\n",
  610. WorkstationName,
  611. status
  612. );
  613. LocalFree(eaBuffer);
  614. return(RtlNtStatusToDosError(status));
  615. }
  616. for (i=oemName.Length; i < (NETBIOS_NAME_LEN - 1); i++) {
  617. nameBuffer[i] = 0x20;
  618. }
  619. nameBuffer[NETBIOS_NAME_LEN-1] = 0;
  620. //
  621. // Open an address object handle.
  622. //
  623. RtlInitUnicodeString(&transportString, TransportName);
  624. InitializeObjectAttributes(
  625. &objectAttributes,
  626. &transportString,
  627. OBJ_CASE_INSENSITIVE,
  628. (HANDLE) NULL,
  629. (PSECURITY_DESCRIPTOR) NULL
  630. );
  631. status = NtCreateFile(
  632. WorkstationNameHandle,
  633. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  634. &objectAttributes,
  635. &ioStatusBlock,
  636. NULL,
  637. FILE_ATTRIBUTE_NORMAL,
  638. FILE_SHARE_READ | FILE_SHARE_WRITE,
  639. FILE_OPEN_IF,
  640. 0,
  641. eaBuffer,
  642. eaLength
  643. );
  644. if (status == STATUS_SUCCESS) {
  645. status = ioStatusBlock.Status;
  646. }
  647. LocalFree(eaBuffer);
  648. status = RtlNtStatusToDosError(status);
  649. if (status != ERROR_SUCCESS) {
  650. (NetNameLogEvent)(
  651. ResourceHandle,
  652. LOG_ERROR,
  653. L"Failed to register workstation name %1!ws! on transport %2!ws!, "
  654. L"error %3!u!.\n",
  655. WorkstationName,
  656. TransportName,
  657. status
  658. );
  659. }
  660. else {
  661. (NetNameLogEvent)(
  662. ResourceHandle,
  663. LOG_INFORMATION,
  664. L"Registered workstation name %1!ws! on transport %2!ws!.\n",
  665. WorkstationName,
  666. TransportName
  667. );
  668. }
  669. return(status);
  670. } // AddWorkstationName
  671. DNS_STATUS
  672. AddDnsNames(
  673. IN PCLUS_WORKER Worker,
  674. IN LPWSTR AlternateComputerName,
  675. IN HKEY ResourceKey,
  676. IN RESOURCE_HANDLE ResourceHandle,
  677. IN PDOMAIN_ADDRESS_MAPPING DomainMapList,
  678. IN DWORD DomainMapCount,
  679. IN BOOL FailOnAnyError,
  680. OUT PULONG NumberOfDnsLists,
  681. OUT PDNS_LISTS * DnsLists,
  682. OUT PULONG NumberOfRegisteredNames
  683. )
  684. /*++
  685. Routine Description:
  686. For the given set of IP addresses and their corresponding DNS domains,
  687. build DNS records that will register the network name in the domain(s)
  688. associated with the IP address. Lists of A and PTR records are built which
  689. are used by RegisterDnsRecords to publish the name/address associations at
  690. the DNS server. If the names can't be registered now,
  691. NetNameUpdateDnsServer will attempt to register them. This is the only
  692. shot at building the lists; if this portion fails, then the resource is
  693. failed.
  694. This routine also checks for whether a DNS zone accepts dynamic
  695. updates. DnsUpdateTest will tell us if the zone is dynamic or not, and if
  696. dynamic and integrated with the DS as a secure zone, whether the caller
  697. has sufficient permission to modify the entry.
  698. For non-dynamic zones, Netbios ends up being the only mechanism by which a
  699. name gets registered and therefore, DNS registration failures are not
  700. fatal unless the RequireDNS property is set to true.
  701. If the zone is dynamic but the caller lacks sufficient permission, we view
  702. that as DNS having precedence over Netbios. In that case, the resource is
  703. failed.
  704. Arguments:
  705. Worker - used to check if we should terminate early
  706. AlternateComputerName - NetBIOS network name to be registered
  707. ResourceKey - used to log events to the system event log
  708. ResourceHandle - for logging to the cluster log
  709. DomainMapList - list of IP address domain names pairs for registration
  710. DomainMapCount - # of entries in DomainMapList
  711. FailOnAnyError - used to enforce RequireDNS; true if we should bail on any
  712. error
  713. NumberOfDnsLists - pointer to location of final count of entries in DnsLists
  714. DnsLists - array of lists that contain A and PTR listheads
  715. NumberOfRegisteredNames - pointer to location of final count of names that
  716. actually got registered
  717. Return Value:
  718. DNS_STATUS indicating whether it worked or not. If the DNS lists couldn't
  719. be built, always return an error.
  720. --*/
  721. {
  722. LPWSTR fqNameARec = NULL;
  723. LPWSTR fqNamePTRRec = NULL;
  724. DWORD fqNameLength;
  725. DWORD listheadFreeEntries = 0;
  726. DWORD listheadCount = 0;
  727. PDNS_LISTS dnsLists = NULL;
  728. DWORD mapIndex;
  729. DWORD index;
  730. DNS_STATUS dnsStatus = DNS_ERROR_RCODE_NO_ERROR;
  731. DNS_STATUS ptrRecStatus;
  732. PDNS_RECORD PTRRecord;
  733. PDNS_RECORD ARecord;
  734. LPWSTR PTRName = NULL;
  735. BOOL ARecTimeout;
  736. BOOL PTRRecTimeout;
  737. //
  738. // run through the list of domain map structs and register the names where
  739. // appopriate
  740. //
  741. for ( mapIndex = 0; mapIndex < DomainMapCount; ++mapIndex ) {
  742. if ( ClusWorkerCheckTerminate( Worker )) {
  743. dnsStatus = ERROR_OPERATION_ABORTED;
  744. goto error_exit;
  745. }
  746. ASSERT( DomainMapList[ mapIndex ].DomainName != NULL );
  747. //
  748. // create the fully qualified DNS name and make a copy for the PTR
  749. // records. DnsRecordListFree operates in a way that makes it
  750. // difficult to use the same buffer multiple times. It is easier to
  751. // allocate separate buffers for everything and let DnsRecordListFree
  752. // clean up.
  753. //
  754. fqNameLength = (wcslen( DomainMapList[ mapIndex ].DomainName ) +
  755. wcslen( AlternateComputerName ) +
  756. 2 // one for "." and one for null
  757. )
  758. * sizeof( WCHAR );
  759. fqNameARec = LocalAlloc( LMEM_FIXED, fqNameLength );
  760. fqNamePTRRec = LocalAlloc( LMEM_FIXED, fqNameLength );
  761. if ( fqNameARec == NULL || fqNamePTRRec == NULL ) {
  762. dnsStatus = GetLastError();
  763. (NetNameLogEvent)(ResourceHandle,
  764. LOG_ERROR,
  765. L"Can't allocate memory for DNS name for address %1!ws!, "
  766. L"status %2!u!.\n",
  767. DomainMapList[ mapIndex ].IpAddress,
  768. dnsStatus);
  769. goto error_exit;
  770. }
  771. wcscpy( fqNameARec, AlternateComputerName );
  772. wcscat( fqNameARec, L"." );
  773. wcscat( fqNameARec, DomainMapList[ mapIndex ].DomainName );
  774. _wcslwr( fqNameARec );
  775. wcscpy( fqNamePTRRec, fqNameARec );
  776. //
  777. // see if this domain is updatable.
  778. //
  779. ARecTimeout = FALSE;
  780. dnsStatus = DnsUpdateTest(NULL,
  781. fqNameARec,
  782. 0,
  783. DomainMapList[ mapIndex ].DnsServerList);
  784. #if DBG_DNSLIST
  785. {
  786. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  787. struct in_addr addr;
  788. addr.s_addr = DomainMapList[ mapIndex ].DnsServerList->AddrArray[0];
  789. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  790. _snwprintf(buf, COUNT_OF( buf ) - 1,
  791. L"AddDnsNames UPDATETEST: %ws on %.32ws (%hs) returned %u\n",
  792. fqNameARec,
  793. DomainMapList[ mapIndex ].ConnectoidName,
  794. inet_ntoa( addr ),
  795. dnsStatus);
  796. OutputDebugStringW( buf );
  797. }
  798. #endif
  799. if ( dnsStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  800. //
  801. // zone does not accept dynamic updates.
  802. //
  803. (NetNameLogEvent)(ResourceHandle,
  804. LOG_INFORMATION,
  805. L"%1!ws! does not accept dynamic DNS registration updates over "
  806. L"adapter '%2!ws!'.\n",
  807. DomainMapList[ mapIndex ].DomainName,
  808. DomainMapList[ mapIndex ].ConnectoidName);
  809. //
  810. // by freeing the name storage, we'll never to be able to register
  811. // the name. On the other hand, if the zone was changed to be
  812. // dynamic while the name was online, the admin would have to wait
  813. // 20 minutes before we would retry the registration. I suspect
  814. // that cycling the name would be preferred.
  815. //
  816. LocalFree( fqNameARec );
  817. LocalFree( fqNamePTRRec );
  818. fqNameARec = NULL;
  819. fqNamePTRRec = NULL;
  820. if ( FailOnAnyError ) {
  821. goto error_exit;
  822. } else {
  823. continue;
  824. }
  825. } else if ( dnsStatus == DNS_ERROR_RCODE_REFUSED ) {
  826. //
  827. // secure zone and we don't have credentials to change the
  828. // name. fail the resource.
  829. //
  830. (NetNameLogEvent)(ResourceHandle,
  831. LOG_WARNING,
  832. L"%1!ws! is a secure zone and has refused the registration of "
  833. L"%2!ws! over adapter '%3!ws!'.\n",
  834. DomainMapList[ mapIndex ].DomainName,
  835. fqNameARec,
  836. DomainMapList[ mapIndex ].ConnectoidName);
  837. LogDnsFailureToEventLog(ResourceKey,
  838. fqNameARec,
  839. AlternateComputerName,
  840. dnsStatus,
  841. DomainMapList[ mapIndex ].ConnectoidName);
  842. if ( FailOnAnyError ) {
  843. goto error_exit;
  844. } else {
  845. continue;
  846. }
  847. } else if ( dnsStatus == ERROR_TIMEOUT ) {
  848. //
  849. // couldn't contact a server so we're not sure if it allows
  850. // updates or not. build the records anyway and we'll deal with it
  851. // during the query period
  852. //
  853. if ( FailOnAnyError ) {
  854. goto error_exit;
  855. } else {
  856. ARecTimeout = TRUE;
  857. }
  858. } else if ( dnsStatus == DNS_ERROR_RCODE_YXDOMAIN ) {
  859. //
  860. // the record we asked about in DnsUpdateTest is not there but it
  861. // can be dynamically registered.
  862. //
  863. } else if ( dnsStatus != ERROR_SUCCESS ) {
  864. //
  865. // bad juju but only fail to bring the name online if DNS is
  866. // required. If any one of the registrations is successful, then
  867. // we consider that goodness.
  868. //
  869. (NetNameLogEvent)(ResourceHandle,
  870. LOG_WARNING,
  871. L"Testing %1!ws! for dynamic updates failed over adapter "
  872. L"'%3!ws!', status %2!u!.\n",
  873. fqNameARec,
  874. dnsStatus,
  875. DomainMapList[ mapIndex ].ConnectoidName);
  876. LogDnsFailureToEventLog(ResourceKey,
  877. fqNameARec,
  878. AlternateComputerName,
  879. dnsStatus,
  880. DomainMapList[ mapIndex ].ConnectoidName);
  881. if ( FailOnAnyError ) {
  882. goto error_exit;
  883. } else {
  884. continue;
  885. }
  886. }
  887. //
  888. // allocate memory to hold an array of DNS list data for the A and PTR
  889. // records. Separate lists are maintained for the different record types.
  890. //
  891. if (listheadFreeEntries == 0) {
  892. dnsStatus = GrowBlock((PCHAR *)&dnsLists,
  893. listheadCount,
  894. sizeof( *dnsLists ),
  895. &listheadFreeEntries);
  896. if ( dnsStatus != ERROR_SUCCESS) {
  897. (NetNameLogEvent)(ResourceHandle,
  898. LOG_ERROR,
  899. L"Unable to allocate memory (1).\n");
  900. goto error_exit;
  901. }
  902. }
  903. //
  904. // if the FQDN is already in use in another DNS record and the
  905. // connectoid names for the two FQDNs we're adding are the same, then
  906. // we have to add this new IP address entry to the existing DNS list.
  907. //
  908. for ( index = 0; index < listheadCount; ++index ) {
  909. if ( ClRtlStrICmp( dnsLists[index].A_RRSet.pFirstRR->pName,
  910. fqNameARec
  911. ) == 0 )
  912. {
  913. #if DBG_DNSLIST
  914. {
  915. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 50];
  916. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  917. _snwprintf( buf, COUNT_OF( buf ) - 1,
  918. L"DNS NAME MATCH w/ index %d: %ws\n",
  919. index, fqNameARec );
  920. OutputDebugStringW(buf);
  921. }
  922. #endif
  923. //
  924. // FQDNs are equal; how about the connectoids?
  925. //
  926. if (ClRtlStrICmp(DomainMapList[ mapIndex ].ConnectoidName,
  927. dnsLists[index].ConnectoidName )
  928. ==
  929. 0 )
  930. {
  931. break;
  932. }
  933. }
  934. }
  935. #if DBG_DNSLIST
  936. {
  937. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 80];
  938. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  939. _snwprintf(buf, COUNT_OF( buf ) - 1,
  940. L"ADDING (%ws, %ws, %.32ws) to dnsList[%d], lhCount = %d, DomMapList index = %d\n",
  941. fqNameARec,
  942. DomainMapList[mapIndex].IpAddress,
  943. DomainMapList[mapIndex].ConnectoidName,
  944. index,
  945. listheadCount,
  946. mapIndex );
  947. OutputDebugStringW(buf);
  948. }
  949. #endif
  950. if ( index == listheadCount ) {
  951. //
  952. // it's not, so init a new pair of listheads and adjust the
  953. // distinct listhead count
  954. //
  955. DNS_RRSET_INIT( dnsLists[ index ].A_RRSet );
  956. DNS_RRSET_INIT( dnsLists[ index ].PTR_RRSet );
  957. ++listheadCount;
  958. --listheadFreeEntries;
  959. }
  960. dnsLists[ index ].UpdateTestTimeout = ARecTimeout;
  961. if ( ClusWorkerCheckTerminate( Worker )) {
  962. dnsStatus = ERROR_OPERATION_ABORTED;
  963. goto error_exit;
  964. }
  965. //
  966. // build the PTR records. Per DNS dev, this should be considered a
  967. // warning instead of a failure. We note the failures and bring the
  968. // name online.
  969. //
  970. PTRName = BuildUnicodeReverseName( DomainMapList[ mapIndex ].IpAddress );
  971. if ( PTRName != NULL ) {
  972. PTRRecTimeout = FALSE;
  973. ptrRecStatus = DnsUpdateTest(NULL,
  974. PTRName,
  975. 0,
  976. DomainMapList[ mapIndex ].DnsServerList);
  977. #if DBG_DNSLIST
  978. {
  979. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  980. struct in_addr addr;
  981. addr.s_addr = DomainMapList[ mapIndex ].DnsServerList->AddrArray[0];
  982. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  983. _snwprintf(buf, COUNT_OF( buf ) - 1,
  984. L"AddDnsNames UPDATETEST: %ws on %.32ws (%hs) returned %u\n",
  985. PTRName,
  986. DomainMapList[ mapIndex ].ConnectoidName,
  987. inet_ntoa( addr ),
  988. ptrRecStatus);
  989. OutputDebugStringW( buf );
  990. }
  991. #endif
  992. if ( ptrRecStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  993. //
  994. // zone does not accept dynamic updates.
  995. //
  996. (NetNameLogEvent)(ResourceHandle,
  997. LOG_INFORMATION,
  998. L"The zone for %1!ws! does not accept dynamic DNS "
  999. L"registration updates over adapter '%2!ws!'.\n",
  1000. PTRName,
  1001. DomainMapList[ mapIndex ].ConnectoidName);
  1002. LocalFree( PTRName );
  1003. LocalFree( fqNamePTRRec );
  1004. PTRName = NULL;
  1005. fqNamePTRRec = NULL;
  1006. } else if ( ptrRecStatus == DNS_ERROR_RCODE_REFUSED ) {
  1007. //
  1008. // secure zone and we don't have credentials to change the
  1009. // name. fail the resource.
  1010. //
  1011. (NetNameLogEvent)(ResourceHandle,
  1012. LOG_WARNING,
  1013. L"%1!ws! is a secure zone and has refused the registration of "
  1014. L"%2!ws! over adapter '%3!ws!'.\n",
  1015. DomainMapList[ mapIndex ].DomainName,
  1016. PTRName,
  1017. DomainMapList[ mapIndex ].ConnectoidName);
  1018. } else if ( ptrRecStatus == ERROR_TIMEOUT ) {
  1019. //
  1020. // couldn't contact a server so we're not sure if it allows
  1021. // updates or not. build the records anyway and we'll deal
  1022. // with it during the query period
  1023. //
  1024. (NetNameLogEvent)(ResourceHandle,
  1025. LOG_WARNING,
  1026. L"The server for %1!ws! could not be contacted over adapter '%2!ws!' "
  1027. L"to determine whether it accepts DNS registration updates. "
  1028. L"Retrying at a later time.\n",
  1029. PTRName,
  1030. DomainMapList[ mapIndex ].ConnectoidName);
  1031. PTRRecTimeout = TRUE;
  1032. ptrRecStatus = ERROR_SUCCESS;
  1033. } else if ( ptrRecStatus == DNS_ERROR_RCODE_YXDOMAIN ) {
  1034. //
  1035. // the record we asked about in DnsUpdateTest is not there but
  1036. // it can be dynamically registered.
  1037. //
  1038. ptrRecStatus = ERROR_SUCCESS;
  1039. } else if ( ptrRecStatus != ERROR_SUCCESS ) {
  1040. //
  1041. // bad juju - log the error but don't fail the name since
  1042. // these are just lowly PTR records.
  1043. //
  1044. (NetNameLogEvent)(ResourceHandle,
  1045. LOG_WARNING,
  1046. L"Testing %1!ws! for dynamic updates over adapter '%3!ws!' "
  1047. L"failed, status %2!u!.\n",
  1048. PTRName,
  1049. ptrRecStatus,
  1050. DomainMapList[ mapIndex ].ConnectoidName);
  1051. }
  1052. if ( ptrRecStatus == ERROR_SUCCESS ) {
  1053. //
  1054. // build the PTR rec
  1055. //
  1056. PTRRecord = DnsRecordBuild_W(&dnsLists[ index ].PTR_RRSet,
  1057. PTRName,
  1058. DNS_TYPE_PTR,
  1059. TRUE,
  1060. 0,
  1061. 1,
  1062. &fqNamePTRRec);
  1063. if (PTRRecord != NULL) {
  1064. //
  1065. // BUGBUG - DNS doesn't free the owner and data fields for
  1066. // us in DnsRecordListFree. Set these flags until we sort
  1067. // out what is happening
  1068. //
  1069. SET_FREE_OWNER( PTRRecord );
  1070. SET_FREE_DATA( PTRRecord );
  1071. //
  1072. // set the time to live so clients don't beat up the
  1073. // server
  1074. //
  1075. PTRRecord->dwTtl = 20 * 60; // 20 minutes
  1076. //
  1077. // "consume" the pointers to name strings. If we got this
  1078. // far, then these pointers have been captured in the DNS
  1079. // record and will be freed when the record is freed by
  1080. // DnsRecordListFree.
  1081. //
  1082. PTRName = NULL;
  1083. fqNamePTRRec = NULL;
  1084. }
  1085. else {
  1086. (NetNameLogEvent)(ResourceHandle,
  1087. LOG_WARNING,
  1088. L"Error building PTR record for owner %1!ws!, addr %2!ws!, status %3!u!\n",
  1089. fqNameARec,
  1090. DomainMapList[ mapIndex ].IpAddress,
  1091. ptrRecStatus = GetLastError());
  1092. LocalFree( PTRName );
  1093. LocalFree( fqNamePTRRec );
  1094. PTRName = NULL;
  1095. fqNamePTRRec = NULL;
  1096. }
  1097. } // if ptrRecStatus == ERROR_SUCCESS
  1098. } // if PTRName != NULL
  1099. else {
  1100. ptrRecStatus = GetLastError();
  1101. (NetNameLogEvent)(ResourceHandle,
  1102. LOG_ERROR,
  1103. L"Error building PTR name for owner %1!ws!, addr %2!ws!, status %3!u!\n",
  1104. fqNameARec,
  1105. DomainMapList[ mapIndex ].IpAddress,
  1106. ptrRecStatus);
  1107. LocalFree( fqNamePTRRec );
  1108. fqNamePTRRec = NULL;
  1109. }
  1110. //
  1111. // build the A rec
  1112. //
  1113. ARecord = DnsRecordBuild_W(&dnsLists[ index ].A_RRSet,
  1114. fqNameARec,
  1115. DNS_TYPE_A,
  1116. TRUE,
  1117. 0,
  1118. 1,
  1119. &DomainMapList[ mapIndex ].IpAddress);
  1120. if ( ARecord == NULL ) {
  1121. (NetNameLogEvent)(ResourceHandle,
  1122. LOG_ERROR,
  1123. L"Error building A rec for owner %1!ws!, addr %2!ws!, status %3!u!\n",
  1124. fqNameARec,
  1125. DomainMapList[ mapIndex ].IpAddress,
  1126. dnsStatus = GetLastError());
  1127. goto error_exit;
  1128. }
  1129. //
  1130. // set the time to live so clients don't beat up the server
  1131. //
  1132. ARecord->dwTtl = 20 * 60; // 20 minutes
  1133. //
  1134. // BUGBUG - DNS doesn't free the owner and data fields for us in
  1135. // DnsRecordListFree. Set these flags until we sort out what is
  1136. // happening
  1137. //
  1138. SET_FREE_OWNER( ARecord );
  1139. SET_FREE_DATA( ARecord );
  1140. //
  1141. // "consume" this pointer as well
  1142. //
  1143. fqNameARec = NULL;
  1144. //
  1145. // capture the DNS server list and connectoid name for this entry
  1146. //
  1147. dnsLists[ index ].DnsServerList = DomainMapList[ mapIndex ].DnsServerList;
  1148. DomainMapList[ mapIndex ].DnsServerList = NULL;
  1149. dnsLists[ index ].ConnectoidName = ResUtilDupString( DomainMapList[ mapIndex ].ConnectoidName );
  1150. if ( dnsLists[ index ].ConnectoidName == NULL ) {
  1151. (NetNameLogEvent)(ResourceHandle,
  1152. LOG_ERROR,
  1153. L"Unable to allocate memory .\n");
  1154. goto error_exit;
  1155. }
  1156. } // end of for each entry in DomainMapCount
  1157. //
  1158. // update the DNS server with the records that were just created
  1159. //
  1160. *NumberOfRegisteredNames = 0;
  1161. for( index = 0; index < listheadCount; ++index ) {
  1162. if ( ClusWorkerCheckTerminate( Worker )) {
  1163. dnsStatus = ERROR_OPERATION_ABORTED;
  1164. goto error_exit;
  1165. }
  1166. //
  1167. // if we made it this far, we know that the server is dynamic or we
  1168. // timed out trying to figure that out. For the timeout case, we'll
  1169. // assume that the servers are dynamic and let NetNameUpdateDnsServer
  1170. // discover otherwise.
  1171. //
  1172. dnsLists[ index ].ForwardZoneIsDynamic = TRUE;
  1173. dnsLists[ index ].ReverseZoneIsDynamic = TRUE;
  1174. dnsStatus = RegisterDnsRecords(&dnsLists[ index ],
  1175. AlternateComputerName,
  1176. ResourceKey,
  1177. ResourceHandle,
  1178. TRUE, /* LogRegistration */
  1179. NumberOfRegisteredNames);
  1180. if ( dnsStatus != ERROR_SUCCESS && FailOnAnyError ) {
  1181. goto error_exit;
  1182. }
  1183. }
  1184. *NumberOfDnsLists = listheadCount;
  1185. *DnsLists = dnsLists;
  1186. return dnsStatus;
  1187. error_exit:
  1188. if ( dnsLists != NULL ) {
  1189. while ( listheadCount-- ) {
  1190. DnsRecordListFree(
  1191. dnsLists[listheadCount].PTR_RRSet.pFirstRR,
  1192. DnsFreeRecordListDeep );
  1193. DnsRecordListFree(
  1194. dnsLists[listheadCount].A_RRSet.pFirstRR,
  1195. DnsFreeRecordListDeep );
  1196. if ( dnsLists[listheadCount].DnsServerList != NULL ) {
  1197. LocalFree( dnsLists[listheadCount].DnsServerList );
  1198. }
  1199. if ( dnsLists[listheadCount].ConnectoidName != NULL ) {
  1200. LocalFree( dnsLists[listheadCount].ConnectoidName );
  1201. }
  1202. }
  1203. LocalFree( dnsLists );
  1204. }
  1205. if ( PTRName != NULL ) {
  1206. LocalFree( PTRName );
  1207. }
  1208. if ( fqNamePTRRec != NULL ) {
  1209. LocalFree( fqNamePTRRec );
  1210. }
  1211. if ( fqNameARec != NULL ) {
  1212. LocalFree( fqNameARec );
  1213. }
  1214. *NumberOfDnsLists = 0;
  1215. *NumberOfRegisteredNames = 0;
  1216. *DnsLists = NULL;
  1217. return dnsStatus;
  1218. } // AddDnsNames
  1219. VOID
  1220. LogDnsFailureToEventLog(
  1221. IN HKEY ResourceKey,
  1222. IN LPWSTR DnsName,
  1223. IN LPWSTR ResourceName,
  1224. IN DWORD Status,
  1225. IN LPWSTR ConnectoidName
  1226. )
  1227. /*++
  1228. Routine Description:
  1229. Log dns name failures to the event log
  1230. Arguments:
  1231. DnsName - FQ DNS name that failed to be registered
  1232. ResourceName - associated resource
  1233. Status - status returned by DNSAPI
  1234. Return Value:
  1235. NONE
  1236. --*/
  1237. {
  1238. LPWSTR msgBuff;
  1239. DWORD msgBytes;
  1240. msgBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1241. FORMAT_MESSAGE_FROM_SYSTEM,
  1242. NULL,
  1243. Status,
  1244. 0,
  1245. (LPWSTR)&msgBuff,
  1246. 0,
  1247. NULL);
  1248. if ( msgBytes > 0 ) {
  1249. ClusResLogSystemEventByKeyData3(ResourceKey,
  1250. LOG_UNUSUAL,
  1251. RES_NETNAME_DNS_REGISTRATION_MISSING,
  1252. sizeof( Status ),
  1253. &Status,
  1254. DnsName,
  1255. msgBuff,
  1256. ConnectoidName);
  1257. LocalFree( msgBuff );
  1258. }
  1259. } // LogDnsFailureToEventLog
  1260. //
  1261. // Exported Routines
  1262. //
  1263. LPWSTR
  1264. BuildUnicodeReverseName(
  1265. IN LPWSTR IpAddress
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. Given an Ip address, build a reverse DNS name for publishing as
  1270. a PTR record
  1271. Arguments:
  1272. IpAddress - unicode version of dotted decimal IP address
  1273. Return Value:
  1274. address of pointer to buffer with reverse name. Null if an error occured
  1275. --*/
  1276. {
  1277. ULONG ipAddress;
  1278. PCHAR ansiReverseName;
  1279. PCHAR pAnsi;
  1280. ULONG ansiNameLength;
  1281. PWCHAR unicodeReverseName;
  1282. PWCHAR pUni;
  1283. CHAR ansiIpAddress[ 64 ];
  1284. //
  1285. // allocate enough space for both the ANSI and Unicode versions
  1286. //
  1287. ansiReverseName = LocalAlloc( LMEM_FIXED, DNS_MAX_IP4_REVERSE_NAME_BUFFER_LENGTH );
  1288. if ( ansiReverseName == NULL ) {
  1289. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1290. return NULL;
  1291. }
  1292. unicodeReverseName = LocalAlloc( LMEM_FIXED, DNS_MAX_IP4_REVERSE_NAME_BUFFER_LENGTH * sizeof(WCHAR));
  1293. if ( unicodeReverseName == NULL ) {
  1294. LocalFree( ansiReverseName );
  1295. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1296. return NULL;
  1297. }
  1298. //
  1299. // convert to ansi, have DNS create the name, and then convert back to
  1300. // unicode
  1301. //
  1302. wcstombs( ansiIpAddress, IpAddress, sizeof( ansiIpAddress ));
  1303. ipAddress = inet_addr( ansiIpAddress );
  1304. DnsWriteReverseNameStringForIpAddress( ansiReverseName, ipAddress );
  1305. //
  1306. // convert to Unicode
  1307. //
  1308. ansiNameLength = strlen( ansiReverseName ) + 1;
  1309. mbstowcs( unicodeReverseName, ansiReverseName, ansiNameLength );
  1310. LocalFree( ansiReverseName );
  1311. return unicodeReverseName;
  1312. } // BuildUnicodeReverseName
  1313. DWORD
  1314. RegisterDnsRecords(
  1315. IN PDNS_LISTS DnsLists,
  1316. IN LPWSTR NetworkName,
  1317. IN HKEY ResourceKey,
  1318. IN RESOURCE_HANDLE ResourceHandle,
  1319. IN BOOL LogRegistration,
  1320. OUT PULONG NumberOfRegisteredNames
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. Register the A and PTR records specified in DnsLists with the DNS server.
  1325. Arguments:
  1326. DnsLists - pointer to the list of structs holding the record sets to
  1327. be registered
  1328. NetworkName - host name portion of name being registered
  1329. ResourceKey - used to log events to the event viewer
  1330. ResourceHandle - used to log messages in the cluster log
  1331. LogRegistration - TRUE if the successful registration should be logged to the cluster log
  1332. NumberOfRegisteredNames - pointer that receives count of successful registrations
  1333. Return Value:
  1334. None
  1335. --*/
  1336. {
  1337. DNS_STATUS ARecStatus;
  1338. DNS_STATUS PTRRecStatus;
  1339. DNS_STATUS dnsStatus;
  1340. PDNS_RECORD dnsRecord;
  1341. PDNS_RECORD nextDnsRecord;
  1342. ULONG registeredCount = 0;
  1343. //
  1344. // check the status of DnsUpdateTest on this name. If we've previously
  1345. // timed out, then try again.
  1346. //
  1347. if ( DnsLists->UpdateTestTimeout ) {
  1348. DnsLists->UpdateTestTimeout = FALSE;
  1349. dnsStatus = DnsUpdateTest(NULL,
  1350. DnsLists->A_RRSet.pFirstRR->pName,
  1351. 0,
  1352. DnsLists->DnsServerList);
  1353. #if DBG_DNSLIST
  1354. {
  1355. WCHAR buf[DNS_MAX_NAME_BUFFER_LENGTH + 64];
  1356. struct in_addr addr;
  1357. addr.s_addr = DnsLists->DnsServerList->AddrArray[0];
  1358. buf[ COUNT_OF( buf ) - 1 ] = UNICODE_NULL;
  1359. _snwprintf(buf, COUNT_OF( buf ) - 1,
  1360. L"RegisterDnsRecords UPDATETEST: %ws on %.32ws (%hs) returned %u\n",
  1361. DnsLists->A_RRSet.pFirstRR->pName,
  1362. DnsLists->ConnectoidName,
  1363. inet_ntoa( addr ),
  1364. dnsStatus);
  1365. OutputDebugStringW( buf );
  1366. }
  1367. #endif
  1368. if ( dnsStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  1369. //
  1370. // zone does not accept dynamic updates. Invalidate this entry
  1371. //
  1372. (NetNameLogEvent)(ResourceHandle,
  1373. LOG_INFORMATION,
  1374. L"%1!ws! does not accept dynamic DNS registration updates over "
  1375. L"adapter '%2!ws!'.\n",
  1376. DnsLists->A_RRSet.pFirstRR->pName,
  1377. DnsLists->ConnectoidName);
  1378. DnsLists->ForwardZoneIsDynamic = FALSE;
  1379. return dnsStatus;
  1380. } else if ( dnsStatus == DNS_ERROR_RCODE_REFUSED ) {
  1381. //
  1382. // secure zone and we don't have credentials to change the
  1383. // name. fail the resource.
  1384. //
  1385. (NetNameLogEvent)(ResourceHandle,
  1386. LOG_WARNING,
  1387. L"The registration of %1!ws! in a secure zone was refused "
  1388. L"because the record was already registered but owned by a "
  1389. L"different user.\n",
  1390. DnsLists->A_RRSet.pFirstRR->pName);
  1391. if (!DnsLists->AErrorLogged ||
  1392. dnsStatus != DnsLists->LastARecQueryStatus ) {
  1393. LogDnsFailureToEventLog(ResourceKey,
  1394. DnsLists->A_RRSet.pFirstRR->pName,
  1395. NetworkName,
  1396. dnsStatus,
  1397. DnsLists->ConnectoidName);
  1398. DnsLists->AErrorLogged = TRUE;
  1399. }
  1400. DnsLists->LastARecQueryStatus = dnsStatus;
  1401. return dnsStatus;
  1402. } else if ( dnsStatus == ERROR_TIMEOUT ) {
  1403. //
  1404. // couldn't contact a server so we're not sure if it allows
  1405. // updates or not.
  1406. //
  1407. (NetNameLogEvent)(ResourceHandle,
  1408. LOG_WARNING,
  1409. L"The server for %1!ws! could not be contacted over adapter "
  1410. L"'%2!ws!' to determine whether it accepts DNS registration "
  1411. L"updates. Retrying at a later time.\n",
  1412. DnsLists->A_RRSet.pFirstRR->pName,
  1413. DnsLists->ConnectoidName);
  1414. if (!DnsLists->AErrorLogged ) {
  1415. LogDnsFailureToEventLog(ResourceKey,
  1416. DnsLists->A_RRSet.pFirstRR->pName,
  1417. NetworkName,
  1418. dnsStatus,
  1419. DnsLists->ConnectoidName);
  1420. DnsLists->AErrorLogged = TRUE;
  1421. }
  1422. DnsLists->UpdateTestTimeout = TRUE;
  1423. return dnsStatus;
  1424. } else if ( dnsStatus == DNS_ERROR_RCODE_YXDOMAIN ) {
  1425. //
  1426. // the record we asked about in DnsUpdateTest is not there but it
  1427. // can be dynamically registered.
  1428. //
  1429. } else if ( dnsStatus != ERROR_SUCCESS ) {
  1430. //
  1431. // bad juju
  1432. //
  1433. (NetNameLogEvent)(ResourceHandle,
  1434. LOG_WARNING,
  1435. L"Testing %1!ws! for dynamic updates failed over adapter "
  1436. L"'%3!ws!', status %2!u!.\n",
  1437. DnsLists->A_RRSet.pFirstRR->pName,
  1438. dnsStatus,
  1439. DnsLists->ConnectoidName);
  1440. if (!DnsLists->AErrorLogged ||
  1441. dnsStatus != DnsLists->LastARecQueryStatus ) {
  1442. LogDnsFailureToEventLog(ResourceKey,
  1443. DnsLists->A_RRSet.pFirstRR->pName,
  1444. NetworkName,
  1445. dnsStatus,
  1446. DnsLists->ConnectoidName);
  1447. DnsLists->AErrorLogged = TRUE;
  1448. }
  1449. DnsLists->LastARecQueryStatus = dnsStatus;
  1450. return dnsStatus;
  1451. }
  1452. //
  1453. // since we previously timed out but (at this point) are going to
  1454. // register the records, adjust the logging flag so we get this time
  1455. // recorded.
  1456. //
  1457. LogRegistration = TRUE;
  1458. } // end if the update test had previously timed out
  1459. #if DBG
  1460. (NetNameLogEvent)(ResourceHandle,
  1461. LOG_INFORMATION,
  1462. L"Registering %1!ws! over '%2!ws!'\n",
  1463. DnsLists->A_RRSet.pFirstRR->pName,
  1464. DnsLists->ConnectoidName);
  1465. #endif
  1466. //
  1467. // register the A Recs
  1468. //
  1469. ARecStatus = DnsReplaceRecordSetW(DnsLists->A_RRSet.pFirstRR,
  1470. DNS_UPDATE_SECURITY_USE_DEFAULT,
  1471. NULL,
  1472. DnsLists->DnsServerList,
  1473. NULL);
  1474. if ( ARecStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  1475. ++registeredCount;
  1476. DnsLists->AErrorLogged = FALSE;
  1477. if ( LogRegistration ) {
  1478. dnsRecord = DnsLists->A_RRSet.pFirstRR;
  1479. while ( dnsRecord != NULL ) {
  1480. struct in_addr ipAddress;
  1481. ipAddress.s_addr = dnsRecord->Data.A.IpAddress;
  1482. (NetNameLogEvent)(ResourceHandle,
  1483. LOG_INFORMATION,
  1484. L"Registered DNS name %1!ws! with IP Address %2!hs! "
  1485. L"over adapter '%3!ws!'.\n",
  1486. dnsRecord->pName,
  1487. inet_ntoa( ipAddress ),
  1488. DnsLists->ConnectoidName);
  1489. dnsRecord = dnsRecord->pNext;
  1490. }
  1491. }
  1492. } else {
  1493. //
  1494. // it failed. log an error to the cluster log and change the worker
  1495. // thread polling period. If we haven't logged an event before or the
  1496. // error is different from the previous error, log it in the event log
  1497. //
  1498. if ( ARecStatus == ERROR_TIMEOUT ) {
  1499. (NetNameLogEvent)(ResourceHandle,
  1500. LOG_WARNING,
  1501. L"The DNS server couldn't be contacted to update the registration "
  1502. L"for %1!ws!. Retrying at a later time.\n",
  1503. DnsLists->A_RRSet.pFirstRR->pName);
  1504. }
  1505. else {
  1506. (NetNameLogEvent)(ResourceHandle,
  1507. LOG_ERROR,
  1508. L"Failed to register DNS A records for owner %1!ws! over "
  1509. L"adapter '%3!ws!', status %2!u!\n",
  1510. DnsLists->A_RRSet.pFirstRR->pName,
  1511. ARecStatus,
  1512. DnsLists->ConnectoidName);
  1513. }
  1514. NetNameWorkerCheckPeriod = NETNAME_WORKER_PROBLEM_CHECK_PERIOD;
  1515. if (!DnsLists->AErrorLogged ||
  1516. ARecStatus != DnsLists->LastARecQueryStatus ) {
  1517. LogDnsFailureToEventLog(ResourceKey,
  1518. DnsLists->A_RRSet.pFirstRR->pName,
  1519. NetworkName,
  1520. ARecStatus,
  1521. DnsLists->ConnectoidName);
  1522. DnsLists->AErrorLogged = TRUE;
  1523. }
  1524. }
  1525. //
  1526. // Record the status of the registration in the list for this
  1527. // owner. NetnameLooksAlive will check this value to determine the health
  1528. // of this set of registrations. Use interlocked to co-ordinate with
  1529. // Is/LooksAlive.
  1530. //
  1531. InterlockedExchange( &DnsLists->LastARecQueryStatus, ARecStatus );
  1532. //
  1533. // don't bother with PTR recs if bad juju happened with the A recs. we'll
  1534. // try to register them the next time the DNS check thread runs
  1535. //
  1536. if ( ARecStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  1537. //
  1538. // dynamic DNS requires that the pName must be the same for a given
  1539. // set of records in an RRSET. The pName for a set of PTR records will
  1540. // always be different. Maintaining a huge pile of RRSets, one per PTR
  1541. // record is ridiculous (or at least I thought so when I orginally
  1542. // wrote this; in hind sight, this was a bad decision - charlwi).
  1543. //
  1544. // AddDnsNames linked all these recs together. Now we have to register
  1545. // them one at time by remembering the link, breaking it, registering,
  1546. // restoring the link and moving on to the next record.
  1547. //
  1548. // The ErrorLogged logic is broken since we don't keep the status for
  1549. // each (separate) registration. It's an approximation at best.
  1550. //
  1551. // In addition, it is possible for the server to accept A records
  1552. // dynamically but disallow PTR records hence the check to see if we
  1553. // have records to register is up front.
  1554. //
  1555. // Finally, we use ModifyRecordsInSet instead of ReplaceRecordSet due
  1556. // to the organization of the PTR RRSET. When two names map to the
  1557. // same IP address, we have identical reverse addr strings in more
  1558. // than one DNS_LIST entry. If ReplaceRecordSet were used instead, it
  1559. // would delete all but one of the reverse address mappings. In hind
  1560. // sight, each DNS_LIST entry should have hosted either an A or PTR
  1561. // RRSet but not both.
  1562. //
  1563. dnsRecord = DnsLists->PTR_RRSet.pFirstRR;
  1564. while ( dnsRecord != NULL ) {
  1565. nextDnsRecord = dnsRecord->pNext;
  1566. dnsRecord->pNext = NULL;
  1567. PTRRecStatus = DnsModifyRecordsInSet_W(dnsRecord,
  1568. NULL,
  1569. DNS_UPDATE_SECURITY_USE_DEFAULT,
  1570. NULL,
  1571. DnsLists->DnsServerList,
  1572. NULL);
  1573. if ( PTRRecStatus == DNS_ERROR_RCODE_NO_ERROR ) {
  1574. DnsLists->PTRErrorLogged = FALSE;
  1575. if ( LogRegistration ) {
  1576. (NetNameLogEvent)(ResourceHandle,
  1577. LOG_INFORMATION,
  1578. L"Registered DNS PTR record %1!ws! for host %2!ws! "
  1579. L"over adapter '%3!ws!'\n",
  1580. dnsRecord->pName,
  1581. DnsLists->A_RRSet.pFirstRR->pName,
  1582. DnsLists->ConnectoidName);
  1583. }
  1584. } else {
  1585. (NetNameLogEvent)(ResourceHandle,
  1586. LOG_WARNING,
  1587. L"Failed to register DNS PTR record %1!ws! for host "
  1588. L"%2!ws! over adapter '%4!ws!', status %3!u!\n",
  1589. dnsRecord->pName,
  1590. DnsLists->A_RRSet.pFirstRR->pName,
  1591. PTRRecStatus,
  1592. DnsLists->ConnectoidName);
  1593. if (!DnsLists->PTRErrorLogged ||
  1594. PTRRecStatus != DnsLists->LastPTRRecQueryStatus )
  1595. {
  1596. DnsLists->PTRErrorLogged = TRUE;
  1597. }
  1598. }
  1599. InterlockedExchange(&DnsLists->LastPTRRecQueryStatus,
  1600. PTRRecStatus);
  1601. dnsRecord->pNext = nextDnsRecord;
  1602. dnsRecord = nextDnsRecord;
  1603. }
  1604. } // end if A rec registration was successful
  1605. else {
  1606. //
  1607. // since we don't end up trying the PTR records because of the A rec
  1608. // failure, we'll propagate the A rec error code in the PTR status.
  1609. //
  1610. InterlockedExchange(&DnsLists->LastPTRRecQueryStatus,
  1611. ARecStatus);
  1612. }
  1613. *NumberOfRegisteredNames = registeredCount;
  1614. return ARecStatus;
  1615. } // RegisterDnsRecords
  1616. VOID
  1617. DeleteAlternateComputerName(
  1618. IN LPWSTR AlternateComputerName,
  1619. IN LPWSTR DomainName OPTIONAL,
  1620. IN HANDLE * NameHandleList,
  1621. IN DWORD NameHandleCount,
  1622. IN RESOURCE_HANDLE ResourceHandle
  1623. )
  1624. {
  1625. NET_API_STATUS status;
  1626. if ( NameHandleCount > 0 ) {
  1627. status = DeleteServerName(ResourceHandle, AlternateComputerName);
  1628. if (status != ERROR_SUCCESS) {
  1629. (NetNameLogEvent)(ResourceHandle,
  1630. LOG_WARNING,
  1631. L"Failed to delete server name %1!ws!, status %2!u!.\n",
  1632. AlternateComputerName,
  1633. status);
  1634. }
  1635. //
  1636. // now remove the creds associated with this name
  1637. //
  1638. if ( DomainName != NULL ) {
  1639. status = NNCredentialOperation(ResourceHandle,
  1640. AlternateComputerName,
  1641. DomainName,
  1642. NULL,
  1643. NNRemoveCredential);
  1644. if (status != ERROR_SUCCESS) {
  1645. (NetNameLogEvent)(ResourceHandle,
  1646. LOG_WARNING,
  1647. L"Failed to remove credentials for %1!ws!, status %2!u!.\n",
  1648. AlternateComputerName,
  1649. status);
  1650. }
  1651. }
  1652. }
  1653. while ( NameHandleCount-- ) {
  1654. CloseHandle(NameHandleList[NameHandleCount]);
  1655. NameHandleList[NameHandleCount] = NULL;
  1656. (NetNameLogEvent)(ResourceHandle,
  1657. LOG_INFORMATION,
  1658. L"Deleted workstation name %1!ws! from transport %2!u!.\n",
  1659. AlternateComputerName,
  1660. NameHandleCount
  1661. );
  1662. }
  1663. } // DeleteAlternateComputerName
  1664. DWORD
  1665. AddAlternateComputerName(
  1666. IN PCLUS_WORKER Worker,
  1667. IN PNETNAME_RESOURCE Resource,
  1668. IN LPWSTR * TransportList,
  1669. IN DWORD TransportCount,
  1670. IN PDOMAIN_ADDRESS_MAPPING DomainMapList,
  1671. IN DWORD DomainMapCount
  1672. )
  1673. /*++
  1674. Routine Description:
  1675. Instantiate the cluster name on this node. This will create the <00> and
  1676. <20> Netbios endpoints, register A and PTR records with DNS and create a
  1677. backing computer object in the DS if appropriate.
  1678. Arguments:
  1679. Worker - used to check if we should terminate early
  1680. Resource - pointer to resource context data
  1681. TransportList - list of Netbios transports on which to add the names
  1682. TransportCount - count of transports in TransportList
  1683. DomainMapList - list of name to IP address mappings for building DNS records
  1684. DomainMapCount - count of entries in DomainMapList
  1685. Return Value:
  1686. ERROR_SUCCESS if ok, otherwise Win32 error
  1687. --*/
  1688. {
  1689. LPWSTR alternateComputerName = Resource->Params.NetworkName;
  1690. DWORD status = ERROR_SUCCESS;
  1691. DWORD setValueStatus;
  1692. DWORD i;
  1693. DWORD handleCount = 0;
  1694. LONG numberOfDnsNamesRegistered = 0;
  1695. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  1696. //
  1697. // clear all the status values so we don't show left over crud if we fail
  1698. // early on.
  1699. //
  1700. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1701. PARAM_NAME__STATUS_NETBIOS,
  1702. 0,
  1703. NULL);
  1704. if ( setValueStatus != ERROR_SUCCESS ) {
  1705. (NetNameLogEvent)(Resource->ResourceHandle,
  1706. LOG_ERROR,
  1707. L"Failed to clear StatusNetbios property - status %1!u!\n",
  1708. setValueStatus);
  1709. return setValueStatus;
  1710. }
  1711. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1712. PARAM_NAME__STATUS_DNS,
  1713. 0,
  1714. NULL);
  1715. if ( setValueStatus != ERROR_SUCCESS ) {
  1716. (NetNameLogEvent)(Resource->ResourceHandle,
  1717. LOG_ERROR,
  1718. L"Failed to clear StatusDNS property - status %1!u!\n",
  1719. setValueStatus);
  1720. return setValueStatus;
  1721. }
  1722. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1723. PARAM_NAME__STATUS_KERBEROS,
  1724. 0,
  1725. NULL);
  1726. if ( setValueStatus != ERROR_SUCCESS ) {
  1727. (NetNameLogEvent)(Resource->ResourceHandle,
  1728. LOG_ERROR,
  1729. L"Failed to clear StatusKerberos property - status %1!u!\n",
  1730. setValueStatus);
  1731. return setValueStatus;
  1732. }
  1733. //
  1734. // register DNS name(s) with server
  1735. //
  1736. status = AddDnsNames(Worker,
  1737. alternateComputerName,
  1738. Resource->ResKey,
  1739. resourceHandle,
  1740. DomainMapList,
  1741. DomainMapCount,
  1742. Resource->Params.RequireDNS, // FailOnAnyError
  1743. &Resource->NumberOfDnsLists,
  1744. &Resource->DnsLists,
  1745. &numberOfDnsNamesRegistered);
  1746. if ( status != ERROR_SUCCESS ) {
  1747. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1748. PARAM_NAME__STATUS_DNS,
  1749. status,
  1750. NULL);
  1751. if ( setValueStatus != ERROR_SUCCESS ) {
  1752. (NetNameLogEvent)(Resource->ResourceHandle,
  1753. LOG_ERROR,
  1754. L"Failed to register DNS records and can't set StatusDNS property - "
  1755. L"DNS status: %1!u!, property status %2!u!\n",
  1756. status,
  1757. setValueStatus);
  1758. return setValueStatus;
  1759. }
  1760. }
  1761. if ( status == ERROR_OPERATION_ABORTED ) {
  1762. return status;
  1763. }
  1764. if ( status != ERROR_SUCCESS && Resource->Params.RequireDNS ) {
  1765. LPWSTR msgBuff;
  1766. DWORD msgBytes;
  1767. //
  1768. // log a message if we weren't terminated and DNS registration failed
  1769. // and was required
  1770. //
  1771. msgBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1772. FORMAT_MESSAGE_FROM_SYSTEM,
  1773. NULL,
  1774. status,
  1775. 0,
  1776. (LPWSTR)&msgBuff,
  1777. 0,
  1778. NULL);
  1779. if ( msgBytes > 0 ) {
  1780. ClusResLogSystemEventByKey1(Resource->ResKey,
  1781. LOG_CRITICAL,
  1782. RES_NETNAME_DNS_REGISTRATION_FAILED,
  1783. msgBuff);
  1784. LocalFree( msgBuff );
  1785. } else {
  1786. ClusResLogSystemEventByKeyData(Resource->ResKey,
  1787. LOG_CRITICAL,
  1788. RES_NETNAME_DNS_REGISTRATION_FAILED_STATUS,
  1789. sizeof( status ),
  1790. &status);
  1791. }
  1792. return status;
  1793. }
  1794. //
  1795. // see if we need to fiddle with a computer object
  1796. //
  1797. Resource->DoKerberosCheck = FALSE;
  1798. if ( Resource->Params.RequireKerberos ) {
  1799. PWCHAR machinePwd = NULL;
  1800. PWCHAR domainName;
  1801. //
  1802. // CreatingDC indicates whether we think we have a CO or not.
  1803. //
  1804. if ( Resource->Params.CreatingDC == NULL ) {
  1805. status = AddComputerObject( Worker, Resource, &machinePwd );
  1806. } else {
  1807. status = UpdateComputerObject( Worker, Resource, &machinePwd );
  1808. }
  1809. Resource->KerberosStatus = status;
  1810. if ( status == ERROR_SUCCESS ) {
  1811. //
  1812. // add the credentials to the LocalSystem and NetworkService
  1813. // LUIDs. use the domain name that is part of CreatingDC.
  1814. //
  1815. // ISSUE: have to find out if this works for domains where domain
  1816. // name is different from DNS name
  1817. //
  1818. domainName = wcschr( Resource->Params.CreatingDC, L'.' );
  1819. if ( domainName ) {
  1820. ++domainName;
  1821. }
  1822. status = NNCredentialOperation(Resource->ResourceHandle,
  1823. alternateComputerName,
  1824. domainName,
  1825. machinePwd,
  1826. NNAddCredential);
  1827. if ( status == ERROR_SUCCESS ) {
  1828. Resource->DoKerberosCheck = TRUE;
  1829. } else {
  1830. (NetNameLogEvent)(Resource->ResourceHandle,
  1831. LOG_ERROR,
  1832. L"Failed to add credentials to LSA for computer account "
  1833. L"%1!ws! - status %2!u!\n",
  1834. alternateComputerName,
  1835. status);
  1836. if ( status == ERROR_PRIVILEGE_NOT_HELD ) {
  1837. ClusResLogSystemEventByKey1(Resource->ResKey,
  1838. LOG_CRITICAL,
  1839. RES_NETNAME_TCB_NOT_HELD,
  1840. Resource->Params.NetworkName);
  1841. }
  1842. else {
  1843. ClusResLogSystemEventByKeyData1(Resource->ResKey,
  1844. LOG_CRITICAL,
  1845. RES_NETNAME_LSA_ERROR,
  1846. sizeof( status ),
  1847. &status,
  1848. Resource->Params.NetworkName);
  1849. }
  1850. }
  1851. } else {
  1852. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1853. PARAM_NAME__STATUS_KERBEROS,
  1854. status,
  1855. NULL);
  1856. if ( setValueStatus != ERROR_SUCCESS ) {
  1857. (NetNameLogEvent)(Resource->ResourceHandle,
  1858. LOG_ERROR,
  1859. L"Kerberos operation failed and unable to set StatusKerberos property. "
  1860. L"Kerberos status: %1!u! - property status %2!u!\n",
  1861. status,
  1862. setValueStatus);
  1863. status = setValueStatus;
  1864. }
  1865. }
  1866. if ( machinePwd != NULL ) {
  1867. volatile PWCHAR p = machinePwd;
  1868. while ( *p != UNICODE_NULL ) {
  1869. *p++ = UNICODE_NULL;
  1870. }
  1871. LocalFree( machinePwd );
  1872. }
  1873. if ( status != ERROR_SUCCESS ) {
  1874. return status;
  1875. }
  1876. } else {
  1877. BOOL objectFound = FALSE;
  1878. HRESULT hr;
  1879. LPWSTR hostingDCName = NULL;
  1880. //
  1881. // see if a CO exists with this name. If it does, don't go online.
  1882. //
  1883. hr = IsComputerObjectInDS(Resource->ResourceHandle,
  1884. Resource->NodeName,
  1885. Resource->Params.NetworkName,
  1886. NULL,
  1887. &objectFound,
  1888. NULL,
  1889. &hostingDCName);
  1890. if ( SUCCEEDED( hr ) && objectFound ) {
  1891. (NetNameLogEvent)(Resource->ResourceHandle,
  1892. LOG_ERROR,
  1893. L"Kerberos authentication is disabled for this resource "
  1894. L"but a computer account named %1!ws! was found on %2!ws!. "
  1895. L"Authentication based on Kerberos to this network "
  1896. L"name will fail while this is the case. To bring "
  1897. L"the resource online, set the RequireKerberos property "
  1898. L"to one or delete the computer account from Active "
  1899. L"Directory.\n",
  1900. Resource->Params.NetworkName,
  1901. hostingDCName);
  1902. ClusResLogSystemEventByKey1(Resource->ResKey,
  1903. LOG_CRITICAL,
  1904. RES_NETNAME_COMPOBJ_IN_DS,
  1905. Resource->Params.NetworkName);
  1906. //
  1907. // ISSUE: depending on how 402981 is fixed, we might be able to
  1908. // remove this restriction. ToddS might fix it such that kerb will
  1909. // ignore disabled accounts and let the negotiate package fall
  1910. // back to NTLM. If this is the case, then we can remove this as
  1911. // long as the DCs are running Windows Server 2003. Hmm....
  1912. //
  1913. // When a CO exists, clients will get a ticket. If the name goes
  1914. // online without a password, the server will fail to decrypt its
  1915. // portion of the ticket. Since this is an authoritative failure,
  1916. // negotitate won't fallback and retry with NTLM. This penalizes
  1917. // explicit NTLM users but I'm guessing they are far outnumbered by
  1918. // Kerb and Negotiate users.
  1919. //
  1920. status = E_ADS_OBJECT_EXISTS;
  1921. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1922. PARAM_NAME__STATUS_KERBEROS,
  1923. status,
  1924. NULL);
  1925. if ( setValueStatus != ERROR_SUCCESS ) {
  1926. (NetNameLogEvent)(Resource->ResourceHandle,
  1927. LOG_ERROR,
  1928. L"Unable to set StatusKerberos property. Kerberos status: "
  1929. L"%1!u! - property status %2!u!\n",
  1930. status,
  1931. setValueStatus);
  1932. status = setValueStatus;
  1933. }
  1934. LocalFree( hostingDCName );
  1935. return status;
  1936. }
  1937. }
  1938. //
  1939. // bring NetBT names online
  1940. //
  1941. status = ERROR_SUCCESS;
  1942. for (i=0; i<TransportCount; i++) {
  1943. if ( ClusWorkerCheckTerminate( Worker )) {
  1944. status = ERROR_OPERATION_ABORTED;
  1945. goto cleanup;
  1946. }
  1947. status = AddServerName(resourceHandle,
  1948. alternateComputerName,
  1949. Resource->Params.NetworkRemap,
  1950. TransportList[i],
  1951. (BOOLEAN) ((i == 0) ? TRUE : FALSE)); // CheckNameFirst
  1952. if ( status == NERR_ServerNotStarted ) {
  1953. status = ERROR_SUCCESS;
  1954. }
  1955. if ( status != ERROR_SUCCESS ) {
  1956. goto cleanup;
  1957. }
  1958. if ( ClusWorkerCheckTerminate( Worker )) {
  1959. status = ERROR_OPERATION_ABORTED;
  1960. goto cleanup;
  1961. }
  1962. status = AddWorkstationName(
  1963. alternateComputerName,
  1964. TransportList[i],
  1965. resourceHandle,
  1966. &(Resource->NameHandleList[i])
  1967. );
  1968. if (status != ERROR_SUCCESS) {
  1969. goto cleanup;
  1970. }
  1971. handleCount++;
  1972. }
  1973. //
  1974. // if didn't register any NetBt or DNS names, then fail the netname.
  1975. //
  1976. if ( TransportCount == 0 && numberOfDnsNamesRegistered == 0 ) {
  1977. ClusResLogSystemEvent1(LOG_CRITICAL,
  1978. RES_NETNAME_NOT_REGISTERED,
  1979. alternateComputerName);
  1980. status = ERROR_RESOURCE_FAILED;
  1981. }
  1982. cleanup:
  1983. if ( status != ERROR_SUCCESS ) {
  1984. LPWSTR msgBuff;
  1985. DWORD msgBytes;
  1986. setValueStatus = ResUtilSetDwordValue(Resource->ParametersKey,
  1987. PARAM_NAME__STATUS_NETBIOS,
  1988. status,
  1989. NULL);
  1990. if ( setValueStatus != ERROR_SUCCESS ) {
  1991. (NetNameLogEvent)(Resource->ResourceHandle,
  1992. LOG_ERROR,
  1993. L"Adding network name failed and unable to set "
  1994. L"StatusNetbios property. Netbios status: %1!u! - property "
  1995. L"status %2!u!\n",
  1996. status,
  1997. setValueStatus);
  1998. status = setValueStatus;
  1999. }
  2000. //
  2001. // lookup error message text
  2002. //
  2003. msgBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  2004. FORMAT_MESSAGE_FROM_SYSTEM,
  2005. NULL,
  2006. status,
  2007. 0,
  2008. (LPWSTR)&msgBuff,
  2009. 0,
  2010. NULL);
  2011. if ( msgBytes > 0 ) {
  2012. ClusResLogSystemEventByKey1(Resource->ResKey,
  2013. LOG_CRITICAL,
  2014. RES_NETNAME_CANT_ADD_NAME2,
  2015. msgBuff);
  2016. LocalFree( msgBuff );
  2017. } else {
  2018. ClusResLogSystemEventByKeyData(Resource->ResKey,
  2019. LOG_CRITICAL,
  2020. RES_NETNAME_CANT_ADD_NAME_STATUS,
  2021. sizeof(status),
  2022. &status);
  2023. }
  2024. }
  2025. return status;
  2026. } // AddAlternateComputerName