Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2645 lines
67 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. crypto.c
  5. Abstract:
  6. Interfaces for registering and deregistering crypto checkpoint
  7. handlers.
  8. Author:
  9. Jeff Spelman (jeffspel) 11/10/1998
  10. Revision History:
  11. Charlie Wickham (charlwi) 7/7/00
  12. added "how this works" section
  13. --*/
  14. #include "cpp.h"
  15. #include "wincrypt.h"
  16. #if 0
  17. How crypto checkpointing works
  18. Crypto checkpointing allows a crypto key container to be associated with a
  19. resource. When that resource is moved to another node in the cluster, the key
  20. container is constructed/updated from the checkpoint information on the previous
  21. hosting node. The key container is not replicated; it only appears on a node if
  22. the resource is moved to that node. Keys in the container must be exportable.
  23. The user identifies the crypto key container by passing in a string of the form
  24. "Type\Name\Key" where Type is CSP Provider type, Name is the provider name, and
  25. Key is the key container name.
  26. Checkpoints are added in CpckAddCryptoCheckpoint. Checkpoint information is
  27. stored in two places: in the CryptoSync key under the resource key and in a
  28. datafile on the quorum drive. A new key, called CryptoSync, is created under
  29. the resource key. In this key are values that are of the form 00000001,
  30. 00000002, etc. The data associated with the value is the string identifying
  31. the crypto key container. The datafile contains all the information to restore
  32. the crypto key container on another node in the cluster, i.e., a header
  33. (CRYPTO_KEY_FILE_DATA), the signature and exchange keys if they exist, and the
  34. security descriptor associated with key container.
  35. Upon receiving the control code, the cluster service cracks the string into its
  36. component parts and stores the data in a CRYPTO_KEY_INFO structure. The
  37. CryptoSync key is opened/created and a check is made to see if the checkpoint
  38. already exists. If not, a new ID is found and the checkpoint is saved to a file
  39. on the quorum disk.
  40. When the resource is moved to another node, the FM calls CpckReplicateCryptoKeys
  41. to restore the keys on that node. This routine reads the file and creates the
  42. key container, imports the keys and sets the security descr. on the container.
  43. Delete cleans up registry entry and file.
  44. #endif
  45. //
  46. // Local type and structure definitions
  47. //
  48. typedef struct _CPCK_ADD_CONTEXT {
  49. BOOL fFound;
  50. BYTE *pbInfo;
  51. DWORD cbInfo;
  52. } CPCK_ADD_CONTEXT, *PCPCK_ADD_CONTEXT;
  53. typedef struct _CPCK_DEL_CONTEXT {
  54. DWORD dwId;
  55. BYTE *pbInfo;
  56. DWORD cbInfo;
  57. } CPCK_DEL_CONTEXT, *PCPCK_DEL_CONTEXT;
  58. typedef struct _CPCK_GET_CONTEXT {
  59. DWORD cCheckpoints;
  60. BOOL fNeedMoreData;
  61. DWORD cbAvailable;
  62. DWORD cbRequired;
  63. BYTE *pbOutput;
  64. } CPCK_GET_CONTEXT, *PCPCK_GET_CONTEXT;
  65. // struct for Crypto Key information
  66. typedef struct _CRYPTO_KEY_INFO {
  67. DWORD dwVersion;
  68. DWORD dwProvType;
  69. LPWSTR pwszProvName;
  70. LPWSTR pwszContainer;
  71. } CRYPTO_KEY_INFO, *PCRYPTO_KEY_INFO;
  72. // current version for the CRYPTO_KEY_INFO struct
  73. #define CRYPTO_KEY_INFO_VERSION 1
  74. // struct for key data when writing and reading from files
  75. #define SALT_SIZE 16
  76. #define IV_SIZE 8
  77. typedef struct _CRYPTO_KEY_FILE_DATA {
  78. DWORD dwVersion;
  79. DWORD cbSig;
  80. DWORD cbExch;
  81. DWORD cbSecDescr;
  82. struct _CRYPTO_KEY_FILE_INITIALIZATION_DATA {
  83. BYTE rgbSigIV[IV_SIZE];
  84. BYTE rgbExchIV[IV_SIZE];
  85. BYTE rgbSalt[SALT_SIZE];
  86. };
  87. } CRYPTO_KEY_FILE_DATA, *PCRYPTO_KEY_FILE_DATA;
  88. // current version for the CRYPTO_KEY_INFO struct
  89. #define CRYPTO_KEY_FILE_DATA_VERSION 1
  90. //
  91. // Local function prototypes
  92. //
  93. BOOL
  94. CpckReplicateCallback(
  95. IN LPWSTR ValueName,
  96. IN LPVOID ValueData,
  97. IN DWORD ValueType,
  98. IN DWORD ValueSize,
  99. IN PFM_RESOURCE Resource
  100. );
  101. BOOL
  102. CpckAddCheckpointCallback(
  103. IN LPWSTR ValueName,
  104. IN LPVOID ValueData,
  105. IN DWORD ValueType,
  106. IN DWORD ValueSize,
  107. IN PCPCK_ADD_CONTEXT Context
  108. );
  109. BOOL
  110. CpckDeleteCheckpointCallback(
  111. IN LPWSTR ValueName,
  112. IN LPVOID ValueData,
  113. IN DWORD ValueType,
  114. IN DWORD ValueSize,
  115. IN PCPCK_DEL_CONTEXT Context
  116. );
  117. BOOL
  118. CpckGetCheckpointsCallback(
  119. IN LPWSTR ValueName,
  120. IN LPVOID ValueData,
  121. IN DWORD ValueType,
  122. IN DWORD ValueSize,
  123. IN PCPCK_GET_CONTEXT Context
  124. );
  125. DWORD
  126. CpckInstallKeyContainer(
  127. IN HCRYPTPROV hProv,
  128. IN LPWSTR FileName
  129. );
  130. DWORD
  131. CpckCheckpoint(
  132. IN PFM_RESOURCE Resource,
  133. IN HCRYPTPROV hProv,
  134. IN DWORD dwId,
  135. IN CRYPTO_KEY_INFO *pCryptoKeyInfo
  136. );
  137. CL_NODE_ID
  138. CppGetQuorumNodeId(
  139. VOID
  140. );
  141. DWORD
  142. CpckReplicateCryptoKeys(
  143. IN PFM_RESOURCE Resource
  144. )
  145. /*++
  146. Routine Description:
  147. Restores any crypto key checkpoints for this resource.
  148. Arguments:
  149. Resource - Supplies the resource.
  150. Return Value:
  151. ERROR_SUCCESS if successful
  152. Win32 error code otherwise
  153. --*/
  154. {
  155. DWORD Status;
  156. HDMKEY ResourceKey;
  157. HDMKEY CryptoSyncKey;
  158. //
  159. // Open up the resource's key
  160. //
  161. ResourceKey = DmOpenKey(DmResourcesKey,
  162. OmObjectId(Resource),
  163. KEY_READ);
  164. CL_ASSERT(ResourceKey != NULL);
  165. //
  166. // Open up the CryptoSync key
  167. //
  168. CryptoSyncKey = DmOpenKey(ResourceKey,
  169. L"CryptoSync",
  170. KEY_READ);
  171. DmCloseKey(ResourceKey);
  172. if (CryptoSyncKey != NULL) {
  173. DmEnumValues(CryptoSyncKey,
  174. CpckReplicateCallback,
  175. Resource);
  176. DmCloseKey(CryptoSyncKey);
  177. }
  178. return(ERROR_SUCCESS);
  179. } // CpckReplicateCryptoKeys
  180. void
  181. FreeCryptoKeyInfo(
  182. IN OUT CRYPTO_KEY_INFO *pCryptoKeyInfo
  183. )
  184. /*++
  185. Routine Description:
  186. Frees the string pointers in the structure.
  187. Arguments:
  188. CryptoKeyInfo - Pointer to the CRYPTO_KEY_INFO structure which
  189. --*/
  190. {
  191. if (NULL != pCryptoKeyInfo)
  192. {
  193. if (NULL != pCryptoKeyInfo->pwszProvName)
  194. {
  195. LocalFree(pCryptoKeyInfo->pwszProvName);
  196. pCryptoKeyInfo->pwszProvName = NULL;
  197. }
  198. if (NULL != pCryptoKeyInfo->pwszContainer)
  199. {
  200. LocalFree(pCryptoKeyInfo->pwszContainer);
  201. pCryptoKeyInfo->pwszContainer = NULL;
  202. }
  203. }
  204. } // FreeCryptoKeyInfo
  205. DWORD
  206. CpckValueToCryptoKeyInfo(
  207. OUT CRYPTO_KEY_INFO *pCryptoKeyInfo,
  208. IN LPVOID ValueData,
  209. IN DWORD ValueSize
  210. )
  211. /*++
  212. Routine Description:
  213. Converts from a binary blob into a CryptoKeyInfo structure. Basically
  214. this just does some value and pointer assignments.
  215. Arguments:
  216. CryptoKeyInfo - Pointer to the CRYPTO_KEY_INFO structure which is filled in
  217. ValueData - Supplies the value data (this is the binary blob)
  218. ValueSize - Supplies the size of ValueData
  219. Return Value:
  220. ERROR_SUCCESS if successful
  221. Win32 error code otherwise
  222. --*/
  223. {
  224. DWORD *pdw;
  225. WCHAR *pwsz = (WCHAR*)ValueData;
  226. DWORD cb = sizeof(DWORD) * 2;
  227. DWORD cwch;
  228. DWORD i;
  229. DWORD Status = ERROR_SUCCESS;
  230. // make sure the length is OK
  231. if (ValueSize < sizeof(WCHAR) * 3)
  232. {
  233. Status = ERROR_INVALID_PARAMETER;
  234. goto Ret;
  235. }
  236. // first is the Provider type
  237. for (i = 0; i < (ValueSize - 3) / sizeof(WCHAR); i++)
  238. {
  239. if (L'\\' == pwsz[i])
  240. {
  241. pwsz[i] = L'\0';
  242. break;
  243. }
  244. }
  245. if ((ValueSize - 3) / sizeof(WCHAR) == i)
  246. {
  247. Status = ERROR_INVALID_PARAMETER;
  248. goto Ret;
  249. }
  250. pCryptoKeyInfo->dwProvType = _wtoi(pwsz);
  251. pwsz[i] = L'\\';
  252. cwch = i;
  253. // grab the provider name pointer
  254. for (i = i + 1; i < (ValueSize - 2) / sizeof(WCHAR); i++)
  255. {
  256. if (L'\\' == pwsz[i])
  257. {
  258. pwsz[i] = L'\0';
  259. break;
  260. }
  261. }
  262. if ((ValueSize - 2) / sizeof(WCHAR) == i)
  263. {
  264. Status = ERROR_INVALID_PARAMETER;
  265. goto Ret;
  266. }
  267. cb = (wcslen(&pwsz[cwch + 1]) + 1) * sizeof(WCHAR);
  268. if (NULL == (pCryptoKeyInfo->pwszProvName =
  269. (WCHAR*)LocalAlloc(LMEM_ZEROINIT, cb)))
  270. {
  271. Status = ERROR_NOT_ENOUGH_MEMORY;
  272. goto Ret;
  273. }
  274. wcscpy(pCryptoKeyInfo->pwszProvName, &pwsz[cwch + 1]);
  275. pwsz[i] = L'\\';
  276. cwch = i;
  277. // grab the container name pointer
  278. cb = (wcslen(&pwsz[cwch + 1]) + 1) * sizeof(WCHAR);
  279. if (NULL == (pCryptoKeyInfo->pwszContainer =
  280. (WCHAR*)LocalAlloc(LMEM_ZEROINIT, cb)))
  281. {
  282. Status = ERROR_NOT_ENOUGH_MEMORY;
  283. goto Ret;
  284. }
  285. wcscpy(pCryptoKeyInfo->pwszContainer, &pwsz[cwch + 1]);
  286. Ret:
  287. return (Status);
  288. } // CpckValueToCryptoKeyInfo
  289. DWORD
  290. CpckOpenCryptoKeyContainer(
  291. IN CRYPTO_KEY_INFO *pCryptoKeyInfo,
  292. IN BOOL fCreate,
  293. OUT HCRYPTPROV *phProv
  294. )
  295. /*++
  296. Routine Description:
  297. Opens a crypto key container (always uses CRYPT_MACHINE_KEYSET). Checks
  298. for either a signature and/or an exchange key and that they are
  299. exportable.
  300. Arguments:
  301. pCryptKeyInfo - Supplies the information for opening the container
  302. fCreate - Flag indicating if container is to be created
  303. phProv - The resulting Crypto Provider handle
  304. Return Value:
  305. ERROR_SUCCESS if succeeds
  306. Crypto Error code if it fails
  307. --*/
  308. {
  309. BOOLEAN WasEnabled;
  310. HCRYPTKEY hSigKey = 0;
  311. HCRYPTKEY hExchKey = 0;
  312. DWORD dwPermissions;
  313. DWORD cbPermissions;
  314. DWORD Status = 0;
  315. //
  316. // Attempt to open the specified crypto key container.
  317. //
  318. if (!CryptAcquireContextW(phProv,
  319. pCryptoKeyInfo->pwszContainer,
  320. pCryptoKeyInfo->pwszProvName,
  321. pCryptoKeyInfo->dwProvType,
  322. CRYPT_MACHINE_KEYSET))
  323. {
  324. if (fCreate)
  325. {
  326. //
  327. // if unable to open then create the container
  328. //
  329. if (!CryptAcquireContextW(phProv,
  330. pCryptoKeyInfo->pwszContainer,
  331. pCryptoKeyInfo->pwszProvName,
  332. pCryptoKeyInfo->dwProvType,
  333. CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
  334. {
  335. Status = GetLastError();
  336. }
  337. }
  338. else
  339. {
  340. Status = GetLastError();
  341. }
  342. }
  343. // if failed then try with BACKUP/RESTORE privilege
  344. if (0 != Status)
  345. {
  346. //
  347. //
  348. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  349. &WasEnabled);
  350. if ( Status != ERROR_SUCCESS )
  351. {
  352. ClRtlLogPrint(LOG_CRITICAL,
  353. "[CPCK] CpckOpenCryptoKeyContainer failed to enable thread privilege %1!d!...\n",
  354. Status);
  355. goto Ret;
  356. }
  357. if (!CryptAcquireContextW(phProv,
  358. pCryptoKeyInfo->pwszContainer,
  359. pCryptoKeyInfo->pwszProvName,
  360. pCryptoKeyInfo->dwProvType,
  361. CRYPT_MACHINE_KEYSET))
  362. {
  363. if (fCreate)
  364. {
  365. //
  366. // if unable to open then create the container
  367. //
  368. if (!CryptAcquireContextW(phProv,
  369. pCryptoKeyInfo->pwszContainer,
  370. pCryptoKeyInfo->pwszProvName,
  371. pCryptoKeyInfo->dwProvType,
  372. CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
  373. {
  374. Status = GetLastError();
  375. }
  376. }
  377. else
  378. {
  379. Status = GetLastError();
  380. }
  381. }
  382. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  383. WasEnabled);
  384. }
  385. if ((0 == Status) && (!fCreate))
  386. {
  387. // check if there is a sig key
  388. if (CryptGetUserKey(*phProv, AT_SIGNATURE, &hSigKey))
  389. {
  390. // check if key is exportable
  391. cbPermissions = sizeof(DWORD);
  392. if (!CryptGetKeyParam(hSigKey,
  393. KP_PERMISSIONS,
  394. (BYTE*)&dwPermissions,
  395. &cbPermissions,
  396. 0))
  397. {
  398. Status = GetLastError();
  399. goto Ret;
  400. }
  401. if (!(dwPermissions & CRYPT_EXPORT))
  402. {
  403. Status = (DWORD)NTE_BAD_KEY;
  404. goto Ret;
  405. }
  406. }
  407. // check if there is an exchange key
  408. if (CryptGetUserKey(*phProv, AT_KEYEXCHANGE, &hExchKey))
  409. {
  410. // check if key is exportable
  411. cbPermissions = sizeof(DWORD);
  412. if (!CryptGetKeyParam(hExchKey,
  413. KP_PERMISSIONS,
  414. (BYTE*)&dwPermissions,
  415. &cbPermissions,
  416. 0))
  417. {
  418. Status = GetLastError();
  419. goto Ret;
  420. }
  421. if (!(dwPermissions & CRYPT_EXPORT))
  422. {
  423. Status = (DWORD)NTE_BAD_KEY;
  424. goto Ret;
  425. }
  426. }
  427. }
  428. Ret:
  429. if (hSigKey)
  430. CryptDestroyKey(hSigKey);
  431. if (hExchKey)
  432. CryptDestroyKey(hExchKey);
  433. return Status;
  434. } // CpckOpenCryptoKeyContainer
  435. BOOL
  436. CpckReplicateCallback(
  437. IN LPWSTR ValueName,
  438. IN LPVOID ValueData,
  439. IN DWORD ValueType,
  440. IN DWORD ValueSize,
  441. IN PFM_RESOURCE Resource
  442. )
  443. /*++
  444. Routine Description:
  445. Value enumeration callback for watching a resource's crypto key
  446. checkpoints.
  447. Arguments:
  448. ValueName - Supplies the name of the value (this is the checkpoint ID)
  449. ValueData - Supplies the value data (this is the registry crypto key info)
  450. ValueType - Supplies the value type (must be REG_BINARY)
  451. ValueSize - Supplies the size of ValueData
  452. Resource - Supplies the resource this value is a crypto key checkpoint for
  453. Return Value:
  454. TRUE to continue enumeration
  455. --*/
  456. {
  457. DWORD Id;
  458. DWORD Status;
  459. WCHAR TempFile[MAX_PATH];
  460. CRYPTO_KEY_INFO CryptoKeyInfo;
  461. HCRYPTPROV hProv = 0;
  462. BOOL fRet = TRUE;
  463. memset(&CryptoKeyInfo, 0, sizeof(CryptoKeyInfo));
  464. Id = wcstol(ValueName, NULL, 16); // skip past the 'Crypto' prefix
  465. if (Id == 0) {
  466. ClRtlLogPrint(LOG_UNUSUAL,
  467. "[CPCK] CpckReplicateCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  468. ValueName,
  469. OmObjectName(Resource));
  470. goto Ret;
  471. }
  472. //
  473. // convert from binary blob into a Crypto Key Info structure
  474. //
  475. Status = CpckValueToCryptoKeyInfo(&CryptoKeyInfo,
  476. ValueData,
  477. ValueSize);
  478. if (Status != ERROR_SUCCESS) {
  479. ClRtlLogPrint(LOG_UNUSUAL,
  480. "[CPCK] CpckReplicateCallback invalid crypto info %1!ws! for resource %2!ws!\n",
  481. ValueName,
  482. OmObjectName(Resource));
  483. goto Ret;
  484. }
  485. Status = CpckOpenCryptoKeyContainer(&CryptoKeyInfo,
  486. TRUE,
  487. &hProv);
  488. if (Status != ERROR_SUCCESS) {
  489. ClRtlLogPrint(LOG_UNUSUAL,
  490. "[CPCK] CpckReplicateCallback CryptAcquireContext failed for %1!ws! %2!ws! with %3!d! for resource %4!ws!\n",
  491. CryptoKeyInfo.pwszContainer,
  492. CryptoKeyInfo.pwszProvName,
  493. Status,
  494. OmObjectName(Resource));
  495. goto Ret;
  496. }
  497. ClRtlLogPrint(LOG_NOISE,
  498. "[CPCK] CpckReplicateCallback retrieving crypto id %1!lx! for resource %2!ws\n",
  499. Id,
  500. OmObjectName(Resource));
  501. //
  502. // See if there is any checkpoint data for this ID.
  503. //
  504. Status = DmCreateTempFileName(TempFile);
  505. if (Status != ERROR_SUCCESS) {
  506. CL_UNEXPECTED_ERROR( Status );
  507. }
  508. Status = CpGetDataFile(Resource,
  509. Id,
  510. TempFile,
  511. TRUE);
  512. if (Status != ERROR_SUCCESS) {
  513. ClRtlLogPrint(LOG_UNUSUAL,
  514. "[CPCK] CpckReplicateCallback - CpGetDataFile for id %1!lx! resource %2!ws! failed %3!d!\n",
  515. Id,
  516. OmObjectName(Resource),
  517. Status);
  518. } else {
  519. //
  520. // Finally install the checkpointed file into the registry.
  521. //
  522. Status = CpckInstallKeyContainer(hProv, TempFile);
  523. if (Status != ERROR_SUCCESS) {
  524. ClRtlLogPrint(LOG_CRITICAL,
  525. "[CPCK] CpckReplicateCallback: could not restore temp file %1!ws! to container %2!ws! error %3!d!\n",
  526. TempFile,
  527. CryptoKeyInfo.pwszContainer,
  528. Status);
  529. // Log the event for crypto key failure
  530. CsLogEventData2(LOG_CRITICAL,
  531. CP_CRYPTO_CKPT_RESTORE_FAILED,
  532. sizeof(Status),
  533. &Status,
  534. OmObjectName(Resource),
  535. CryptoKeyInfo.pwszContainer);
  536. }
  537. }
  538. DeleteFile(TempFile);
  539. //
  540. // watcher for crypto keys is not currently available or needed
  541. //
  542. Ret:
  543. FreeCryptoKeyInfo(&CryptoKeyInfo);
  544. if (hProv)
  545. CryptReleaseContext(hProv, 0);
  546. return fRet;
  547. } // CpckReplicateCallback
  548. DWORD
  549. CpckAddCryptoCheckpoint(
  550. IN PFM_RESOURCE Resource,
  551. IN PVOID InBuffer,
  552. IN DWORD InBufferSize
  553. )
  554. /*++
  555. Routine Description:
  556. Adds a new crypto key checkpoint to a resource's list.
  557. Arguments:
  558. Resource - supplies the resource the crypto key checkpoint should be added to.
  559. InBuffer - Supplies the crypto key information (always CRYPT_MACHINE_KEYSET)
  560. InBufferSize - Supplies the length of InBuffer
  561. Return Value:
  562. ERROR_SUCCESS if successful
  563. Win32 error code otherwise
  564. --*/
  565. {
  566. HDMKEY SyncKey;
  567. CPCK_ADD_CONTEXT Context;
  568. HDMKEY ResourceKey = NULL;
  569. HDMKEY CryptoSyncKey = NULL;
  570. DWORD Disposition;
  571. DWORD Id;
  572. WCHAR IdName[9];
  573. DWORD Status;
  574. CLUSTER_RESOURCE_STATE State;
  575. BOOLEAN WasEnabled;
  576. DWORD Count=60;
  577. CRYPTO_KEY_INFO CryptoKeyInfo;
  578. HCRYPTPROV hProv = 0;
  579. memset(&CryptoKeyInfo, 0, sizeof(CryptoKeyInfo));
  580. //
  581. // convert from binary blob into a Crypto Key Info structure
  582. //
  583. Status = CpckValueToCryptoKeyInfo(&CryptoKeyInfo,
  584. InBuffer,
  585. InBufferSize);
  586. if (Status != ERROR_SUCCESS) {
  587. ClRtlLogPrint(LOG_UNUSUAL,
  588. "[CPCK] CpckAddCryptoCheckpoint: invalid crypto info for resource %1!ws!\n",
  589. OmObjectName(Resource));
  590. goto Ret;
  591. }
  592. Status = CpckOpenCryptoKeyContainer(&CryptoKeyInfo,
  593. FALSE,
  594. &hProv);
  595. if (Status != ERROR_SUCCESS) {
  596. ClRtlLogPrint(LOG_UNUSUAL,
  597. "[CPCK] CpckAddCryptoCheckpoint: open key container failed for "
  598. "container %1!ws! (provider: %2!ws!) with %3!d! for resource %4!ws!\n",
  599. CryptoKeyInfo.pwszContainer,
  600. CryptoKeyInfo.pwszProvName,
  601. Status,
  602. OmObjectName(Resource));
  603. goto Ret;
  604. }
  605. //
  606. // Open up the resource's key
  607. //
  608. ResourceKey = DmOpenKey(DmResourcesKey,
  609. OmObjectId(Resource),
  610. KEY_READ);
  611. if( ResourceKey == NULL ) {
  612. Status = GetLastError();
  613. ClRtlLogPrint(LOG_CRITICAL,
  614. "[CPCK] CpckAddCryptoCheckpoint: couldn't open Resource key for %1!ws! error %2!d!\n",
  615. OmObjectName(Resource),
  616. Status);
  617. goto Ret;
  618. }
  619. //
  620. // Open up the CryptoSync key
  621. //
  622. CryptoSyncKey = DmCreateKey(ResourceKey,
  623. L"CryptoSync",
  624. 0,
  625. KEY_READ | KEY_WRITE,
  626. NULL,
  627. &Disposition);
  628. DmCloseKey(ResourceKey);
  629. if (CryptoSyncKey == NULL) {
  630. Status = GetLastError();
  631. ClRtlLogPrint(LOG_CRITICAL,
  632. "[CPCK] CpckAddCryptoCheckpoint: couldn't create CryptoSync key for "
  633. "resource %1!ws! error %2!d!\n",
  634. OmObjectName(Resource),
  635. Status);
  636. goto Ret;
  637. }
  638. if (Disposition == REG_OPENED_EXISTING_KEY) {
  639. //
  640. // Enumerate all the other values to make sure this key is
  641. // not already registered.
  642. //
  643. Context.fFound = FALSE;
  644. Context.pbInfo = InBuffer;
  645. Context.cbInfo = InBufferSize;
  646. DmEnumValues(CryptoSyncKey,
  647. CpckAddCheckpointCallback,
  648. &Context);
  649. if (Context.fFound) {
  650. //
  651. // This checkpoint already exists.
  652. //
  653. ClRtlLogPrint(LOG_UNUSUAL,
  654. "[CPCK] CpckAddCryptoCheckpoint: failing attempt to add duplicate "
  655. "checkpoint for resource %1!ws!, container %2!ws! (provider: %3!ws!)\n",
  656. OmObjectName(Resource),
  657. CryptoKeyInfo.pwszContainer,
  658. CryptoKeyInfo.pwszProvName);
  659. Status = ERROR_ALREADY_EXISTS;
  660. goto Ret;
  661. }
  662. //
  663. // Now we need to find a unique checkpoint ID for this registry subtree.
  664. // Start at 1 and keep trying value names until we get to one that does
  665. // not already exist.
  666. //
  667. for (Id=1; ; Id++) {
  668. DWORD dwType;
  669. DWORD cbData;
  670. wsprintfW(IdName,L"%08lx",Id);
  671. cbData = 0;
  672. Status = DmQueryValue(CryptoSyncKey,
  673. IdName,
  674. &dwType,
  675. NULL,
  676. &cbData);
  677. if (Status == ERROR_FILE_NOT_FOUND) {
  678. //
  679. // Found a free ID.
  680. //
  681. break;
  682. }
  683. }
  684. } else {
  685. //
  686. // The crypto sync reg key was just created, so this must be the only checkpoint
  687. // that exists.
  688. //
  689. Id = 1;
  690. wsprintfW(IdName, L"%08lx",Id);
  691. }
  692. ClRtlLogPrint(LOG_NOISE,
  693. "[CPCK] CpckAddCryptoCheckpoint: creating new checkpoint id %1!d! "
  694. "for resource %2!ws!, container %3!ws! (provider: %4!ws!)\n",
  695. Id,
  696. OmObjectName(Resource),
  697. CryptoKeyInfo.pwszContainer,
  698. CryptoKeyInfo.pwszProvName);
  699. Status = DmSetValue(CryptoSyncKey,
  700. IdName,
  701. REG_BINARY,
  702. (CONST BYTE *)InBuffer,
  703. InBufferSize);
  704. if (Status != ERROR_SUCCESS) {
  705. ClRtlLogPrint(LOG_CRITICAL,
  706. "[CPCK] CpckAddCryptoCheckpoint: failed to create new checkpoint id %1!d! "
  707. "for resource %2!ws!, container %3!ws! (provider: %4!ws!)\n",
  708. Id,
  709. OmObjectName(Resource),
  710. CryptoKeyInfo.pwszContainer,
  711. CryptoKeyInfo.pwszProvName);
  712. goto Ret;
  713. }
  714. RetryCheckpoint:
  715. //
  716. // Take the initial checkpoint
  717. //
  718. Status = CpckCheckpoint(Resource,
  719. hProv,
  720. Id,
  721. &CryptoKeyInfo);
  722. // this may fail due to quorum resource being offline. We could do one of
  723. // two things here, wait for quorum resource to come online or retry. We
  724. // retry as this may be called from the online routines of a resource and
  725. // we dont want to add any circular waits.
  726. if ((Status == ERROR_ACCESS_DENIED) ||
  727. (Status == ERROR_INVALID_FUNCTION) ||
  728. (Status == ERROR_NOT_READY) ||
  729. (Status == RPC_X_INVALID_PIPE_OPERATION) ||
  730. (Status == ERROR_BUSY) ||
  731. (Status == ERROR_SWAPERROR))
  732. {
  733. if (Count--)
  734. {
  735. Sleep(1000);
  736. goto RetryCheckpoint;
  737. }
  738. #if DBG
  739. else
  740. {
  741. if (IsDebuggerPresent())
  742. DebugBreak();
  743. }
  744. #endif
  745. }
  746. if (Status != ERROR_SUCCESS) {
  747. ClRtlLogPrint(LOG_CRITICAL,
  748. "[CPCK] CpckAddCryptoCheckpoint: failed to take initial checkpoint for "
  749. "resource %1!ws!, container %2!ws! (provider: %3!ws!), error %4!d!\n",
  750. OmObjectName(Resource),
  751. CryptoKeyInfo.pwszContainer,
  752. CryptoKeyInfo.pwszProvName,
  753. Status);
  754. goto Ret;
  755. }
  756. Ret:
  757. FreeCryptoKeyInfo(&CryptoKeyInfo);
  758. if (hProv)
  759. CryptReleaseContext(hProv, 0);
  760. if (CryptoSyncKey)
  761. DmCloseKey(CryptoSyncKey);
  762. return(Status);
  763. } // CpckAddCryptoCheckpoint
  764. BOOL
  765. CpckAddCheckpointCallback(
  766. IN LPWSTR ValueName,
  767. IN LPVOID ValueData,
  768. IN DWORD ValueType,
  769. IN DWORD ValueSize,
  770. IN PCPCK_ADD_CONTEXT Context
  771. )
  772. /*++
  773. Routine Description:
  774. Value enumeration callback for adding a new registry
  775. checkpoint subtrees. This is only used to see if the specified
  776. registry subtree is already being watched.
  777. Arguments:
  778. ValueName - Supplies the name of the value (this is the checkpoint ID)
  779. ValueData - Supplies the value data (this is the crypto key information)
  780. ValueType - Supplies the value type (must be REG_BINARY)
  781. ValueSize - Supplies the size of ValueData
  782. Context - Supplies the callback context
  783. Return Value:
  784. TRUE to continue enumeration
  785. FALSE if a match is found and enumeration should be stopped
  786. --*/
  787. {
  788. if (memcmp(ValueData, Context->pbInfo, Context->cbInfo) == 0) {
  789. //
  790. // Found a match
  791. //
  792. Context->fFound = TRUE;
  793. return(FALSE);
  794. }
  795. return(TRUE);
  796. } // CpckAddCheckpointCallback
  797. DWORD
  798. CpckDeleteCryptoCheckpoint(
  799. IN PFM_RESOURCE Resource,
  800. IN PVOID InBuffer,
  801. IN DWORD InBufferSize
  802. )
  803. /*++
  804. Routine Description:
  805. Removes a crypto key checkpoint from a resource's list.
  806. Arguments:
  807. Resource - supplies the resource the registry checkpoint should be added to.
  808. InBuffer - Supplies the crypto key information (always CRYPT_MACHINE_KEYSET)
  809. InBufferSize - Supplies the length of InBuffer
  810. Return Value:
  811. ERROR_SUCCESS if successful
  812. Win32 error code otherwise
  813. --*/
  814. {
  815. CPCK_DEL_CONTEXT Context;
  816. HDMKEY ResourceKey;
  817. HDMKEY CryptoSyncKey;
  818. DWORD Status;
  819. WCHAR ValueId[9];
  820. LPWSTR pszFileName=NULL;
  821. LPWSTR pszDirectoryName=NULL;
  822. CLUSTER_RESOURCE_STATE State;
  823. //
  824. // Open up the resource's key
  825. //
  826. ResourceKey = DmOpenKey(DmResourcesKey,
  827. OmObjectId(Resource),
  828. KEY_READ);
  829. CL_ASSERT(ResourceKey != NULL);
  830. //
  831. // Open up the CryptoSync key
  832. //
  833. CryptoSyncKey = DmOpenKey(ResourceKey,
  834. L"CryptoSync",
  835. KEY_READ | KEY_WRITE);
  836. DmCloseKey(ResourceKey);
  837. if (CryptoSyncKey == NULL) {
  838. Status = GetLastError();
  839. ClRtlLogPrint(LOG_NOISE,
  840. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't open CryptoSync key error %1!d!\n",
  841. Status);
  842. return(Status);
  843. }
  844. //
  845. // Enumerate all the values to find this one
  846. //
  847. Context.dwId = 0;
  848. Context.pbInfo = InBuffer;
  849. Context.cbInfo = InBufferSize;
  850. DmEnumValues(CryptoSyncKey,
  851. CpckDeleteCheckpointCallback,
  852. &Context);
  853. if (Context.dwId == 0) {
  854. //
  855. // The specified tree was not found.
  856. //
  857. DmCloseKey(CryptoSyncKey);
  858. return(ERROR_FILE_NOT_FOUND);
  859. }
  860. wsprintfW(ValueId,L"%08lx",Context.dwId);
  861. Status = DmDeleteValue(CryptoSyncKey, ValueId);
  862. DmCloseKey(CryptoSyncKey);
  863. if (Status != ERROR_SUCCESS) {
  864. ClRtlLogPrint(LOG_CRITICAL,
  865. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't delete value %1!ws! error %2!d!\n",
  866. ValueId,
  867. Status);
  868. return(Status);
  869. }
  870. //delete the file corresponding to this checkpoint
  871. Status = CpckDeleteCryptoFile(Resource, Context.dwId, NULL);
  872. if (Status != ERROR_SUCCESS) {
  873. ClRtlLogPrint(LOG_CRITICAL,
  874. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't delete checkpoint file , error %1!d!\n",
  875. Status);
  876. return(Status);
  877. }
  878. return(Status);
  879. } // CpckDeleteCryptoCheckpoint
  880. DWORD
  881. CpckRemoveResourceCheckpoints(
  882. IN PFM_RESOURCE Resource
  883. )
  884. /*++
  885. Routine Description:
  886. This is called when a resource is deleted to remove all the checkpoints
  887. and the related stuff in the registry.
  888. Arguments:
  889. Resource - supplies the resource
  890. Return Value:
  891. ERROR_SUCCESS if successful
  892. Win32 error code otherwise
  893. --*/
  894. {
  895. DWORD Status;
  896. //delete all the checkpoints corresponding to this resource
  897. Status = CpckDeleteCryptoFile(Resource, 0, NULL);
  898. if (Status != ERROR_SUCCESS)
  899. {
  900. ClRtlLogPrint(LOG_CRITICAL,
  901. "[CPCK] CpckRemoveResourceCheckpoints, CpckDeleteCheckpointFile failed %1!d!\n",
  902. Status);
  903. goto FnExit;
  904. }
  905. FnExit:
  906. return(Status);
  907. } // CpckRemoveResourceCheckpoints
  908. BOOL
  909. CpckDeleteCheckpointCallback(
  910. IN LPWSTR ValueName,
  911. IN LPVOID ValueData,
  912. IN DWORD ValueType,
  913. IN DWORD ValueSize,
  914. IN PCPCK_DEL_CONTEXT Context
  915. )
  916. /*++
  917. Routine Description:
  918. Value enumeration callback for deleting an old registry
  919. checkpoint subtrees.
  920. Arguments:
  921. ValueName - Supplies the name of the value (this is the checkpoint ID)
  922. ValueData - Supplies the value data (this is the crypto info)
  923. ValueType - Supplies the value type (must be REG_BINARY)
  924. ValueSize - Supplies the size of ValueData
  925. Context - Supplies the callback context
  926. Return Value:
  927. TRUE to continue enumeration
  928. FALSE if a match is found and enumeration should be stopped
  929. --*/
  930. {
  931. if (memcmp(ValueData, Context->pbInfo, Context->cbInfo) == 0) {
  932. //
  933. // Found a match
  934. //
  935. Context->dwId = wcstol(ValueName, NULL, 16); // skip past the 'Crypto' prefix
  936. return(FALSE);
  937. }
  938. return(TRUE);
  939. } // CpckDeleteCheckpointCallback
  940. DWORD
  941. CpckGetCryptoCheckpoints(
  942. IN PFM_RESOURCE Resource,
  943. OUT PUCHAR OutBuffer,
  944. IN DWORD OutBufferSize,
  945. OUT LPDWORD BytesReturned,
  946. OUT LPDWORD Required
  947. )
  948. /*++
  949. Routine Description:
  950. Retrieves a list of the resource's crypto checkpoints
  951. Arguments:
  952. Resource - Supplies the resource whose crypto checkpoints should be retrieved.
  953. OutBuffer - Supplies a pointer to the output buffer.
  954. OutBufferSize - Supplies the size (in bytes) of the output buffer.
  955. BytesReturned - Returns the number of bytes written to the output buffer.
  956. Required - Returns the number of bytes required. (if the output buffer was insufficient)
  957. Return Value:
  958. ERROR_SUCCESS if successful
  959. Win32 error code otherwise
  960. --*/
  961. {
  962. CPCK_GET_CONTEXT Context;
  963. HDMKEY ResourceKey;
  964. HDMKEY CryptoSyncKey;
  965. DWORD Status;
  966. *BytesReturned = 0;
  967. *Required = 0;
  968. //
  969. // Open up the resource's key
  970. //
  971. ResourceKey = DmOpenKey(DmResourcesKey,
  972. OmObjectId(Resource),
  973. KEY_READ);
  974. CL_ASSERT(ResourceKey != NULL);
  975. //
  976. // Open up the CryptoSync key
  977. //
  978. CryptoSyncKey = DmOpenKey(ResourceKey,
  979. L"CryptoSync",
  980. KEY_READ | KEY_WRITE);
  981. DmCloseKey(ResourceKey);
  982. if (CryptoSyncKey == NULL) {
  983. //
  984. // No reg sync key, therefore there are no subtrees
  985. //
  986. return(ERROR_SUCCESS);
  987. }
  988. Context.cCheckpoints = 0;
  989. ZeroMemory(OutBuffer, OutBufferSize);
  990. Context.cbRequired = sizeof(WCHAR);
  991. if (OutBufferSize < sizeof(WCHAR) * 2)
  992. {
  993. Context.fNeedMoreData = TRUE;
  994. Context.cbAvailable = 0;
  995. *BytesReturned = 0;
  996. }
  997. else
  998. {
  999. Context.fNeedMoreData = FALSE;
  1000. Context.cbAvailable = OutBufferSize - sizeof(WCHAR);
  1001. Context.pbOutput = (BYTE*)(OutBuffer);
  1002. *BytesReturned = sizeof(WCHAR) * 2;
  1003. }
  1004. DmEnumValues(CryptoSyncKey,
  1005. CpckGetCheckpointsCallback,
  1006. &Context);
  1007. DmCloseKey(CryptoSyncKey);
  1008. if ((0 != Context.cCheckpoints) && Context.fNeedMoreData) {
  1009. Status = ERROR_MORE_DATA;
  1010. } else {
  1011. Status = ERROR_SUCCESS;
  1012. }
  1013. if ( 0 == Context.cCheckpoints ) {
  1014. *BytesReturned = 0;
  1015. *Required = 0;
  1016. } else {
  1017. if ( Context.fNeedMoreData ) {
  1018. *Required = Context.cbRequired;
  1019. } else {
  1020. *BytesReturned = (DWORD)(Context.pbOutput - OutBuffer);
  1021. }
  1022. }
  1023. return(Status);
  1024. } // CpckGetCryptoCheckpoints
  1025. BOOL
  1026. CpckGetCheckpointsCallback(
  1027. IN LPWSTR ValueName,
  1028. IN LPVOID ValueData,
  1029. IN DWORD ValueType,
  1030. IN DWORD ValueSize,
  1031. IN PCPCK_GET_CONTEXT Context
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. Value enumeration callback for retrieving all of a resource's
  1036. checkpoint subtrees.
  1037. Arguments:
  1038. ValueName - Supplies the name of the value (this is the checkpoint ID)
  1039. ValueData - Supplies the value data (this is the crypto info)
  1040. ValueType - Supplies the value type (must be REG_BINARY)
  1041. ValueSize - Supplies the size of ValueData
  1042. Context - Supplies the callback context
  1043. Return Value:
  1044. TRUE to continue enumeration
  1045. --*/
  1046. {
  1047. Context->cbRequired += ValueSize;
  1048. Context->cCheckpoints++;
  1049. if (Context->cbAvailable >= ValueSize) {
  1050. CopyMemory(Context->pbOutput, ValueData, ValueSize);
  1051. Context->pbOutput += ValueSize;
  1052. Context->cbAvailable -= ValueSize;
  1053. } else {
  1054. Context->fNeedMoreData = TRUE;
  1055. }
  1056. return(TRUE);
  1057. } // CpckGetCheckpointsCallback
  1058. DWORD
  1059. CpckGenSymKey(
  1060. IN HCRYPTPROV hProv,
  1061. IN BYTE *pbSalt,
  1062. IN BYTE *pbIV,
  1063. OUT HCRYPTKEY *phSymKey
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. Generate a session key based on the specified Salt and IV.
  1068. Arguments:
  1069. hProv - Handle to the crypto provider (key container)
  1070. pbSalt - Salt value
  1071. pbIV - IV value
  1072. phSymKey - Resulting symmetric key (CALG_RC2)
  1073. Return Value:
  1074. ERROR_SUCCESS if successful
  1075. Win32 error code otherwise
  1076. --*/
  1077. {
  1078. HCRYPTHASH hHash = 0;
  1079. DWORD cbPassword = 0;
  1080. DWORD Status;
  1081. if (!CryptCreateHash(hProv,
  1082. CALG_SHA1,
  1083. 0,
  1084. 0,
  1085. &hHash))
  1086. {
  1087. Status = GetLastError();
  1088. goto Ret;
  1089. }
  1090. if (!CryptHashData(hHash,
  1091. pbSalt,
  1092. SALT_SIZE,
  1093. 0))
  1094. {
  1095. Status = GetLastError();
  1096. goto Ret;
  1097. }
  1098. // derive the key from the hash
  1099. if (!CryptDeriveKey(hProv,
  1100. CALG_RC2,
  1101. hHash,
  1102. 0,
  1103. phSymKey))
  1104. {
  1105. Status = GetLastError();
  1106. goto Ret;
  1107. }
  1108. // set the IV on the key
  1109. if (!CryptSetKeyParam(*phSymKey,
  1110. KP_IV,
  1111. pbIV,
  1112. 0))
  1113. {
  1114. Status = GetLastError();
  1115. goto Ret;
  1116. }
  1117. Status = ERROR_SUCCESS;
  1118. Ret:
  1119. if (hHash)
  1120. CryptDestroyHash(hHash);
  1121. return (Status);
  1122. } // CpckGenSymKey
  1123. DWORD
  1124. CpckExportPrivateKey(
  1125. IN HCRYPTPROV hProv,
  1126. IN HCRYPTKEY hKey,
  1127. IN BYTE *pbIV,
  1128. IN BYTE *pbSalt,
  1129. OUT BYTE *pbExportedKey,
  1130. OUT DWORD *pcbExportedKey
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Exports the private key data.
  1135. Arguments:
  1136. hProv - Handle to the crypto provider (key container)
  1137. hKey - Handle to the key to export
  1138. pbIV - IV for the symmetric key
  1139. pbSalt - Salt to generate symmetric key
  1140. pbExportedKey - Supplies the buffer the key is to be exported into
  1141. pcbExportedKey - Supplies the length of the buffer, if pbExportedKey is
  1142. NULL then this will be the length of the key to export
  1143. Return Value:
  1144. ERROR_SUCCESS if successful
  1145. Win32 error code otherwise
  1146. --*/
  1147. {
  1148. HCRYPTKEY hSymKey = 0;
  1149. DWORD Status;
  1150. // create the symmetric key to encrypt the private key with
  1151. Status = CpckGenSymKey(hProv,
  1152. pbSalt,
  1153. pbIV,
  1154. &hSymKey);
  1155. if (0 != Status)
  1156. {
  1157. goto Ret;
  1158. }
  1159. // Export the key
  1160. if (!CryptExportKey(hKey,
  1161. hSymKey,
  1162. PRIVATEKEYBLOB,
  1163. 0,
  1164. pbExportedKey,
  1165. pcbExportedKey))
  1166. {
  1167. Status = GetLastError();
  1168. goto Ret;
  1169. }
  1170. Status = ERROR_SUCCESS;
  1171. Ret:
  1172. if (hSymKey)
  1173. CryptDestroyKey(hSymKey);
  1174. return (Status);
  1175. } // CpckExportPrivateKey
  1176. DWORD
  1177. CpckGetKeyContainerSecDescr(
  1178. IN HCRYPTPROV hProv,
  1179. OUT PSECURITY_DESCRIPTOR *ppSecDescr,
  1180. OUT DWORD *pcbSecDescr
  1181. )
  1182. /*++
  1183. Routine Description:
  1184. Gets the key container security descriptor so that when replicated
  1185. the same descriptor may be set on the replicated key.
  1186. Arguments:
  1187. hProv - Handle to the crypto provider (key container)
  1188. ppSecDescr - Pointer to buffer holding security descriptor
  1189. pcbSecDescr - Pointer to the length of the returned security descriptor
  1190. Return Value:
  1191. ERROR_SUCCESS if successful
  1192. Win32 error code otherwise
  1193. --*/
  1194. {
  1195. PTOKEN_PRIVILEGES pPrevPriv = NULL;
  1196. DWORD cbPrevPriv = 0;
  1197. BYTE rgbNewPriv[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
  1198. PTOKEN_PRIVILEGES pNewPriv = (PTOKEN_PRIVILEGES)rgbNewPriv;
  1199. SECURITY_DESCRIPTOR_CONTROL Control;
  1200. DWORD dwRevision;
  1201. HANDLE hToken = 0;
  1202. PSECURITY_DESCRIPTOR pNewSD = NULL;
  1203. DWORD dw;
  1204. DWORD dwFlags;
  1205. DWORD Status = ERROR_SUCCESS;
  1206. // check if there is a thread token
  1207. if (FALSE == OpenThreadToken(GetCurrentThread(),
  1208. MAXIMUM_ALLOWED,
  1209. TRUE,
  1210. &hToken))
  1211. {
  1212. // get the process token
  1213. if (FALSE == OpenProcessToken(GetCurrentProcess(),
  1214. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1215. &hToken))
  1216. {
  1217. Status = GetLastError();
  1218. goto Ret;
  1219. }
  1220. }
  1221. // set up the new priviledge state
  1222. memset(rgbNewPriv, 0, sizeof(rgbNewPriv));
  1223. pNewPriv->PrivilegeCount = 1;
  1224. if(!LookupPrivilegeValueW(NULL, SE_SECURITY_NAME,
  1225. &(pNewPriv->Privileges[0].Luid)))
  1226. {
  1227. goto Ret;
  1228. }
  1229. pNewPriv->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1230. // get the length of the previous state
  1231. AdjustTokenPrivileges(hToken,
  1232. FALSE,
  1233. (PTOKEN_PRIVILEGES)pNewPriv,
  1234. sizeof(dw),
  1235. (PTOKEN_PRIVILEGES)&dw,
  1236. &cbPrevPriv);
  1237. // alloc for the previous state
  1238. if (NULL == (pPrevPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_ZEROINIT,
  1239. cbPrevPriv)))
  1240. {
  1241. Status = ERROR_NOT_ENOUGH_MEMORY;
  1242. goto Ret;
  1243. }
  1244. // adjust the priviledge and get the previous state
  1245. if (!AdjustTokenPrivileges(hToken,
  1246. FALSE,
  1247. pNewPriv,
  1248. cbPrevPriv,
  1249. (PTOKEN_PRIVILEGES)pPrevPriv,
  1250. &cbPrevPriv))
  1251. {
  1252. Status = GetLastError();
  1253. goto Ret;
  1254. }
  1255. dwFlags = OWNER_SECURITY_INFORMATION |
  1256. GROUP_SECURITY_INFORMATION |
  1257. DACL_SECURITY_INFORMATION |
  1258. SACL_SECURITY_INFORMATION ;
  1259. // get the security descriptor
  1260. if (CryptGetProvParam(hProv,
  1261. PP_KEYSET_SEC_DESCR,
  1262. NULL,
  1263. pcbSecDescr,
  1264. dwFlags))
  1265. {
  1266. if (NULL != (*ppSecDescr =
  1267. (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_ZEROINIT,
  1268. *pcbSecDescr)))
  1269. {
  1270. if (!CryptGetProvParam(hProv,
  1271. PP_KEYSET_SEC_DESCR,
  1272. (BYTE*)(*ppSecDescr),
  1273. pcbSecDescr,
  1274. dwFlags))
  1275. {
  1276. Status = GetLastError();
  1277. }
  1278. }
  1279. else
  1280. {
  1281. Status = ERROR_NOT_ENOUGH_MEMORY;
  1282. }
  1283. }
  1284. else
  1285. {
  1286. Status = GetLastError();
  1287. }
  1288. // adjust the priviledge to the previous state
  1289. if (!AdjustTokenPrivileges(hToken,
  1290. FALSE,
  1291. pPrevPriv,
  1292. 0,
  1293. NULL,
  1294. NULL))
  1295. {
  1296. Status = GetLastError();
  1297. goto Ret;
  1298. }
  1299. if (ERROR_SUCCESS != Status)
  1300. {
  1301. goto Ret;
  1302. }
  1303. // ge the control on the security descriptor to check if self relative
  1304. if (!GetSecurityDescriptorControl(*ppSecDescr,
  1305. &Control,
  1306. &dwRevision))
  1307. {
  1308. Status = GetLastError();
  1309. goto Ret;
  1310. }
  1311. // if not self relative then make a self relative copy
  1312. if (!(SE_SELF_RELATIVE & Control))
  1313. {
  1314. if (NULL == (pNewSD =
  1315. (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_ZEROINIT,
  1316. *pcbSecDescr)))
  1317. {
  1318. Status = ERROR_NOT_ENOUGH_MEMORY;
  1319. goto Ret;
  1320. }
  1321. if (!MakeSelfRelativeSD(*ppSecDescr,
  1322. pNewSD,
  1323. pcbSecDescr))
  1324. {
  1325. Status = GetLastError();
  1326. goto Ret;
  1327. }
  1328. LocalFree(*ppSecDescr);
  1329. *ppSecDescr = (BYTE*)pNewSD;
  1330. pNewSD = NULL;
  1331. }
  1332. Status = ERROR_SUCCESS;
  1333. Ret:
  1334. if (pPrevPriv)
  1335. LocalFree(pPrevPriv);
  1336. if (pNewSD)
  1337. LocalFree(pNewSD);
  1338. if (hToken)
  1339. CloseHandle(hToken);
  1340. return Status;
  1341. } // CpckGetKeyContainerSecDescr
  1342. DWORD
  1343. CpckStoreKeyContainer(
  1344. IN HCRYPTPROV hProv,
  1345. IN CRYPTO_KEY_INFO *pCryptoKeyInfo,
  1346. IN LPWSTR TempFile
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. Writes the key container associated with the provider handle to a
  1351. the specified file.
  1352. Arguments:
  1353. hProv - Handle to the crypto provider (key container)
  1354. pCryptoKeyInfo - Crypto key information (password if given)
  1355. TempFile - Supplies the file which the key data is to be written to
  1356. Return Value:
  1357. ERROR_SUCCESS if successful
  1358. Win32 error code otherwise
  1359. --*/
  1360. {
  1361. CRYPTO_KEY_FILE_DATA KeyFileData;
  1362. HCRYPTKEY hSigKey = 0;
  1363. HCRYPTKEY hExchKey = 0;
  1364. BYTE *pb = NULL;
  1365. DWORD cb = 0;
  1366. DWORD dwBytesWritten;
  1367. HANDLE hFile = INVALID_HANDLE_VALUE;
  1368. DWORD dwPermissions = 0;
  1369. DWORD cbPermissions ;
  1370. PSECURITY_DESCRIPTOR pSecDescr = NULL;
  1371. DWORD cbSecDescr;
  1372. DWORD Status;
  1373. memset(&KeyFileData, 0, sizeof(KeyFileData));
  1374. // generate the necessary random data for salt and IVs.
  1375. // calls with the sig IV buffer but this will fill the
  1376. // exch IV and Salt as well since the buffer len is 32
  1377. if (!CryptGenRandom(hProv,
  1378. sizeof(struct _CRYPTO_KEY_FILE_INITIALIZATION_DATA),
  1379. KeyFileData.rgbSigIV))
  1380. {
  1381. Status = GetLastError();
  1382. goto Ret;
  1383. }
  1384. KeyFileData.dwVersion = CRYPTO_KEY_FILE_DATA_VERSION;
  1385. // calculate the length of key data
  1386. cb = sizeof(KeyFileData);
  1387. // get the self relative security descriptor
  1388. Status = CpckGetKeyContainerSecDescr(hProv,
  1389. &pSecDescr,
  1390. &cbSecDescr);
  1391. if (ERROR_SUCCESS != Status)
  1392. {
  1393. goto Ret;
  1394. }
  1395. cb += cbSecDescr;
  1396. // get sig key length if necessary
  1397. if (CryptGetUserKey(hProv, AT_SIGNATURE, &hSigKey))
  1398. {
  1399. // check if key is exportable
  1400. cbPermissions = sizeof(DWORD);
  1401. if (!CryptGetKeyParam(hSigKey,
  1402. KP_PERMISSIONS,
  1403. (BYTE*)&dwPermissions,
  1404. &cbPermissions,
  1405. 0))
  1406. {
  1407. Status = GetLastError();
  1408. goto Ret;
  1409. }
  1410. if (!(dwPermissions & CRYPT_EXPORT))
  1411. {
  1412. Status = (DWORD)NTE_BAD_KEY;
  1413. goto Ret;
  1414. }
  1415. // get the sig key length
  1416. Status = CpckExportPrivateKey(hProv,
  1417. hSigKey,
  1418. KeyFileData.rgbSigIV,
  1419. KeyFileData.rgbSalt,
  1420. NULL,
  1421. &(KeyFileData.cbSig));
  1422. if (0 != Status)
  1423. {
  1424. goto Ret;
  1425. }
  1426. cb += KeyFileData.cbSig;
  1427. }
  1428. // get key exchange key length if necessary
  1429. if (CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hExchKey))
  1430. {
  1431. // check if key is exportable
  1432. dwPermissions = 0;
  1433. cbPermissions = sizeof(DWORD);
  1434. if (!CryptGetKeyParam(hExchKey,
  1435. KP_PERMISSIONS,
  1436. (BYTE*)&dwPermissions,
  1437. &cbPermissions,
  1438. 0))
  1439. {
  1440. Status = GetLastError();
  1441. goto Ret;
  1442. }
  1443. if (!(dwPermissions & CRYPT_EXPORT))
  1444. {
  1445. Status = (DWORD)NTE_BAD_KEY;
  1446. goto Ret;
  1447. }
  1448. // get the exchange key length
  1449. Status = CpckExportPrivateKey(hProv,
  1450. hExchKey,
  1451. KeyFileData.rgbExchIV,
  1452. KeyFileData.rgbSalt,
  1453. NULL,
  1454. &(KeyFileData.cbExch));
  1455. if (0 != Status)
  1456. {
  1457. goto Ret;
  1458. }
  1459. cb += KeyFileData.cbExch;
  1460. }
  1461. // allocate space for the keys
  1462. if (NULL == (pb = LocalAlloc(LMEM_ZEROINIT, cb)))
  1463. {
  1464. Status = ERROR_NOT_ENOUGH_MEMORY;
  1465. goto Ret;
  1466. }
  1467. // copy the key file data into the pb
  1468. cb = sizeof(KeyFileData);
  1469. // copy the signature key
  1470. if (0 != hSigKey)
  1471. {
  1472. Status = CpckExportPrivateKey(hProv,
  1473. hSigKey,
  1474. KeyFileData.rgbSigIV,
  1475. KeyFileData.rgbSalt,
  1476. pb + cb,
  1477. &(KeyFileData.cbSig));
  1478. if (0 != Status)
  1479. {
  1480. goto Ret;
  1481. }
  1482. cb += KeyFileData.cbSig;
  1483. }
  1484. // copy the key exchange key
  1485. if (0 != hExchKey)
  1486. {
  1487. Status = CpckExportPrivateKey(hProv,
  1488. hExchKey,
  1489. KeyFileData.rgbExchIV,
  1490. KeyFileData.rgbSalt,
  1491. pb + cb,
  1492. &(KeyFileData.cbExch));
  1493. if (0 != Status)
  1494. {
  1495. goto Ret;
  1496. }
  1497. cb += KeyFileData.cbExch;
  1498. }
  1499. // copy the security descriptor
  1500. CopyMemory(pb + cb, (BYTE*)pSecDescr, cbSecDescr);
  1501. cb += cbSecDescr;
  1502. // copy the lengths
  1503. CopyMemory(pb, &KeyFileData, sizeof(KeyFileData));
  1504. // write the buffer to the file
  1505. hFile = CreateFileW(TempFile,
  1506. GENERIC_WRITE,
  1507. 0,
  1508. NULL,
  1509. OPEN_ALWAYS,
  1510. FILE_FLAG_SEQUENTIAL_SCAN,
  1511. NULL);
  1512. if (INVALID_HANDLE_VALUE == hFile)
  1513. {
  1514. Status = GetLastError();
  1515. goto Ret;
  1516. }
  1517. if (!WriteFile(hFile, pb, cb, &dwBytesWritten, NULL))
  1518. {
  1519. Status = GetLastError();
  1520. goto Ret;
  1521. }
  1522. Status = ERROR_SUCCESS;
  1523. Ret:
  1524. if (pSecDescr)
  1525. LocalFree(pSecDescr);
  1526. if(INVALID_HANDLE_VALUE != hFile)
  1527. CloseHandle(hFile);
  1528. if (pb)
  1529. LocalFree(pb);
  1530. if (hSigKey)
  1531. CryptDestroyKey(hSigKey);
  1532. if (hExchKey)
  1533. CryptDestroyKey(hExchKey);
  1534. return (Status);
  1535. } // CpckStoreKeyContainer
  1536. DWORD
  1537. CpckSaveCheckpointToFile(
  1538. IN HCRYPTPROV hProv,
  1539. IN CRYPTO_KEY_INFO *pCryptoKeyInfo,
  1540. IN LPWSTR TempFile)
  1541. /*++
  1542. Routine Description:
  1543. have DM create a temp file and call the routine that exports the keys and
  1544. writes the checkpoint file.
  1545. Arguments:
  1546. hProv - Handle to the crypto provider (key container)
  1547. pCryptoKeyInfo - Crypto key information (password if given)
  1548. TempFile - Supplies the file which the key data is to be written to
  1549. Return Value:
  1550. ERROR_SUCCESS if successful
  1551. Win32 error code otherwise
  1552. --*/
  1553. {
  1554. DWORD Status;
  1555. Status = DmCreateTempFileName(TempFile);
  1556. if (Status != ERROR_SUCCESS) {
  1557. CL_UNEXPECTED_ERROR( Status );
  1558. TempFile[0] = L'\0';
  1559. return(Status);
  1560. }
  1561. // put the key information into the file
  1562. Status = CpckStoreKeyContainer(hProv, pCryptoKeyInfo, TempFile);
  1563. if (Status != ERROR_SUCCESS)
  1564. {
  1565. ClRtlLogPrint(LOG_UNUSUAL,
  1566. "[CPCK] CpckSaveCheckpointToFile failed to get store container %1!ws! %2!ws! to file %3!ws! error %4!d!\n",
  1567. pCryptoKeyInfo->pwszContainer,
  1568. pCryptoKeyInfo->pwszProvName,
  1569. TempFile,
  1570. Status);
  1571. CL_LOGFAILURE(Status);
  1572. DeleteFile(TempFile);
  1573. TempFile[0] = L'\0';
  1574. }
  1575. return(Status);
  1576. } // CpckSaveCheckpointToFile
  1577. DWORD
  1578. CpckCheckpoint(
  1579. IN PFM_RESOURCE Resource,
  1580. IN HCRYPTPROV hProv,
  1581. IN DWORD dwId,
  1582. IN CRYPTO_KEY_INFO *pCryptoKeyInfo
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. Takes a checkpoint of the specified crypto key.
  1587. Arguments:
  1588. Resource - Supplies the resource this is a checkpoint for.
  1589. hKey - Supplies the crypto info to checkpoint
  1590. dwId - Supplies the checkpoint ID.
  1591. KeyName - Supplies the name of the registry key.
  1592. Return Value:
  1593. ERROR_SUCCESS if successful
  1594. Win32 error code otherwise
  1595. --*/
  1596. {
  1597. DWORD Status;
  1598. WCHAR TempFile[MAX_PATH];
  1599. Status = CpckSaveCheckpointToFile(hProv, pCryptoKeyInfo, TempFile);
  1600. if (Status == ERROR_SUCCESS)
  1601. {
  1602. //
  1603. // Got a file with the right bits in it. Checkpoint the
  1604. // file.
  1605. //
  1606. Status = CpSaveDataFile(Resource,
  1607. dwId,
  1608. TempFile,
  1609. TRUE);
  1610. if (Status != ERROR_SUCCESS) {
  1611. ClRtlLogPrint(LOG_CRITICAL,
  1612. "[CPCK] CpckCheckpoint - CpSaveData failed %1!d!\n",
  1613. Status);
  1614. }
  1615. }
  1616. //if the file was created, delete it
  1617. if (TempFile[0] != L'\0')
  1618. DeleteFile(TempFile);
  1619. return(Status);
  1620. } // CpckCheckpoint
  1621. DWORD
  1622. CpckSetKeyContainerSecDescr(
  1623. IN HCRYPTPROV hProv,
  1624. IN BYTE *pbSecDescr,
  1625. IN DWORD cbSecDescr
  1626. )
  1627. /*++
  1628. Routine Description:
  1629. Sets the key container security descriptor.
  1630. Arguments:
  1631. hProv - Handle to the crypto provider (key container)
  1632. pbSecDescr - Buffer holding security descriptor
  1633. cbSecDescr - Length of the security descriptor
  1634. Return Value:
  1635. ERROR_SUCCESS if successful
  1636. Win32 error code otherwise
  1637. --*/
  1638. {
  1639. PTOKEN_PRIVILEGES pPrevPriv = NULL;
  1640. DWORD cbPrevPriv = 0;
  1641. BYTE rgbNewPriv[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
  1642. PTOKEN_PRIVILEGES pNewPriv = (PTOKEN_PRIVILEGES)rgbNewPriv;
  1643. HANDLE hToken = 0;
  1644. DWORD dw;
  1645. DWORD dwFlags;
  1646. DWORD Status = ERROR_SUCCESS;
  1647. // check if there is a thread token
  1648. if (FALSE == OpenThreadToken(GetCurrentThread(),
  1649. MAXIMUM_ALLOWED,
  1650. TRUE,
  1651. &hToken))
  1652. {
  1653. // get the process token
  1654. if (FALSE == OpenProcessToken(GetCurrentProcess(),
  1655. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1656. &hToken))
  1657. {
  1658. Status = GetLastError();
  1659. goto Ret;
  1660. }
  1661. }
  1662. // set up the new priviledge state
  1663. memset(rgbNewPriv, 0, sizeof(rgbNewPriv));
  1664. pNewPriv->PrivilegeCount = 1;
  1665. if(!LookupPrivilegeValueW(NULL, SE_SECURITY_NAME,
  1666. &(pNewPriv->Privileges[0].Luid)))
  1667. {
  1668. goto Ret;
  1669. }
  1670. pNewPriv->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1671. // get the length of the previous state
  1672. AdjustTokenPrivileges(hToken,
  1673. FALSE,
  1674. (PTOKEN_PRIVILEGES)pNewPriv,
  1675. sizeof(dw),
  1676. (PTOKEN_PRIVILEGES)&dw,
  1677. &cbPrevPriv);
  1678. // alloc for the previous state
  1679. if (NULL == (pPrevPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_ZEROINIT,
  1680. cbPrevPriv)))
  1681. {
  1682. Status = ERROR_NOT_ENOUGH_MEMORY;
  1683. goto Ret;
  1684. }
  1685. // adjust the priviledge and get the previous state
  1686. AdjustTokenPrivileges(hToken,
  1687. FALSE,
  1688. pNewPriv,
  1689. cbPrevPriv,
  1690. (PTOKEN_PRIVILEGES)pPrevPriv,
  1691. &cbPrevPriv);
  1692. dwFlags = OWNER_SECURITY_INFORMATION |
  1693. GROUP_SECURITY_INFORMATION |
  1694. DACL_SECURITY_INFORMATION |
  1695. SACL_SECURITY_INFORMATION ;
  1696. // get the security descriptor
  1697. if (!CryptSetProvParam(hProv,
  1698. PP_KEYSET_SEC_DESCR,
  1699. pbSecDescr,
  1700. dwFlags))
  1701. {
  1702. Status = GetLastError();
  1703. }
  1704. // adjust the priviledge to the previous state
  1705. if (!AdjustTokenPrivileges(hToken,
  1706. FALSE,
  1707. pPrevPriv,
  1708. 0,
  1709. NULL,
  1710. NULL))
  1711. {
  1712. Status = GetLastError();
  1713. goto Ret;
  1714. }
  1715. if (ERROR_SUCCESS != Status)
  1716. {
  1717. goto Ret;
  1718. }
  1719. Status = ERROR_SUCCESS;
  1720. Ret:
  1721. if (pPrevPriv)
  1722. LocalFree(pPrevPriv);
  1723. if (hToken)
  1724. CloseHandle(hToken);
  1725. return Status;
  1726. } // CpckSetKeyContainerSecDescr
  1727. DWORD
  1728. CpckImportPrivateKey(
  1729. IN HCRYPTPROV hProv,
  1730. IN BYTE *pbIV,
  1731. IN BYTE *pbSalt,
  1732. IN BYTE *pbKey,
  1733. IN DWORD cbKey
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. Exports the private key data.
  1738. Arguments:
  1739. hProv - Handle to the crypto provider (key container)
  1740. hKey - Handle to the key to export
  1741. pbIV - IV for the symmetric key
  1742. pbSalt - Salt to generate symmetric key
  1743. pbKey - Supplies the buffer the key is in
  1744. cbKey - Supplies the length of the key buffer
  1745. Return Value:
  1746. ERROR_SUCCESS if successful
  1747. Win32 error code otherwise
  1748. --*/
  1749. {
  1750. BOOLEAN WasEnabled;
  1751. HCRYPTKEY hSymKey = 0;
  1752. HCRYPTKEY hKey = 0;
  1753. DWORD Status = ERROR_SUCCESS;
  1754. // create the symmetric key to encrypt the private key with
  1755. Status = CpckGenSymKey(hProv,
  1756. pbSalt,
  1757. pbIV,
  1758. &hSymKey);
  1759. if (0 != Status)
  1760. {
  1761. goto Ret;
  1762. }
  1763. // Import the key
  1764. if (!CryptImportKey(hProv,
  1765. pbKey,
  1766. cbKey,
  1767. hSymKey,
  1768. CRYPT_EXPORTABLE,
  1769. &hKey))
  1770. {
  1771. // if failed then try with BACKUP/RESTORE
  1772. ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  1773. &WasEnabled);
  1774. if (!CryptImportKey(hProv,
  1775. pbKey,
  1776. cbKey,
  1777. hSymKey,
  1778. CRYPT_EXPORTABLE,
  1779. &hKey))
  1780. {
  1781. Status = GetLastError();
  1782. }
  1783. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  1784. WasEnabled);
  1785. }
  1786. Ret:
  1787. if (hSymKey)
  1788. CryptDestroyKey(hSymKey);
  1789. if (hKey)
  1790. CryptDestroyKey(hKey);
  1791. return (Status);
  1792. } // CpckImportPrivateKey
  1793. DWORD
  1794. CpckInstallKeyContainer(
  1795. IN HCRYPTPROV hProv,
  1796. IN LPWSTR FileName
  1797. )
  1798. /*++
  1799. Routine Description:
  1800. Installs new crypto key information from a specified file.
  1801. Arguments:
  1802. hProv - Supplies the provider handle where FileName will be installed to.
  1803. FileName - The name of the file from which to read the crypto key info
  1804. to install.
  1805. Return Value:
  1806. ERROR_SUCCESS if the installation completed successfully
  1807. Win32 error code otherwise.
  1808. --*/
  1809. {
  1810. HANDLE hMap = NULL;
  1811. BYTE *pbFile = NULL;
  1812. HANDLE hFile = INVALID_HANDLE_VALUE;
  1813. DWORD cbFile = 0;
  1814. DWORD *pdwVersion;
  1815. CRYPTO_KEY_FILE_DATA *pKeyFileData;
  1816. DWORD Status;
  1817. // read the key data from the file
  1818. hFile = CreateFileW(FileName,
  1819. GENERIC_READ,
  1820. FILE_SHARE_READ,
  1821. NULL,
  1822. OPEN_EXISTING,
  1823. FILE_FLAG_SEQUENTIAL_SCAN,
  1824. NULL);
  1825. if (INVALID_HANDLE_VALUE == hFile)
  1826. {
  1827. Status = GetLastError();
  1828. goto Ret;
  1829. }
  1830. if (0xFFFFFFFF == (cbFile = GetFileSize(hFile, NULL)))
  1831. {
  1832. Status = GetLastError();
  1833. goto Ret;
  1834. }
  1835. if (sizeof(CRYPTO_KEY_FILE_DATA) > cbFile)
  1836. {
  1837. Status = ERROR_FILE_INVALID;
  1838. goto Ret;
  1839. }
  1840. if (NULL == (hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY,
  1841. 0, 0, NULL)))
  1842. {
  1843. Status = GetLastError();
  1844. goto Ret;
  1845. }
  1846. if (NULL == (pbFile = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ,
  1847. 0, 0, 0 )))
  1848. {
  1849. Status = GetLastError();
  1850. goto Ret;
  1851. }
  1852. // get the length information out of the file
  1853. pKeyFileData = (CRYPTO_KEY_FILE_DATA*)pbFile;
  1854. if (CRYPTO_KEY_FILE_DATA_VERSION != pKeyFileData->dwVersion)
  1855. {
  1856. Status = ERROR_FILE_INVALID;
  1857. goto Ret;
  1858. }
  1859. if ((sizeof(CRYPTO_KEY_FILE_DATA) + pKeyFileData->cbSig +
  1860. pKeyFileData->cbExch) > cbFile)
  1861. {
  1862. Status = ERROR_FILE_INVALID;
  1863. goto Ret;
  1864. }
  1865. if (pKeyFileData->cbSig)
  1866. {
  1867. // import the sig key if there is one
  1868. Status = CpckImportPrivateKey(hProv,
  1869. pKeyFileData->rgbSigIV,
  1870. pKeyFileData->rgbSalt,
  1871. pbFile + sizeof(CRYPTO_KEY_FILE_DATA),
  1872. pKeyFileData->cbSig);
  1873. if (0 != Status)
  1874. {
  1875. goto Ret;
  1876. }
  1877. }
  1878. if (pKeyFileData->cbExch)
  1879. {
  1880. // import the exch key if there is one
  1881. Status = CpckImportPrivateKey(hProv,
  1882. pKeyFileData->rgbExchIV,
  1883. pKeyFileData->rgbSalt,
  1884. pbFile + sizeof(CRYPTO_KEY_FILE_DATA) +
  1885. pKeyFileData->cbSig,
  1886. pKeyFileData->cbExch);
  1887. if (0 != Status)
  1888. {
  1889. goto Ret;
  1890. }
  1891. }
  1892. Status = CpckSetKeyContainerSecDescr(hProv,
  1893. pbFile + sizeof(CRYPTO_KEY_FILE_DATA) +
  1894. pKeyFileData->cbSig + pKeyFileData->cbExch,
  1895. pKeyFileData->cbSecDescr);
  1896. if (ERROR_SUCCESS != Status)
  1897. {
  1898. goto Ret;
  1899. }
  1900. Status = ERROR_SUCCESS;
  1901. Ret:
  1902. if(pbFile)
  1903. UnmapViewOfFile(pbFile);
  1904. if(hMap)
  1905. CloseHandle(hMap);
  1906. if(INVALID_HANDLE_VALUE != hFile)
  1907. CloseHandle(hFile);
  1908. return(Status);
  1909. } // CpckInstallKeyContainer
  1910. DWORD
  1911. CpckDeleteFile(
  1912. IN PFM_RESOURCE Resource,
  1913. IN DWORD dwCheckpointId,
  1914. IN OPTIONAL LPCWSTR lpszQuorumPath
  1915. )
  1916. /*++
  1917. Routine Description:
  1918. Gets the file corresponding to the checkpoint id relative
  1919. to the supplied path and deletes it.
  1920. Arguments:
  1921. PFM_RESOURCE - Supplies the pointer to the resource.
  1922. dwCheckpointId - The checkpoint id to be deleted. If 0, all
  1923. checkpoints are deleted.
  1924. lpszQuorumPath - If specified, the checkpoint file relative
  1925. to this path is deleted.
  1926. Return Value:
  1927. ERROR_SUCCESS if the completed successfully
  1928. Win32 error code otherwise.
  1929. --*/
  1930. {
  1931. DWORD Status;
  1932. LPWSTR pszFileName=NULL;
  1933. LPWSTR pszDirectoryName=NULL;
  1934. Status = CppGetCheckpointFile(Resource, dwCheckpointId,
  1935. &pszDirectoryName, &pszFileName, lpszQuorumPath, TRUE);
  1936. if (Status != ERROR_SUCCESS) {
  1937. ClRtlLogPrint(LOG_CRITICAL,
  1938. "[CPCK] CpckDeleteFile- couldnt get checkpoint file name, error %1!d!\n",
  1939. Status);
  1940. goto FnExit;
  1941. }
  1942. if (!DeleteFileW(pszFileName))
  1943. {
  1944. Status = GetLastError();
  1945. ClRtlLogPrint(LOG_CRITICAL,
  1946. "[CPCK] CpckDeleteFile - couldn't delete the file, error %1!d!\n",
  1947. Status);
  1948. goto FnExit;
  1949. }
  1950. //
  1951. // Now try and delete the directory.
  1952. //
  1953. if (!RemoveDirectoryW(pszDirectoryName))
  1954. {
  1955. //if there is a failure, we still return success
  1956. //because it may not be possible to delete a directory
  1957. //when it is not empty
  1958. ClRtlLogPrint(LOG_UNUSUAL,
  1959. "[CPCK] CpckDeleteFile- unable to remove directory %1!ws!, error %2!d!\n",
  1960. pszDirectoryName,
  1961. GetLastError());
  1962. }
  1963. FnExit:
  1964. if (pszFileName)
  1965. LocalFree(pszFileName);
  1966. if (pszDirectoryName)
  1967. LocalFree(pszDirectoryName);
  1968. return(Status);
  1969. } // CpckDeleteFile
  1970. BOOL
  1971. CpckRemoveCheckpointFileCallback(
  1972. IN LPWSTR ValueName,
  1973. IN LPVOID ValueData,
  1974. IN DWORD ValueType,
  1975. IN DWORD ValueSize,
  1976. IN PCP_CALLBACK_CONTEXT Context
  1977. )
  1978. /*++
  1979. Routine Description:
  1980. Registry value enumeration callback used when the quorum resource
  1981. is changing. Deletes the specified checkpoint file from the old
  1982. quorum directory.
  1983. Arguments:
  1984. ValueName - Supplies the name of the value (this is the checkpoint ID)
  1985. ValueData - Supplies the value data (this is the crypto info)
  1986. ValueType - Supplies the value type (must be REG_BINARY)
  1987. ValueSize - Supplies the size of ValueData
  1988. Context - Supplies the quorum change context (old path and resource)
  1989. Return Value:
  1990. TRUE to continue enumeration
  1991. --*/
  1992. {
  1993. DWORD Status;
  1994. DWORD Id;
  1995. Id = wcstol(ValueName, NULL, 16);
  1996. if (Id == 0) {
  1997. ClRtlLogPrint(LOG_UNUSUAL,
  1998. "[CPCK] CpckRemoveCheckpointFileCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  1999. ValueName,
  2000. OmObjectName(Context->Resource));
  2001. return(TRUE);
  2002. }
  2003. Status = CpckDeleteFile(Context->Resource, Id, Context->lpszPathName);
  2004. return(TRUE);
  2005. } // CpckRemoveCheckpointFileCallback
  2006. DWORD
  2007. CpckDeleteCheckpointFile(
  2008. IN PFM_RESOURCE Resource,
  2009. IN DWORD dwCheckpointId,
  2010. IN OPTIONAL LPCWSTR lpszQuorumPath
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. Deletes the checkpoint file corresponding the resource.
  2015. This node must be the owner of the quorum resource
  2016. Arguments:
  2017. PFM_RESOURCE - Supplies the pointer to the resource.
  2018. dwCheckpointId - The checkpoint id to be deleted. If 0, all
  2019. checkpoints are deleted.
  2020. lpszQuorumPath - If specified, the checkpoint file relative
  2021. to this path is deleted.
  2022. Return Value:
  2023. ERROR_SUCCESS if completed successfully
  2024. Win32 error code otherwise.
  2025. --*/
  2026. {
  2027. DWORD Status;
  2028. HDMKEY ResourceKey;
  2029. HDMKEY CryptoSyncKey;
  2030. CP_CALLBACK_CONTEXT Context;
  2031. if (dwCheckpointId)
  2032. {
  2033. Status = CpckDeleteFile(Resource, dwCheckpointId, lpszQuorumPath);
  2034. }
  2035. else
  2036. {
  2037. HDMKEY ResourceKey;
  2038. HDMKEY CryptoSyncKey;
  2039. CP_CALLBACK_CONTEXT Context;
  2040. //delete all checkpoints corresponding to this resource
  2041. //
  2042. // Open up the resource's key
  2043. //
  2044. ResourceKey = DmOpenKey(DmResourcesKey,
  2045. OmObjectId(Resource),
  2046. KEY_READ);
  2047. CL_ASSERT(ResourceKey != NULL);
  2048. //
  2049. // Open up the CryptoSync key
  2050. //
  2051. CryptoSyncKey = DmOpenKey(ResourceKey,
  2052. L"CryptoSync",
  2053. KEY_READ | KEY_WRITE);
  2054. DmCloseKey(ResourceKey);
  2055. if (CryptoSyncKey == NULL)
  2056. {
  2057. Status = GetLastError();
  2058. ClRtlLogPrint(LOG_NOISE,
  2059. "[CPCK] CpckDeleteCheckpointFile- couldn't open CryptoSync key error %1!d!\n",
  2060. Status);
  2061. goto FnExit;
  2062. }
  2063. Context.lpszPathName = lpszQuorumPath;
  2064. Context.Resource = Resource;
  2065. //
  2066. // Enumerate all the values and delete them one by one.
  2067. //
  2068. DmEnumValues(CryptoSyncKey,
  2069. CpckRemoveCheckpointFileCallback,
  2070. &Context);
  2071. }
  2072. FnExit:
  2073. return(Status);
  2074. } // CpckDeleteCheckpointFile
  2075. DWORD
  2076. CpckDeleteCryptoFile(
  2077. IN PFM_RESOURCE Resource,
  2078. IN DWORD dwCheckpointId,
  2079. IN OPTIONAL LPCWSTR lpszQuorumPath
  2080. )
  2081. /*++
  2082. Routine Description:
  2083. This function removes the checkpoint file correspoinding to the
  2084. checkpoint id for a given resource from the given directory.
  2085. Arguments:
  2086. Resource - Supplies the resource associated with this data.
  2087. dwCheckpointId - Supplies the unique checkpoint ID describing this data. The caller is responsible
  2088. for ensuring the uniqueness of the checkpoint ID.
  2089. lpszQuorumPath - Supplies the path of the cluster files on a quorum device.
  2090. Return Value:
  2091. ERROR_SUCCESS if successful
  2092. Win32 error code otherwise
  2093. --*/
  2094. {
  2095. CL_NODE_ID OwnerNode;
  2096. DWORD Status;
  2097. do {
  2098. OwnerNode = CppGetQuorumNodeId();
  2099. ClRtlLogPrint(LOG_NOISE,
  2100. "[CPCK] CpckDeleteCryptoFile: removing checkpoint file for id %1!d! at quorum node %2!d!\n",
  2101. dwCheckpointId,
  2102. OwnerNode);
  2103. if (OwnerNode == NmLocalNodeId)
  2104. {
  2105. Status = CpckDeleteCheckpointFile(Resource, dwCheckpointId, lpszQuorumPath);
  2106. }
  2107. else
  2108. {
  2109. Status = CpDeleteCryptoCheckpoint(Session[OwnerNode],
  2110. OmObjectId(Resource),
  2111. dwCheckpointId,
  2112. lpszQuorumPath);
  2113. //talking to an old server, cant perform this function
  2114. //ignore the error
  2115. if (Status == RPC_S_PROCNUM_OUT_OF_RANGE)
  2116. Status = ERROR_SUCCESS;
  2117. }
  2118. if (Status == ERROR_HOST_NODE_NOT_RESOURCE_OWNER) {
  2119. //
  2120. // This node no longer owns the quorum resource, retry.
  2121. //
  2122. ClRtlLogPrint(LOG_UNUSUAL,
  2123. "[CPCK] CpckDeleteCryptoFile: quorum owner %1!d! no longer owner\n",
  2124. OwnerNode);
  2125. }
  2126. } while ( Status == ERROR_HOST_NODE_NOT_RESOURCE_OWNER );
  2127. return(Status);
  2128. } // CpckDeleteCryptoFile