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.

847 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. contain.c
  5. Abstract:
  6. Container manipulators for the IIS cryptographic package.
  7. The following routines are exported by this module:
  8. IISCryptoGetStandardContainer
  9. IISCryptoGetStandardContainer2
  10. IISCryptoGetContainerByName
  11. IISCryptoDeleteContainer
  12. IISCryptoCloseContainer
  13. Author:
  14. Keith Moore (keithmo) 02-Dec-1996
  15. Revision History:
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. //
  20. // Private constants.
  21. //
  22. //
  23. // Private types.
  24. //
  25. //
  26. // Private globals.
  27. //
  28. //
  29. // Private prototypes.
  30. //
  31. HRESULT
  32. IcpGetContainerHelper(
  33. OUT HCRYPTPROV * phProv,
  34. IN LPCTSTR pszContainer,
  35. IN LPCTSTR pszProvider,
  36. IN DWORD dwProvType,
  37. IN DWORD dwAdditionalFlags,
  38. IN BOOL fApplyAcl
  39. );
  40. //
  41. // Public functions.
  42. //
  43. HRESULT
  44. WINAPI
  45. IISCryptoGetStandardContainer(
  46. OUT HCRYPTPROV * phProv,
  47. IN DWORD dwAdditionalFlags
  48. )
  49. /*++
  50. Routine Description:
  51. This routine attempts to open the crypto key container. If the
  52. container does not yet exist, this routine will attempt to create
  53. it.
  54. Arguments:
  55. phProv - Receives the provider handle if successful.
  56. dwAdditionalFlags - Any additional flags that should be passed to
  57. the CryptAcquireContext() API. This is typically used by server
  58. processes that pass in the CRYPT_MACHINE_KEYSET flag.
  59. Return Value:
  60. HRESULT - Completion status, 0 if successful, !0 otherwise.
  61. --*/
  62. {
  63. HRESULT result;
  64. //
  65. // Sanity check.
  66. //
  67. DBG_ASSERT( IcpGlobals.Initialized );
  68. DBG_ASSERT( phProv != NULL );
  69. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 );
  70. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
  71. //
  72. // Let IcpGetContainerHelper() do the dirty work.
  73. //
  74. result = IcpGetContainerHelper(
  75. phProv,
  76. IC_CONTAINER,
  77. IC_PROVIDER,
  78. IC_PROVTYPE,
  79. dwAdditionalFlags,
  80. ( dwAdditionalFlags & CRYPT_MACHINE_KEYSET ) != 0
  81. );
  82. return result;
  83. } // IISCryptoGetStandardContainer
  84. HRESULT
  85. WINAPI
  86. IISCryptoGetStandardContainer2(
  87. OUT HCRYPTPROV * phProv
  88. )
  89. /*++
  90. Routine Description:
  91. This routine attempts to open the crypto key container. If the
  92. container does not yet exist, this routine will attempt to create
  93. it.
  94. Arguments:
  95. phProv - Receives the provider handle if successful.
  96. Return Value:
  97. HRESULT - Completion status, 0 if successful, !0 otherwise.
  98. --*/
  99. {
  100. HRESULT result;
  101. //
  102. // Sanity check.
  103. //
  104. DBG_ASSERT( IcpGlobals.Initialized );
  105. DBG_ASSERT( phProv != NULL );
  106. //
  107. // Let IcpGetContainerHelper() do the dirty work.
  108. //
  109. result = IcpGetContainerHelper(
  110. phProv,
  111. NULL,
  112. NULL,
  113. IC_PROVTYPE,
  114. CRYPT_VERIFYCONTEXT,
  115. FALSE
  116. );
  117. return result;
  118. } // IISCryptoGetStandardContainer2
  119. HRESULT
  120. WINAPI
  121. IISCryptoGetContainerByName(
  122. OUT HCRYPTPROV * phProv,
  123. IN LPTSTR pszContainerName,
  124. IN DWORD dwAdditionalFlags,
  125. IN BOOL fApplyAcl
  126. )
  127. /*++
  128. Routine Description:
  129. This routine attempts to open a specific named crypto key container.
  130. If the container does not yet exist, this routine will attempt to
  131. create it and (optionally) apply an ACL to the container.
  132. Arguments:
  133. phProv - Receives the provider handle if successful.
  134. pszContainerName - The name of the container to open/create.
  135. NULL means temporary container
  136. dwAdditionalFlags - Any additional flags that should be passed to
  137. the CryptAcquireContext() API. This is typically used by server
  138. processes that pass in the CRYPT_MACHINE_KEYSET flag.
  139. fApplyAcl - If TRUE, then an ACL is applied to the container.
  140. Return Value:
  141. HRESULT - Completion status, 0 if successful, !0 otherwise.
  142. --*/
  143. {
  144. HRESULT result;
  145. //
  146. // Sanity check.
  147. //
  148. DBG_ASSERT( IcpGlobals.Initialized );
  149. DBG_ASSERT( phProv != NULL );
  150. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 );
  151. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
  152. //
  153. // Let IcpGetContainerHelper() do the dirty work.
  154. //
  155. result = IcpGetContainerHelper(
  156. phProv,
  157. pszContainerName,
  158. IC_PROVIDER,
  159. IC_PROVTYPE,
  160. dwAdditionalFlags,
  161. fApplyAcl
  162. );
  163. return result;
  164. } // IISCryptoGetContainerByName
  165. HRESULT
  166. WINAPI
  167. IISCryptoDeleteStandardContainer(
  168. IN DWORD dwAdditionalFlags
  169. )
  170. /*++
  171. Routine Description:
  172. This routine deletes the standard crypto key container.
  173. Arguments:
  174. dwAdditionalFlags - Any additional flags that should be passed to
  175. the CryptAcquireContext() API. This is typically used by server
  176. processes that pass in the CRYPT_MACHINE_KEYSET flag.
  177. Return Value:
  178. HRESULT - Completion status, 0 if successful, !0 otherwise.
  179. --*/
  180. {
  181. HRESULT result = NO_ERROR;
  182. BOOL status;
  183. HCRYPTPROV cryptProv;
  184. //
  185. // Sanity check.
  186. //
  187. DBG_ASSERT( IcpGlobals.Initialized );
  188. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 );
  189. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
  190. //
  191. // Short-circuit if cryptography is disabled.
  192. //
  193. if( !IcpGlobals.EnableCryptography ) {
  194. return NO_ERROR;
  195. }
  196. //
  197. // Delete the container.
  198. //
  199. status = CryptAcquireContext(
  200. &cryptProv,
  201. IC_CONTAINER,
  202. IC_PROVIDER,
  203. IC_PROVTYPE,
  204. CRYPT_DELETEKEYSET | dwAdditionalFlags
  205. );
  206. if( !status ) {
  207. result = IcpGetLastError();
  208. }
  209. return result;
  210. } // IISCryptoDeleteStandardContainer
  211. HRESULT
  212. WINAPI
  213. IISCryptoDeleteContainerByName(
  214. IN LPTSTR pszContainerName,
  215. IN DWORD dwAdditionalFlags
  216. )
  217. /*++
  218. Routine Description:
  219. This routine deletes the specified crypto key container.
  220. Arguments:
  221. pszContainerName - The name of the container to delete.
  222. dwAdditionalFlags - Any additional flags that should be passed to
  223. the CryptAcquireContext() API. This is typically used by server
  224. processes that pass in the CRYPT_MACHINE_KEYSET flag.
  225. Return Value:
  226. HRESULT - Completion status, 0 if successful, !0 otherwise.
  227. --*/
  228. {
  229. HRESULT result = NO_ERROR;
  230. BOOL status;
  231. HCRYPTPROV cryptProv;
  232. //
  233. // Sanity check.
  234. //
  235. DBG_ASSERT( IcpGlobals.Initialized );
  236. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 );
  237. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
  238. //
  239. // Short-circuit if cryptography is disabled.
  240. //
  241. if( !IcpGlobals.EnableCryptography ) {
  242. return NO_ERROR;
  243. }
  244. //
  245. // Delete the container.
  246. //
  247. status = CryptAcquireContext(
  248. &cryptProv,
  249. pszContainerName,
  250. IC_PROVIDER,
  251. IC_PROVTYPE,
  252. CRYPT_DELETEKEYSET | dwAdditionalFlags
  253. );
  254. if( !status ) {
  255. result = IcpGetLastError();
  256. }
  257. return result;
  258. } // IISCryptoDeleteContainerByName
  259. HRESULT
  260. WINAPI
  261. IISCryptoCloseContainer(
  262. IN HCRYPTPROV hProv
  263. )
  264. /*++
  265. Routine Description:
  266. This routine closes the container associated with the specified
  267. provider handle.
  268. Arguments:
  269. hProv - A handle to a crypto service provider.
  270. Return Value:
  271. HRESULT - Completion status, 0 if successful, !0 otherwise.
  272. --*/
  273. {
  274. BOOL status;
  275. //
  276. // Sanity check.
  277. //
  278. DBG_ASSERT( IcpGlobals.Initialized );
  279. DBG_ASSERT( hProv != CRYPT_NULL );
  280. //
  281. // Short-circuit if cryptography is disabled.
  282. //
  283. if( !IcpGlobals.EnableCryptography ) {
  284. if( hProv == DUMMY_HPROV ) {
  285. return NO_ERROR;
  286. } else {
  287. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  288. }
  289. }
  290. //
  291. // Close the provider.
  292. //
  293. status = CryptReleaseContext(
  294. hProv,
  295. 0
  296. );
  297. if( status ) {
  298. UpdateContainersClosed();
  299. return NO_ERROR;
  300. }
  301. return IcpGetLastError();
  302. } // IISCryptoCloseContainer
  303. //
  304. // Private functions.
  305. //
  306. HRESULT
  307. IcpGetContainerHelper(
  308. OUT HCRYPTPROV * phProv,
  309. IN LPCTSTR pszContainer,
  310. IN LPCTSTR pszProvider,
  311. IN DWORD dwProvType,
  312. IN DWORD dwAdditionalFlags,
  313. IN BOOL fApplyAcl
  314. )
  315. /*++
  316. Routine Description:
  317. This is a helper routine for IISCryptoGetContainer. It tries
  318. to open/create the specified container in the specified provider.
  319. Arguments:
  320. phProv - Receives the provider handle if successful.
  321. pszContainer - The key container name.
  322. pszProvider - The provider name.
  323. dwProvType - The type of provider to acquire.
  324. dwAdditionalFlags - Any additional flags that should be passed to
  325. the CryptAcquireContext() API. This is typically used by server
  326. processes that pass in the CRYPT_MACHINE_KEYSET flag.
  327. fApplyAcl - If TRUE, then an ACL is applied to the container.
  328. Return Value:
  329. HRESULT - Completion status, 0 if successful, !0 otherwise.
  330. --*/
  331. {
  332. HRESULT result = NO_ERROR;
  333. HCRYPTPROV hProv;
  334. BOOL status;
  335. PSID systemSid;
  336. PSID adminSid;
  337. PACL dacl;
  338. DWORD daclSize;
  339. SECURITY_DESCRIPTOR securityDescriptor;
  340. SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
  341. BOOL isNt = FALSE;
  342. OSVERSIONINFO osInfo;
  343. // Sanity check.
  344. //
  345. DBG_ASSERT( IcpGlobals.Initialized );
  346. DBG_ASSERT( phProv != NULL );
  347. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 );
  348. DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
  349. //
  350. // Short-circuit if cryptography is disabled.
  351. //
  352. if( !IcpGlobals.EnableCryptography ) {
  353. *phProv = DUMMY_HPROV;
  354. return NO_ERROR;
  355. }
  356. //
  357. // Setup our locals so we know how to cleanup on exit.
  358. //
  359. hProv = CRYPT_NULL;
  360. systemSid = NULL;
  361. adminSid = NULL;
  362. dacl = NULL;
  363. //
  364. // Grab the lock protecting the container code. This is always
  365. // necessary to prevent race conditions between this code and
  366. // the code below that creates the container & adds a security
  367. // descriptor.
  368. //
  369. IcpAcquireGlobalLock();
  370. //
  371. // Try to open an existing container.
  372. //
  373. if ( pszContainer == NULL )
  374. {
  375. //
  376. // if container is NULL it means that temporary (ephemeral)
  377. // keys will be used
  378. // CRYPT_VERIFYCONTEXT must be used in this case
  379. // keys used for DCOM traffic encryption will be using
  380. // NULL containers
  381. //
  382. status = CryptAcquireContext(
  383. &hProv,
  384. pszContainer,
  385. pszProvider,
  386. dwProvType,
  387. CRYPT_VERIFYCONTEXT
  388. );
  389. if( !status )
  390. {
  391. result = IcpGetLastError();
  392. DBGPRINTF(( DBG_CONTEXT,"IcpGetContainerHelper. CryptAcquireContext(advapi32.dll) with CRYPT_VERIFYCONTEXT failed err=0x%x\n",result));
  393. DBGPRINTF(( DBG_CONTEXT,"args for CryptAcquireContext(%p,%p,%p,%d,%d)\n",&hProv,pszContainer,pszProvider,dwProvType, CRYPT_VERIFYCONTEXT));
  394. goto fatal;
  395. }
  396. else
  397. {
  398. goto success;
  399. }
  400. }
  401. status = CryptAcquireContext(
  402. &hProv,
  403. pszContainer,
  404. pszProvider,
  405. dwProvType,
  406. 0 | dwAdditionalFlags
  407. );
  408. if( !status ) {
  409. result = IcpGetLastError();
  410. }
  411. if( SUCCEEDED(result) ) {
  412. DBG_ASSERT( hProv != CRYPT_NULL );
  413. *phProv = hProv;
  414. IcpReleaseGlobalLock();
  415. UpdateContainersOpened();
  416. return NO_ERROR;
  417. }
  418. //
  419. // Could not open the container. If the failure was anything
  420. // other than NTE_BAD_KEYSET, then we're toast.
  421. //
  422. if( result != NTE_BAD_KEYSET ) {
  423. DBGPRINTF(( DBG_CONTEXT,"IcpGetContainerHelper. CryptAcquireContext(advapi32.dll) failed err=0x%x.toast.\n",result));
  424. DBGPRINTF(( DBG_CONTEXT,"args for CryptAcquireContext(%p,%p,%p,%d,%d)\n",&hProv,pszContainer,pszProvider,dwProvType,CRYPT_NEWKEYSET | dwAdditionalFlags));
  425. hProv = CRYPT_NULL;
  426. goto fatal;
  427. }
  428. if(result == NTE_BAD_KEYSET)
  429. {
  430. DBGPRINTF(( DBG_CONTEXT,"CryptAcquireContext(%p,%p,%p,%d,%d) returned NTE_BAD_KEYSET, so lets create a keyset now...\n",&hProv,pszContainer,pszProvider,dwProvType,0 | dwAdditionalFlags));
  431. }
  432. //
  433. // OK, CryptAcquireContext() failed with NTE_BAD_KEYSET, meaning
  434. // that the container does not yet exist, so create it now.
  435. //
  436. status = CryptAcquireContext(
  437. &hProv,
  438. pszContainer,
  439. pszProvider,
  440. dwProvType,
  441. CRYPT_NEWKEYSET | dwAdditionalFlags
  442. );
  443. if( status ) {
  444. result = NO_ERROR;
  445. } else {
  446. result = IcpGetLastError();
  447. }
  448. if( FAILED(result) ) {
  449. DBGPRINTF(( DBG_CONTEXT,"IcpGetContainerHelper. CryptAcquireContext(advapi32.dll) failed err=0x%x.\n",result));
  450. DBGPRINTF(( DBG_CONTEXT,"args for CryptAcquireContext(%p,%p,%p,%d,%d)\n",&hProv,pszContainer,pszProvider,dwProvType,CRYPT_NEWKEYSET | dwAdditionalFlags));
  451. hProv = CRYPT_NULL;
  452. goto fatal;
  453. }
  454. //
  455. // We've created the container. If requested, then we must create
  456. // a security descriptor for the container. This security descriptor
  457. // allows full access to the the container by the local system and
  458. // the local administrators group. Other login contexts may not
  459. // access the container.
  460. //
  461. // Of course, we only need to do this under NT...
  462. //
  463. osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  464. if ( GetVersionEx( &osInfo ) ) {
  465. isNt = (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
  466. }
  467. if( fApplyAcl && isNt ) {
  468. //
  469. // Initialize the security descriptor.
  470. //
  471. status = InitializeSecurityDescriptor(
  472. &securityDescriptor,
  473. SECURITY_DESCRIPTOR_REVISION
  474. );
  475. if( !status ) {
  476. result = IcpGetLastError();
  477. goto fatal;
  478. }
  479. //
  480. // Create the SIDs for the local system and admin group.
  481. //
  482. status = AllocateAndInitializeSid(
  483. &ntAuthority,
  484. 1,
  485. SECURITY_LOCAL_SYSTEM_RID,
  486. 0,
  487. 0,
  488. 0,
  489. 0,
  490. 0,
  491. 0,
  492. 0,
  493. &systemSid
  494. );
  495. if( !status ) {
  496. result = IcpGetLastError();
  497. goto fatal;
  498. }
  499. status= AllocateAndInitializeSid(
  500. &ntAuthority,
  501. 2,
  502. SECURITY_BUILTIN_DOMAIN_RID,
  503. DOMAIN_ALIAS_RID_ADMINS,
  504. 0,
  505. 0,
  506. 0,
  507. 0,
  508. 0,
  509. 0,
  510. &adminSid
  511. );
  512. if( !status ) {
  513. result = IcpGetLastError();
  514. goto fatal;
  515. }
  516. //
  517. // Create the DACL containing an access-allowed ACE
  518. // for the local system and admin SIDs.
  519. //
  520. daclSize = sizeof(ACL)
  521. + sizeof(ACCESS_ALLOWED_ACE)
  522. + GetLengthSid(adminSid)
  523. + sizeof(ACCESS_ALLOWED_ACE)
  524. + GetLengthSid(systemSid)
  525. - sizeof(DWORD);
  526. dacl = (PACL)IcpAllocMemory( daclSize );
  527. if( dacl == NULL ) {
  528. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  529. goto fatal;
  530. }
  531. status = InitializeAcl(
  532. dacl,
  533. daclSize,
  534. ACL_REVISION
  535. );
  536. if( !status ) {
  537. result = IcpGetLastError();
  538. goto fatal;
  539. }
  540. status = AddAccessAllowedAce(
  541. dacl,
  542. ACL_REVISION,
  543. KEY_ALL_ACCESS,
  544. systemSid
  545. );
  546. if( !status ) {
  547. result = IcpGetLastError();
  548. goto fatal;
  549. }
  550. status = AddAccessAllowedAce(
  551. dacl,
  552. ACL_REVISION,
  553. KEY_ALL_ACCESS,
  554. adminSid
  555. );
  556. if( !status ) {
  557. result = IcpGetLastError();
  558. goto fatal;
  559. }
  560. //
  561. // Set the DACL into the security descriptor.
  562. //
  563. status = SetSecurityDescriptorDacl(
  564. &securityDescriptor,
  565. TRUE,
  566. dacl,
  567. FALSE
  568. );
  569. if( !status ) {
  570. result = IcpGetLastError();
  571. goto fatal;
  572. }
  573. //
  574. // And (finally!) set the security descriptor on the
  575. // container.
  576. //
  577. status = CryptSetProvParam(
  578. hProv,
  579. PP_KEYSET_SEC_DESCR,
  580. (BYTE *)&securityDescriptor,
  581. DACL_SECURITY_INFORMATION
  582. );
  583. if( !status ) {
  584. result = IcpGetLastError();
  585. goto fatal;
  586. }
  587. }
  588. success:
  589. //
  590. // Success!
  591. //
  592. DBG_ASSERT( hProv != CRYPT_NULL );
  593. *phProv = hProv;
  594. UpdateContainersOpened();
  595. result = NO_ERROR;
  596. fatal:
  597. if( dacl != NULL ) {
  598. IcpFreeMemory( dacl );
  599. }
  600. if( adminSid != NULL ) {
  601. FreeSid( adminSid );
  602. }
  603. if( systemSid != NULL ) {
  604. FreeSid( systemSid );
  605. }
  606. if( hProv != CRYPT_NULL && FAILED(result) ) {
  607. DBG_REQUIRE( CryptReleaseContext(
  608. hProv,
  609. 0
  610. ) );
  611. }
  612. IcpReleaseGlobalLock();
  613. return result;
  614. } // IcpGetContainerHelper