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.

3275 lines
87 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. setpass.c
  5. Abstract:
  6. Routines for setting the cluster service account password.
  7. Author:
  8. Rui Hu (ruihu) 22-June-2001
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "nmp.h"
  13. #include <ntlsa.h>
  14. #include <ntmsv1_0.h>
  15. #include <wincrypt.h>
  16. /////////////////////////////////////////////////////////////////////////////
  17. //
  18. // General information about using the Crypto API
  19. //
  20. // Use CryptAcquireContext CRYPT_VERIFYCONTEXT for hashing and bulk
  21. // encryption. The verify-context makes this call a bit faster.
  22. //
  23. // Use CryptGenRandom to generate the salt for your encryption key.
  24. //
  25. // Grab 20 bytes of previously agreed base data.
  26. // You�ll use it for your encryption key, and for the Mac key.
  27. //
  28. // To generate your MAC, hash the first 10 bytes of base data. Then call
  29. // CryptDeriveKey CALG_RC2 and specify 128 bit key size. Then call
  30. // CryptSetKeyParam KP_EFFECTIVE_KEYLEN and specify 128 bit effective key
  31. // size. Then call CryptCreateHash CALG_MAC, and specify the rc2 key you
  32. // just created. Then hash all of your message using this Mac, and extract
  33. // the 8 byte result.
  34. //
  35. // Calling CryptHashData() to hash all of your message. All of my
  36. // message = salt + encrypted message. Using CryptGetHashParam() to
  37. // extract the 8 byte result.
  38. //
  39. // To generate your encryption key, hash the second 10 bytes of base data.
  40. // Then hash 16 bytes of random salt. The call CryptDeriveKey CALG_RC2 and
  41. // specify 128 bit key size. Then encrypt your message data. Don�t encrypt
  42. // your salt or your Mac result; those can be sent in the clear.
  43. //
  44. //////////////////////////////////////////////////////////////////////////////
  45. /////////////////////////////////////////////////////////////////////////////
  46. //
  47. // Data
  48. //
  49. /////////////////////////////////////////////////////////////////////////////
  50. LPWSTR NmpLastNewPasswordEncrypted = NULL;
  51. DWORD NmpLastNewPasswordEncryptedLength = 0;
  52. /////////////////////////////////////////////////////////////////////////////
  53. //
  54. // Function Declaration
  55. //
  56. /////////////////////////////////////////////////////////////////////////////
  57. DWORD
  58. NmpGetSharedCommonKey(
  59. OUT BYTE **SharedCommonKey,
  60. OUT DWORD *SharedCommonKeyLen,
  61. OUT BYTE **SharedCommonKeyFirstHalf,
  62. OUT DWORD *SharedCommonKeyFirstHalfLen,
  63. OUT BYTE **SharedCommonKeySecondHalf,
  64. OUT DWORD *SharedCommonKeySecondHalfLen
  65. );
  66. DWORD
  67. NmpDeriveSessionKeyEx(
  68. IN HCRYPTPROV CryptProv,
  69. IN ALG_ID EncryptionAlgoId,
  70. IN DWORD Flags,
  71. IN BYTE *BaseData,
  72. IN DWORD BaseDataLen,
  73. IN BYTE *SaltBuffer,
  74. IN DWORD SaltBufferLen,
  75. OUT HCRYPTKEY *CryptKey
  76. );
  77. /////////////////////////////////////////////////////////////////////////////
  78. //
  79. // Helper Functions
  80. //
  81. /////////////////////////////////////////////////////////////////////////////
  82. DWORD
  83. NmpProtectData(IN PVOID Data,
  84. IN DWORD DataLength,
  85. OUT PVOID *EncryptedData,
  86. OUT DWORD *EncryptedDataLength
  87. )
  88. /*++
  89. Routine Description:
  90. Encrypt data using DP API.
  91. Notes:
  92. The memory where EncryptedData points to is allocated by the system.
  93. User is responsible to call LocalFree(EncryptedData) to release the
  94. memory after its usage.
  95. --*/
  96. {
  97. DWORD Status = ERROR_SUCCESS;
  98. BOOL Success;
  99. DATA_BLOB DataIn;
  100. DATA_BLOB DataOut;
  101. DataIn.pbData = Data;
  102. DataIn.cbData = DataLength;
  103. Success = CryptProtectData(&DataIn, // data to be encrypted
  104. NULL, // description string
  105. NULL,
  106. NULL,
  107. NULL,
  108. 0, // flags
  109. &DataOut // encrypted data
  110. );
  111. if (!Success)
  112. {
  113. Status = GetLastError();
  114. ClRtlLogPrint(LOG_UNUSUAL,
  115. "[NM] Failed to encrypt data using CryptProtectData, "
  116. "status %1!u!.\n",
  117. Status
  118. );
  119. goto error_exit;
  120. }
  121. *EncryptedData = DataOut.pbData;
  122. *EncryptedDataLength = DataOut.cbData;
  123. error_exit:
  124. return (Status);
  125. } // NmpProtectData()
  126. DWORD
  127. NmpUnprotectData(
  128. IN PVOID EncryptedData,
  129. IN DWORD EncryptedDataLength,
  130. OUT PVOID * Data,
  131. OUT DWORD * DataLength
  132. )
  133. /*++
  134. Routine Description:
  135. Decrypt data using DP API.
  136. Arguments:
  137. Return Value:
  138. ERROR_SUCCESS if the routine completes successfully.
  139. A Win32 error code otherwise.
  140. Notes:
  141. Memory is allocated for Data by the system. User is responsible to
  142. release this memory using LocalFree(Data) after its usage.
  143. --*/
  144. {
  145. BOOL Success;
  146. DATA_BLOB DataIn;
  147. DATA_BLOB DataOut;
  148. DWORD Status = ERROR_SUCCESS;
  149. ZeroMemory(&DataOut, sizeof(DataOut));
  150. DataIn.pbData = EncryptedData;
  151. DataIn.cbData = EncryptedDataLength;
  152. Success = CryptUnprotectData(&DataIn, // data to be decrypted
  153. NULL,
  154. NULL,
  155. NULL,
  156. NULL,
  157. 0, // flags
  158. &DataOut // decrypted data
  159. );
  160. if (!Success)
  161. {
  162. Status = GetLastError();
  163. ClRtlLogPrint(LOG_UNUSUAL,
  164. "[NM] Failed to decrypt data using CryptUnprotectData, "
  165. "status %1!u!.\n",
  166. Status
  167. );
  168. goto error_exit;
  169. }
  170. *Data = DataOut.pbData;
  171. *DataLength = DataOut.cbData;
  172. error_exit:
  173. return (Status);
  174. } // NmpUnprotectData()
  175. DWORD
  176. NmpCreateCSPHandle(
  177. OUT HCRYPTPROV *CryptProvider
  178. )
  179. /*++
  180. Routine Description:
  181. Arguments:
  182. Return Value:
  183. ERROR_SUCCESS if successful
  184. Win32 error code otherwise.
  185. Notes:
  186. --*/
  187. {
  188. DWORD ReturnStatus;
  189. BOOL Success;
  190. //
  191. // Get a handle to default key container within CSP MS_ENHANCED_PROV.
  192. //
  193. Success = CryptAcquireContext(
  194. CryptProvider, // output: handle to crypto provider
  195. NULL, // default key container
  196. MS_ENHANCED_PROV, // provider name
  197. PROV_RSA_FULL, // provider type
  198. CRYPT_VERIFYCONTEXT // don't need private keys
  199. );
  200. if (!Success)
  201. {
  202. ReturnStatus = GetLastError();
  203. if (ReturnStatus == NTE_BAD_KEYSET)
  204. { //
  205. // Create a new key container
  206. //
  207. Success = CryptAcquireContext(
  208. CryptProvider,
  209. NULL,
  210. MS_ENHANCED_PROV,
  211. PROV_RSA_FULL,
  212. CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT
  213. );
  214. }
  215. if (!Success)
  216. {
  217. ReturnStatus = GetLastError();
  218. ClRtlLogPrint(
  219. LOG_CRITICAL,
  220. "[NM] CreateCSPHandle: Failed to acquire crypto context, "
  221. "status %1!u!.\n",
  222. ReturnStatus
  223. );
  224. return ReturnStatus;
  225. }
  226. }
  227. return(ERROR_SUCCESS);
  228. } // NmpCreateCSPHandle()
  229. DWORD
  230. NmpCreateRandomNumber(OUT PVOID * RandomNumber,
  231. IN DWORD RandomNumberSize
  232. )
  233. /*++
  234. Routine Description:
  235. Create a random number.
  236. Arguments:
  237. RandomNumber - [OUT] A pointer to random number generated.
  238. RandomNumberSize - [IN] The size of random number to be generated in
  239. number of bytes.
  240. Return Value:
  241. ERROR_SUCCESS if the routine completes successfully.
  242. A Win32 error code otherwise.
  243. Notes:
  244. On successful return, the system allocates memory for RandomNumber.
  245. User is responsible to release the memory using LocalFree() after its usage.
  246. --*/
  247. {
  248. DWORD status = ERROR_SUCCESS;
  249. BOOL GenRandomSuccess = FALSE;
  250. PBYTE randomNumber;
  251. randomNumber = LocalAlloc(0, RandomNumberSize);
  252. if (randomNumber == NULL)
  253. {
  254. ClRtlLogPrint(LOG_CRITICAL,
  255. "[NM] Failed to allocate %1!u! bytes.\n",
  256. RandomNumberSize
  257. );
  258. status = ERROR_NOT_ENOUGH_MEMORY;
  259. return (status);
  260. }
  261. GenRandomSuccess = CryptGenRandom(NmCryptServiceProvider,
  262. RandomNumberSize,
  263. randomNumber
  264. );
  265. if (!GenRandomSuccess)
  266. {
  267. status = GetLastError();
  268. ClRtlLogPrint(
  269. LOG_CRITICAL,
  270. "[NM] Unable to generate random number, "
  271. "status %1!u!.\n",
  272. status
  273. );
  274. goto error_exit;
  275. }
  276. #ifdef MULTICAST_DEBUG
  277. NmpDbgPrintData(L"NmpCreateRandomNumber:",
  278. randomNumber,
  279. RandomNumberSize
  280. );
  281. #endif
  282. error_exit:
  283. if (status == ERROR_SUCCESS)
  284. {
  285. *RandomNumber = randomNumber;
  286. }
  287. return status;
  288. } // NmpCreateRandomNumber
  289. DWORD
  290. NmpDeriveSessionKey(
  291. IN HCRYPTPROV CryptProv,
  292. IN ALG_ID EncryptionAlgoId,
  293. IN DWORD Flags,
  294. IN BYTE *SaltBuffer,
  295. IN DWORD SaltBufferLen,
  296. OUT HCRYPTKEY *CryptKey
  297. )
  298. /*++
  299. Routine Description:
  300. This function derives a session key for encryption/decryption.
  301. The derived session key is based on shared NM cluster key and
  302. SaltBuffer.
  303. Arguments:
  304. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  305. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  306. key is to be generated.
  307. Flags - [IN] Specifies the type of key generated.
  308. SaltBuffer - [IN] Pointer to Salt.
  309. CryptKey - [OUT] Pointer to session key.
  310. Return Value:
  311. ERROR_SUCCESS if successful
  312. Win32 error code otherwise.
  313. Notes:
  314. The hash algorithm used is CALG_MD5.
  315. --*/
  316. {
  317. HCRYPTHASH CryptHash = 0;
  318. DWORD Status;
  319. BOOL Success;
  320. BYTE *SharedCommonKey = NULL;
  321. DWORD SharedCommonKeyLen = 0;
  322. BYTE *SharedCommonKeyFirstHalf = NULL;
  323. DWORD SharedCommonKeyFirstHalfLen = 0;
  324. BYTE *SharedCommonKeySecondHalf = NULL;
  325. DWORD SharedCommonKeySecondHalfLen = 0;
  326. //
  327. // Get the base key to be used to encrypt the data
  328. //
  329. Status = NmpGetSharedCommonKey(
  330. &SharedCommonKey,
  331. &SharedCommonKeyLen,
  332. &SharedCommonKeyFirstHalf,
  333. &SharedCommonKeyFirstHalfLen,
  334. &SharedCommonKeySecondHalf,
  335. &SharedCommonKeySecondHalfLen
  336. );
  337. if (Status != ERROR_SUCCESS) {
  338. goto ErrorExit;
  339. }
  340. Status = NmpDeriveSessionKeyEx(CryptProv,
  341. EncryptionAlgoId,
  342. Flags,
  343. SharedCommonKey, // BaseData
  344. SharedCommonKeyLen, // BaseDataLen
  345. SaltBuffer,
  346. SaltBufferLen,
  347. CryptKey
  348. );
  349. if (Status != ERROR_SUCCESS) {
  350. goto ErrorExit;
  351. }
  352. ErrorExit:
  353. if (SharedCommonKey != NULL)
  354. {
  355. RtlSecureZeroMemory(SharedCommonKey, SharedCommonKeyLen);
  356. HeapFree(GetProcessHeap(), 0, SharedCommonKey);
  357. SharedCommonKey = NULL;
  358. SharedCommonKeyLen = 0;
  359. SharedCommonKeyFirstHalf = NULL;
  360. SharedCommonKeyFirstHalfLen = 0;
  361. SharedCommonKeySecondHalf = NULL;
  362. SharedCommonKeySecondHalfLen = 0;
  363. }
  364. return Status;
  365. } // NmpDeriveSessionKey()
  366. DWORD
  367. NmpDeriveSessionKeyEx(
  368. IN HCRYPTPROV CryptProv,
  369. IN ALG_ID EncryptionAlgoId,
  370. IN DWORD Flags,
  371. IN BYTE *BaseData,
  372. IN DWORD BaseDataLen,
  373. IN BYTE *SaltBuffer,
  374. IN DWORD SaltBufferLen,
  375. OUT HCRYPTKEY *CryptKey
  376. )
  377. /*++
  378. Routine Description:
  379. This function derives a session key for encryption/decryption.
  380. Arguments:
  381. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  382. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  383. key is to be generated.
  384. Flags - [IN] Specifies the type of key generated.
  385. BaseData - [IN] The base data value from which a cryptographic session
  386. key is derived.
  387. BaseDataLen - [IN] Length in bytes of the input BaseData buffer.
  388. SaltBuffer - [IN] Pointer to Salt.
  389. CryptKey - [OUT] Pointer to session key.
  390. Return Value:
  391. ERROR_SUCCESS if successful
  392. Win32 error code otherwise.
  393. Notes:
  394. --*/
  395. {
  396. HCRYPTHASH CryptHash = 0;
  397. DWORD Status;
  398. BOOL Success;
  399. //
  400. // Create a hash object
  401. //
  402. Success = CryptCreateHash(
  403. CryptProv,
  404. CALG_MD5, // MD5 hashing algorithm.
  405. 0,
  406. 0,
  407. &CryptHash // output: a handle to the new hash object.
  408. );
  409. if (!Success)
  410. {
  411. Status=GetLastError();
  412. ClRtlLogPrint(
  413. LOG_CRITICAL,
  414. "[NM] DeriveSessionKey: Failed to create hash, status %1!u!.\n",
  415. Status
  416. );
  417. goto ErrorExit;
  418. }
  419. //
  420. // Add BaseData to hash object
  421. //
  422. Success = CryptHashData(
  423. CryptHash,
  424. BaseData,
  425. BaseDataLen,
  426. 0 // Flags
  427. );
  428. if (!Success)
  429. {
  430. Status = GetLastError();
  431. ClRtlLogPrint(
  432. LOG_CRITICAL,
  433. "[NM] DeriveSessionKey: Failed to hash base data, status %1!u!.\n",
  434. Status
  435. );
  436. goto ErrorExit;
  437. }
  438. //
  439. // Add Salt to hash object
  440. //
  441. Success = CryptHashData(CryptHash, SaltBuffer, SaltBufferLen, 0);
  442. if (!Success)
  443. {
  444. Status = GetLastError();
  445. ClRtlLogPrint(
  446. LOG_CRITICAL,
  447. "[NM] DeriveSessionKey: Failed to hash salt data, status %1!u!.\n",
  448. Status
  449. );
  450. goto ErrorExit;
  451. }
  452. //
  453. // Derive a session key from the hash object
  454. //
  455. Success = CryptDeriveKey(
  456. CryptProv,
  457. EncryptionAlgoId,
  458. CryptHash,
  459. Flags,
  460. CryptKey // output: handle of the generated key
  461. );
  462. if (!Success)
  463. {
  464. Status = GetLastError();
  465. ClRtlLogPrint(
  466. LOG_CRITICAL,
  467. "[NM] DeriveSessionKey: Failed to derive key, status %1!u!.\n",
  468. Status
  469. );
  470. goto ErrorExit;
  471. }
  472. Status = ERROR_SUCCESS;
  473. ErrorExit:
  474. // Destroy hash object
  475. if (CryptHash)
  476. {
  477. if (!CryptDestroyHash(CryptHash))
  478. {
  479. ClRtlLogPrint(
  480. LOG_ERROR,
  481. "[NM] DeriveSessionKey: Failed to destroy hash, "
  482. "status %1!u!.\n",
  483. GetLastError()
  484. );
  485. }
  486. }
  487. return Status;
  488. } // NmpDeriveSessionKeyEx()
  489. DWORD
  490. NmpEncryptMessage(
  491. IN HCRYPTPROV CryptProv,
  492. IN ALG_ID EncryptionAlgoId,
  493. IN DWORD Flags,
  494. OUT BYTE *SaltBuffer,
  495. IN DWORD SaltBufferLen,
  496. IN BYTE *BaseData,
  497. IN DWORD BaseDataLen,
  498. IN BYTE *InputEncryptData,
  499. IN OUT DWORD *EncryptDataLen,
  500. IN DWORD InputEncryptDataBufLen,
  501. OUT BYTE **OutputEncryptData,
  502. IN BOOLEAN CreateSaltFlag
  503. )
  504. /*++
  505. Routine Description:
  506. This function encrypts message (data).
  507. Arguments:
  508. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  509. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  510. key is to be generated.
  511. Flags - [IN] Specifies the type of key generated.
  512. SaltBuffer - [OUT] Pointer to Salt.
  513. BaseData - [IN] The base data value from which a cryptographic session
  514. key is derived.
  515. BaseDataLen - [IN] Length in bytes of the input BaseData buffer.
  516. InputEncryptData - [IN] Message (data) to be encrypted.
  517. EncryptDataLen - [IN/OUT] Before calling this function, the DWORD value
  518. is set to the number of bytes to be encrypted. Upon
  519. return, the DWORD value contains the length of the
  520. encrypted message (data) in bytes
  521. InputEncryptDataBufLen - [IN] Length in bytes of the input
  522. InputEncryptData buffer. This value may be
  523. bigger than EncryptDataLen when it is an
  524. input parameter.
  525. OutputEncryptData - [OUT] Encrypted message (data).
  526. CreateSaltFlag - [IN] Flag indicating if salt should be generated.
  527. Return Value:
  528. ERROR_SUCCESS if successful
  529. Win32 error code otherwise.
  530. Notes:
  531. --*/
  532. {
  533. HCRYPTKEY CryptKey = 0;
  534. DWORD Status;
  535. DWORD i;
  536. DWORD dwOriginalEncryptDataLen = 0;
  537. DWORD dwOutputEncryptDataBufLen = 0;
  538. BOOL Success;
  539. //
  540. // Create the random salt bytes if needed
  541. //
  542. if (CreateSaltFlag == TRUE)
  543. {
  544. Success = CryptGenRandom(
  545. CryptProv,
  546. SaltBufferLen, // bytes of random data to generate
  547. SaltBuffer // output buffer
  548. );
  549. if (!Success)
  550. {
  551. Status = GetLastError();
  552. ClRtlLogPrint(
  553. LOG_CRITICAL,
  554. "[NM] EncryptMessage: Unable to generate salt data, "
  555. "status %1!u!.\n",
  556. Status
  557. );
  558. goto ErrorExit;
  559. }
  560. }
  561. //
  562. // Derive the session key from the base data and salt
  563. //
  564. Status = NmpDeriveSessionKeyEx(
  565. CryptProv,
  566. EncryptionAlgoId, // RC2 block encryption algorithm
  567. Flags, // NMP_KEY_LENGTH, // key length = 128 bits
  568. BaseData,
  569. BaseDataLen,
  570. SaltBuffer,
  571. SaltBufferLen,
  572. &CryptKey
  573. );
  574. if (Status != ERROR_SUCCESS)
  575. {
  576. ClRtlLogPrint(
  577. LOG_CRITICAL,
  578. "[NM] EncryptMessage: Failed to derive session key, "
  579. "status %1!u!.\n",
  580. Status
  581. );
  582. goto ErrorExit;
  583. }
  584. //
  585. // Encrypt data
  586. //
  587. //
  588. // Save length of data to be encrypted
  589. //
  590. dwOriginalEncryptDataLen = *EncryptDataLen;
  591. //
  592. // Call CryptEncrypt() with pbData as NULL to determine the number of
  593. // bytes required for the returned data.
  594. //
  595. Success = CryptEncrypt(
  596. CryptKey, // Handle to the encryption key.
  597. 0,
  598. TRUE, // Final
  599. 0,
  600. NULL, // Pointer to data to be encrypted
  601. EncryptDataLen, // Output: size of buffer required
  602. InputEncryptDataBufLen // Length in bytes of input buffer
  603. );
  604. if (!Success)
  605. {
  606. Status=GetLastError();
  607. ClRtlLogPrint(
  608. LOG_CRITICAL,
  609. "[NM] EncryptMessage: First encryption pass failed, "
  610. "status %1!u!.\n",
  611. Status
  612. );
  613. goto ErrorExit;
  614. }
  615. dwOutputEncryptDataBufLen = *EncryptDataLen;
  616. //
  617. // Allocate a buffer sufficient to hold encrypted data.
  618. //
  619. *OutputEncryptData = HeapAlloc(
  620. GetProcessHeap(),
  621. HEAP_ZERO_MEMORY,
  622. dwOutputEncryptDataBufLen
  623. );
  624. if (*OutputEncryptData == NULL)
  625. {
  626. ClRtlLogPrint(
  627. LOG_CRITICAL,
  628. "[NM] EncryptMessage: Failed to allocate %1!u! bytes for "
  629. "encrypted data buffer.\n",
  630. dwOutputEncryptDataBufLen
  631. );
  632. Status = ERROR_NOT_ENOUGH_MEMORY;
  633. goto ErrorExit;
  634. }
  635. CopyMemory(*OutputEncryptData, InputEncryptData, dwOriginalEncryptDataLen);
  636. //
  637. // Set EncryptDataLen back to its original
  638. //
  639. *EncryptDataLen = dwOriginalEncryptDataLen;
  640. Success = CryptEncrypt(
  641. CryptKey,
  642. 0,
  643. TRUE,
  644. 0,
  645. (BYTE *)*OutputEncryptData,
  646. EncryptDataLen,
  647. dwOutputEncryptDataBufLen
  648. );
  649. if (!Success)
  650. {
  651. Status = GetLastError();
  652. ClRtlLogPrint(
  653. LOG_CRITICAL,
  654. "[NM] EncryptMessage: second encryption pass failed, "
  655. "status %1!u!.\n",
  656. Status
  657. );
  658. goto ErrorExit;
  659. }
  660. Status = ERROR_SUCCESS;
  661. ErrorExit:
  662. if ( (Status != ERROR_SUCCESS) && (*OutputEncryptData != NULL) )
  663. {
  664. if (!HeapFree(GetProcessHeap(), 0, *OutputEncryptData))
  665. {
  666. ClRtlLogPrint(
  667. LOG_UNUSUAL,
  668. "[NM] EncryptMessage: Failed to free encryption buffer, "
  669. "status %1!u!.\n",
  670. GetLastError()
  671. );
  672. }
  673. *OutputEncryptData = NULL;
  674. }
  675. // Destroy CryptKey
  676. if (CryptKey)
  677. {
  678. if (!CryptDestroyKey(CryptKey))
  679. {
  680. ClRtlLogPrint(
  681. LOG_UNUSUAL,
  682. "[NM] EncryptMessage: Failed to free encryption key, "
  683. "status %1!u!.\n",
  684. GetLastError()
  685. );
  686. }
  687. }
  688. return Status;
  689. } //NmpEncryptMessage()
  690. DWORD
  691. NmpCreateMAC(
  692. IN HCRYPTPROV CryptProv,
  693. IN ALG_ID EncryptionAlgoId,
  694. IN DWORD Flags,
  695. IN BYTE *BaseData,
  696. IN DWORD BaseDataLen,
  697. IN BYTE *InputData1,
  698. IN DWORD InputData1Len,
  699. IN BYTE *InputData2,
  700. IN DWORD InputData2Len,
  701. OUT BYTE **ReturnData,
  702. OUT DWORD *ReturnDataLen
  703. )
  704. /*++
  705. Routine Description:
  706. This fucntion creates a MAC (Message Authorization Code) for InputData.
  707. Arguments:
  708. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  709. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  710. key is to be generated.
  711. Flags - [IN] Specifies the type of key generated.
  712. BaseData - [IN] The base data value from which a cryptographic session key is
  713. derived.
  714. BaseDataLen - [IN] Length in bytes of the input BaseData buffer.
  715. InputData1 - [IN] Pointer to input data.
  716. InputData1Len - [IN] Length of input data.
  717. InputData2 - [IN] Pointer to input data.
  718. InputData2Len - [IN] Length of input data.
  719. ReturnData - [OUT] MAC created.
  720. ReturnDataLen - [OUT] Length of MAC created.
  721. Return Value:
  722. ERROR_SUCCESS if successful
  723. Win32 error code otherwise.
  724. Notes:
  725. --*/
  726. {
  727. HCRYPTHASH CryptHash[2];
  728. HCRYPTKEY CryptKey = 0;
  729. DWORD dwKeyLen = 0;
  730. DWORD Status;
  731. BOOL Success;
  732. CryptHash[0] = 0;
  733. CryptHash[1] = 0;
  734. //
  735. // Create a hash object
  736. //
  737. Success = CryptCreateHash(CryptProv, CALG_MD5, 0, 0, &CryptHash[0]);
  738. if (!Success)
  739. {
  740. Status = GetLastError();
  741. ClRtlLogPrint(
  742. LOG_CRITICAL,
  743. "[NM] CreateMAC: Failed to create first hash, status %1!u!.\n",
  744. Status
  745. );
  746. goto ErrorExit;
  747. }
  748. //
  749. // add BaseData to hash object
  750. //
  751. Success = CryptHashData(CryptHash[0], BaseData, BaseDataLen, 0);
  752. if (!Success)
  753. {
  754. Status = GetLastError();
  755. ClRtlLogPrint(
  756. LOG_CRITICAL,
  757. "[NM] CreateMAC: Failed to add base data to hash, status %1!u!.\n",
  758. Status
  759. );
  760. goto ErrorExit;
  761. }
  762. //
  763. // Derive a session key from the hash object
  764. //
  765. Success = CryptDeriveKey(
  766. CryptProv,
  767. EncryptionAlgoId,
  768. CryptHash[0],
  769. Flags,
  770. &CryptKey
  771. );
  772. if (!Success)
  773. {
  774. Status = GetLastError();
  775. ClRtlLogPrint(
  776. LOG_CRITICAL,
  777. "[NM] CreateMAC: Failed to derive session key, status %1!u!.\n",
  778. Status
  779. );
  780. goto ErrorExit;
  781. }
  782. //
  783. // Set effective key length to 128 bits
  784. //
  785. dwKeyLen = 128;
  786. Success = CryptSetKeyParam(
  787. CryptKey,
  788. KP_EFFECTIVE_KEYLEN,
  789. (BYTE *) &dwKeyLen,
  790. 0
  791. );
  792. if (!Success)
  793. {
  794. Status = GetLastError();
  795. ClRtlLogPrint(
  796. LOG_CRITICAL,
  797. "[NM] CreateMAC: Failed to set key length, status %1!u!.\n",
  798. Status
  799. );
  800. goto ErrorExit;
  801. }
  802. //
  803. // Create a hash object
  804. //
  805. Success = CryptCreateHash(
  806. CryptProv,
  807. CALG_MAC,
  808. CryptKey,
  809. 0,
  810. &CryptHash[1]
  811. );
  812. if (!Success)
  813. {
  814. Status = GetLastError();
  815. ClRtlLogPrint(
  816. LOG_CRITICAL,
  817. "[NM] CreateMAC: Failed to create second hash, status %1!u!.\n",
  818. Status
  819. );
  820. goto ErrorExit;
  821. }
  822. //
  823. // add InputData1 to hash object
  824. //
  825. Success = CryptHashData(CryptHash[1], InputData1, InputData1Len, 0);
  826. if (!Success)
  827. {
  828. Status = GetLastError();
  829. ClRtlLogPrint(
  830. LOG_CRITICAL,
  831. "[NM] CreateMAC: Failed to add InputData1 to hash, "
  832. "status %1!u!.\n",
  833. Status
  834. );
  835. goto ErrorExit;
  836. }
  837. //
  838. // add InputData2 to hash object
  839. //
  840. Success = CryptHashData(CryptHash[1], InputData2, InputData2Len, 0);
  841. if (!Success)
  842. {
  843. Status = GetLastError();
  844. ClRtlLogPrint(
  845. LOG_CRITICAL,
  846. "[NM] CreateMAC: Failed to add InputData2 to hash, "
  847. "status %1!u!.\n",
  848. Status
  849. );
  850. goto ErrorExit;
  851. }
  852. //
  853. // Retrieve hash value of hash object
  854. //
  855. Success = CryptGetHashParam(
  856. CryptHash[1], // Handle to the hash object being queried.
  857. HP_HASHVAL, // Hash value
  858. *ReturnData, // Output: the specified value data.
  859. ReturnDataLen, // input buffer size, output bytes stored
  860. 0 // Reserved
  861. );
  862. if (!Success)
  863. {
  864. Status = GetLastError();
  865. ClRtlLogPrint(
  866. LOG_CRITICAL,
  867. "[NM] CreateMAC: Failed to retrieve hash value, status %1!u!.\n",
  868. Status
  869. );
  870. goto ErrorExit;
  871. }
  872. Status = ERROR_SUCCESS;
  873. ErrorExit:
  874. // Destroy hash object
  875. if (CryptHash[0])
  876. if (!CryptDestroyHash(CryptHash[0]))
  877. {
  878. ClRtlLogPrint(
  879. LOG_UNUSUAL,
  880. "[NM] CreateMAC: Failed to free first hash, status %1!u!.\n",
  881. GetLastError());
  882. }
  883. if (CryptHash[1])
  884. if (!CryptDestroyHash(CryptHash[1]))
  885. {
  886. ClRtlLogPrint(
  887. LOG_UNUSUAL,
  888. "[NM] CreateMAC: Failed to free second hash, status %1!u!.\n",
  889. GetLastError());
  890. }
  891. // Destroy CryptKey
  892. if (CryptKey)
  893. {
  894. if (!CryptDestroyKey(CryptKey))
  895. {
  896. ClRtlLogPrint(
  897. LOG_UNUSUAL,
  898. "[NM] CreateMAC: Failed to free key, status %1!u!.\n",
  899. GetLastError()
  900. );
  901. }
  902. }
  903. return Status;
  904. } // NmpCreateMAC()
  905. DWORD
  906. NmpGetCurrentNumberOfUpAndPausedNodes(
  907. VOID
  908. )
  909. /*++
  910. Routine Description:
  911. Counts the number of nodes that are in the UP or PAUSED states.
  912. Arguments:
  913. None
  914. Return Value:
  915. ERROR_SUCCESS if successful
  916. Win32 error code otherwise.
  917. Notes:
  918. Must be called with NmpLock held.
  919. --*/
  920. {
  921. DWORD dwCnt = 0;
  922. PLIST_ENTRY pListEntry;
  923. PNM_NODE node;
  924. for ( pListEntry = NmpNodeList.Flink;
  925. pListEntry != &NmpNodeList;
  926. pListEntry = pListEntry->Flink )
  927. {
  928. node = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  929. if (NM_NODE_UP(node))
  930. {
  931. dwCnt++;
  932. }
  933. }
  934. return(dwCnt);
  935. } // NmpGetCurrentNumberOfUpAndPausedNodes()
  936. DWORD
  937. NmpGetSharedCommonKey(
  938. OUT BYTE **SharedCommonKey,
  939. OUT DWORD *SharedCommonKeyLen,
  940. OUT BYTE **SharedCommonKeyFirstHalf,
  941. OUT DWORD *SharedCommonKeyFirstHalfLen,
  942. OUT BYTE **SharedCommonKeySecondHalf,
  943. OUT DWORD *SharedCommonKeySecondHalfLen
  944. )
  945. /*++
  946. Routine Description:
  947. Arguments:
  948. Return Value:
  949. ERROR_SUCCESS if successful
  950. Win32 error code otherwise.
  951. Notes:
  952. --*/
  953. {
  954. DWORD Status;
  955. //
  956. // Figure out how much memory to allocate for the key buffer
  957. //
  958. Status = NmpGetClusterKey(NULL, SharedCommonKeyLen);
  959. if (Status == ERROR_FILE_NOT_FOUND)
  960. {
  961. Status = NmpCreateClusterInstanceId();
  962. if (Status != ERROR_SUCCESS)
  963. {
  964. ClRtlLogPrint(
  965. LOG_CRITICAL,
  966. "[NM] GetSharedCommonKey: Failed to create instance ID, "
  967. "status %1!u!.\n",
  968. Status
  969. );
  970. goto ErrorExit;
  971. }
  972. Status = NmpRederiveClusterKey();
  973. if (Status != ERROR_SUCCESS)
  974. {
  975. ClRtlLogPrint(
  976. LOG_CRITICAL,
  977. "[NM] GetSharedCommonKey: Failed to regenerate key, "
  978. "status %1!u!.\n",
  979. Status
  980. );
  981. goto ErrorExit;
  982. }
  983. Status = NmpGetClusterKey(NULL, SharedCommonKeyLen);
  984. }
  985. if (Status != ERROR_INSUFFICIENT_BUFFER)
  986. {
  987. CL_ASSERT(Status == ERROR_INSUFFICIENT_BUFFER);
  988. Status = ERROR_INVALID_DATA;
  989. goto ErrorExit;
  990. }
  991. #ifdef SetServiceAccountPasswordDebug
  992. else
  993. {
  994. ClRtlLogPrint(
  995. LOG_ERROR,
  996. "[NM] NmpGetSharedCommonKey(): *SharedCommonKeyLen=%1!u!.\n",
  997. *SharedCommonKeyLen
  998. );
  999. }
  1000. #endif
  1001. *SharedCommonKey = HeapAlloc(
  1002. GetProcessHeap(),
  1003. HEAP_ZERO_MEMORY,
  1004. *SharedCommonKeyLen
  1005. );
  1006. if (*SharedCommonKey == NULL)
  1007. {
  1008. ClRtlLogPrint(
  1009. LOG_CRITICAL,
  1010. "[NM] GetSharedCommonKey: Failed to allocate %1!u! bytes "
  1011. "for key buffer.\n",
  1012. *SharedCommonKeyLen
  1013. );
  1014. Status = ERROR_NOT_ENOUGH_MEMORY;
  1015. goto ErrorExit;
  1016. }
  1017. Status = NmpGetClusterKey(*SharedCommonKey, SharedCommonKeyLen);
  1018. if (Status != ERROR_SUCCESS)
  1019. {
  1020. ClRtlLogPrint(
  1021. LOG_CRITICAL,
  1022. "[NM] GetSharedCommonKey: Failed to get cluster key, "
  1023. "status %1!u!.\n",
  1024. Status
  1025. );
  1026. goto ErrorExit;
  1027. }
  1028. *SharedCommonKeyFirstHalf = *SharedCommonKey;
  1029. *SharedCommonKeyFirstHalfLen = *SharedCommonKeyLen/2;
  1030. *SharedCommonKeySecondHalf = *SharedCommonKeyFirstHalf +
  1031. *SharedCommonKeyFirstHalfLen;
  1032. *SharedCommonKeySecondHalfLen = *SharedCommonKeyLen -
  1033. *SharedCommonKeyFirstHalfLen;
  1034. Status = ERROR_SUCCESS;
  1035. ErrorExit:
  1036. if ( (Status != ERROR_SUCCESS) && (*SharedCommonKey != NULL) ) {
  1037. if (!HeapFree(GetProcessHeap(), 0, *SharedCommonKey))
  1038. {
  1039. ClRtlLogPrint(
  1040. LOG_UNUSUAL,
  1041. "[NM] GetSharedCommonKey: Failed to free key buffer, "
  1042. "status %1!u!.\n",
  1043. GetLastError()
  1044. );
  1045. }
  1046. *SharedCommonKey = NULL;
  1047. }
  1048. return Status;
  1049. } // NmpGetSharedCommonKey()
  1050. DWORD
  1051. NmpVerifyMAC(
  1052. IN HCRYPTPROV CryptProv,
  1053. IN ALG_ID EncryptionAlgoId,
  1054. IN DWORD Flags,
  1055. IN BYTE *BaseData,
  1056. IN DWORD BaseDataLen,
  1057. IN BYTE *InputData1,
  1058. IN DWORD InputData1Len,
  1059. IN BYTE *InputData2,
  1060. IN DWORD InputData2Len,
  1061. IN BYTE **ReturnData,
  1062. IN DWORD *ReturnDataLen,
  1063. IN BYTE* InputMACData,
  1064. IN DWORD InputMACDataLen
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. This fucntion checks if a message was corrupted on wire.
  1069. Arguments:
  1070. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  1071. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  1072. key is to be generated.
  1073. Flags - [IN] Specifies the type of key generated.
  1074. BaseData - [IN] The base data value from which a cryptographic session
  1075. key is derived.
  1076. BaseDataLen - [IN] Length in bytes of the input BaseData buffer.
  1077. InputData1 - [IN] Pointer to input data.
  1078. InputData1Len - [IN] Length of input data.
  1079. InputData2 - [IN] Pointer to input data.
  1080. InputData2Len - [IN] Length of input data.
  1081. InputMACData - [IN] MAC associated with input data.
  1082. InputMACDataLan - [IN] Length of MAC.
  1083. Return Value:
  1084. ERROR_SUCCESS if message was not corrupted.
  1085. Win32 error code otherwise.
  1086. Notes:
  1087. --*/
  1088. {
  1089. DWORD dwKeyLen = 0;
  1090. DWORD Status;
  1091. DWORD i;
  1092. Status = NmpCreateMAC(
  1093. CryptProv,
  1094. EncryptionAlgoId,
  1095. Flags,
  1096. BaseData,
  1097. BaseDataLen,
  1098. InputData1,
  1099. InputData1Len,
  1100. InputData2,
  1101. InputData2Len,
  1102. ReturnData,
  1103. ReturnDataLen
  1104. );
  1105. if (Status != ERROR_SUCCESS) {
  1106. ClRtlLogPrint(
  1107. LOG_CRITICAL,
  1108. "[NM] VerifyMAC: Failed to create local MAC, status %1!u!.\n",
  1109. Status
  1110. );
  1111. goto ErrorExit;
  1112. }
  1113. if (*ReturnDataLen != InputMACDataLen)
  1114. {
  1115. Status = CRYPT_E_HASH_VALUE;
  1116. ClRtlLogPrint(
  1117. LOG_CRITICAL,
  1118. "[NM] VerifyMAC: Verification failed because the MAC data length "
  1119. "does not match.\n"
  1120. );
  1121. goto ErrorExit;
  1122. }
  1123. if (memcmp(*ReturnData, InputMACData, InputMACDataLen) != 0)
  1124. {
  1125. Status = ERROR_FILE_CORRUPT;
  1126. ClRtlLogPrint(
  1127. LOG_CRITICAL,
  1128. "[NM] VerifyMAC: Verification failed because the MAC data does "
  1129. "not match.\n"
  1130. );
  1131. goto ErrorExit;
  1132. }
  1133. Status = ERROR_SUCCESS;
  1134. ErrorExit:
  1135. return Status;
  1136. } // NmpVerifyMAC()
  1137. DWORD
  1138. NmpDecryptMessage(
  1139. IN HCRYPTPROV CryptProv,
  1140. IN ALG_ID EncryptionAlgoId,
  1141. IN DWORD Flags,
  1142. IN BYTE *SaltBuffer,
  1143. IN DWORD SaltBufferLen,
  1144. IN BYTE *BaseData,
  1145. IN DWORD BaseDataLen,
  1146. IN BYTE *DecryptData,
  1147. IN OUT DWORD *DecryptDataLen,
  1148. OUT BYTE **RetData
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This function decrypts message (data).
  1153. Arguments:
  1154. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  1155. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  1156. key is to be generated.
  1157. Flags - [IN] Specifies the type of key generated.
  1158. SaltBuffer - [IN] Salt.
  1159. BaseData - [IN] The base data value from which a cryptographic session key is derived.
  1160. BaseDataLen - [IN] Length in bytes of the input BaseData buffer.
  1161. DecryptData - [IN] Message (data) to be decrypted.
  1162. DecryptDataLen - [IN/OUT] Before calling this function, the DWORD value is set to the number
  1163. of bytes to be decrypted. Upon return, the DWORD value contains the
  1164. number of bytes of the decrypted plaintext.
  1165. RetData - [OUT] Decrypted plaintext.
  1166. Return Value:
  1167. ERROR_SUCCESS if successful
  1168. Win32 error code otherwise.
  1169. Notes:
  1170. --*/
  1171. {
  1172. HCRYPTKEY CryptKey = 0;
  1173. DWORD Status;
  1174. BOOL Success;
  1175. Status = NmpDeriveSessionKeyEx(
  1176. CryptProv,
  1177. EncryptionAlgoId,
  1178. Flags,
  1179. BaseData,
  1180. BaseDataLen,
  1181. SaltBuffer,
  1182. SaltBufferLen,
  1183. &CryptKey
  1184. );
  1185. if (Status != ERROR_SUCCESS)
  1186. {
  1187. ClRtlLogPrint(
  1188. LOG_CRITICAL,
  1189. "[NM] DecryptMessage: Failed to derive session key, "
  1190. "status %1!u!.\n",
  1191. Status
  1192. );
  1193. goto ErrorExit;
  1194. }
  1195. //
  1196. // Decrypt data
  1197. //
  1198. *RetData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *DecryptDataLen);
  1199. if (*RetData == NULL)
  1200. {
  1201. ClRtlLogPrint(
  1202. LOG_CRITICAL,
  1203. "[NM] DecryptMessage: Failed to allocate %1!u! bytes for "
  1204. "decryption buffer.\n",
  1205. *DecryptDataLen
  1206. );
  1207. Status = ERROR_NOT_ENOUGH_MEMORY;
  1208. goto ErrorExit;
  1209. }
  1210. CopyMemory(*RetData, DecryptData, *DecryptDataLen);
  1211. Success = CryptDecrypt(
  1212. CryptKey,
  1213. 0,
  1214. TRUE, // Final
  1215. 0,
  1216. *RetData, // Buffer holding the data to be decrypted.
  1217. DecryptDataLen // input buffer length, output bytes decrypted
  1218. );
  1219. if (!Success)
  1220. {
  1221. Status = GetLastError();
  1222. ClRtlLogPrint(
  1223. LOG_CRITICAL,
  1224. "[NM] DecryptMessage: Failed to decrypt message, status %1!u!.\n",
  1225. Status
  1226. );
  1227. goto ErrorExit;
  1228. }
  1229. Status = ERROR_SUCCESS;
  1230. ErrorExit:
  1231. if ( (Status != ERROR_SUCCESS) && (*RetData != NULL) )
  1232. {
  1233. if (!HeapFree(GetProcessHeap(), 0, *RetData))
  1234. {
  1235. ClRtlLogPrint(
  1236. LOG_ERROR,
  1237. "[NM] DecryptMessage: Failed to free decryption buffer, "
  1238. "status %1!u!\n",
  1239. GetLastError()
  1240. );
  1241. }
  1242. *RetData = NULL;
  1243. }
  1244. //
  1245. // Destroy CyrptKey
  1246. //
  1247. if (CryptKey)
  1248. if (!CryptDestroyKey(CryptKey))
  1249. {
  1250. ClRtlLogPrint(
  1251. LOG_ERROR,
  1252. "[NM] DecryptMessage: Failed to free session key, "
  1253. "status %1!u!.\n",
  1254. GetLastError()
  1255. );
  1256. }
  1257. return Status;
  1258. } // NmpDecryptMessage()
  1259. DWORD
  1260. NmpEncryptDataAndCreateMAC(
  1261. IN HCRYPTPROV CryptProv,
  1262. IN ALG_ID EncryptionAlgoId,
  1263. IN DWORD Flags,
  1264. IN PBYTE Data,
  1265. IN DWORD DataLength,
  1266. IN PVOID EncryptionKey,
  1267. IN DWORD EncryptionKeyLength,
  1268. IN BOOL CreateSalt,
  1269. OUT PBYTE *Salt,
  1270. IN DWORD SaltLength,
  1271. OUT PBYTE *EncryptedData,
  1272. OUT DWORD *EncryptedDataLength,
  1273. OUT PBYTE *MAC,
  1274. IN OUT DWORD *MACLength
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. This function encrypts data and creates MAC.
  1279. Arguments:
  1280. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  1281. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  1282. session key is to be generated.
  1283. Flags - [IN] Specifies the type of session key to be generated.
  1284. Data - [IN] Data to be encrypted.
  1285. DataLength - [IN] Length in bytes of Data.
  1286. EncryptionKey - [IN] The base data value from which a cryptographic session
  1287. key is derived.
  1288. EncryptionKeyLength - [IN] Length in bytes of the input EncryptionKey.
  1289. CreateSalt - [IN] Flag indicating if salt should be generated.
  1290. Salt - [OUT] Salt created.
  1291. SaltLength - [IN] Length in bytes of Salt.
  1292. EncryptData - [OUT] Encrypted data.
  1293. EncryptedDataLength - [OUT] Length in bytes of EncryptedData.
  1294. MAC - [OUT] MAC (Message Authorization Code) created.
  1295. MACLength - [IN/OUT] Before calling this function, the DWORD value
  1296. is set to the expected number of bytes to be generated
  1297. for MAC. Upon return, the DWORD value contains the length
  1298. of the MAC generated in bytes.
  1299. Return Value:
  1300. ERROR_SUCCESS if successful
  1301. Win32 error code otherwise.
  1302. Notes:
  1303. On successful return, memory is allocated for Salt, EncryptedData, and
  1304. MAC. User is responsible to call HeapFree() to free the memory after usage.
  1305. --*/
  1306. {
  1307. PBYTE salt = NULL;
  1308. PBYTE encryptedData = NULL;
  1309. DWORD encryptedDataLength;
  1310. PBYTE mac = NULL;
  1311. DWORD macLength;
  1312. DWORD Status = ERROR_SUCCESS;
  1313. PBYTE EncryptionKeyFirstHalf;
  1314. DWORD EncryptionKeyFirstHalfLength;
  1315. PBYTE EncryptionKeySecondHalf;
  1316. DWORD EncryptionKeySecondHalfLength;
  1317. EncryptionKeyFirstHalf = EncryptionKey;
  1318. EncryptionKeyFirstHalfLength = EncryptionKeyLength/2;
  1319. EncryptionKeySecondHalf = EncryptionKeyFirstHalf +
  1320. EncryptionKeyFirstHalfLength;
  1321. EncryptionKeySecondHalfLength = EncryptionKeyLength -
  1322. EncryptionKeyFirstHalfLength;
  1323. //
  1324. // Allocate space for Salt
  1325. //
  1326. if (CreateSalt == TRUE)
  1327. {
  1328. salt = HeapAlloc(
  1329. GetProcessHeap(),
  1330. HEAP_ZERO_MEMORY,
  1331. SaltLength
  1332. );
  1333. if (salt == NULL)
  1334. {
  1335. ClRtlLogPrint(
  1336. LOG_CRITICAL,
  1337. "[NM] NmpEncryptDataAndCreateMAC: Failed to allocate %1!u! "
  1338. "bytes of memory for encryption salt.\n",
  1339. SaltLength
  1340. );
  1341. Status = ERROR_NOT_ENOUGH_MEMORY;
  1342. goto ErrorExit;
  1343. }
  1344. }
  1345. else
  1346. {
  1347. salt = *Salt;
  1348. }
  1349. //
  1350. // Encrypt data
  1351. //
  1352. encryptedDataLength = DataLength;
  1353. Status = NmpEncryptMessage(CryptProv,
  1354. EncryptionAlgoId,
  1355. Flags,
  1356. salt,
  1357. SaltLength,
  1358. EncryptionKeyFirstHalf,
  1359. EncryptionKeyFirstHalfLength,
  1360. Data,
  1361. &encryptedDataLength,
  1362. DataLength,
  1363. &encryptedData,
  1364. TRUE
  1365. );
  1366. if (Status != ERROR_SUCCESS)
  1367. {
  1368. ClRtlLogPrint(
  1369. LOG_CRITICAL,
  1370. "[NM] NmpEncryptDataAndCreateMAC: Failed to encrypt password, "
  1371. "status %1!u!.\n",
  1372. Status
  1373. );
  1374. goto ErrorExit;
  1375. }
  1376. //
  1377. // Allocate space for MAC
  1378. //
  1379. mac = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *MACLength);
  1380. if (mac == NULL)
  1381. {
  1382. ClRtlLogPrint(
  1383. LOG_CRITICAL,
  1384. "[NM] NmpEncryptDataAndCreateMAC: Failed to allocate %1!u! "
  1385. "bytes for MAC.\n",
  1386. *MACLength
  1387. );
  1388. Status = ERROR_NOT_ENOUGH_MEMORY;
  1389. goto ErrorExit;
  1390. }
  1391. //
  1392. // Create MAC
  1393. //
  1394. macLength = *MACLength;
  1395. Status = NmpCreateMAC(
  1396. CryptProv,
  1397. EncryptionAlgoId,
  1398. Flags,
  1399. EncryptionKeySecondHalf,
  1400. EncryptionKeySecondHalfLength,
  1401. salt,
  1402. SaltLength,
  1403. encryptedData,
  1404. encryptedDataLength,
  1405. &mac,
  1406. &macLength
  1407. );
  1408. if (Status != ERROR_SUCCESS)
  1409. {
  1410. ClRtlLogPrint(
  1411. LOG_CRITICAL,
  1412. "[NM] NmpEncryptDataAndCreateMAC: Failed to create MAC, "
  1413. "status %1!u!.\n",
  1414. Status
  1415. );
  1416. goto ErrorExit;
  1417. }
  1418. if (CreateSalt == TRUE)
  1419. {
  1420. *Salt = salt;
  1421. }
  1422. *EncryptedData = encryptedData;
  1423. *EncryptedDataLength = encryptedDataLength;
  1424. *MAC = mac;
  1425. *MACLength = macLength;
  1426. ErrorExit:
  1427. if (Status != ERROR_SUCCESS)
  1428. {
  1429. if (salt != NULL)
  1430. {
  1431. HeapFree(GetProcessHeap(), 0, salt);
  1432. }
  1433. if (mac != NULL)
  1434. {
  1435. HeapFree(GetProcessHeap(), 0, mac);
  1436. }
  1437. }
  1438. return (Status);
  1439. } // NmpEncryptDataAndCreateMAC
  1440. DWORD
  1441. NmpVerifyMACAndDecryptData(
  1442. IN HCRYPTPROV CryptProv,
  1443. IN ALG_ID EcnryptionAlgoId,
  1444. IN DWORD Flags,
  1445. IN PBYTE MAC,
  1446. IN DWORD MACLength,
  1447. IN DWORD MACExpectedSize,
  1448. IN PBYTE EncryptedData,
  1449. IN DWORD EncryptedDataLength,
  1450. IN PVOID EncryptionKey,
  1451. IN DWORD EncryptionKeyLength,
  1452. IN PBYTE Salt,
  1453. IN DWORD SaltLength,
  1454. OUT PBYTE *DecryptedData,
  1455. OUT DWORD *DecryptedDataLength
  1456. )
  1457. /*++
  1458. Routine Description:
  1459. This function verifies MAC and decrypts data.
  1460. Arguments:
  1461. CryptProv - [IN] Handle to CSP (Crypto Service Provider).
  1462. EncryptionAlgoId - [IN] The symmetric encryption algorithm for which the
  1463. session key is to be generated.
  1464. Flags - [IN] Specifies the type of session key to be generated.
  1465. MAC - [IN] MAC (Message Authorization Code) received.
  1466. MACLength - [IN] Length in bytes of received MAC.
  1467. MACExpectedSize - [IN] Expected size in bytes of MAC.
  1468. EncryptedData - [IN] Encrypted data received.
  1469. EncryptedDataLength - [IN] Length in bytes of encrypted data received.
  1470. EncryptionKey - [IN] The base data value from which a cryptographic session
  1471. key is derived.
  1472. EncryptionKeyLength - [IN] Length in bytes of the input EncryptionKey.
  1473. Salt - [IN] Salt received.
  1474. SaltLength - [IN] Length in bytes of Salt.
  1475. DecryptedData - [OUT] Decrypted data.
  1476. DecryptedDataLength - [OUT] Decrypted data length in bytes.
  1477. Return Value:
  1478. ERROR_SUCCESS if successful
  1479. Win32 error code otherwise.
  1480. Notes:
  1481. On successful return, memory is allocated for DecryptedData. User is
  1482. responsible to call HeapFree() to free the memory after usage.
  1483. --*/
  1484. {
  1485. DWORD ReturnStatus;
  1486. DWORD GenMACDataLen;
  1487. PBYTE GenMACData = NULL;
  1488. PBYTE decryptedData;
  1489. DWORD decryptedDataLength;
  1490. PBYTE EncryptionKeyFirstHalf;
  1491. DWORD EncryptionKeyFirstHalfLength;
  1492. PBYTE EncryptionKeySecondHalf;
  1493. DWORD EncryptionKeySecondHalfLength;
  1494. EncryptionKeyFirstHalf = EncryptionKey;
  1495. EncryptionKeyFirstHalfLength = EncryptionKeyLength/2;
  1496. EncryptionKeySecondHalf = EncryptionKeyFirstHalf +
  1497. EncryptionKeyFirstHalfLength;
  1498. EncryptionKeySecondHalfLength = EncryptionKeyLength -
  1499. EncryptionKeyFirstHalfLength;
  1500. //
  1501. // Verify MAC
  1502. //
  1503. GenMACDataLen = MACExpectedSize;
  1504. GenMACData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, GenMACDataLen);
  1505. if (GenMACData == NULL)
  1506. {
  1507. ClRtlLogPrint(
  1508. LOG_CRITICAL,
  1509. "[NM] NmpVerifyMACAndDecryptData: Failed to allocate "
  1510. "%1!u! bytes for MAC.\n",
  1511. GenMACDataLen
  1512. );
  1513. ReturnStatus = ERROR_NOT_ENOUGH_MEMORY;
  1514. goto ErrorExit;
  1515. }
  1516. ReturnStatus = NmpVerifyMAC(
  1517. CryptProv,
  1518. EcnryptionAlgoId,
  1519. Flags,
  1520. EncryptionKeySecondHalf,
  1521. EncryptionKeySecondHalfLength,
  1522. Salt,
  1523. SaltLength,
  1524. EncryptedData,
  1525. EncryptedDataLength,
  1526. &GenMACData,
  1527. &GenMACDataLen,
  1528. MAC,
  1529. MACLength
  1530. );
  1531. if (ReturnStatus != ERROR_SUCCESS)
  1532. {
  1533. ClRtlLogPrint(
  1534. LOG_CRITICAL,
  1535. "[NM] NmpVerifyMACAndDecryptData: Failed to verify MAC, "
  1536. "status %1!u!\n",
  1537. ReturnStatus
  1538. );
  1539. goto ErrorExit;
  1540. }
  1541. //
  1542. // Decrypt Message
  1543. //
  1544. decryptedDataLength = EncryptedDataLength;
  1545. ReturnStatus = NmpDecryptMessage(
  1546. CryptProv,
  1547. EcnryptionAlgoId,
  1548. Flags,
  1549. Salt,
  1550. SaltLength,
  1551. EncryptionKeyFirstHalf,
  1552. EncryptionKeyFirstHalfLength,
  1553. EncryptedData,
  1554. &decryptedDataLength,
  1555. &decryptedData
  1556. );
  1557. if (ReturnStatus != ERROR_SUCCESS)
  1558. {
  1559. ClRtlLogPrint(
  1560. LOG_CRITICAL,
  1561. "[NM] NmpVerifyMACAndDecryptData: Failed to decrypt "
  1562. "message, status %1!u!\n",
  1563. ReturnStatus
  1564. );
  1565. goto ErrorExit;
  1566. }
  1567. *DecryptedData = decryptedData;
  1568. *DecryptedDataLength = decryptedDataLength;
  1569. ErrorExit:
  1570. if (GenMACData != NULL)
  1571. {
  1572. HeapFree(GetProcessHeap(), 0, GenMACData);
  1573. }
  1574. return (ReturnStatus);
  1575. } // NmpVerifyMACAndDecryptData()
  1576. DWORD NmpCheckDecryptedPassword(BYTE* NewPassword,
  1577. DWORD NewPasswordLen)
  1578. /*++
  1579. Routine Description:
  1580. This routine checks if the decrypted new password returned by
  1581. NmpDecryptMessage (NewPassword) is an eligible UNICODE string
  1582. with length equal to NewPasswordLen/sizeof(WCHAR)-1.
  1583. Arguments:
  1584. [IN] NewPassword - Decrypted new password returned by
  1585. NmpDecryptMessage.
  1586. [IN] NewPasswordLen - Decrypted new password length returned by
  1587. NmpDecryptMessage.
  1588. Return Value:
  1589. ERROR_SUCCESS if successful.
  1590. ERROR_FILE_CORRUPT if NewPassword is not an eligible UNICODE string with
  1591. length equal to NewPasswordLen/sizeof(WCHAR)-1.
  1592. Notes:
  1593. --*/
  1594. {
  1595. DWORD Status = ERROR_SUCCESS;
  1596. BYTE *byte_ptr;
  1597. WCHAR *wchar_ptr;
  1598. if (NewPasswordLen < sizeof(WCHAR)) {
  1599. // should contain at least UNICODE_NULL
  1600. Status = ERROR_FILE_CORRUPT;
  1601. goto ErrorExit;
  1602. }
  1603. if ( (NewPasswordLen % sizeof(WCHAR))!=0 ) {
  1604. // Number of bytes should be multiple of sizeof(WCHAR).
  1605. Status = ERROR_FILE_CORRUPT;
  1606. goto ErrorExit;
  1607. }
  1608. byte_ptr = NewPassword + (NewPasswordLen - sizeof(WCHAR));
  1609. wchar_ptr = (WCHAR*) byte_ptr;
  1610. if (*wchar_ptr != UNICODE_NULL) {
  1611. // UNICODE string should end by UNICODE_NULL
  1612. Status = ERROR_FILE_CORRUPT;
  1613. goto ErrorExit;
  1614. }
  1615. if (NewPasswordLen !=
  1616. (wcslen((LPWSTR) NewPassword) + 1) * sizeof(WCHAR))
  1617. // eligible UNICODE string with length equal to NewPasswordLen-1
  1618. {
  1619. Status = ERROR_FILE_CORRUPT;
  1620. goto ErrorExit;
  1621. }
  1622. ErrorExit:
  1623. return Status;
  1624. } // NmpCheckDecryptedPassword
  1625. /////////////////////////////////////////////////////////////////////////////
  1626. //
  1627. // Routines called by other cluster service components
  1628. //
  1629. /////////////////////////////////////////////////////////////////////////////
  1630. DWORD
  1631. NmSetServiceAccountPassword(
  1632. IN LPCWSTR DomainName,
  1633. IN LPCWSTR AccountName,
  1634. IN LPWSTR NewPassword,
  1635. IN DWORD dwFlags,
  1636. OUT PCLUSTER_SET_PASSWORD_STATUS ReturnStatusBuffer,
  1637. IN DWORD ReturnStatusBufferSize,
  1638. OUT DWORD *SizeReturned,
  1639. OUT DWORD *ExpectedBufferSize
  1640. )
  1641. /*++
  1642. Routine Description:
  1643. Change cluster service account password on Service Control Manager
  1644. Database and LSA password cache on every node of cluster.
  1645. Return execution status on each node.
  1646. Arguments:
  1647. DomainName - Domain name of cluster service account
  1648. AccountName - Account name of cluster service account
  1649. NewPassword - New password for cluster service account.
  1650. dwFlags - Describing how the password update should be made to
  1651. the cluster. The dwFlags parameter is optional. If set, the
  1652. following value is valid:
  1653. CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES
  1654. Apply the update even if some nodes are not
  1655. actively participating in the cluster (i.e. not
  1656. ClusterNodeStateUp or ClusterNodeStatePaused).
  1657. By default, the update is only applied if all
  1658. nodes are up.
  1659. ReturnStatusBuffer - Array that captures the return status of the
  1660. update handler for each node that attempts to
  1661. apply the update.
  1662. ReturnStatusBufferSize - Size of ReturnStatusBuffer in number
  1663. of elements.
  1664. SizeReturned - Number of elements written into ReturnStatusBuffer.
  1665. ExpectedBufferSize - specifies the minimum required size of
  1666. ReturnStatusBuffer when ERROR_MORE_DATA
  1667. is returned.
  1668. Return Value:
  1669. ERROR_SUCCESS if successful
  1670. Win32 error code otherwise.
  1671. Notes:
  1672. --*/
  1673. {
  1674. BYTE *SharedCommonKey = NULL;
  1675. DWORD SharedCommonKeyLen = 0;
  1676. BYTE *SharedCommonKeyFirstHalf = NULL;
  1677. DWORD SharedCommonKeyFirstHalfLen = 0;
  1678. BYTE *SharedCommonKeySecondHalf = NULL;
  1679. DWORD SharedCommonKeySecondHalfLen = 0;
  1680. DWORD Status;
  1681. BYTE *EncryptedNewPassword = NULL;
  1682. DWORD EncryptedNewPasswordLen = 0;
  1683. HCRYPTPROV CryptProvider = 0;
  1684. BYTE *SaltBuf = NULL;
  1685. DWORD SaltBufLen = NMP_SALT_BUFFER_LEN;
  1686. BYTE *MACData = NULL;
  1687. DWORD MACDataLen = 0;
  1688. PGUM_NODE_UPDATE_HANDLER_STATUS GumReturnStatusBuffer = NULL;
  1689. DWORD dwSize = 0;
  1690. DWORD dwNumberOfUpAndPausedNodes;
  1691. ClRtlLogPrint(
  1692. LOG_NOISE,
  1693. "[NM] Received a request to change the service account password.\n"
  1694. );
  1695. NmpAcquireLock();
  1696. if (!NmpLockedEnterApi(NmStateOnline))
  1697. {
  1698. ClRtlLogPrint(
  1699. LOG_CRITICAL,
  1700. "[NM] Not in valid state to process request to change the "
  1701. "service account password.\n"
  1702. );
  1703. NmpReleaseLock();
  1704. return ERROR_NODE_NOT_AVAILABLE;
  1705. }
  1706. //
  1707. // Check to see if it is a mixed cluster
  1708. //
  1709. if (NmpIsNT5NodeInCluster == TRUE)
  1710. {
  1711. ClRtlLogPrint(
  1712. LOG_CRITICAL,
  1713. "[NM] SetServiceAccountPassword: this cluster contains NT4 or W2K "
  1714. "nodes. The password cannot be changed on this cluster.\n"
  1715. );
  1716. NmpReleaseLock();
  1717. Status = ERROR_CLUSTER_OLD_VERSION;
  1718. goto ErrorExit;
  1719. }
  1720. //
  1721. // Check to see if ReturnStatusBuffer is big enough.
  1722. //
  1723. dwNumberOfUpAndPausedNodes = NmpGetCurrentNumberOfUpAndPausedNodes();
  1724. if (ReturnStatusBufferSize < dwNumberOfUpAndPausedNodes)
  1725. {
  1726. ClRtlLogPrint(
  1727. LOG_CRITICAL,
  1728. "[NM] SetServiceAccountPassword: ReturnStatusBuffer is"
  1729. "too small. Needs to be %1!u! bytes.\n",
  1730. dwNumberOfUpAndPausedNodes * sizeof(CLUSTER_SET_PASSWORD_STATUS)
  1731. );
  1732. NmpReleaseLock();
  1733. *ExpectedBufferSize = dwNumberOfUpAndPausedNodes;
  1734. Status = ERROR_MORE_DATA;
  1735. goto ErrorExit;
  1736. }
  1737. //
  1738. // Check to see if all nodes are available
  1739. //
  1740. if ( (dwFlags != CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES) &&
  1741. (dwNumberOfUpAndPausedNodes != NmpNodeCount)
  1742. )
  1743. {
  1744. ClRtlLogPrint(
  1745. LOG_CRITICAL,
  1746. "[NM] SetServiceAccountPassword: All cluster nodes"
  1747. " are not available. The password cannot be changed on"
  1748. " this cluster.\n"
  1749. );
  1750. NmpReleaseLock();
  1751. Status = ERROR_ALL_NODES_NOT_AVAILABLE;
  1752. goto ErrorExit;
  1753. }
  1754. NmpReleaseLock();
  1755. //
  1756. // Open the crypto provider
  1757. //
  1758. Status = NmpCreateCSPHandle(&CryptProvider);
  1759. if (Status != ERROR_SUCCESS) {
  1760. goto ErrorExit;
  1761. }
  1762. //
  1763. // Encrypt the new password for transmission on the network as part of
  1764. // a global update
  1765. //
  1766. //
  1767. // Get the base key to be used to encrypt the data
  1768. //
  1769. Status = NmpGetSharedCommonKey(
  1770. &SharedCommonKey,
  1771. &SharedCommonKeyLen,
  1772. &SharedCommonKeyFirstHalf,
  1773. &SharedCommonKeyFirstHalfLen,
  1774. &SharedCommonKeySecondHalf,
  1775. &SharedCommonKeySecondHalfLen
  1776. );
  1777. if (Status != ERROR_SUCCESS) {
  1778. goto ErrorExit;
  1779. }
  1780. EncryptedNewPasswordLen = (wcslen(NewPassword) + 1) * sizeof(WCHAR);
  1781. MACDataLen = NMP_MAC_DATA_LENGTH_EXPECTED;
  1782. Status =
  1783. NmpEncryptDataAndCreateMAC(
  1784. CryptProvider,
  1785. NMP_ENCRYPT_ALGORITHM, // RC2 block encryption algorithm
  1786. NMP_KEY_LENGTH, // key length = 128 bits
  1787. (BYTE *) NewPassword, // Data
  1788. EncryptedNewPasswordLen, //DataLength
  1789. SharedCommonKey, // EncryptionKey
  1790. SharedCommonKeyLen, // EncryptionKeyLength
  1791. TRUE, // CreateSalt
  1792. &SaltBuf, // Salt
  1793. NMP_SALT_BUFFER_LEN, // SaltLength
  1794. &EncryptedNewPassword, // EncryptedData
  1795. &EncryptedNewPasswordLen, // EncryptedDataLength
  1796. &MACData, // MAC
  1797. &MACDataLen // MACLength
  1798. );
  1799. if (Status != ERROR_SUCCESS)
  1800. {
  1801. ClRtlLogPrint(
  1802. LOG_CRITICAL,
  1803. "[NM] SetServiceAccountPassword: Failed to encrypt password "
  1804. "or create MAC, status %1!u!.\n",
  1805. Status
  1806. );
  1807. goto ErrorExit;
  1808. }
  1809. //
  1810. // Allocate memory for GumReturnStatusBuffer
  1811. //
  1812. CL_ASSERT(NmMaxNodeId != 0);
  1813. dwSize = (NmMaxNodeId + 1) * sizeof(GUM_NODE_UPDATE_HANDLER_STATUS);
  1814. GumReturnStatusBuffer = HeapAlloc(
  1815. GetProcessHeap(),
  1816. HEAP_ZERO_MEMORY,
  1817. dwSize
  1818. );
  1819. if (GumReturnStatusBuffer == NULL)
  1820. {
  1821. ClRtlLogPrint(
  1822. LOG_CRITICAL,
  1823. "[NM] SetServiceAccountPassword: Failed to allocate %1!u! bytes "
  1824. "for global update status buffer.\n",
  1825. dwSize
  1826. );
  1827. Status = ERROR_NOT_ENOUGH_MEMORY;
  1828. goto ErrorExit;
  1829. }
  1830. //
  1831. // Issue the global update
  1832. //
  1833. Status = GumSendUpdateExReturnInfo(
  1834. GumUpdateMembership,
  1835. NmUpdateSetServiceAccountPassword,
  1836. GumReturnStatusBuffer,
  1837. 8,
  1838. (wcslen(DomainName) + 1) * sizeof(WCHAR),
  1839. DomainName,
  1840. (wcslen(AccountName) + 1) * sizeof(WCHAR),
  1841. AccountName,
  1842. EncryptedNewPasswordLen,
  1843. EncryptedNewPassword,
  1844. sizeof(EncryptedNewPasswordLen),
  1845. &EncryptedNewPasswordLen,
  1846. NMP_SALT_BUFFER_LEN,
  1847. SaltBuf,
  1848. sizeof(SaltBufLen),
  1849. &SaltBufLen,
  1850. MACDataLen,
  1851. MACData,
  1852. sizeof(MACDataLen),
  1853. &MACDataLen
  1854. );
  1855. if (Status != ERROR_SUCCESS)
  1856. {
  1857. ClRtlLogPrint(
  1858. LOG_CRITICAL,
  1859. "[NM] SetServiceAccountPassword: Global update failed, "
  1860. "status %1!u!.\n",
  1861. Status
  1862. );
  1863. }
  1864. else
  1865. {
  1866. //
  1867. // Transfer return status from GumReturnStatusBuffer to
  1868. // ReturnStatusBuffer
  1869. //
  1870. DWORD sizeRemaining = ReturnStatusBufferSize;
  1871. DWORD nodeIndex, returnIndex;
  1872. NmpAcquireLock();
  1873. for ( nodeIndex = ClusterMinNodeId, returnIndex = 0;
  1874. nodeIndex <= NmMaxNodeId;
  1875. nodeIndex++
  1876. )
  1877. {
  1878. if (sizeRemaining < 1) {
  1879. break;
  1880. }
  1881. if (GumReturnStatusBuffer[nodeIndex].UpdateAttempted)
  1882. {
  1883. //
  1884. // An update was attempted for this node.
  1885. // Capture the execution status.
  1886. //
  1887. ReturnStatusBuffer[returnIndex].NodeId = nodeIndex;
  1888. ReturnStatusBuffer[returnIndex].SetAttempted = TRUE;
  1889. ReturnStatusBuffer[returnIndex].ReturnStatus =
  1890. GumReturnStatusBuffer[nodeIndex].ReturnStatus;
  1891. sizeRemaining--;
  1892. returnIndex++;
  1893. }
  1894. else if ( NmpIdArray[nodeIndex] != NULL ) {
  1895. //
  1896. // An update was not attempted but the node exists.
  1897. // Implies that the node was not up when the update
  1898. // was attempted.
  1899. //
  1900. ReturnStatusBuffer[returnIndex].NodeId = nodeIndex;
  1901. ReturnStatusBuffer[returnIndex].SetAttempted = FALSE;
  1902. ReturnStatusBuffer[returnIndex].ReturnStatus =
  1903. ERROR_CLUSTER_NODE_DOWN;
  1904. sizeRemaining--;
  1905. returnIndex++;
  1906. }
  1907. //
  1908. // else the node does not exist, so we do not add an
  1909. // entry to the return status array.
  1910. //
  1911. } // endfor
  1912. NmpReleaseLock();
  1913. *SizeReturned = ReturnStatusBufferSize - sizeRemaining;
  1914. } //else
  1915. ErrorExit:
  1916. // Zero out NewPassword
  1917. RtlSecureZeroMemory(NewPassword, (wcslen(NewPassword) + 1) * sizeof(WCHAR));
  1918. if (SharedCommonKey != NULL)
  1919. {
  1920. RtlSecureZeroMemory(SharedCommonKey, SharedCommonKeyLen);
  1921. HeapFree(GetProcessHeap(), 0, SharedCommonKey);
  1922. SharedCommonKey = NULL;
  1923. SharedCommonKeyLen = 0;
  1924. SharedCommonKeyFirstHalf = NULL;
  1925. SharedCommonKeyFirstHalfLen = 0;
  1926. SharedCommonKeySecondHalf = NULL;
  1927. SharedCommonKeySecondHalfLen = 0;
  1928. }
  1929. if (SaltBuf != NULL)
  1930. {
  1931. if (!HeapFree(GetProcessHeap(), 0, SaltBuf))
  1932. {
  1933. ClRtlLogPrint(
  1934. LOG_UNUSUAL,
  1935. "[NM] SetServiceAccountPassword: Failed to free salt buffer, "
  1936. "status %1!u!.\n",
  1937. GetLastError()
  1938. );
  1939. }
  1940. }
  1941. if (MACData != NULL)
  1942. {
  1943. if (!HeapFree(GetProcessHeap(), 0, MACData))
  1944. {
  1945. ClRtlLogPrint(
  1946. LOG_UNUSUAL,
  1947. "[NM] SetServiceAccountPassword: Failed to free MAC buffer, "
  1948. "status %1!u!.\n",
  1949. GetLastError()
  1950. );
  1951. }
  1952. }
  1953. if (EncryptedNewPassword != NULL)
  1954. {
  1955. if (!HeapFree(GetProcessHeap(), 0, EncryptedNewPassword))
  1956. {
  1957. ClRtlLogPrint(
  1958. LOG_UNUSUAL,
  1959. "[NM] SetServiceAccountPassword: Failed to free password "
  1960. "buffer, status %1!u!.\n",
  1961. GetLastError()
  1962. );
  1963. }
  1964. }
  1965. if (GumReturnStatusBuffer != NULL)
  1966. {
  1967. if (!HeapFree(GetProcessHeap(), 0, GumReturnStatusBuffer))
  1968. {
  1969. ClRtlLogPrint(
  1970. LOG_UNUSUAL,
  1971. "[NM] SetServiceAccountPassword: Failed to free global "
  1972. "update status buffer, status %1!u!.\n",
  1973. GetLastError()
  1974. );
  1975. }
  1976. }
  1977. //
  1978. // Release the CSP.
  1979. //
  1980. if(CryptProvider)
  1981. {
  1982. if (!CryptReleaseContext(CryptProvider,0))
  1983. {
  1984. ClRtlLogPrint(
  1985. LOG_UNUSUAL,
  1986. "[NM] SetServiceAccountPassword: Failed to free provider "
  1987. "handle, status %1!u!\n",
  1988. GetLastError()
  1989. );
  1990. }
  1991. }
  1992. NmpLeaveApi();
  1993. return(Status);
  1994. } // NmSetServiceAccountPassword
  1995. /////////////////////////////////////////////////////////////////////////////
  1996. //
  1997. // Handlers for global updates
  1998. //
  1999. /////////////////////////////////////////////////////////////////////////////
  2000. DWORD
  2001. NmpUpdateSetServiceAccountPassword(
  2002. IN BOOL SourceNode,
  2003. IN LPWSTR DomainName,
  2004. IN LPWSTR AccountName,
  2005. IN LPBYTE EncryptedNewPassword,
  2006. IN LPDWORD EncryptedNewPasswordLen,
  2007. IN LPBYTE SaltBuf,
  2008. IN LPDWORD SaltBufLen,
  2009. IN LPBYTE MACData,
  2010. IN LPDWORD MACDataLen
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. This routine changes password for cluster service account on both Service
  2015. Control Manager Database (SCM) and LSA password cache on local node.
  2016. Arguments:
  2017. SourceNode - [IN] Specifies whether or not this is the source node for
  2018. the update
  2019. DomainName - [IN] Domain name of cluster service account.
  2020. AccountName - [IN] Account name of cluster service account.
  2021. EncryptedNewPassword - [IN] New (encrypted) password for cluster service account.
  2022. EncryptedNewPasswordLen - [IN] Length of new (encrypted) password for cluster service account.
  2023. SaltBuf - [IN] Pointer to salt buffer.
  2024. SaltBufLen - [IN] Length of salt buffer.
  2025. MACData - [IN] Pointer to MAC data.
  2026. MACDataLen - [IN] Length of MAC data.
  2027. Return Value:
  2028. ERROR_SUCCESS if successful
  2029. Win32 error code otherwise.
  2030. Notes:
  2031. --*/
  2032. {
  2033. BYTE *SharedCommonKey = NULL;
  2034. DWORD SharedCommonKeyLen = 0;
  2035. BYTE *SharedCommonKeyFirstHalf = NULL;
  2036. DWORD SharedCommonKeyFirstHalfLen = 0;
  2037. BYTE *SharedCommonKeySecondHalf = NULL;
  2038. DWORD SharedCommonKeySecondHalfLen = 0;
  2039. SC_HANDLE ScmHandle = NULL;
  2040. SC_HANDLE ClusSvcHandle = NULL;
  2041. BOOL Success = FALSE;
  2042. DWORD ReturnStatus;
  2043. NTSTATUS Status;
  2044. NTSTATUS SubStatus;
  2045. LSA_STRING LsaStringBuf;
  2046. char *AuthPackage = MSV1_0_PACKAGE_NAME;
  2047. HANDLE LsaHandle = NULL;
  2048. ULONG PackageId;
  2049. PMSV1_0_CHANGEPASSWORD_REQUEST Request = NULL;
  2050. ULONG RequestSize;
  2051. PBYTE Where;
  2052. PVOID Response = NULL;
  2053. ULONG ResponseSize;
  2054. LPQUERY_SERVICE_LOCK_STATUS LpqslsBuf = NULL;
  2055. DWORD DwBytesNeeded;
  2056. DWORD LocalNewPasswordLen = 0;
  2057. BYTE *DecryptedNewPassword = NULL;
  2058. DWORD DecryptedNewPasswordLength = 0;
  2059. HCRYPTPROV CryptProvider = 0;
  2060. DATA_BLOB DataIn;
  2061. DATA_BLOB DataOut;
  2062. if (!NmpEnterApi(NmStateOnline)) {
  2063. ClRtlLogPrint(
  2064. LOG_NOISE,
  2065. "[NM] Not in valid state to process UpdateSetServiceAccountPassword "
  2066. "update.\n"
  2067. );
  2068. return(ERROR_NODE_NOT_AVAILABLE);
  2069. }
  2070. ClRtlLogPrint(
  2071. LOG_NOISE,
  2072. "[NM] Received update to set the cluster service account password.\n"
  2073. );
  2074. ClusterLogEvent0(LOG_NOISE,
  2075. LOG_CURRENT_MODULE,
  2076. __FILE__,
  2077. __LINE__,
  2078. SERVICE_PASSWORD_CHANGE_INITIATED,
  2079. 0,
  2080. NULL
  2081. );
  2082. //
  2083. // Open crypto provider
  2084. //
  2085. ReturnStatus = NmpCreateCSPHandle(&CryptProvider);
  2086. if (ReturnStatus != ERROR_SUCCESS) {
  2087. ClRtlLogPrint(
  2088. LOG_CRITICAL,
  2089. "[NM] UpdateSetServiceAccountPassword: Failed to aquire "
  2090. "crypto provider handle, status %1!u!.\n",
  2091. ReturnStatus
  2092. );
  2093. goto ErrorExit;
  2094. }
  2095. ReturnStatus = NmpGetSharedCommonKey(
  2096. &SharedCommonKey,
  2097. &SharedCommonKeyLen,
  2098. &SharedCommonKeyFirstHalf,
  2099. &SharedCommonKeyFirstHalfLen,
  2100. &SharedCommonKeySecondHalf,
  2101. &SharedCommonKeySecondHalfLen
  2102. );
  2103. if (ReturnStatus != ERROR_SUCCESS) {
  2104. ClRtlLogPrint(
  2105. LOG_CRITICAL,
  2106. "[NM] UpdateSetServiceAccountPassword: Failed to get "
  2107. "common key, status %1!u!.\n",
  2108. ReturnStatus
  2109. );
  2110. goto ErrorExit;
  2111. }
  2112. ReturnStatus = NmpVerifyMACAndDecryptData(
  2113. CryptProvider,
  2114. NMP_ENCRYPT_ALGORITHM, // RC2 block encryption algorithm
  2115. NMP_KEY_LENGTH, // key length = 128 bits
  2116. MACData, // MAC
  2117. *MACDataLen, // MAC length
  2118. NMP_MAC_DATA_LENGTH_EXPECTED, // MAC expected size
  2119. EncryptedNewPassword, // encrypted data
  2120. *EncryptedNewPasswordLen, // encrypted data length
  2121. SharedCommonKey, // encryption key
  2122. SharedCommonKeyLen, // encryption key length
  2123. SaltBuf, // salt
  2124. *SaltBufLen, // salt length
  2125. &DecryptedNewPassword, // decrypted data
  2126. &LocalNewPasswordLen // decrypted data length
  2127. );
  2128. if (ReturnStatus != ERROR_SUCCESS)
  2129. {
  2130. ClRtlLogPrint(
  2131. LOG_CRITICAL,
  2132. "[NM] UpdateSetServiceAccountPassword: Failed to verify MAC "
  2133. "or decrypt data, status %1!u!\n",
  2134. ReturnStatus
  2135. );
  2136. goto ErrorExit;
  2137. }
  2138. ReturnStatus = NmpCheckDecryptedPassword(DecryptedNewPassword,
  2139. LocalNewPasswordLen);
  2140. if ( ReturnStatus != ERROR_SUCCESS )
  2141. {
  2142. ClRtlLogPrint(
  2143. LOG_CRITICAL,
  2144. "[NM] UpdateSetServiceAccountPassword: decrypted new password "
  2145. "is not an eligible UNICODE string with length equal to %1!u!.\n",
  2146. LocalNewPasswordLen
  2147. );
  2148. goto ErrorExit;
  2149. }
  2150. DecryptedNewPasswordLength = LocalNewPasswordLen;
  2151. //
  2152. // Check if this is the same password that was used in the last change.
  2153. // If so, we will ignore it to avoid flushing the old password cache.
  2154. //
  2155. if (NmpLastNewPasswordEncryptedLength != 0)
  2156. {
  2157. DataIn.pbData = (BYTE *) NmpLastNewPasswordEncrypted;
  2158. DataIn.cbData = NmpLastNewPasswordEncryptedLength;
  2159. Success = CryptUnprotectData(&DataIn, // data to be encrypted
  2160. NULL, // description string
  2161. NULL,
  2162. NULL,
  2163. NULL,
  2164. 0, // flags
  2165. &DataOut // encrypted data
  2166. );
  2167. if (!Success)
  2168. {
  2169. ReturnStatus = GetLastError();
  2170. ClRtlLogPrint(LOG_UNUSUAL,
  2171. "[NM] UpdateSetServiceAccountPassword: Failed to "
  2172. "decrypt data using CryptUnprotectData, "
  2173. "status %1!u!.\n",
  2174. ReturnStatus
  2175. );
  2176. goto ErrorExit;
  2177. }
  2178. if (DataOut.cbData == DecryptedNewPasswordLength)
  2179. {
  2180. if ( memcmp( DataOut.pbData,
  2181. DecryptedNewPassword,
  2182. DecryptedNewPasswordLength
  2183. )
  2184. == 0
  2185. )
  2186. {
  2187. //
  2188. // They are the same. No need to change again.
  2189. //
  2190. //
  2191. // Release memory allocated by previous CryptProtectData().
  2192. //
  2193. RtlSecureZeroMemory(DataOut.pbData, DataOut.cbData);
  2194. DataOut.cbData = 0;
  2195. LocalFree(DataOut.pbData);
  2196. ClRtlLogPrint(
  2197. LOG_NOISE,
  2198. "[NM] UpdateSetServiceAccountPassword: New password is "
  2199. "identical to current password. Skipping password change.\n"
  2200. );
  2201. ReturnStatus = ERROR_SUCCESS;
  2202. goto ErrorExit;
  2203. }
  2204. }
  2205. //
  2206. // Release memory allocated by previous CryptProtectData().
  2207. //
  2208. RtlSecureZeroMemory(DataOut.pbData, DataOut.cbData);
  2209. DataOut.cbData = 0;
  2210. LocalFree(DataOut.pbData);
  2211. } // if (NmpLastNewPasswordEncryptedLength != 0)
  2212. //
  2213. // Change password in SCM database
  2214. //
  2215. //
  2216. // Establish a connection to the service control manager on local host
  2217. // and open service control manager database
  2218. //
  2219. ScmHandle = OpenSCManager(
  2220. NULL, // connect to local machine
  2221. NULL, // open SERVICES_ACTIVE_DATABASE
  2222. GENERIC_WRITE
  2223. );
  2224. if (ScmHandle == NULL)
  2225. {
  2226. ReturnStatus = GetLastError();
  2227. ClRtlLogPrint(
  2228. LOG_CRITICAL,
  2229. "[NM] UpdateSetServiceAccountPassword: Failed to connect to "
  2230. "the SCM, status %1!u!.\n",
  2231. ReturnStatus
  2232. );
  2233. goto ErrorExit;
  2234. }
  2235. //
  2236. // Open a handle to the cluster service
  2237. //
  2238. ClusSvcHandle = OpenService(ScmHandle, L"clussvc", GENERIC_WRITE);
  2239. if (ClusSvcHandle == NULL)
  2240. {
  2241. ReturnStatus = GetLastError();
  2242. ClRtlLogPrint(
  2243. LOG_CRITICAL,
  2244. "[NM] UpdateSetServiceAccountPassword: Failed to open a "
  2245. "handle to the cluster service, status %1!u!.\n",
  2246. ReturnStatus
  2247. );
  2248. goto ErrorExit;
  2249. }
  2250. //
  2251. // Set the password property for the cluster service
  2252. //
  2253. Success = ChangeServiceConfig(
  2254. ClusSvcHandle, // Handle to the service.
  2255. SERVICE_NO_CHANGE, // type of service
  2256. SERVICE_NO_CHANGE, // when to start service
  2257. SERVICE_NO_CHANGE, // severity of start failure
  2258. NULL,
  2259. NULL,
  2260. NULL,
  2261. NULL,
  2262. NULL,
  2263. (LPCWSTR) DecryptedNewPassword,
  2264. NULL
  2265. );
  2266. if (!Success)
  2267. {
  2268. ReturnStatus = GetLastError();
  2269. ClRtlLogPrint(
  2270. LOG_CRITICAL,
  2271. "[NM] UpdateSetServiceAccountPassword: Failed to update the SCM "
  2272. "database, status %1!u!.\n",
  2273. ReturnStatus
  2274. );
  2275. goto ErrorExit;
  2276. }
  2277. //
  2278. // Close the handle to cluster service.
  2279. //
  2280. Success = CloseServiceHandle(ClusSvcHandle);
  2281. ClusSvcHandle = NULL;
  2282. if (!Success)
  2283. {
  2284. ReturnStatus = GetLastError();
  2285. ClRtlLogPrint(
  2286. LOG_UNUSUAL,
  2287. "[NM] UpdateSetServiceAccountPassword: Failed to close "
  2288. "handle to the cluster service, status %1!u!.\n",
  2289. ReturnStatus
  2290. );
  2291. goto ErrorExit;
  2292. }
  2293. //
  2294. // Close the handle to Service Database
  2295. //
  2296. Success = CloseServiceHandle(ScmHandle);
  2297. ScmHandle = NULL;
  2298. if (!Success)
  2299. {
  2300. ReturnStatus=GetLastError();
  2301. ClRtlLogPrint(
  2302. LOG_UNUSUAL,
  2303. "[NM] UpdateSetServiceAccountPassword: Failed to close "
  2304. "handle to the SCM, status %1!u!.\n",
  2305. ReturnStatus
  2306. );
  2307. goto ErrorExit;
  2308. }
  2309. ClRtlLogPrint(
  2310. LOG_NOISE,
  2311. "[NM] UpdateSetServiceAccountPassword: Updated the SCM database.\n"
  2312. );
  2313. //
  2314. // Change password in LSA cache
  2315. //
  2316. Status = LsaConnectUntrusted(&LsaHandle);
  2317. if (Status != STATUS_SUCCESS)
  2318. {
  2319. ReturnStatus = LsaNtStatusToWinError(Status);
  2320. ClRtlLogPrint(
  2321. LOG_CRITICAL,
  2322. "[NM] UpdateSetServiceAccountPassword: Failed to connect to "
  2323. "the LSA, status %1!u!.\n",
  2324. ReturnStatus
  2325. );
  2326. goto ErrorExit;
  2327. }
  2328. RtlInitString(&LsaStringBuf, AuthPackage);
  2329. Status = LsaLookupAuthenticationPackage(
  2330. LsaHandle, // Handle
  2331. &LsaStringBuf, // MSV1_0 authentication package
  2332. &PackageId // output: authentication package identifier
  2333. );
  2334. if (Status != STATUS_SUCCESS)
  2335. {
  2336. ReturnStatus = LsaNtStatusToWinError(Status);
  2337. ClRtlLogPrint(
  2338. LOG_CRITICAL,
  2339. "[NM] UpdateSetServiceAccountPassword: Failed to lookup "
  2340. "authentication package, status %1!u!.\n",
  2341. ReturnStatus
  2342. );
  2343. goto ErrorExit;
  2344. }
  2345. //
  2346. // Prepare to call LsaCallAuthenticationPackage()
  2347. //
  2348. RequestSize = sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) +
  2349. ( ( wcslen(AccountName) +
  2350. wcslen(DomainName) +
  2351. wcslen((LPWSTR) DecryptedNewPassword) + 3
  2352. ) * sizeof(WCHAR)
  2353. );
  2354. Request = (PMSV1_0_CHANGEPASSWORD_REQUEST)
  2355. HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, RequestSize);
  2356. if (Request == NULL)
  2357. {
  2358. ClRtlLogPrint(
  2359. LOG_CRITICAL,
  2360. "[NM] UpdateSetServiceAccountPassword: Failed to allocate %1!u! "
  2361. "bytes for LSA request buffer.\n",
  2362. RequestSize
  2363. );
  2364. ReturnStatus = ERROR_NOT_ENOUGH_MEMORY;
  2365. goto ErrorExit;
  2366. }
  2367. Where = (PBYTE) (Request + 1);
  2368. Request->MessageType = MsV1_0ChangeCachedPassword;
  2369. wcscpy( (LPWSTR) Where, DomainName );
  2370. RtlInitUnicodeString( &Request->DomainName, (wchar_t *) Where );
  2371. Where += Request->DomainName.MaximumLength;
  2372. wcscpy((LPWSTR) Where, AccountName );
  2373. RtlInitUnicodeString( &Request->AccountName, (wchar_t *) Where );
  2374. Where += Request->AccountName.MaximumLength;
  2375. wcscpy((LPWSTR) Where, (LPWSTR) DecryptedNewPassword );
  2376. RtlInitUnicodeString( &Request->NewPassword, (wchar_t *) Where );
  2377. Where += Request->NewPassword.MaximumLength;
  2378. Status = LsaCallAuthenticationPackage(
  2379. LsaHandle,
  2380. PackageId,
  2381. Request, // MSV1_0_CHANGEPASSWORD_REQUEST
  2382. RequestSize,
  2383. &Response,
  2384. &ResponseSize,
  2385. &SubStatus // Receives NSTATUS code indicating the
  2386. // completion status of the authentication
  2387. // package if ERROR_SUCCESS is returned.
  2388. );
  2389. if (Status != STATUS_SUCCESS)
  2390. {
  2391. ReturnStatus = LsaNtStatusToWinError(Status);
  2392. ClRtlLogPrint(
  2393. LOG_CRITICAL,
  2394. "[NM] UpdateSetServiceAccountPassword: Failed to update the "
  2395. "LSA password cache, status %1!u!.\n",
  2396. ReturnStatus
  2397. );
  2398. goto ErrorExit;
  2399. }
  2400. else if (LsaNtStatusToWinError(SubStatus) != ERROR_SUCCESS)
  2401. {
  2402. ReturnStatus = LsaNtStatusToWinError(SubStatus);
  2403. ClRtlLogPrint(
  2404. LOG_CRITICAL,
  2405. "[NM] UpdateSetServiceAccountPassword: Failed to update the "
  2406. "LSA password cache, substatus %1!u!.\n",
  2407. ReturnStatus
  2408. );
  2409. goto ErrorExit;
  2410. }
  2411. ClRtlLogPrint(
  2412. LOG_NOISE,
  2413. "[NM] UpdateSetServiceAccountPassword: Updated the LSA password "
  2414. "cache.\n"
  2415. );
  2416. //
  2417. // Rederive cluster encryption key based on new password
  2418. //
  2419. ReturnStatus = NmpRederiveClusterKey();
  2420. if (ReturnStatus != ERROR_SUCCESS)
  2421. {
  2422. ClRtlLogPrint(
  2423. LOG_CRITICAL,
  2424. "[NM] UpdateSetServiceAccountPassword: Failed to regenerate "
  2425. "the cluster service encryption key, status %1!u!.\n",
  2426. ReturnStatus
  2427. );
  2428. goto ErrorExit;
  2429. }
  2430. ClRtlLogPrint(
  2431. LOG_NOISE,
  2432. "[NM] UpdateSetServiceAccountPassword: Regenerated cluster service "
  2433. "encryption key.\n"
  2434. );
  2435. //
  2436. // Store the new password for comparison on the next change request
  2437. //
  2438. //
  2439. // release last stored protected password
  2440. //
  2441. if (NmpLastNewPasswordEncrypted != NULL)
  2442. {
  2443. // Release memory allocated by previous CryptProtectData().
  2444. LocalFree(NmpLastNewPasswordEncrypted);
  2445. NmpLastNewPasswordEncrypted = NULL;
  2446. NmpLastNewPasswordEncryptedLength = 0;
  2447. }
  2448. //
  2449. // Protect new password
  2450. //
  2451. ReturnStatus = NmpProtectData(DecryptedNewPassword,
  2452. DecryptedNewPasswordLength,
  2453. &NmpLastNewPasswordEncrypted,
  2454. &NmpLastNewPasswordEncryptedLength
  2455. );
  2456. if (ReturnStatus != ERROR_SUCCESS)
  2457. {
  2458. ClRtlLogPrint(LOG_UNUSUAL,
  2459. "[NM] UpdateSetServiceAccountPassword: Failed to encrypt data "
  2460. "using CryptProtectData, "
  2461. "status %1!u!.\n",
  2462. ReturnStatus
  2463. );
  2464. goto ErrorExit;
  2465. }
  2466. // Log successful password change event
  2467. ClusterLogEvent0(LOG_NOISE,
  2468. LOG_CURRENT_MODULE,
  2469. __FILE__,
  2470. __LINE__,
  2471. SERVICE_PASSWORD_CHANGE_SUCCESS,
  2472. 0,
  2473. NULL
  2474. );
  2475. ReturnStatus = ERROR_SUCCESS;
  2476. ErrorExit:
  2477. NmpLeaveApi();
  2478. if (DecryptedNewPassword != NULL)
  2479. {
  2480. // Zero DecryptedNewPassword
  2481. RtlSecureZeroMemory(DecryptedNewPassword, DecryptedNewPasswordLength);
  2482. if (!HeapFree(GetProcessHeap(), 0, DecryptedNewPassword))
  2483. {
  2484. ClRtlLogPrint(
  2485. LOG_UNUSUAL,
  2486. "[NM] UpdateSetServiceAccountPassword: Failed to free "
  2487. "decrypted password buffer, status %1!u!\n",
  2488. GetLastError()
  2489. );
  2490. }
  2491. DecryptedNewPassword = NULL;
  2492. DecryptedNewPasswordLength = 0;
  2493. }
  2494. if (SharedCommonKey != NULL)
  2495. {
  2496. RtlSecureZeroMemory(SharedCommonKey, SharedCommonKeyLen);
  2497. HeapFree(GetProcessHeap(), 0, SharedCommonKey);
  2498. SharedCommonKey = NULL;
  2499. SharedCommonKeyLen = 0;
  2500. SharedCommonKeyFirstHalf = NULL;
  2501. SharedCommonKeyFirstHalfLen = 0;
  2502. SharedCommonKeySecondHalf = NULL;
  2503. SharedCommonKeySecondHalfLen = 0;
  2504. }
  2505. // Log failed password change event
  2506. if ( ReturnStatus != ERROR_SUCCESS )
  2507. {
  2508. ClusterLogEvent0(LOG_CRITICAL,
  2509. LOG_CURRENT_MODULE,
  2510. __FILE__,
  2511. __LINE__,
  2512. SERVICE_PASSWORD_CHANGE_FAILED,
  2513. sizeof(ReturnStatus),
  2514. (PVOID) &ReturnStatus
  2515. );
  2516. }
  2517. // Close the handle to cluster service.
  2518. if (ClusSvcHandle != NULL)
  2519. {
  2520. Success = CloseServiceHandle(ClusSvcHandle);
  2521. if (!Success)
  2522. {
  2523. ClRtlLogPrint(
  2524. LOG_UNUSUAL,
  2525. "[NM] UpdateSetServiceAccountPassword: Failed to close "
  2526. "handle to cluster service, status %1!u!.\n",
  2527. GetLastError()
  2528. );
  2529. }
  2530. }
  2531. // Close the handle to Service Database
  2532. if (ScmHandle != NULL)
  2533. {
  2534. Success = CloseServiceHandle(ScmHandle);
  2535. if (!Success)
  2536. {
  2537. ClRtlLogPrint(
  2538. LOG_UNUSUAL,
  2539. "[NM] UpdateSetServiceAccountPassword: Failed to close "
  2540. "handle to SCM, status %1!u!.\n",
  2541. GetLastError()
  2542. );
  2543. }
  2544. }
  2545. if (LsaHandle != NULL)
  2546. {
  2547. Status = LsaDeregisterLogonProcess(LsaHandle);
  2548. if (Status != STATUS_SUCCESS)
  2549. {
  2550. ClRtlLogPrint(
  2551. LOG_UNUSUAL,
  2552. "[NM] UpdateSetServiceAccountPassword: Failed to deregister "
  2553. "with LSA, status %1!u!.\n",
  2554. LsaNtStatusToWinError(Status)
  2555. );
  2556. }
  2557. }
  2558. if (Request != NULL)
  2559. {
  2560. if (!HeapFree(GetProcessHeap(), 0, Request))
  2561. {
  2562. ClRtlLogPrint(
  2563. LOG_UNUSUAL,
  2564. "[NM] UpdateSetServiceAccountPassword: Failed to free "
  2565. "LSA request buffer, status %1!u!.\n",
  2566. GetLastError()
  2567. );
  2568. }
  2569. }
  2570. if (Response != NULL)
  2571. {
  2572. Status = LsaFreeReturnBuffer(Response);
  2573. if (Status != STATUS_SUCCESS)
  2574. {
  2575. ClRtlLogPrint(
  2576. LOG_UNUSUAL,
  2577. "[NM] UpdateSetServiceAccountPassword: Failed to free "
  2578. "LSA return buffer, status %1!u!.\n",
  2579. LsaNtStatusToWinError(Status)
  2580. );
  2581. }
  2582. }
  2583. // Release the CSP.
  2584. if(CryptProvider)
  2585. {
  2586. if (!CryptReleaseContext(CryptProvider,0))
  2587. {
  2588. ClRtlLogPrint(
  2589. LOG_UNUSUAL,
  2590. "NM] UpdateSetServiceAccountPassword: Failed to release "
  2591. "crypto provider, status %1!u!\n",
  2592. GetLastError()
  2593. );
  2594. }
  2595. }
  2596. return(ReturnStatus);
  2597. } // NmpUpdateSetServiceAccountPassword