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.

1838 lines
46 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. nmutil.c
  5. Abstract:
  6. Miscellaneous utility routines for the Node Manager component.
  7. Author:
  8. Mike Massa (mikemas) 26-Oct-1996
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "service.h"
  13. #include "nmp.h"
  14. #include <ntlsa.h>
  15. #include <ntmsv1_0.h>
  16. #include <Wincrypt.h>
  17. PVOID NmpEncryptedClusterKey = NULL;
  18. DWORD NmpEncryptedClusterKeyLength = 0;
  19. DWORD
  20. NmpQueryString(
  21. IN HDMKEY Key,
  22. IN LPCWSTR ValueName,
  23. IN DWORD ValueType,
  24. IN LPWSTR *StringBuffer,
  25. IN OUT LPDWORD StringBufferSize,
  26. OUT LPDWORD StringSize
  27. )
  28. /*++
  29. Routine Description:
  30. Reads a REG_SZ or REG_MULTI_SZ registry value. If the StringBuffer is
  31. not large enough to hold the data, it is reallocated.
  32. Arguments:
  33. Key - Open key for the value to be read.
  34. ValueName - Unicode name of the value to be read.
  35. ValueType - REG_SZ or REG_MULTI_SZ.
  36. StringBuffer - Buffer into which to place the value data.
  37. StringBufferSize - Pointer to the size of the StringBuffer. This parameter
  38. is updated if StringBuffer is reallocated.
  39. StringSize - The size of the data returned in StringBuffer, including
  40. the terminating null character.
  41. Return Value:
  42. The status of the registry query.
  43. Notes:
  44. To avoid deadlock with DM, must not be called with NM lock held.
  45. --*/
  46. {
  47. DWORD status;
  48. DWORD valueType;
  49. WCHAR *temp;
  50. DWORD oldBufferSize = *StringBufferSize;
  51. BOOL noBuffer = FALSE;
  52. if (*StringBufferSize == 0) {
  53. noBuffer = TRUE;
  54. }
  55. *StringSize = *StringBufferSize;
  56. status = DmQueryValue( Key,
  57. ValueName,
  58. &valueType,
  59. (LPBYTE) *StringBuffer,
  60. StringSize
  61. );
  62. if (status == NO_ERROR) {
  63. if (!noBuffer ) {
  64. if (valueType == ValueType) {
  65. return(NO_ERROR);
  66. }
  67. else {
  68. return(ERROR_INVALID_PARAMETER);
  69. }
  70. }
  71. status = ERROR_MORE_DATA;
  72. }
  73. if (status == ERROR_MORE_DATA) {
  74. temp = MIDL_user_allocate(*StringSize);
  75. if (temp == NULL) {
  76. *StringSize = 0;
  77. return(ERROR_NOT_ENOUGH_MEMORY);
  78. }
  79. if (!noBuffer) {
  80. MIDL_user_free(*StringBuffer);
  81. }
  82. *StringBuffer = temp;
  83. *StringBufferSize = *StringSize;
  84. status = DmQueryValue( Key,
  85. ValueName,
  86. &valueType,
  87. (LPBYTE) *StringBuffer,
  88. StringSize
  89. );
  90. if (status == NO_ERROR) {
  91. if (valueType == ValueType) {
  92. return(NO_ERROR);
  93. }
  94. else {
  95. *StringSize = 0;
  96. return(ERROR_INVALID_PARAMETER);
  97. }
  98. }
  99. }
  100. return(status);
  101. } // NmpQueryString
  102. //
  103. // Routines to support the common network configuration code.
  104. //
  105. VOID
  106. ClNetPrint(
  107. IN ULONG LogLevel,
  108. IN PCHAR FormatString,
  109. ...
  110. )
  111. {
  112. CHAR buffer[256];
  113. DWORD bytes;
  114. va_list argList;
  115. va_start(argList, FormatString);
  116. bytes = FormatMessageA(
  117. FORMAT_MESSAGE_FROM_STRING,
  118. FormatString,
  119. 0,
  120. 0,
  121. buffer,
  122. sizeof(buffer),
  123. &argList
  124. );
  125. va_end(argList);
  126. if (bytes != 0) {
  127. ClRtlLogPrint(LogLevel, "%1!hs!", buffer);
  128. }
  129. return;
  130. } // ClNetPrint
  131. VOID
  132. ClNetLogEvent(
  133. IN DWORD LogLevel,
  134. IN DWORD MessageId
  135. )
  136. {
  137. CsLogEvent(LogLevel, MessageId);
  138. return;
  139. } // ClNetLogEvent
  140. VOID
  141. ClNetLogEvent1(
  142. IN DWORD LogLevel,
  143. IN DWORD MessageId,
  144. IN LPCWSTR Arg1
  145. )
  146. {
  147. CsLogEvent1(LogLevel, MessageId, Arg1);
  148. return;
  149. } // ClNetLogEvent1
  150. VOID
  151. ClNetLogEvent2(
  152. IN DWORD LogLevel,
  153. IN DWORD MessageId,
  154. IN LPCWSTR Arg1,
  155. IN LPCWSTR Arg2
  156. )
  157. {
  158. CsLogEvent2(LogLevel, MessageId, Arg1, Arg2);
  159. return;
  160. } // ClNetLogEvent2
  161. VOID
  162. ClNetLogEvent3(
  163. IN DWORD LogLevel,
  164. IN DWORD MessageId,
  165. IN LPCWSTR Arg1,
  166. IN LPCWSTR Arg2,
  167. IN LPCWSTR Arg3
  168. )
  169. {
  170. CsLogEvent3(LogLevel, MessageId, Arg1, Arg2, Arg3);
  171. return;
  172. } // ClNetLogEvent3
  173. BOOLEAN
  174. NmpLockedEnterApi(
  175. NM_STATE RequiredState
  176. )
  177. {
  178. if (NmpState >= RequiredState) {
  179. NmpActiveThreadCount++;
  180. CL_ASSERT(NmpActiveThreadCount != 0);
  181. return(TRUE);
  182. }
  183. return(FALSE);
  184. } // NmpLockedEnterApi
  185. BOOLEAN
  186. NmpEnterApi(
  187. NM_STATE RequiredState
  188. )
  189. {
  190. BOOLEAN mayEnter;
  191. NmpAcquireLock();
  192. mayEnter = NmpLockedEnterApi(RequiredState);
  193. NmpReleaseLock();
  194. return(mayEnter);
  195. } // NmpEnterApi
  196. VOID
  197. NmpLockedLeaveApi(
  198. VOID
  199. )
  200. {
  201. CL_ASSERT(NmpActiveThreadCount > 0);
  202. NmpActiveThreadCount--;
  203. if ((NmpActiveThreadCount == 0) && (NmpState == NmStateOfflinePending)) {
  204. SetEvent(NmpShutdownEvent);
  205. }
  206. return;
  207. } // NmpLockedLeaveApi
  208. VOID
  209. NmpLeaveApi(
  210. VOID
  211. )
  212. {
  213. NmpAcquireLock();
  214. NmpLockedLeaveApi();
  215. NmpReleaseLock();
  216. return;
  217. } // NmpLeaveApi
  218. //
  219. // Routines to provide a cluster shared key for signing and encrypting
  220. // data.
  221. //
  222. DWORD
  223. NmpGetLogonId(
  224. OUT LUID * LogonId
  225. )
  226. {
  227. HANDLE tokenHandle = NULL;
  228. TOKEN_STATISTICS tokenInfo;
  229. DWORD bytesReturned;
  230. BOOL success = FALSE;
  231. DWORD status;
  232. if (LogonId == NULL) {
  233. status = STATUS_UNSUCCESSFUL;
  234. goto error_exit;
  235. }
  236. if (!OpenProcessToken(
  237. GetCurrentProcess(),
  238. TOKEN_QUERY,
  239. &tokenHandle
  240. )) {
  241. status = GetLastError();
  242. ClRtlLogPrint(LOG_UNUSUAL,
  243. "[NM] Failed to open process token, status %1!u!.\n",
  244. status
  245. );
  246. goto error_exit;
  247. }
  248. if (!GetTokenInformation(
  249. tokenHandle,
  250. TokenStatistics,
  251. &tokenInfo,
  252. sizeof(tokenInfo),
  253. &bytesReturned
  254. )) {
  255. status = GetLastError();
  256. ClRtlLogPrint(LOG_UNUSUAL,
  257. "[NM] Failed to get token information, status %1!u!.\n",
  258. status
  259. );
  260. goto error_exit;
  261. }
  262. RtlCopyMemory(LogonId, &(tokenInfo.AuthenticationId), sizeof(LUID));
  263. status = STATUS_SUCCESS;
  264. error_exit:
  265. if (tokenHandle != NULL) {
  266. CloseHandle(tokenHandle);
  267. }
  268. return(status);
  269. } // NmpGetLogonId
  270. DWORD
  271. NmpConnectToLsaPrivileged(
  272. OUT HANDLE * LsaHandle,
  273. OUT BOOLEAN * Trusted
  274. )
  275. /*++
  276. Routine Description:
  277. Connect to LSA.
  278. If running as a service, there is no need to enable the TCB privilege.
  279. The fix for bug 337751 allows the cluster service account to issue
  280. a MSV1_0_XXX requests even if it does not have a trusted connection
  281. to LSA.
  282. If not running as a service, try to elevate the privilege to TCB to
  283. connect trusted. Fail the call if TCB privilege cannot be enabled.
  284. If TCB is enabled and was previously not enabled, it is restored prior
  285. to returning.
  286. Callers that need to connect to LSA without requiring service logon
  287. or TCB can simply use LsaConnectUntrusted.
  288. Arguments:
  289. LsaHandle - returns LSA handle. Must be cleaned up by caller
  290. Trusted - returns whether connection is trusted
  291. Return value:
  292. Win32 error code.
  293. --*/
  294. {
  295. DWORD status;
  296. BOOLEAN wasEnabled = FALSE;
  297. BOOLEAN trusted = FALSE;
  298. DWORD ignore;
  299. STRING name;
  300. HANDLE lsaHandle = NULL;
  301. //
  302. // Try to turn on TCB privilege if running in console mode.
  303. //
  304. if (!CsRunningAsService) {
  305. status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &wasEnabled);
  306. if (!NT_SUCCESS(status)) {
  307. status = LsaNtStatusToWinError(status);
  308. #if CLUSTER_BETA
  309. ClRtlLogPrint(LOG_NOISE,
  310. "[NM] Failed to turn on TCB privilege, status %1!u!.\n",
  311. status
  312. );
  313. #endif // CLUSTER_BETA
  314. return(status);
  315. } else {
  316. #if CLUSTER_BETA
  317. ClRtlLogPrint(LOG_NOISE,
  318. "[NM] Turned on TCB privilege, wasEnabled = %1!ws!.\n",
  319. (wasEnabled) ? L"TRUE" : L"FALSE"
  320. );
  321. #endif // CLUSTER_BETA
  322. trusted = TRUE;
  323. }
  324. }
  325. //
  326. // Establish contact with LSA.
  327. //
  328. if (trusted) {
  329. RtlInitString(&name, "ClusSvcNM");
  330. status = LsaRegisterLogonProcess(&name, &lsaHandle, &ignore);
  331. //
  332. // Turn off TCB privilege
  333. //
  334. if (!wasEnabled) {
  335. DWORD subStatus;
  336. subStatus = RtlAdjustPrivilege(
  337. SE_TCB_PRIVILEGE,
  338. FALSE,
  339. FALSE,
  340. &wasEnabled
  341. );
  342. if (!NT_SUCCESS(subStatus)) {
  343. ClRtlLogPrint(LOG_UNUSUAL,
  344. "[NM] Failed to disable TCB privilege, "
  345. "status %1!u!.\n",
  346. subStatus
  347. );
  348. } else {
  349. #if CLUSTER_BETA
  350. ClRtlLogPrint(LOG_NOISE,
  351. "[NM] Turned off TCB privilege.\n"
  352. );
  353. #endif // CLUSTER_BETA
  354. }
  355. }
  356. }
  357. else {
  358. status = LsaConnectUntrusted(&lsaHandle);
  359. }
  360. if (!NT_SUCCESS(status)) {
  361. status = LsaNtStatusToWinError(status);
  362. ClRtlLogPrint(LOG_UNUSUAL,
  363. "[NM] Failed to obtain LSA logon handle in %1!ws! mode, "
  364. "status %2!u!.\n",
  365. (trusted) ? L"trusted" : L"untrusted", status
  366. );
  367. } else {
  368. *LsaHandle = lsaHandle;
  369. *Trusted = trusted;
  370. }
  371. return(status);
  372. } // NmpConnectToLsaPrivileged
  373. DWORD
  374. NmpDeriveClusterKey(
  375. IN PVOID MixingBytes,
  376. IN DWORD MixingBytesSize,
  377. OUT PVOID * Key,
  378. OUT DWORD * KeyLength
  379. )
  380. /*++
  381. Routine Description:
  382. Derive the cluster key using mixing bytes. Allocate a buffer
  383. for the key and return it.
  384. Arguments:
  385. Key - set to buffer containing key
  386. KeyLength - length of resulting key
  387. --*/
  388. {
  389. LUID logonId;
  390. BOOLEAN trusted = FALSE;
  391. HANDLE lsaHandle = NULL;
  392. STRING name;
  393. DWORD packageId = 0;
  394. DWORD requestSize;
  395. PMSV1_0_DERIVECRED_REQUEST request = NULL;
  396. DWORD responseSize;
  397. PMSV1_0_DERIVECRED_RESPONSE response = NULL;
  398. PUCHAR key;
  399. DWORD keyLength;
  400. DWORD status = STATUS_SUCCESS;
  401. DWORD subStatus = STATUS_SUCCESS;
  402. status = NmpGetLogonId(&logonId);
  403. if (!NT_SUCCESS(status)) {
  404. ClRtlLogPrint(
  405. LOG_UNUSUAL,
  406. "[NM] Failed to determine logon ID, status %1!u!.\n",
  407. status
  408. );
  409. goto error_exit;
  410. }
  411. status = NmpConnectToLsaPrivileged(&lsaHandle, &trusted);
  412. if (status != ERROR_SUCCESS) {
  413. ClRtlLogPrint(LOG_UNUSUAL,
  414. "[NM] Failed to connect to LSA, status %1!u!.\n",
  415. status
  416. );
  417. goto error_exit;
  418. }
  419. //
  420. // Lookup the authentication package.
  421. //
  422. RtlInitString( &name, MSV1_0_PACKAGE_NAME );
  423. status = LsaLookupAuthenticationPackage(lsaHandle, &name, &packageId);
  424. if (!NT_SUCCESS(status)) {
  425. status = LsaNtStatusToWinError(status);
  426. ClRtlLogPrint(LOG_UNUSUAL,
  427. "[NM] Failed to local authentication package with "
  428. "name %1!ws!, status %2!u!.\n",
  429. name.Buffer, status
  430. );
  431. goto error_exit;
  432. }
  433. //
  434. // Build the derive credentials request with the provided
  435. // mixing bytes.
  436. //
  437. requestSize = sizeof(MSV1_0_DERIVECRED_REQUEST) + MixingBytesSize;
  438. request = LocalAlloc(LMEM_FIXED, requestSize);
  439. if (request == NULL) {
  440. ClRtlLogPrint(LOG_UNUSUAL,
  441. "[NM] Failed to allocate LSA request of size %1!u! bytes.\n",
  442. requestSize
  443. );
  444. status = ERROR_NOT_ENOUGH_MEMORY;
  445. goto error_exit;
  446. }
  447. request->MessageType = MsV1_0DeriveCredential;
  448. RtlCopyMemory(&(request->LogonId), &logonId, sizeof(logonId));
  449. request->DeriveCredType = MSV1_0_DERIVECRED_TYPE_SHA1;
  450. request->DeriveCredInfoLength = MixingBytesSize;
  451. RtlCopyMemory(
  452. &(request->DeriveCredSubmitBuffer[0]),
  453. MixingBytes,
  454. MixingBytesSize
  455. );
  456. //
  457. // Make the call through LSA to the authentication package.
  458. //
  459. status = LsaCallAuthenticationPackage(
  460. lsaHandle,
  461. packageId,
  462. request,
  463. requestSize,
  464. &response,
  465. &responseSize,
  466. &subStatus
  467. );
  468. if (!NT_SUCCESS(status)) {
  469. status = LsaNtStatusToWinError(status);
  470. subStatus = LsaNtStatusToWinError(subStatus);
  471. ClRtlLogPrint(LOG_UNUSUAL,
  472. "[NM] DeriveCredential call to authentication "
  473. "package failed, status %1!u!, auth package "
  474. "status %2!u!.\n", status, subStatus
  475. );
  476. goto error_exit;
  477. }
  478. //
  479. // Allocate a non-LSA buffer to store the key.
  480. //
  481. keyLength = response->DeriveCredInfoLength;
  482. key = MIDL_user_allocate(keyLength);
  483. if (key == NULL) {
  484. status = ERROR_NOT_ENOUGH_MEMORY;
  485. ClRtlLogPrint(LOG_UNUSUAL,
  486. "[NM] Failed to allocate buffer for cluster "
  487. "key of size %1!u!.\n",
  488. keyLength
  489. );
  490. goto error_exit;
  491. }
  492. //
  493. // Store the derived credentials in the key buffer.
  494. //
  495. RtlCopyMemory(key, &(response->DeriveCredReturnBuffer[0]), keyLength);
  496. //
  497. // Zero the derived credential buffer to be extra paranoid.
  498. //
  499. RtlZeroMemory(
  500. &(response->DeriveCredReturnBuffer[0]),
  501. response->DeriveCredInfoLength
  502. );
  503. status = STATUS_SUCCESS;
  504. *Key = key;
  505. *KeyLength = keyLength;
  506. error_exit:
  507. if (lsaHandle != NULL) {
  508. LsaDeregisterLogonProcess(lsaHandle);
  509. lsaHandle = NULL;
  510. }
  511. if (request != NULL) {
  512. LocalFree(request);
  513. request = NULL;
  514. }
  515. if (response != NULL) {
  516. LsaFreeReturnBuffer(response);
  517. response = NULL;
  518. }
  519. return(status);
  520. } // NmpDeriveClusterKey
  521. DWORD
  522. NmpGetClusterKey(
  523. OUT PVOID KeyBuffer,
  524. IN OUT DWORD * KeyBufferLength
  525. )
  526. /*++
  527. Routine Description:
  528. Decrypt and copy the shared cluster key into the buffer provided.
  529. Arguments:
  530. KeyBuffer - buffer to which key should be copied
  531. KeyBufferLength - IN: length of KeyBuffer
  532. OUT: required buffer size, if input
  533. buffer length is insufficient
  534. Return value:
  535. ERROR_INSUFFICIENT_BUFFER if KeyBuffer is too small.
  536. ERROR_FILE_NOT_FOUND if NmpEncryptedClusterKey has not
  537. yet been generated.
  538. ERROR_SUCCESS on success.
  539. Notes:
  540. Acquires and releases NM lock. Since NM lock is
  541. implemented as a critical section, calling thread
  542. is permitted to already hold NM lock.
  543. --*/
  544. {
  545. DWORD status;
  546. BOOL DecryptingDataSucceeded = FALSE;
  547. BOOL Success;
  548. DATA_BLOB DataIn;
  549. DATA_BLOB DataOut;
  550. RtlZeroMemory(&DataOut, sizeof(DataOut));
  551. NmpAcquireLock();
  552. if (NmpEncryptedClusterKey == NULL) {
  553. status = ERROR_FILE_NOT_FOUND;
  554. ClRtlLogPrint(LOG_UNUSUAL,
  555. "[NM] The cluster key has not yet been derived.\n"
  556. );
  557. } else{
  558. //
  559. // Decrypt cluster key
  560. //
  561. DataIn.pbData = NmpEncryptedClusterKey;
  562. DataIn.cbData = NmpEncryptedClusterKeyLength;
  563. Success = CryptUnprotectData(&DataIn, // data to be decrypted
  564. NULL,
  565. NULL,
  566. NULL,
  567. NULL,
  568. 0, // flags
  569. &DataOut // decrypted data
  570. );
  571. if (!Success)
  572. {
  573. status = GetLastError();
  574. ClRtlLogPrint(LOG_UNUSUAL,
  575. "[NM] Failed to decrypt data using CryptUnprotectData, "
  576. "status %1!u!.\n",
  577. status
  578. );
  579. goto error_exit;
  580. }
  581. DecryptingDataSucceeded = TRUE;
  582. if (KeyBuffer == NULL || DataOut.cbData > *KeyBufferLength) {
  583. status = ERROR_INSUFFICIENT_BUFFER;
  584. } else {
  585. RtlCopyMemory(KeyBuffer, DataOut.pbData, DataOut.cbData);
  586. status = ERROR_SUCCESS;
  587. }
  588. *KeyBufferLength = DataOut.cbData;
  589. }
  590. error_exit:
  591. NmpReleaseLock();
  592. if (DecryptingDataSucceeded)
  593. {
  594. //
  595. // Zero the encrypted data before releasing the memory.
  596. //
  597. RtlSecureZeroMemory(DataOut.pbData, DataOut.cbData);
  598. }
  599. if (DataOut.pbData != NULL)
  600. {
  601. LocalFree(DataOut.pbData);
  602. }
  603. // To be extra secure.
  604. RtlSecureZeroMemory(&DataOut, sizeof(DataOut));
  605. return(status);
  606. } // NmpGetClusterKey
  607. DWORD
  608. NmpRederiveClusterKey(
  609. VOID
  610. )
  611. /*++
  612. Routine Description:
  613. Forces rederivation of cluster key.
  614. Must be called during cluster initialization to generate
  615. cluster key the first time.
  616. Otherwise called when cluster password changes, since the
  617. cluster key is based on the cluster service account password.
  618. Notes:
  619. Acquires and releases NM lock.
  620. --*/
  621. {
  622. DWORD status;
  623. BOOLEAN lockAcquired;
  624. PVOID key = NULL;
  625. DWORD keyLength = 0;
  626. PVOID oldEncryptedKey = NULL;
  627. DWORD oldEncryptedKeyLength = 0;
  628. PVOID mixingBytes = NULL;
  629. DWORD mixingBytesSize;
  630. NmpAcquireLock();
  631. lockAcquired = TRUE;
  632. NmpLockedEnterApi(NmStateOnlinePending);
  633. //
  634. // Form the mixing bytes.
  635. //
  636. if (NmpClusterInstanceId == NULL) {
  637. status = ERROR_INVALID_PARAMETER;
  638. ClRtlLogPrint(LOG_UNUSUAL,
  639. "[NM] Need cluster instance id in order to derive "
  640. "cluster key, status %1!u!.\n",
  641. status
  642. );
  643. goto error_exit;
  644. }
  645. mixingBytesSize = NM_WCSLEN(NmpClusterInstanceId);
  646. mixingBytes = MIDL_user_allocate(mixingBytesSize);
  647. if (mixingBytes == NULL) {
  648. status = ERROR_NOT_ENOUGH_MEMORY;
  649. ClRtlLogPrint(LOG_UNUSUAL,
  650. "[NM] Failed to allocate buffer of size %1!u! "
  651. "for mixing bytes to derive cluster key.\n",
  652. mixingBytesSize
  653. );
  654. goto error_exit;
  655. }
  656. RtlCopyMemory(mixingBytes, NmpClusterInstanceId, mixingBytesSize);
  657. //
  658. // Make a copy of the old encrypted key to detect changes.
  659. //
  660. if (NmpEncryptedClusterKey != NULL) {
  661. CL_ASSERT(NmpEncryptedClusterKeyLength > 0);
  662. oldEncryptedKey = MIDL_user_allocate(NmpEncryptedClusterKeyLength);
  663. if (oldEncryptedKey == NULL) {
  664. ClRtlLogPrint(LOG_UNUSUAL,
  665. "[NM] Failed to allocate buffer for cluster "
  666. "key copy.\n"
  667. );
  668. status = ERROR_NOT_ENOUGH_MEMORY;
  669. goto error_exit;
  670. }
  671. oldEncryptedKeyLength = NmpEncryptedClusterKeyLength;
  672. RtlCopyMemory(oldEncryptedKey,
  673. NmpEncryptedClusterKey,
  674. NmpEncryptedClusterKeyLength
  675. );
  676. }
  677. NmpReleaseLock();
  678. lockAcquired = FALSE;
  679. status = NmpDeriveClusterKey(
  680. mixingBytes,
  681. mixingBytesSize,
  682. &key,
  683. &keyLength
  684. );
  685. if (status != ERROR_SUCCESS) {
  686. ClRtlLogPrint(LOG_UNUSUAL,
  687. "[NM] Failed to derive cluster key, "
  688. "status %1!u!.\n",
  689. status
  690. );
  691. goto error_exit;
  692. }
  693. NmpAcquireLock();
  694. lockAcquired = TRUE;
  695. //
  696. // Make sure another thread didn't beat us in obtaining a key.
  697. // We replace the cluster key with the generated key if it is
  698. // not different from the old key (or somebody set it to NULL).
  699. //
  700. if (NmpEncryptedClusterKey != NULL &&
  701. (oldEncryptedKey == NULL ||
  702. NmpEncryptedClusterKeyLength != oldEncryptedKeyLength ||
  703. RtlCompareMemory(
  704. NmpEncryptedClusterKey,
  705. oldEncryptedKey,
  706. oldEncryptedKeyLength
  707. ) != oldEncryptedKeyLength
  708. )
  709. ) {
  710. //
  711. // Keep the current NmpEncryptedClusterKey.
  712. //
  713. } else {
  714. //
  715. // Encrypt derived credentials and store them
  716. //
  717. if (NmpEncryptedClusterKey != NULL)
  718. {
  719. RtlSecureZeroMemory(NmpEncryptedClusterKey, NmpEncryptedClusterKeyLength);
  720. LocalFree(NmpEncryptedClusterKey);
  721. }
  722. status = NmpProtectData(key,
  723. keyLength,
  724. &NmpEncryptedClusterKey,
  725. &NmpEncryptedClusterKeyLength
  726. );
  727. if (status != ERROR_SUCCESS)
  728. {
  729. ClRtlLogPrint(LOG_UNUSUAL,
  730. "[NM] Failed to encrypt data using CryptProtectData, "
  731. "status %1!u!.\n",
  732. status
  733. );
  734. goto error_exit;
  735. }
  736. }
  737. error_exit:
  738. if (lockAcquired) {
  739. NmpLockedLeaveApi();
  740. NmpReleaseLock();
  741. } else {
  742. NmpLeaveApi();
  743. }
  744. if (oldEncryptedKey != NULL)
  745. {
  746. MIDL_user_free(oldEncryptedKey);
  747. }
  748. if (key != NULL) {
  749. RtlSecureZeroMemory(key, keyLength);
  750. MIDL_user_free(key);
  751. key = NULL;
  752. keyLength = 0;
  753. }
  754. if (mixingBytes != NULL) {
  755. MIDL_user_free(mixingBytes);
  756. mixingBytes = NULL;
  757. }
  758. return(status);
  759. } // NmpRederiveClusterKey
  760. VOID
  761. NmpFreeClusterKey(
  762. VOID
  763. )
  764. /*++
  765. Routine Description:
  766. Called during NmShutdown.
  767. --*/
  768. {
  769. if (NmpEncryptedClusterKey != NULL) {
  770. RtlSecureZeroMemory(NmpEncryptedClusterKey, NmpEncryptedClusterKeyLength);
  771. LocalFree(NmpEncryptedClusterKey);
  772. NmpEncryptedClusterKey = NULL;
  773. NmpEncryptedClusterKeyLength = 0;
  774. }
  775. return;
  776. } // NmpFreeClusterKey
  777. DWORD
  778. NmpSetLsaProcessOptions(
  779. IN ULONG ProcessOptions
  780. )
  781. /*++
  782. Routine Description:
  783. Set LSA options for this process.
  784. Arguments:
  785. ProcessOptions - MSV1_0_OPTION_XXX process option bit flags
  786. Return Value:
  787. ERROR_SUCCESS if successful
  788. Win32 error code otherwise.
  789. Notes:
  790. --*/
  791. {
  792. DWORD ReturnStatus;
  793. NTSTATUS Status;
  794. BOOLEAN trusted = FALSE;
  795. HANDLE hLsa = NULL;
  796. LSA_STRING LsaStringBuf;
  797. char *AuthPackage = MSV1_0_PACKAGE_NAME;
  798. ULONG PackageId;
  799. ULONG cbOptionsRequest, cbResponse;
  800. MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
  801. PVOID Response = NULL;
  802. ULONG ResponseSize;
  803. NTSTATUS SubStatus;
  804. ReturnStatus = NmpConnectToLsaPrivileged(&hLsa, &trusted);
  805. if (ReturnStatus != ERROR_SUCCESS) {
  806. ClRtlLogPrint(LOG_CRITICAL,
  807. "[NM] Failed to connect to the LSA server while setting "
  808. "process options, status %1!u!.\n",
  809. ReturnStatus
  810. );
  811. goto ErrorExit;
  812. }
  813. RtlInitString(&LsaStringBuf, AuthPackage);
  814. Status = LsaLookupAuthenticationPackage(
  815. hLsa,
  816. &LsaStringBuf, // MSV1_0 authentication package
  817. &PackageId // output: authentication package identifier.
  818. );
  819. if (Status != STATUS_SUCCESS)
  820. {
  821. ReturnStatus = LsaNtStatusToWinError(Status);
  822. ClRtlLogPrint(
  823. LOG_CRITICAL,
  824. "[NM] Authentication package lookup failed while "
  825. "setting LSA process options, status %1!u!.\n",
  826. ReturnStatus
  827. );
  828. goto ErrorExit;
  829. }
  830. cbOptionsRequest = sizeof(OptionsRequest);
  831. ZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
  832. OptionsRequest.MessageType = MsV1_0SetProcessOption;
  833. OptionsRequest.ProcessOptions = ProcessOptions;
  834. Status = LsaCallAuthenticationPackage(
  835. hLsa,
  836. PackageId,
  837. &OptionsRequest,
  838. cbOptionsRequest,
  839. &Response,
  840. &ResponseSize,
  841. &SubStatus
  842. );
  843. if (Status != STATUS_SUCCESS)
  844. {
  845. ReturnStatus = LsaNtStatusToWinError(Status);
  846. ClRtlLogPrint(
  847. LOG_CRITICAL,
  848. "[NM] Failed to set LSA process options (1) to %1!x! , "
  849. "status %2!u!.\n",
  850. ProcessOptions, ReturnStatus
  851. );
  852. goto ErrorExit;
  853. }
  854. else if (LsaNtStatusToWinError(SubStatus) != ERROR_SUCCESS)
  855. {
  856. ReturnStatus = LsaNtStatusToWinError(SubStatus);
  857. ClRtlLogPrint(
  858. LOG_CRITICAL,
  859. "[NM] Failed to set LSA process options (2) to %1!x! , "
  860. "status %2!u!.\n",
  861. ProcessOptions, ReturnStatus
  862. );
  863. goto ErrorExit;
  864. }
  865. ReturnStatus = ERROR_SUCCESS;
  866. ErrorExit:
  867. if (hLsa != NULL) {
  868. LsaDeregisterLogonProcess(hLsa);
  869. hLsa = NULL;
  870. }
  871. return ReturnStatus;
  872. } // NmpSetLsaProcessOptions
  873. // Helper routines used for encryption on the wire data
  874. // currently used only by dmsync.c to secure transfer of checkpoints
  875. // Here the pattern how this routines should be used
  876. // (Crafted to produce the least amout of code change in dm to encrypt/decrypt data going over an RPC pipe)
  877. //
  878. // Encryption:
  879. // NmCryptor_Init(Cryptor)
  880. //
  881. // NmCryptor_PrepareEncryptionBuffer(Cryptor, Buffer, Size);
  882. // <Put upto Cryptor->PayloadSize bytes of data into Cryptor->PayloadBuffer (say X bytes)>
  883. // NmCryptor_Encrypt(&Cryptor, X);
  884. // <transmit/store encrypted bytes from Cryptor->EncryptedBuffer, Cryptor->EncryptedSize>
  885. //
  886. // ... repeat PrepareEncryptionBuffer/Encrypt for as many time as you need
  887. //
  888. // NmCryptor_Destroy(Cryptor)
  889. //
  890. // Decryption:
  891. //
  892. // NmCryptor_Init(Cryptor)
  893. //
  894. // <Copy the data to be decrypted into some buffer>
  895. // NmCryptor_Decrypt(Cryptor, Buffer, Size);
  896. // <Get the data from Cryptor->PayloadBuffer, Cryptor->PayloadSize>
  897. //
  898. // ... repeat NmCryptor_Decrypt for as many packets you have to decrypt ...
  899. //
  900. // NmCryptor_Destroy(Cryptor)
  901. typedef struct _NMP_CRYPTOR_HEADER {
  902. BYTE Salt[16]; // random goo which is mixed with the shared secret to produce a key
  903. BYTE SaltQuickSig[16]; // simple xor of salt bytes with 0xFF used as a quick test whether stuff is encrypted or not
  904. BYTE SaltSlowSig[16]; // encrypted salt bytes to check for the valid encryption key
  905. } NM_CRYPTOR_HEADER, *PNM_CRYPTOR_HEADER;
  906. VOID
  907. NmCryptor_Init(
  908. IN OUT PNM_CRYPTOR Cryptor,
  909. IN BOOL EnableEncryption)
  910. {
  911. ZeroMemory(Cryptor, sizeof(*Cryptor));
  912. Cryptor->EncryptionDisabled = !EnableEncryption;
  913. }
  914. BOOL NmpVerifyQuickSig(IN PNM_CRYPTOR_HEADER hdr)
  915. {
  916. int i;
  917. if (hdr->SaltQuickSig[0] != 'Q' || hdr->SaltQuickSig[1] != 'S') {
  918. return FALSE;
  919. }
  920. for (i = 2; i < sizeof(hdr->Salt); ++i) {
  921. if (hdr->SaltQuickSig[i] != (hdr->Salt[i] ^ 0xFF) ) {
  922. return FALSE;
  923. }
  924. }
  925. return TRUE;
  926. }
  927. VOID NmpMakeQuickSig(IN PNM_CRYPTOR_HEADER hdr)
  928. {
  929. int i;
  930. for (i = 2; i < sizeof(hdr->Salt); ++i) {
  931. hdr->SaltQuickSig[i] = hdr->Salt[i] ^ 0xFF;
  932. }
  933. hdr->SaltQuickSig[0] = 'Q'; // to make it easier to spot in the sniff
  934. hdr->SaltQuickSig[1] = 'S'; //
  935. }
  936. DWORD NmpCryptor_PrepareKey(
  937. IN OUT PNM_CRYPTOR Cryptor,
  938. IN BOOL GenerateSalt)
  939. /*++
  940. Routine Description:
  941. Calls prepares the key for encrption/decryption.
  942. Creates a symmetric key by mixing random 128bit salt with cluster password derived secret
  943. Arguments:
  944. GenerateSalt - if true, salt is generated, if false, salt is read from a buffer
  945. Return Value:
  946. ERROR_SUCCESS if successful
  947. Win32 error code otherwise.
  948. --*/
  949. {
  950. DWORD Status = ERROR_SUCCESS;
  951. DWORD ClusterKeyLen = 0;
  952. PBYTE ClusterKey = NULL;
  953. PNM_CRYPTOR_HEADER hdr = (PNM_CRYPTOR_HEADER)Cryptor->EncryptedBuffer;
  954. if (GenerateSalt) {
  955. // Check that a buffer is big enough
  956. // to hold encryption header
  957. if (Cryptor->EncryptedSize < sizeof(*hdr)) {
  958. ClRtlLogPrint(LOG_CRITICAL,
  959. "[NM] Cryptor: No room for the header, buffer size is only %1!u!.\n",
  960. Cryptor->EncryptedSize
  961. );
  962. return ERROR_INSUFFICIENT_BUFFER;
  963. }
  964. } else {
  965. // Otherwise, do a quick check whether the incoming data
  966. // is encrypted
  967. if (Cryptor->EncryptedSize < sizeof(*hdr)) {
  968. Cryptor->EncryptionDisabled = TRUE;
  969. return ERROR_SUCCESS;
  970. }
  971. if ( !NmpVerifyQuickSig(hdr) ) {
  972. ClRtlLogPrint(LOG_UNUSUAL,
  973. "[NM] Cryptor: Data is not encrypted.\n"
  974. );
  975. Cryptor->EncryptionDisabled = TRUE;
  976. return ERROR_SUCCESS;
  977. }
  978. }
  979. Status = NmpCreateCSPHandle(&Cryptor->CryptProv);
  980. if (Status != ERROR_SUCCESS) {
  981. return Status;
  982. }
  983. if (GenerateSalt) {
  984. if (!CryptGenRandom(Cryptor->CryptProv, sizeof(hdr->Salt), hdr->Salt)){
  985. Status = GetLastError();
  986. ClRtlLogPrint(LOG_CRITICAL,
  987. "[NM] Cryptor: CryptGenRandom failed %1!u!.\n",
  988. Status
  989. );
  990. goto exit_gracefully;
  991. }
  992. }
  993. Status = NmpDeriveSessionKey(
  994. Cryptor->CryptProv,
  995. CALG_RC4, 128 << 16, // algorithm, key length
  996. hdr->Salt, sizeof(hdr->Salt),
  997. &Cryptor->CryptKey);
  998. if (Status != ERROR_SUCCESS) {
  999. goto exit_gracefully; // error logged by NmpDeriveSessionKey
  1000. }
  1001. if (GenerateSalt) {
  1002. DWORD Len = sizeof(hdr->SaltSlowSig);
  1003. // Encrypt SlowSig so that the receiver can verify the validity
  1004. // of an encryption key of a sender
  1005. memcpy(hdr->SaltSlowSig, hdr->Salt, sizeof(hdr->SaltSlowSig));
  1006. if (!CryptEncrypt(Cryptor->CryptKey, 0, FALSE, 0, // hash,final,flags
  1007. hdr->SaltSlowSig, &Len, Len))
  1008. {
  1009. Status = GetLastError();
  1010. ClRtlLogPrint(LOG_CRITICAL,
  1011. "[NM] Failed to Encrypt signature, status %1!u!.\n",
  1012. Status
  1013. );
  1014. goto exit_gracefully;
  1015. }
  1016. // now make quick signature (to test whether the incoming data is encrypted)
  1017. NmpMakeQuickSig(hdr);
  1018. } else {
  1019. DWORD Len = sizeof(hdr->SaltSlowSig);
  1020. // Verify encrypted portion of the signature
  1021. if (!CryptDecrypt(Cryptor->CryptKey, 0, FALSE, 0, // hash,final,flags
  1022. hdr->SaltSlowSig, &Len))
  1023. {
  1024. Status = GetLastError();
  1025. ClRtlLogPrint(LOG_CRITICAL,
  1026. "[NM] Failed to Decrypt signature, status %1!u!.\n",
  1027. Status
  1028. );
  1029. goto exit_gracefully;
  1030. }
  1031. if (memcmp(hdr->Salt, hdr->SaltSlowSig, sizeof(hdr->SaltSlowSig)) != 0) {
  1032. Status = ERROR_DECRYPTION_FAILED;
  1033. ClRtlLogPrint(LOG_CRITICAL,
  1034. "[NM] Signatures don't match.\n"
  1035. );
  1036. goto exit_gracefully;
  1037. }
  1038. }
  1039. Cryptor->KeyGenerated = TRUE;
  1040. exit_gracefully:
  1041. return Status;
  1042. }
  1043. DWORD
  1044. NmCryptor_Decrypt(
  1045. IN OUT PNM_CRYPTOR Cryptor,
  1046. IN OUT PVOID Buffer,
  1047. IN DWORD BufferSize)
  1048. /*++
  1049. Routine Description:
  1050. Decrypts the supplied buffer
  1051. Return Value:
  1052. ERROR_SUCCESS if successful
  1053. Win32 error code otherwise.
  1054. Notes:
  1055. If the routine succeeds, use
  1056. Cryptor->PayloadBuffer
  1057. Cryptor->PayloadSize
  1058. fields to get to the decrypted data
  1059. --*/
  1060. {
  1061. DWORD Status = ERROR_SUCCESS;
  1062. Cryptor->PayloadBuffer = (PBYTE)Buffer;
  1063. Cryptor->PayloadSize = BufferSize;
  1064. Cryptor->EncryptedBuffer = Cryptor->PayloadBuffer;
  1065. Cryptor->EncryptedSize = BufferSize;
  1066. if (Cryptor->EncryptionDisabled) {
  1067. return ERROR_SUCCESS;
  1068. }
  1069. if (!Cryptor->KeyGenerated) {
  1070. Status = NmpCryptor_PrepareKey(Cryptor, FALSE);
  1071. if (Status != ERROR_SUCCESS) {
  1072. return Status;
  1073. }
  1074. if (Cryptor->EncryptionDisabled) {
  1075. ClRtlLogPrint(LOG_UNUSUAL,
  1076. "[NM] Cryptor received unencrypted data.\n"
  1077. );
  1078. return ERROR_SUCCESS;
  1079. }
  1080. Cryptor->PayloadBuffer = Cryptor->PayloadBuffer + sizeof(NM_CRYPTOR_HEADER);
  1081. Cryptor->PayloadSize -= sizeof(NM_CRYPTOR_HEADER);
  1082. }
  1083. if (!CryptDecrypt(Cryptor->CryptKey, 0, FALSE, 0,
  1084. Cryptor->PayloadBuffer, &Cryptor->PayloadSize))
  1085. {
  1086. Status = GetLastError();
  1087. ClRtlLogPrint(LOG_CRITICAL,
  1088. "[NM] Failed to Decrypt buffer, status %1!u!.\n",
  1089. Status
  1090. );
  1091. }
  1092. return Status;
  1093. }
  1094. VOID
  1095. NmCryptor_PrepareEncryptionBuffer(
  1096. IN OUT PNM_CRYPTOR Cryptor,
  1097. IN OUT PVOID Buffer,
  1098. IN DWORD BufferSize)
  1099. /*++
  1100. Routine Description:
  1101. Supplies the information about the buffer ti be used for encryption
  1102. Return Value:
  1103. ERROR_SUCCESS if successful
  1104. Win32 error code otherwise.
  1105. Notes:
  1106. When the function returns, use
  1107. Cryptor->PayloadBuffer
  1108. Cryptor->PayloadSize
  1109. to figure out where to put the data to be encrypted
  1110. --*/
  1111. {
  1112. Cryptor->PayloadBuffer = (PBYTE)Buffer;
  1113. Cryptor->PayloadSize = BufferSize;
  1114. Cryptor->EncryptedBuffer = Cryptor->PayloadBuffer;
  1115. Cryptor->EncryptedSize = BufferSize;
  1116. if (Cryptor->EncryptionDisabled || Cryptor->KeyGenerated) {
  1117. return;
  1118. }
  1119. if (NmpIsNT5NodeInCluster == FALSE) {
  1120. // Create room for the header
  1121. Cryptor->PayloadBuffer += sizeof(NM_CRYPTOR_HEADER);
  1122. Cryptor->PayloadSize -= sizeof(NM_CRYPTOR_HEADER);
  1123. } else {
  1124. Cryptor->EncryptionDisabled = TRUE;
  1125. }
  1126. }
  1127. DWORD
  1128. NmCryptor_Encrypt(
  1129. IN OUT PNM_CRYPTOR Cryptor,
  1130. DWORD DataSize)
  1131. /*++
  1132. Routine Description:
  1133. Encrypts DataSize bytes
  1134. Return Value:
  1135. ERROR_SUCCESS if successful
  1136. Win32 error code otherwise.
  1137. Notes:
  1138. Input data are in the buffer pointed by
  1139. Cryptor->PayloadSize (prepared by NmCryptor_PrepareEncryptionBuffer routine)
  1140. Output data are in:
  1141. Cryptor->EncryptedBuffer == Whatever buffer was supplied to NmCryptor_PrepareEncryptionBuffer
  1142. Cryptor->EncryptedSize
  1143. --*/
  1144. {
  1145. DWORD Status = ERROR_SUCCESS;
  1146. if (Cryptor->EncryptionDisabled) {
  1147. Cryptor->EncryptedSize = DataSize;
  1148. return ERROR_SUCCESS;
  1149. }
  1150. if (!Cryptor->KeyGenerated) {
  1151. Status = NmpCryptor_PrepareKey(Cryptor, TRUE);
  1152. if (Status != ERROR_SUCCESS) {
  1153. return Status;
  1154. }
  1155. }
  1156. if (!CryptEncrypt(Cryptor->CryptKey, 0, FALSE, 0,
  1157. Cryptor->PayloadBuffer, &DataSize, Cryptor->EncryptedSize))
  1158. {
  1159. Status = GetLastError();
  1160. ClRtlLogPrint(LOG_CRITICAL,
  1161. "[NM] Failed to Encrypt buffer, status %1!u!.\n",
  1162. Status
  1163. );
  1164. }
  1165. Cryptor->EncryptedSize =
  1166. DataSize + (int)(Cryptor->PayloadBuffer - Cryptor->EncryptedBuffer);
  1167. return Status;
  1168. }
  1169. VOID
  1170. NmCryptor_Destroy(
  1171. PNM_CRYPTOR Cryptor)
  1172. {
  1173. if (Cryptor == NULL) {
  1174. return;
  1175. }
  1176. if (Cryptor->CryptKey) {
  1177. CryptDestroyKey(Cryptor->CryptKey);
  1178. }
  1179. if (Cryptor->CryptProv) {
  1180. CryptReleaseContext(Cryptor->CryptProv, 0);
  1181. }
  1182. }
  1183. void
  1184. NmpFreeNetworkMulticastKey(
  1185. PNM_NETWORK_MULTICASTKEY networkMulticastKey
  1186. )
  1187. {
  1188. if (networkMulticastKey != NULL)
  1189. {
  1190. if (networkMulticastKey->EncryptedMulticastKey != NULL)
  1191. {
  1192. MIDL_user_free(networkMulticastKey->EncryptedMulticastKey);
  1193. }
  1194. if (networkMulticastKey->MAC != NULL)
  1195. {
  1196. MIDL_user_free(networkMulticastKey->MAC);
  1197. }
  1198. if (networkMulticastKey->Salt != NULL)
  1199. {
  1200. MIDL_user_free(networkMulticastKey->Salt);
  1201. }
  1202. MIDL_user_free(networkMulticastKey);
  1203. }
  1204. } // NmpFreeNetworkMulticastKey()
  1205. DWORD
  1206. NmpGetMulticastKeyFromNMLeader(
  1207. IN DWORD LeaderNodeId,
  1208. IN LPWSTR NodeIdString,
  1209. IN LPWSTR NetworkId,
  1210. IN PNM_NETWORK_MULTICASTKEY * MulticastKey
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. Issue a retrieve request for network multicast key to NM leader.
  1215. Arguments:
  1216. Return Value:
  1217. ERROR_SUCCESS if the request is successful.
  1218. Win32 error code on failure.
  1219. Notes:
  1220. This routine mimics GumpUpdateRemoteNode. In Longhorn, there
  1221. should be one generic async RPC call wrapper.
  1222. --*/
  1223. {
  1224. DWORD Status;
  1225. HANDLE hEventHandle;
  1226. BOOL result;
  1227. PNM_NODE Node = NULL;
  1228. HANDLE handleArr[2];
  1229. RPC_ASYNC_STATE AsyncState;
  1230. RPC_BINDING_HANDLE rpcBinding;
  1231. //
  1232. // Prepare for async RPC. We do this here to avoid hitting a failure
  1233. // after the update is already in progress.
  1234. //
  1235. ZeroMemory((PVOID) &AsyncState, sizeof(RPC_ASYNC_STATE));
  1236. AsyncState.u.hEvent = CreateEvent(
  1237. NULL, // no attributes
  1238. TRUE, // manual reset
  1239. FALSE, // initial state unsignalled
  1240. NULL // no object name
  1241. );
  1242. if (AsyncState.u.hEvent == NULL) {
  1243. Status = GetLastError();
  1244. ClRtlLogPrint(LOG_CRITICAL,
  1245. "[GUM] NmpGetMulticastKeyFromNMLeader: Failed to allocate event object for async "
  1246. "RPC call, status %1!u!\n",
  1247. Status
  1248. );
  1249. return (Status);
  1250. }
  1251. //
  1252. // Initialize the async RPC tracking information
  1253. //
  1254. hEventHandle = AsyncState.u.hEvent;
  1255. AsyncState.u.hEvent = NULL;
  1256. Status = RpcAsyncInitializeHandle(&AsyncState, sizeof(RPC_ASYNC_STATE));
  1257. AsyncState.u.hEvent = hEventHandle;
  1258. if (Status != RPC_S_OK) {
  1259. ClRtlLogPrint(LOG_CRITICAL,
  1260. "[GUM] NmpGetMulticastKeyFromNMLeader: Failed to initialize async RPC status "
  1261. "block, status %1!u!\n",
  1262. Status
  1263. );
  1264. goto error_exit;
  1265. }
  1266. AsyncState.UserInfo = NULL;
  1267. AsyncState.NotificationType = RpcNotificationTypeEvent;
  1268. result = ResetEvent(AsyncState.u.hEvent);
  1269. CL_ASSERT(result != 0);
  1270. //
  1271. // Now hook onto NM node state down event mechanism to detect node downs.
  1272. //
  1273. Node = NmReferenceNodeById(LeaderNodeId);
  1274. CL_ASSERT(Node != NULL);
  1275. if (Node == NULL) {
  1276. Status = GetLastError();
  1277. ClRtlLogPrint(LOG_UNUSUAL,
  1278. "[GUM] NmpGetMulticastKeyFromNMLeader: Failed to reference leader "
  1279. "node id %1!u!, status %2!u!\n",
  1280. LeaderNodeId, Status
  1281. );
  1282. goto error_exit;
  1283. }
  1284. handleArr[0] = AsyncState.u.hEvent;
  1285. handleArr[1] = NmGetNodeStateDownEvent(Node);
  1286. //
  1287. // Get the RPC binding handle for the leader node.
  1288. //
  1289. // Note that there is a race condition here with
  1290. // ClMsgCleanup. The Session array can be freed
  1291. // before we dereference Session. This would lead
  1292. // to an unfortunate AV exception, but it would not
  1293. // be tragic since the service is already terminating
  1294. // abnormally if ClMsgCleanup is executing.
  1295. //
  1296. if (Session != NULL) {
  1297. rpcBinding = Session[LeaderNodeId];
  1298. } else {
  1299. ClRtlLogPrint(LOG_UNUSUAL,
  1300. "[GUM] NmpGetMulticastKeyFromNMLeader: No RPC "
  1301. "binding handle for leader node id %1!u!.\n",
  1302. LeaderNodeId
  1303. );
  1304. Status = ERROR_CLUSTER_NODE_UNREACHABLE;
  1305. goto error_exit;
  1306. }
  1307. try {
  1308. //
  1309. // Get multicast key from the leader
  1310. //
  1311. Status = NmRpcGetNetworkMulticastKey(
  1312. &AsyncState,
  1313. rpcBinding,
  1314. NodeIdString,
  1315. NetworkId,
  1316. MulticastKey
  1317. );
  1318. if (Status == RPC_S_OK) {
  1319. DWORD RpcStatus;
  1320. //
  1321. // The call is pending. Wait for completion.
  1322. //
  1323. Status = WaitForMultipleObjects(
  1324. 2,
  1325. handleArr,
  1326. FALSE,
  1327. INFINITE
  1328. );
  1329. if (Status != WAIT_OBJECT_0) {
  1330. //
  1331. // Something went wrong.
  1332. // Either this is a rpc failure or, the target node went down.
  1333. //
  1334. CL_ASSERT(Status != WAIT_OBJECT_0);
  1335. Status = GetLastError();
  1336. ClRtlLogPrint(LOG_CRITICAL,
  1337. "[GUM] NmpGetMulticastKeyFromNMLeader: Wait for NmRpcGetNetworkMulticastKey"
  1338. " failed, status %1!u!\n",
  1339. Status
  1340. );
  1341. //
  1342. // Cancel the call, just to be safe.
  1343. //
  1344. RpcStatus = RpcAsyncCancelCall(
  1345. &AsyncState,
  1346. TRUE // Abortive cancel
  1347. );
  1348. if (RpcStatus != RPC_S_OK) {
  1349. ClRtlLogPrint(LOG_CRITICAL,
  1350. "[GUM] NmpGetMulticastKeyFromNMLeader: RpcAsyncCancelCall()= "
  1351. " %1!u!\n",
  1352. RpcStatus
  1353. );
  1354. }
  1355. CL_ASSERT(RpcStatus == RPC_S_OK);
  1356. //
  1357. // Wait for the call to complete.
  1358. //
  1359. Status = WaitForSingleObject(
  1360. AsyncState.u.hEvent,
  1361. INFINITE
  1362. );
  1363. if (Status != WAIT_OBJECT_0) {
  1364. ClRtlLogPrint(LOG_CRITICAL,
  1365. "[GUM] NmpGetMulticastKeyFromNMLeader: WaitForSingleObject()= "
  1366. " %1!u!\n",
  1367. Status
  1368. );
  1369. }
  1370. CL_ASSERT(Status == WAIT_OBJECT_0);
  1371. }
  1372. //
  1373. // The call should now be complete. Get the
  1374. // completion status. Any RPC error will be
  1375. // returned in 'RpcStatus'. If there was no
  1376. // RPC error, then any application error will
  1377. // be returned in 'Status'.
  1378. //
  1379. RpcStatus = RpcAsyncCompleteCall(
  1380. &AsyncState,
  1381. &Status
  1382. );
  1383. if (RpcStatus != RPC_S_OK) {
  1384. ClRtlLogPrint(LOG_CRITICAL,
  1385. "[GUM] NmpGetMulticastKeyFromNMLeader: Failed to get "
  1386. "completion status for async RPC call,"
  1387. "status %1!u!\n",
  1388. RpcStatus
  1389. );
  1390. Status = RpcStatus;
  1391. }
  1392. }
  1393. else {
  1394. //
  1395. // An error was returned synchronously.
  1396. //
  1397. ClRtlLogPrint(LOG_CRITICAL,
  1398. "[GUM] NmpGetMulticastKeyFromNMLeader: NmRpcGetNetworkMulticastKey() "
  1399. "failed synchronously, status %1!u!\n",
  1400. Status
  1401. );
  1402. }
  1403. } except (I_RpcExceptionFilter(RpcExceptionCode())) {
  1404. Status = GetExceptionCode();
  1405. }
  1406. error_exit:
  1407. if (AsyncState.u.hEvent != NULL) {
  1408. CloseHandle(AsyncState.u.hEvent);
  1409. }
  1410. if (Node != NULL) {
  1411. OmDereferenceObject(Node);
  1412. }
  1413. return(Status);
  1414. } // NmpGetMulticastKeyFromNMLeader
  1415. #ifdef MULTICAST_DEBUG
  1416. DWORD
  1417. NmpDbgPrintData(LPCWSTR InfoStr,
  1418. PVOID Data,
  1419. DWORD DataLen
  1420. )
  1421. {
  1422. DWORD i;
  1423. ClRtlLogPrint(
  1424. LOG_NOISE,
  1425. "\n\n%1!ws!\n",
  1426. InfoStr);
  1427. for (i=0; i<DataLen/sizeof(DWORD); i++)
  1428. {
  1429. ClRtlLogPrint(
  1430. LOG_NOISE,
  1431. "%1!u! = %2!u!\n",
  1432. i,
  1433. *((DWORD *)Data+i)
  1434. );
  1435. }
  1436. ClRtlLogPrint(
  1437. LOG_NOISE,
  1438. "\n\n"
  1439. );
  1440. return ERROR_SUCCESS;
  1441. } // NmpDbgPrintData()
  1442. #endif