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.

911 lines
28 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. crypto.c
  5. Abstract:
  6. routines for encrypting/decrypting resource data blob. uses crypto API to
  7. generate the key used to encrypt/decrypt the CO password. Key is stored as
  8. a crypto checkpoint associated with the resource.
  9. Author:
  10. Charlie Wickham (charlwi) 14-Feb-2001
  11. Environment:
  12. User Mode
  13. Revision History:
  14. --*/
  15. #define UNICODE 1
  16. #define _UNICODE 1
  17. #include "clusres.h"
  18. #include "clusrtl.h"
  19. #include "netname.h"
  20. #include <wincrypt.h>
  21. #include <lm.h>
  22. //
  23. // defines
  24. //
  25. #define NN_GUID_STRING_BUFFER_LENGTH 37 // includes the terminating NULL
  26. //
  27. // header for encrypted data.
  28. //
  29. typedef struct _NETNAME_ENCRYPTED_DATA {
  30. DWORD Version;
  31. BYTE Data[0];
  32. } NETNAME_ENCRYPTED_DATA, *PNETNAME_ENCRYPTED_DATA;
  33. #define NETNAME_ENCRYPTED_DATA_VERSION 1
  34. //
  35. // Container name is the resource's GUID followed by this decoration
  36. //
  37. WCHAR KeyDecoration[] = L"-Netname Resource Data";
  38. DWORD
  39. BuildKeyName(
  40. IN HRESOURCE ResourceHandle,
  41. IN LPWSTR KeyName,
  42. IN DWORD KeyNameChars
  43. )
  44. /*++
  45. Routine Description:
  46. build the key name (resource GUID followed by decoration)
  47. Arguments:
  48. ResourceHandle - handle to the cluster resource (not the one given to us
  49. by resmon)
  50. KeyName - buffer to receive the constructed name
  51. KeyNameChars - size, in characteres, of KeyName
  52. Return Value:
  53. success, otherwise Win32 error
  54. --*/
  55. {
  56. DWORD status;
  57. DWORD bytesReturned;
  58. DWORD charsReturned;
  59. //
  60. // sanity check
  61. //
  62. if ( KeyNameChars < ( NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ))) {
  63. return ERROR_INSUFFICIENT_BUFFER;
  64. }
  65. //
  66. // get our GUID (ID) to uniquely identify this resource throughout renames
  67. //
  68. status = ClusterResourceControl(ResourceHandle,
  69. NULL,
  70. CLUSCTL_RESOURCE_GET_ID,
  71. NULL,
  72. 0,
  73. KeyName,
  74. KeyNameChars * sizeof( WCHAR ),
  75. &bytesReturned);
  76. charsReturned = bytesReturned / sizeof( WCHAR );
  77. if ( status == ERROR_SUCCESS ) {
  78. if (( charsReturned + COUNT_OF( KeyDecoration )) <= KeyNameChars ) {
  79. wcscat( KeyName, KeyDecoration );
  80. } else {
  81. status = ERROR_INSUFFICIENT_BUFFER;
  82. }
  83. }
  84. return status;
  85. } // BuildKeyName
  86. DWORD
  87. FindNNCryptoContainer(
  88. IN PNETNAME_RESOURCE Resource,
  89. OUT LPWSTR * ContainerName
  90. )
  91. /*++
  92. Routine Description:
  93. find our key name in the list of crypto checkpoints associated with this
  94. resource.
  95. Arguments:
  96. Resource - pointer to resource context info
  97. ContainerName - address of pointer that gets pointer to container name
  98. Return Value:
  99. success if it worked, otherwise Win32 error
  100. --*/
  101. {
  102. DWORD status;
  103. DWORD bytesReturned;
  104. LPWSTR checkpointInfo = NULL;
  105. LPWSTR chkpt;
  106. WCHAR keyName[ NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ) ];
  107. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  108. //
  109. // get our GUID (ID) to uniquely identify this resource throughout renames
  110. //
  111. status = ClusterResourceControl(Resource->ClusterResourceHandle,
  112. NULL,
  113. CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS,
  114. NULL,
  115. 0,
  116. NULL,
  117. 0,
  118. &bytesReturned);
  119. if ( status != ERROR_SUCCESS ) {
  120. (NetNameLogEvent)(resourceHandle,
  121. LOG_ERROR,
  122. L"Couldn't get size of crypto checkpoint info. status %1!u!.\n",
  123. status);
  124. return status;
  125. }
  126. if ( bytesReturned == 0 ) {
  127. return ERROR_FILE_NOT_FOUND;
  128. }
  129. checkpointInfo = LocalAlloc( LMEM_FIXED, bytesReturned );
  130. if ( checkpointInfo == NULL ) {
  131. status = ERROR_NOT_ENOUGH_MEMORY;
  132. (NetNameLogEvent)(resourceHandle,
  133. LOG_ERROR,
  134. L"Couldn't allocate memory for resource's crypto checkpoint info. status %1!u!.\n",
  135. status);
  136. return status;
  137. }
  138. status = ClusterResourceControl(Resource->ClusterResourceHandle,
  139. NULL,
  140. CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS,
  141. NULL,
  142. 0,
  143. checkpointInfo,
  144. bytesReturned,
  145. &bytesReturned);
  146. if ( status != ERROR_SUCCESS ) {
  147. (NetNameLogEvent)(resourceHandle,
  148. LOG_ERROR,
  149. L"Couldn't get crypto checkpoint info. status %1!u!.\n",
  150. status);
  151. goto cleanup;
  152. }
  153. //
  154. // build our key name and look for it by walking the list of checkpoints
  155. //
  156. status = BuildKeyName(Resource->ClusterResourceHandle, keyName, COUNT_OF( keyName ));
  157. if ( status != ERROR_SUCCESS ) {
  158. (NetNameLogEvent)(resourceHandle,
  159. LOG_ERROR,
  160. L"Couldn't build key name for crypto checkpoint. status %1!u!.\n",
  161. status);
  162. goto cleanup;
  163. }
  164. chkpt = wcsstr( checkpointInfo, keyName );
  165. if ( chkpt == NULL ) {
  166. (NetNameLogEvent)(resourceHandle,
  167. LOG_ERROR,
  168. L"Couldn't find key name (%1!ws!) in list of crypto checkpoints.\n",
  169. keyName);
  170. status = ERROR_INVALID_DATA;
  171. goto cleanup;
  172. }
  173. //
  174. // find the beginning of the string or the buffer, get the size, and move
  175. // our string to the beginning of the buffer (which is freed by the
  176. // caller)
  177. //
  178. while ( chkpt != checkpointInfo && *chkpt != UNICODE_NULL ) {
  179. --chkpt;
  180. }
  181. if ( chkpt != checkpointInfo ) {
  182. DWORD stringBytes;
  183. ++chkpt;
  184. stringBytes = (wcslen( chkpt ) + 1 ) * sizeof( WCHAR );
  185. memmove( checkpointInfo, chkpt, stringBytes );
  186. }
  187. *ContainerName = checkpointInfo;
  188. cleanup:
  189. if ( status != ERROR_SUCCESS && checkpointInfo != NULL ) {
  190. LocalFree( checkpointInfo );
  191. *ContainerName = NULL;
  192. }
  193. return status;
  194. } // FindNNCryptoContainer
  195. //
  196. // exported routines
  197. //
  198. DWORD
  199. EncryptNNResourceData(
  200. PNETNAME_RESOURCE Resource,
  201. LPWSTR MachinePwd,
  202. PBYTE * EncryptedInfo,
  203. PDWORD EncryptedInfoLength
  204. )
  205. /*++
  206. Routine Description:
  207. encrypt the password, set a pointer to the encrypted data and store it in
  208. the registry.
  209. Arguments:
  210. ResourceHandle - for logging to the cluster log
  211. MachinePwd - pointer to unicode string password
  212. EncryptedInfo - address of a pointer that receives a pointer to the encrypted blob
  213. EncryptedInfoLength - pointer to a DWORD that receives the length of the blob
  214. Key - handle to netname parameters key where the data is stored
  215. Return Value:
  216. ERROR_SUCCESS, otherwise Win32 error
  217. --*/
  218. {
  219. DWORD status;
  220. DWORD encInfoLength;
  221. DWORD encDataLength = 0;
  222. BOOL success;
  223. DWORD pwdLength = ( wcslen( MachinePwd ) + 1 ) * sizeof( WCHAR );
  224. DWORD provNameLength = 0;
  225. PCHAR provName = NULL;
  226. DWORD provTypeLength;
  227. WCHAR typeBuffer[ 256 ];
  228. DWORD containerNameChars;
  229. PWCHAR containerName = NULL;
  230. WCHAR keyName[ NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ) ];
  231. HCRYPTPROV cryptoProvider = 0;
  232. HCRYPTKEY encryptKey = 0;
  233. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  234. NETNAME_ENCRYPTED_DATA keyGenBuffer; // temp header buffer to generate key
  235. PNETNAME_ENCRYPTED_DATA encryptedInfo = NULL; // final data area
  236. //
  237. // there shouldn't be a checkpoint on the resource but just in case, let's
  238. // cleanup what might be there.
  239. //
  240. RemoveNNCryptoCheckpoint( Resource );
  241. //
  242. // get our GUID (ID) to uniquely identify this resource throughout renames
  243. //
  244. status = BuildKeyName( Resource->ClusterResourceHandle, keyName, COUNT_OF( keyName ));
  245. if ( status != ERROR_SUCCESS ) {
  246. (NetNameLogEvent)(resourceHandle,
  247. LOG_ERROR,
  248. L"Couldn't get resource ID to build crypto container name. status %1!u!.\n",
  249. status);
  250. return status;
  251. }
  252. //
  253. // get a handle to the full RSA provider
  254. //
  255. if ( !CryptAcquireContext(&cryptoProvider,
  256. keyName,
  257. MS_ENHANCED_PROV,
  258. PROV_RSA_FULL,
  259. CRYPT_MACHINE_KEYSET | CRYPT_SILENT))
  260. {
  261. status = GetLastError();
  262. if ( status == NTE_BAD_KEYSET ) {
  263. success = CryptAcquireContext(&cryptoProvider,
  264. keyName,
  265. MS_ENHANCED_PROV,
  266. PROV_RSA_FULL,
  267. CRYPT_MACHINE_KEYSET |
  268. CRYPT_SILENT |
  269. CRYPT_NEWKEYSET);
  270. status = success ? ERROR_SUCCESS : GetLastError();
  271. }
  272. if ( status != ERROR_SUCCESS ) {
  273. (NetNameLogEvent)(resourceHandle,
  274. LOG_ERROR,
  275. L"Can't acquire crypto context for encrypt. status %1!u!.\n",
  276. status);
  277. return status;
  278. }
  279. }
  280. //
  281. // generate a 1024 bit, exportable exchange key pair
  282. //
  283. if ( !CryptGenKey(cryptoProvider,
  284. AT_KEYEXCHANGE,
  285. ( 1024 << 16 ) | CRYPT_EXPORTABLE,
  286. &encryptKey)) {
  287. status = GetLastError();
  288. if ( status != ERROR_SUCCESS ) {
  289. (NetNameLogEvent)(resourceHandle,
  290. LOG_ERROR,
  291. L"Can't generate exchange key for encryption. status %1!u!.\n",
  292. status);
  293. goto cleanup;
  294. }
  295. }
  296. //
  297. // find the size we need for the buffer to receive the encrypted data
  298. //
  299. encDataLength = pwdLength;
  300. if ( CryptEncrypt(encryptKey,
  301. 0,
  302. TRUE,
  303. 0,
  304. NULL,
  305. &encDataLength,
  306. 0))
  307. {
  308. //
  309. // alloc a buffer large enough to hold the data and copy the password into it.
  310. //
  311. ASSERT( encDataLength >= pwdLength );
  312. encInfoLength = sizeof( NETNAME_ENCRYPTED_DATA ) + encDataLength;
  313. encryptedInfo = LocalAlloc( LMEM_FIXED, encInfoLength );
  314. if ( encryptedInfo != NULL ) {
  315. wcscpy( (PWCHAR)encryptedInfo->Data, MachinePwd );
  316. if ( CryptEncrypt(encryptKey,
  317. 0,
  318. TRUE,
  319. 0,
  320. encryptedInfo->Data,
  321. &pwdLength,
  322. encDataLength))
  323. {
  324. encryptedInfo->Version = NETNAME_ENCRYPTED_DATA_VERSION;
  325. status = ResUtilSetBinaryValue(Resource->ParametersKey,
  326. PARAM_NAME__RESOURCE_DATA,
  327. (const LPBYTE)encryptedInfo,
  328. encInfoLength,
  329. NULL,
  330. NULL);
  331. if ( status != ERROR_SUCCESS ) {
  332. (NetNameLogEvent)(resourceHandle,
  333. LOG_ERROR,
  334. L"Can't write %1!u! bytes of data to registry. status %2!u!.\n",
  335. encInfoLength,
  336. status);
  337. goto cleanup;
  338. }
  339. }
  340. else {
  341. status = GetLastError();
  342. (NetNameLogEvent)(resourceHandle,
  343. LOG_ERROR,
  344. L"Can't encrypt %1!u! bytes. status %2!u!.\n",
  345. pwdLength,
  346. status);
  347. goto cleanup;
  348. }
  349. }
  350. else {
  351. status = ERROR_NOT_ENOUGH_MEMORY;
  352. (NetNameLogEvent)(resourceHandle,
  353. LOG_ERROR,
  354. L"Can't allocate %1!u! bytes for encrypted data. status %2!u!.\n",
  355. encInfoLength,
  356. status);
  357. goto cleanup;
  358. }
  359. }
  360. else {
  361. status = GetLastError();
  362. (NetNameLogEvent)(resourceHandle,
  363. LOG_ERROR,
  364. L"Can't determine size of encrypted data buffer for %1!u! bytes of data. status %2!u!.\n",
  365. pwdLength,
  366. status);
  367. goto cleanup;
  368. }
  369. *EncryptedInfoLength = encInfoLength;
  370. *EncryptedInfo = (PBYTE)encryptedInfo;
  371. //
  372. // it all worked; build the key container string and add a crypto
  373. // checkpoint to the resource. Note that provider name is always returned
  374. // as an ANSI string.
  375. //
  376. typeBuffer[ COUNT_OF( typeBuffer ) - 1 ] = UNICODE_NULL;
  377. _snwprintf( typeBuffer, COUNT_OF( typeBuffer ) - 1, L"%u", PROV_RSA_FULL );
  378. if ( !CryptGetProvParam(cryptoProvider,
  379. PP_NAME,
  380. NULL,
  381. &provNameLength,
  382. 0))
  383. {
  384. status = GetLastError();
  385. (NetNameLogEvent)(resourceHandle,
  386. LOG_ERROR,
  387. L"Couldn't get length of provider name. status %1!u!.\n",
  388. status);
  389. goto cleanup;
  390. }
  391. provName = LocalAlloc( LMEM_FIXED, provNameLength );
  392. if ( provName == NULL ) {
  393. status = ERROR_NOT_ENOUGH_MEMORY;
  394. (NetNameLogEvent)(resourceHandle,
  395. LOG_ERROR,
  396. L"Couldn't allocate memory for provider name. status %1!u!.\n",
  397. status);
  398. goto cleanup;
  399. }
  400. if ( !CryptGetProvParam(cryptoProvider,
  401. PP_NAME,
  402. provName,
  403. &provNameLength,
  404. 0))
  405. {
  406. status = GetLastError();
  407. (NetNameLogEvent)(resourceHandle,
  408. LOG_ERROR,
  409. L"Couldn't get provider name. status %1!u!.\n",
  410. status);
  411. goto cleanup;
  412. }
  413. //
  414. // add 2 for the slashes in the key name plus one for the trailing null
  415. //
  416. containerNameChars = wcslen( typeBuffer ) + provNameLength + wcslen( keyName ) + 3;
  417. containerName = LocalAlloc( LMEM_FIXED, containerNameChars * sizeof( WCHAR ));
  418. if ( containerName == NULL ) {
  419. status = ERROR_NOT_ENOUGH_MEMORY;
  420. (NetNameLogEvent)(resourceHandle,
  421. LOG_ERROR,
  422. L"Couldn't allocate memory for checkpoint name. status %1!u!.\n",
  423. status);
  424. goto cleanup;
  425. }
  426. containerName[ containerNameChars - 1 ] = UNICODE_NULL;
  427. containerNameChars = _snwprintf(containerName,
  428. containerNameChars,
  429. L"%ws%\\%hs\\%ws",
  430. typeBuffer,
  431. provName,
  432. keyName );
  433. status = ClusterResourceControl(Resource->ClusterResourceHandle,
  434. NULL,
  435. CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT,
  436. (PVOID)containerName,
  437. ( containerNameChars + 1 ) * sizeof( WCHAR ),
  438. NULL,
  439. 0,
  440. NULL);
  441. if ( status != ERROR_SUCCESS ) {
  442. (NetNameLogEvent)(resourceHandle,
  443. LOG_ERROR,
  444. L"Couldn't set crypto checkpoint. status %1!u!.\n",
  445. status);
  446. }
  447. cleanup:
  448. if ( status != ERROR_SUCCESS && encryptedInfo != NULL ) {
  449. LocalFree( encryptedInfo );
  450. *EncryptedInfo = NULL;
  451. }
  452. if ( encryptKey != 0 ) {
  453. if ( !CryptDestroyKey( encryptKey )) {
  454. (NetNameLogEvent)(resourceHandle,
  455. LOG_WARNING,
  456. L"Couldn't destory encryption key. status %1!u!.\n",
  457. GetLastError());
  458. }
  459. }
  460. if ( !CryptReleaseContext( cryptoProvider, 0 )) {
  461. (NetNameLogEvent)(resourceHandle,
  462. LOG_WARNING,
  463. L"Can't release crypto context. status %1!u!.\n",
  464. GetLastError());
  465. }
  466. if ( provName != NULL ) {
  467. LocalFree( provName );
  468. }
  469. if ( containerName != NULL ) {
  470. LocalFree( containerName );
  471. }
  472. return status;
  473. } // EncryptNNResourceData
  474. DWORD
  475. DecryptNNResourceData(
  476. PNETNAME_RESOURCE Resource,
  477. PBYTE EncryptedInfo,
  478. DWORD EncryptedInfoLength,
  479. LPWSTR MachinePwd
  480. )
  481. /*++
  482. Routine Description:
  483. Reverse of encrypt routine - find our crypto checkpoint container and
  484. decrypt random blob and hand back the password
  485. Arguments:
  486. resourceHandle - used to log into the cluster log
  487. EncryptedInfo - pointer to encrypted info header and data
  488. EncryptedInfoLength - # of bytes in EncryptedInfo
  489. MachinePwd - pointer to buffer that receives the unicode password
  490. Return Value:
  491. ERROR_SUCCESS, otherwise Win32 error
  492. --*/
  493. {
  494. DWORD status = ERROR_SUCCESS;
  495. DWORD encDataLength = EncryptedInfoLength - sizeof( NETNAME_ENCRYPTED_DATA );
  496. DWORD pwdByteLength;
  497. DWORD pwdBufferSize;
  498. PWCHAR machinePwd = NULL;
  499. PWCHAR containerName = NULL;
  500. DWORD providerType;
  501. PWCHAR providerName;
  502. PWCHAR keyName;
  503. PWCHAR p; // for scanning checkpointInfo
  504. DWORD scanCount;
  505. HCRYPTPROV cryptoProvider = 0;
  506. HCRYPTKEY encryptKey = 0;
  507. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  508. PNETNAME_ENCRYPTED_DATA encryptedInfo = (PNETNAME_ENCRYPTED_DATA)EncryptedInfo;
  509. //
  510. // find our container name in this resource's list of crypto checkpoints
  511. //
  512. status = FindNNCryptoContainer( Resource, &containerName );
  513. if ( status != ERROR_SUCCESS ) {
  514. (NetNameLogEvent)(resourceHandle,
  515. LOG_ERROR,
  516. L"Couldn't find resource's container in crypto checkpoint info. status %1!u!.\n",
  517. status);
  518. return status;
  519. }
  520. //
  521. // break returned data into component parts
  522. //
  523. scanCount = swscanf( containerName, L"%d", &providerType );
  524. if ( scanCount == 0 || scanCount == EOF ) {
  525. (NetNameLogEvent)(resourceHandle,
  526. LOG_ERROR,
  527. L"Improperly formatted crypto checkpoint info \"%1!ws!\"\n",
  528. containerName);
  529. status = ERROR_INVALID_PARAMETER;
  530. goto cleanup;
  531. }
  532. p = containerName;
  533. while ( *p != L'\\' && *p != UNICODE_NULL ) ++p; // find backslash
  534. if ( *p == UNICODE_NULL ) {
  535. (NetNameLogEvent)(resourceHandle,
  536. LOG_ERROR,
  537. L"Improperly formatted crypto checkpoint info \"%1!ws!\"\n",
  538. containerName);
  539. status = ERROR_INVALID_PARAMETER;
  540. goto cleanup;
  541. }
  542. ++p; // skip over slash
  543. providerName = p; // remember beginning of provider name
  544. while ( *p != L'\\' && *p != UNICODE_NULL ) ++p; // find backslash
  545. if ( *p == UNICODE_NULL ) {
  546. (NetNameLogEvent)(resourceHandle,
  547. LOG_ERROR,
  548. L"Improperly formatted crypto checkpoint info \"%1!ws!\"\n",
  549. containerName);
  550. status = ERROR_INVALID_PARAMETER;
  551. goto cleanup;
  552. }
  553. *p++ = UNICODE_NULL; // terminate provider name and skip over NULL
  554. keyName = p; // remember container name
  555. //
  556. // get a handle to what was checkpointed
  557. //
  558. if ( !CryptAcquireContext(&cryptoProvider,
  559. keyName,
  560. providerName,
  561. providerType,
  562. CRYPT_MACHINE_KEYSET | CRYPT_SILENT))
  563. {
  564. status = GetLastError();
  565. (NetNameLogEvent)(resourceHandle,
  566. LOG_ERROR,
  567. L"Can't acquire crypto context for container %1!ws! with provider "
  568. L"\"%2!u!\\%3!ws!\". status %4!u!.\n",
  569. keyName,
  570. providerType,
  571. providerName,
  572. status);
  573. goto cleanup;
  574. }
  575. //
  576. // now get a handle to the exchange key
  577. //
  578. if ( ! CryptGetUserKey(cryptoProvider,
  579. AT_KEYEXCHANGE,
  580. &encryptKey))
  581. {
  582. status = GetLastError();
  583. (NetNameLogEvent)(resourceHandle,
  584. LOG_ERROR,
  585. L"Couldn't get size of crypto checkpoint info. status %1!u!.\n",
  586. status);
  587. goto cleanup;
  588. }
  589. //
  590. // CryptDecrypt writes the decrypted data back into the buffer that was
  591. // holding the encrypted data. For this reason, allocate a new buffer that
  592. // will eventually contain the password.
  593. //
  594. pwdByteLength = ( LM20_PWLEN + 1 ) * sizeof( WCHAR );
  595. pwdBufferSize = ( pwdByteLength > encDataLength ? pwdByteLength : encDataLength );
  596. machinePwd = LocalAlloc( LMEM_FIXED, pwdBufferSize );
  597. if ( machinePwd != NULL ) {
  598. RtlCopyMemory( machinePwd, encryptedInfo->Data, encDataLength );
  599. if ( CryptDecrypt(encryptKey,
  600. 0,
  601. TRUE,
  602. 0,
  603. (PBYTE)machinePwd,
  604. &encDataLength))
  605. {
  606. p = machinePwd;
  607. ASSERT( pwdByteLength == encDataLength );
  608. wcscpy( MachinePwd, machinePwd );
  609. while ( *p != UNICODE_NULL ) {
  610. *p++ = UNICODE_NULL;
  611. }
  612. }
  613. else {
  614. status = GetLastError();
  615. (NetNameLogEvent)(resourceHandle,
  616. LOG_ERROR,
  617. L"Can't decrypt %1!u! bytes of data. status %2!u!.\n",
  618. encDataLength,
  619. status);
  620. goto cleanup;
  621. }
  622. }
  623. else {
  624. status = ERROR_NOT_ENOUGH_MEMORY;
  625. (NetNameLogEvent)(resourceHandle,
  626. LOG_ERROR,
  627. L"Can't allocate %1!u! bytes for decrypt. status %2!u!.\n",
  628. pwdBufferSize,
  629. status);
  630. }
  631. cleanup:
  632. if ( machinePwd != NULL) {
  633. LocalFree( machinePwd );
  634. }
  635. if ( encryptKey != 0 ) {
  636. if ( !CryptDestroyKey( encryptKey )) {
  637. (NetNameLogEvent)(resourceHandle,
  638. LOG_WARNING,
  639. L"Couldn't destory session key. status %1!u!.\n",
  640. GetLastError());
  641. }
  642. }
  643. if ( cryptoProvider != 0 ) {
  644. if ( !CryptReleaseContext( cryptoProvider, 0 )) {
  645. (NetNameLogEvent)(resourceHandle,
  646. LOG_WARNING,
  647. L"Can't release crypto context. status %1!u!.\n",
  648. GetLastError());
  649. }
  650. }
  651. if ( containerName != NULL ) {
  652. LocalFree( containerName );
  653. }
  654. return status;
  655. } // DecryptNNResourceData
  656. VOID
  657. RemoveNNCryptoCheckpoint(
  658. PNETNAME_RESOURCE Resource
  659. )
  660. /*++
  661. Routine Description:
  662. Remove any crypto checkpoints associated with this resource. Delete the
  663. crypto container.
  664. Arguments:
  665. Resource - pointer to resource context block
  666. Return Value:
  667. None
  668. --*/
  669. {
  670. PWCHAR containerName = NULL;
  671. DWORD containerLength;
  672. DWORD status;
  673. WCHAR keyName[ NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ) ];
  674. HCRYPTPROV cryptoProvider;
  675. RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
  676. //
  677. // find our container name in this resource's list of crypto checkpoints
  678. //
  679. status = FindNNCryptoContainer( Resource, &containerName );
  680. if ( status != ERROR_SUCCESS ) {
  681. return;
  682. }
  683. //
  684. // remove our container
  685. //
  686. containerLength = ( wcslen( containerName ) + 1 ) * sizeof( WCHAR );
  687. status = ClusterResourceControl(Resource->ClusterResourceHandle,
  688. NULL,
  689. CLUSCTL_RESOURCE_DELETE_CRYPTO_CHECKPOINT,
  690. containerName,
  691. containerLength,
  692. NULL,
  693. 0,
  694. NULL);
  695. if ( status != ERROR_SUCCESS ) {
  696. (NetNameLogEvent)(resourceHandle,
  697. LOG_WARNING,
  698. L"Couldn't remove crypto checkpoint \"%1!ws!\". status %2!u!.\n",
  699. containerName,
  700. status);
  701. }
  702. //
  703. // now delete the container; first, reconstruct the key name
  704. //
  705. status = BuildKeyName(Resource->ClusterResourceHandle, keyName, COUNT_OF( keyName ));
  706. if ( status == ERROR_SUCCESS ) {
  707. if ( CryptAcquireContext(&cryptoProvider,
  708. keyName,
  709. MS_ENHANCED_PROV,
  710. PROV_RSA_FULL,
  711. CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET))
  712. {
  713. (NetNameLogEvent)(resourceHandle,
  714. LOG_INFORMATION,
  715. L"Deleted crypto container \"%1!ws!\".\n",
  716. keyName);
  717. } else {
  718. status = GetLastError();
  719. (NetNameLogEvent)(resourceHandle,
  720. LOG_ERROR,
  721. L"Couldn't delete crypto container \"%1!ws!\". status %2!08X!.\n",
  722. keyName,
  723. status);
  724. }
  725. } else {
  726. (NetNameLogEvent)(resourceHandle,
  727. LOG_WARNING,
  728. L"Couldn't build key container name to delete crypto container. status %1!u!.\n",
  729. status);
  730. }
  731. if ( containerName != NULL ) {
  732. LocalFree( containerName );
  733. }
  734. } // RemoveNNCryptoCheckpoint
  735. /* end crypto.c */