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.

2035 lines
46 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. secdat.cxx
  5. Abstract:
  6. This module implements the ADM_SECURE_DATA class.
  7. Author:
  8. Keith Moore (keithmo) 17-Feb-1997
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <ole2.h>
  15. #include <windows.h>
  16. #define DEFAULT_TRACE_FLAGS (DEBUG_ERROR)
  17. #include <dbgutil.h>
  18. #include <iadmw.h>
  19. #include <icrypt.hxx>
  20. #include <secdat.hxx>
  21. //
  22. // Private constants.
  23. //
  24. #define FREE_BLOB(blob) \
  25. if( blob != NULL ) { \
  26. HRESULT _res; \
  27. _res = ::IISCryptoFreeBlob( blob ); \
  28. DBG_ASSERT( SUCCEEDED(_res) ); \
  29. } else
  30. #if DBG
  31. #define ENABLE_ADM_COUNTERS 1
  32. #define ADM_NOISY 0
  33. #else
  34. #define ENABLE_ADM_COUNTERS 0
  35. #define ADM_NOISY 0
  36. #endif
  37. #if ADM_NOISY
  38. #define NOISYPRINTF(x) DBGPRINTF(x)
  39. #else
  40. #define NOISYPRINTF(x)
  41. #endif
  42. //
  43. // Private types.
  44. //
  45. #if ENABLE_ADM_COUNTERS
  46. typedef struct _ADM_COUNTERS {
  47. LONG ObjectsCreated;
  48. LONG ObjectsDestroyed;
  49. } ADM_COUNTERS, *PADM_COUNTERS;
  50. #define DECLARE_ADM_COUNTERS() ADM_COUNTERS g_AdmCounters
  51. #define UpdateObjectsCreated() InterlockedIncrement( &g_AdmCounters.ObjectsCreated )
  52. #define UpdateObjectsDestroyed() InterlockedIncrement( &g_AdmCounters.ObjectsDestroyed )
  53. #else
  54. #define DECLARE_ADM_COUNTERS()
  55. #define UpdateObjectsCreated()
  56. #define UpdateObjectsDestroyed()
  57. #endif
  58. //
  59. // Private globals.
  60. //
  61. LIST_ENTRY ADM_SECURE_DATA::sm_ServerSecureDataListHead;
  62. LIST_ENTRY ADM_SECURE_DATA::sm_ClientSecureDataListHead;
  63. LIST_ENTRY ADM_GUID_MAP::sm_GuidMapListHead;
  64. CRITICAL_SECTION ADM_SECURE_DATA::sm_ServerSecureDataLock;
  65. CRITICAL_SECTION ADM_SECURE_DATA::sm_ClientSecureDataLock;
  66. CRITICAL_SECTION ADM_GUID_MAP::sm_GuidMapDataLock;
  67. #if DBG
  68. DWORD ADM_SECURE_DATA::sm_ServerSecureDataLockOwner;
  69. DWORD ADM_SECURE_DATA::sm_ClientSecureDataLockOwner;
  70. DWORD ADM_GUID_MAP::sm_GuidMapLockOwner;
  71. PTRACE_LOG ADM_SECURE_DATA::sm_RefTraceLog;
  72. PTRACE_LOG ADM_GUID_MAP::sm_RefTraceLog;
  73. #endif
  74. HCRYPTPROV ADM_SECURE_DATA::sm_ServerCryptoProvider;
  75. HCRYPTPROV ADM_SECURE_DATA::sm_ClientCryptoProvider;
  76. DECLARE_ADM_COUNTERS();
  77. //
  78. // ADM_SECURE_DATA methods.
  79. //
  80. ADM_SECURE_DATA::ADM_SECURE_DATA(
  81. IN IUnknown * Object,
  82. IN GUID guidServer,
  83. IN BOOL bServer
  84. ) :
  85. m_Object( Object ),
  86. m_KeyExchangeClient( NULL ),
  87. m_KeyExchangeServer( NULL ),
  88. m_SendCryptoStorage( NULL ),
  89. m_ReceiveCryptoStorage( NULL ),
  90. m_ReferenceCount( 1 ),
  91. m_guidServer(guidServer),
  92. m_bIsServer(bServer)
  93. /*++
  94. Routine Description:
  95. ADM_SECURE_DATA object constructor.
  96. Arguments:
  97. Object - Pointer to the object to associate.
  98. Return Value:
  99. None.
  100. --*/
  101. {
  102. NOISYPRINTF((
  103. DBG_CONTEXT,
  104. "ADM_SECURE_DATA: creating %08lx,%08lx\n",
  105. this,
  106. Object
  107. ));
  108. //
  109. // Sanity check.
  110. //
  111. DBG_ASSERT( (Object != NULL) || !bServer );
  112. //
  113. // Initialize any complex data members.
  114. //
  115. INITIALIZE_CRITICAL_SECTION( &m_ObjectLock );
  116. //
  117. // Put ourselves on the list.
  118. //
  119. if (bServer) {
  120. AcquireServerDataLock();
  121. InsertHeadList( &sm_ServerSecureDataListHead, &m_SecureDataListEntry );
  122. ReleaseServerDataLock();
  123. }
  124. else {
  125. AcquireClientDataLock();
  126. InsertHeadList( &sm_ClientSecureDataListHead, &m_SecureDataListEntry );
  127. ReleaseClientDataLock();
  128. //
  129. // Clients lifespan is controlled by ADM_GUID_MAP
  130. //
  131. }
  132. UpdateObjectsCreated();
  133. } // ADM_SECURE_DATA::ADM_SECURE_DATA
  134. ADM_SECURE_DATA::~ADM_SECURE_DATA()
  135. /*++
  136. Routine Description:
  137. ADM_SECURE_DATA object destructor.
  138. Arguments:
  139. None.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. NOISYPRINTF((
  145. DBG_CONTEXT,
  146. "~ADM_SECURE_DATA: destroying %08lx,%08lx\n",
  147. this,
  148. m_Object
  149. ));
  150. //
  151. // Sanity check.
  152. //
  153. DBG_ASSERT( m_ReferenceCount == 0 );
  154. //
  155. // Cleanup.
  156. //
  157. CleanupCryptoData();
  158. if (m_bIsServer) {
  159. AcquireServerDataLock();
  160. RemoveEntryList( &m_SecureDataListEntry );
  161. ReleaseServerDataLock();
  162. }
  163. else {
  164. AcquireClientDataLock();
  165. RemoveEntryList( &m_SecureDataListEntry );
  166. ReleaseClientDataLock();
  167. }
  168. DeleteCriticalSection( &m_ObjectLock );
  169. UpdateObjectsDestroyed();
  170. m_Object = NULL;
  171. } // ADM_SECURE_DATA::~ADM_SECURE_DATA
  172. BOOL
  173. ADM_SECURE_DATA::Initialize(
  174. HINSTANCE
  175. )
  176. /*++
  177. Routine Description:
  178. Initializes static global data private to ADM_SECURE_DATA.
  179. Arguments:
  180. hDll - Handle to this DLL.
  181. Return Value:
  182. None.
  183. --*/
  184. {
  185. HRESULT result;
  186. //
  187. // Initialize the crypto stuff.
  188. //
  189. result = ::IISCryptoInitialize();
  190. if( SUCCEEDED(result) ) {
  191. INITIALIZE_CRITICAL_SECTION( &sm_ServerSecureDataLock );
  192. INITIALIZE_CRITICAL_SECTION( &sm_ClientSecureDataLock );
  193. #if DBG
  194. sm_ServerSecureDataLockOwner = 0;
  195. sm_ClientSecureDataLockOwner = 0;
  196. sm_RefTraceLog = CreateRefTraceLog( 1024, 0 );
  197. #endif
  198. InitializeListHead( &sm_ServerSecureDataListHead );
  199. InitializeListHead( &sm_ClientSecureDataListHead );
  200. } else {
  201. DBGPRINTF((
  202. DBG_CONTEXT,
  203. "ADM_SECURE_DATA::Initialize: error %lx\n",
  204. result
  205. ));
  206. }
  207. return SUCCEEDED(result);
  208. } // ADM_SECURE_DATA::Initialize
  209. VOID
  210. ADM_SECURE_DATA::Terminate()
  211. /*++
  212. Routine Description:
  213. Terminates static global data private to ADM_SECURE_DATA.
  214. Arguments:
  215. None.
  216. Return Value:
  217. None.
  218. --*/
  219. {
  220. PLIST_ENTRY entry;
  221. ADM_SECURE_DATA * data;
  222. HRESULT result;
  223. //
  224. // Free any secure data objects on our list.
  225. //
  226. AcquireServerDataLock();
  227. entry = sm_ServerSecureDataListHead.Flink;
  228. while( entry != &sm_ServerSecureDataListHead ) {
  229. data = CONTAINING_RECORD(
  230. entry,
  231. ADM_SECURE_DATA,
  232. m_SecureDataListEntry
  233. );
  234. data->Dereference();
  235. entry = sm_ServerSecureDataListHead.Flink;
  236. }
  237. ReleaseServerDataLock();
  238. AcquireClientDataLock();
  239. entry = sm_ClientSecureDataListHead.Flink;
  240. while( entry != &sm_ClientSecureDataListHead ) {
  241. data = CONTAINING_RECORD(
  242. entry,
  243. ADM_SECURE_DATA,
  244. m_SecureDataListEntry
  245. );
  246. data->Dereference();
  247. entry = sm_ClientSecureDataListHead.Flink;
  248. }
  249. ReleaseClientDataLock();
  250. DBG_ASSERT( IsListEmpty( &sm_ServerSecureDataListHead ) );
  251. DBG_ASSERT( IsListEmpty( &sm_ClientSecureDataListHead ) );
  252. //
  253. // Terminate the crypto stuff.
  254. //
  255. if( sm_ServerCryptoProvider != CRYPT_NULL ) {
  256. result = ::IISCryptoCloseContainer( sm_ServerCryptoProvider );
  257. DBG_ASSERT( SUCCEEDED(result) || (result == RETURNCODETOHRESULT(ERROR_BUSY)) );
  258. sm_ServerCryptoProvider = CRYPT_NULL;
  259. }
  260. if( sm_ClientCryptoProvider != CRYPT_NULL ) {
  261. result = ::IISCryptoCloseContainer( sm_ClientCryptoProvider );
  262. DBG_ASSERT( SUCCEEDED(result) || (result == RETURNCODETOHRESULT(ERROR_BUSY)) );
  263. sm_ClientCryptoProvider = CRYPT_NULL;
  264. }
  265. result = ::IISCryptoTerminate();
  266. DBG_ASSERT( SUCCEEDED(result) );
  267. //
  268. // Final cleanup.
  269. //
  270. DeleteCriticalSection( &sm_ServerSecureDataLock );
  271. DeleteCriticalSection( &sm_ClientSecureDataLock );
  272. #if DBG
  273. if( sm_RefTraceLog != NULL ) {
  274. DestroyRefTraceLog( sm_RefTraceLog );
  275. }
  276. #endif
  277. } // ADM_SECURE_DATA::Terminate
  278. ADM_SECURE_DATA *
  279. ADM_SECURE_DATA::FindAndReferenceServerSecureData(
  280. IN IUnknown * Object,
  281. IN BOOL CreateIfNotFound
  282. )
  283. /*++
  284. Routine Description:
  285. Finds the ADM_SECURE_DATA object associated with Object. If it
  286. cannot be found, then a new ADM_SECURE_DATA object is created
  287. and put on the global list.
  288. Arguments:
  289. Object - The object to search for.
  290. CreateIfNotFound - If the object is not on the list, a new association
  291. will only be created if this flag is TRUE.
  292. Return Value:
  293. ADM_SECURE_DATA * - Pointer to the ADM_SECURE_DATA object if
  294. successful, NULL otherwise.
  295. --*/
  296. {
  297. PLIST_ENTRY entry;
  298. ADM_SECURE_DATA * data;
  299. AcquireServerDataLock();
  300. for( entry = sm_ServerSecureDataListHead.Flink ;
  301. entry != &sm_ServerSecureDataListHead ;
  302. entry = entry->Flink ) {
  303. data = CONTAINING_RECORD(
  304. entry,
  305. ADM_SECURE_DATA,
  306. m_SecureDataListEntry
  307. );
  308. if( data->m_Object == Object ) {
  309. data->Reference();
  310. ReleaseServerDataLock();
  311. return data;
  312. }
  313. }
  314. data = NULL;
  315. if( CreateIfNotFound ) {
  316. GUID guidServer;
  317. HRESULT hresError;
  318. hresError = CoCreateGuid(&guidServer);
  319. if (SUCCEEDED(hresError)) {
  320. data = new ADM_SECURE_DATA( Object,
  321. guidServer,
  322. TRUE );
  323. if( data == NULL ) {
  324. DBGPRINTF((
  325. DBG_CONTEXT,
  326. "ADM_SECURE_DATA::FindAndReferenceServerSecureData: out of memory\n"
  327. ));
  328. } else {
  329. data->Reference();
  330. }
  331. }
  332. else {
  333. DBGPRINTF((
  334. DBG_CONTEXT,
  335. "ADM_SECURE_DATA::FindAndReferenceServerSecureData: CoCreateGuid failed\n"
  336. ));
  337. }
  338. }
  339. ReleaseServerDataLock();
  340. return data;
  341. } // ADM_SECURE_DATA::FindAndReferenceServerSecureData
  342. ADM_SECURE_DATA *
  343. ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData(
  344. IN IUnknown *Object )
  345. /*++
  346. Routine Description:
  347. Finds the ADM_SECURE_DATA object associated with Object. If it
  348. cannot be found, then a new ADM_SECURE_DATA object is created
  349. and put on the global list.
  350. Arguments:
  351. Object - The object to search for.
  352. Return Value:
  353. ADM_SECURE_DATA * - Pointer to the ADM_SECURE_DATA object if
  354. successful, NULL otherwise.
  355. --*/
  356. {
  357. HRESULT hr;
  358. ADM_SECURE_DATA *psecdatData = NULL;
  359. ADM_GUID_MAP *pguidmapData = NULL;
  360. GUID guidServer = { 0 };
  361. AcquireClientDataLock();
  362. pguidmapData = ADM_GUID_MAP::FindAndReferenceGuidMap( Object );
  363. if ( pguidmapData == NULL )
  364. {
  365. // IVANPASH: 591269.
  366. // We cannot keep the critical section locked while making the R_ call
  367. ReleaseClientDataLock();
  368. hr = IMSAdminBaseW_R_GetServerGuid_Proxy( (IMSAdminBaseW *)Object,
  369. &guidServer );
  370. AcquireClientDataLock();
  371. if ( FAILED( hr ) )
  372. {
  373. DBGPRINTF(( DBG_CONTEXT,
  374. "ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData: IMSAdminBaseW_R_GetServerGuid_Proxy failed\n" ));
  375. goto exit;
  376. }
  377. // Retry
  378. pguidmapData = ADM_GUID_MAP::FindAndReferenceGuidMap( Object );
  379. if ( pguidmapData == NULL )
  380. {
  381. pguidmapData = new ADM_GUID_MAP( Object,
  382. guidServer );
  383. if( pguidmapData == NULL )
  384. {
  385. DBGPRINTF(( DBG_CONTEXT,
  386. "ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData: out of memory\n" ));
  387. goto exit;
  388. }
  389. pguidmapData->Reference();
  390. }
  391. }
  392. DBG_ASSERT( pguidmapData != NULL );
  393. psecdatData = FindAndReferenceClientSecureData( pguidmapData );
  394. if ( psecdatData == NULL )
  395. {
  396. //
  397. // AddRef the ADM_SECURE_DATA
  398. // Do this here instead of constructor to
  399. // all handing of errors.
  400. // this may create the ADM_SECURE_DATA
  401. //
  402. psecdatData = new ADM_SECURE_DATA( Object,
  403. pguidmapData->GetGuid(),
  404. FALSE );
  405. if ( psecdatData == NULL )
  406. {
  407. DBGPRINTF(( DBG_CONTEXT,
  408. "ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData: out of memory\n" ));
  409. goto exit;
  410. }
  411. psecdatData->Reference();
  412. }
  413. exit:
  414. if ( pguidmapData != NULL )
  415. {
  416. pguidmapData->Dereference();
  417. pguidmapData = NULL;
  418. }
  419. ReleaseClientDataLock();
  420. return psecdatData;
  421. } // ADM_SECURE_DATA::FindAndReferenceSecureData
  422. ADM_SECURE_DATA *
  423. ADM_SECURE_DATA::FindAndReferenceClientSecureData(
  424. IN ADM_GUID_MAP *pguidmapRelated )
  425. /*++
  426. Routine Description:
  427. Finds the ADM_SECURE_DATA object associated with Object.
  428. Arguments:
  429. pguidmapRelated - The GUID to search for.
  430. Return Value:
  431. ADM_SECURE_DATA * - Pointer to the ADM_SECURE_DATA object if
  432. successful, NULL otherwise.
  433. --*/
  434. {
  435. PLIST_ENTRY entry;
  436. ADM_SECURE_DATA *psecdatData = NULL;
  437. AcquireClientDataLock();
  438. if ( pguidmapRelated == NULL )
  439. {
  440. goto exit;
  441. }
  442. for ( entry = sm_ClientSecureDataListHead.Flink ;
  443. entry != &sm_ClientSecureDataListHead ;
  444. entry = entry->Flink )
  445. {
  446. psecdatData = CONTAINING_RECORD( entry,
  447. ADM_SECURE_DATA,
  448. m_SecureDataListEntry );
  449. DBG_ASSERT( psecdatData->m_guidServer != GUID_NULL );
  450. if ( psecdatData->m_guidServer == pguidmapRelated->GetGuid() )
  451. {
  452. psecdatData->Reference();
  453. goto exit;
  454. }
  455. }
  456. psecdatData = NULL;
  457. exit:
  458. ReleaseClientDataLock();
  459. return psecdatData;
  460. } // ADM_SECURE_DATA::FindAndReferenceSecureData
  461. ADM_SECURE_DATA *
  462. ADM_SECURE_DATA::FindAndReferenceClientSecureData(
  463. IN IUnknown *Object )
  464. /*++
  465. Routine Description:
  466. Finds the ADM_SECURE_DATA object associated with Object.
  467. Arguments:
  468. Object - The object to search for.
  469. Return Value:
  470. ADM_SECURE_DATA * - Pointer to the ADM_SECURE_DATA object if
  471. successful, NULL otherwise.
  472. --*/
  473. {
  474. ADM_SECURE_DATA *psecdatData = NULL;
  475. ADM_GUID_MAP *pguidmapData = NULL;
  476. AcquireClientDataLock();
  477. pguidmapData = ADM_GUID_MAP::FindAndReferenceGuidMap( Object );
  478. if ( pguidmapData == NULL )
  479. {
  480. goto exit;
  481. }
  482. psecdatData = FindAndReferenceClientSecureData( pguidmapData );
  483. exit:
  484. if ( pguidmapData != NULL )
  485. {
  486. pguidmapData->Dereference();
  487. pguidmapData = NULL;
  488. }
  489. ReleaseClientDataLock();
  490. return psecdatData;
  491. } // ADM_SECURE_DATA::FindAndReferenceSecureData
  492. HRESULT
  493. ADM_SECURE_DATA::GetClientSendCryptoStorage(
  494. OUT IIS_CRYPTO_STORAGE ** SendCryptoStorage,
  495. IN IUnknown * Object
  496. )
  497. /*++
  498. Routine Description:
  499. Retrieves the client-side IIS_CRYPTO_STORAGE object to be used for
  500. sending data to the server. This routine will perform the client-side
  501. key exchange if necessary.
  502. Arguments:
  503. SendCryptoStorage - Receives a pointer to the newly created
  504. IIS_CRYPTO_STORAGE object if successful.
  505. Return Value:
  506. HRESULT - 0 if successful, !0 otherwise.
  507. --*/
  508. {
  509. HRESULT result;
  510. //
  511. // Sanity check.
  512. //
  513. DBG_ASSERT( SendCryptoStorage != NULL );
  514. //
  515. // Do that key exchange thang if we don't yet have it.
  516. //
  517. if( m_KeyExchangeClient == NULL ) {
  518. LockThis();
  519. if( m_KeyExchangeClient == NULL ) {
  520. result = DoClientSideKeyExchange(Object);
  521. if( FAILED(result) ) {
  522. UnlockThis();
  523. return result;
  524. }
  525. }
  526. UnlockThis();
  527. }
  528. DBG_ASSERT( m_SendCryptoStorage != NULL );
  529. *SendCryptoStorage = m_SendCryptoStorage;
  530. return NO_ERROR;
  531. } // ADM_SECURE_DATA::GetClientSendCryptoStorage
  532. HRESULT
  533. ADM_SECURE_DATA::GetClientReceiveCryptoStorage(
  534. OUT IIS_CRYPTO_STORAGE ** ReceiveCryptoStorage,
  535. IUnknown * Object
  536. )
  537. /*++
  538. Routine Description:
  539. Retrieves the client-side IIS_CRYPTO_STORAGE object to be used for
  540. receiving data from the server. This routine will perform the
  541. client-side key exchange if necessary.
  542. Arguments:
  543. ReceiveCryptoStorage - Receives a pointer to the newly created
  544. IIS_CRYPTO_STORAGE object if successful.
  545. Return Value:
  546. HRESULT - 0 if successful, !0 otherwise.
  547. --*/
  548. {
  549. HRESULT result;
  550. //
  551. // Sanity check.
  552. //
  553. DBG_ASSERT( ReceiveCryptoStorage != NULL );
  554. //
  555. // Do that key exchange thang if we don't yet have it.
  556. //
  557. if( m_KeyExchangeClient == NULL ) {
  558. LockThis();
  559. if( m_KeyExchangeClient == NULL ) {
  560. result = DoClientSideKeyExchange(Object);
  561. if( FAILED(result) ) {
  562. UnlockThis();
  563. return result;
  564. }
  565. }
  566. UnlockThis();
  567. }
  568. DBG_ASSERT( m_ReceiveCryptoStorage != NULL );
  569. *ReceiveCryptoStorage = m_ReceiveCryptoStorage;
  570. return NO_ERROR;
  571. } // ADM_SECURE_DATA::GetClientReceiveCryptoStorage
  572. HRESULT
  573. ADM_SECURE_DATA::GetServerSendCryptoStorage(
  574. OUT IIS_CRYPTO_STORAGE ** SendCryptoStorage
  575. )
  576. /*++
  577. Routine Description:
  578. Retrieves the server-side IIS_CRYPTO_STORAGE object to be used for
  579. sending data to the client.
  580. Arguments:
  581. SendCryptoStorage - Receives a pointer to the newly created
  582. IIS_CRYPTO_STORAGE object if successful.
  583. Return Value:
  584. HRESULT - 0 if successful, !0 otherwise.
  585. --*/
  586. {
  587. if( m_SendCryptoStorage != NULL ) {
  588. *SendCryptoStorage = m_SendCryptoStorage;
  589. return NO_ERROR;
  590. }
  591. return MD_ERROR_SECURE_CHANNEL_FAILURE;
  592. } // ADM_SECURE_DATA::GetServerSendCryptoStorage
  593. HRESULT
  594. ADM_SECURE_DATA::GetServerReceiveCryptoStorage(
  595. OUT IIS_CRYPTO_STORAGE ** ReceiveCryptoStorage
  596. )
  597. /*++
  598. Routine Description:
  599. Retrieves the server-side IIS_CRYPTO_STORAGE object to be used for
  600. receiving data from the client.
  601. Arguments:
  602. ReceiveCryptoStorage - Receives a pointer to the newly created
  603. IIS_CRYPTO_STORAGE object if successful.
  604. Return Value:
  605. HRESULT - 0 if successful, !0 otherwise.
  606. --*/
  607. {
  608. if( m_ReceiveCryptoStorage != NULL ) {
  609. *ReceiveCryptoStorage = m_ReceiveCryptoStorage;
  610. return NO_ERROR;
  611. }
  612. return MD_ERROR_SECURE_CHANNEL_FAILURE;
  613. } // ADM_SECURE_DATA::GetServerReceiveCryptoStorage
  614. HRESULT
  615. ADM_SECURE_DATA::DoClientSideKeyExchange(
  616. IUnknown * Object
  617. )
  618. /*++
  619. Routine Description:
  620. Performs all the client-side magic necessary to exchange session
  621. keys with the server.
  622. Arguments:
  623. None.
  624. Return Value:
  625. HRESULT - 0 if successful, !0 otherwise.
  626. --*/
  627. {
  628. HRESULT result;
  629. HCRYPTPROV prov;
  630. IIS_CRYPTO_EXCHANGE_CLIENT * keyExchangeClient;
  631. IIS_CRYPTO_BLOB *clientKeyExchangeKeyBlob;
  632. IIS_CRYPTO_BLOB *clientSignatureKeyBlob;
  633. IIS_CRYPTO_BLOB *clientSessionKeyBlob;
  634. IIS_CRYPTO_BLOB *clientHashBlob;
  635. IIS_CRYPTO_BLOB *serverKeyExchangeKeyBlob;
  636. IIS_CRYPTO_BLOB *serverSignatureKeyBlob;
  637. IIS_CRYPTO_BLOB *serverSessionKeyBlob;
  638. IIS_CRYPTO_BLOB *serverHashBlob;
  639. //
  640. // Sanity check.
  641. //
  642. DBG_ASSERT( Object != NULL );
  643. DBG_ASSERT( m_KeyExchangeClient == NULL );
  644. DBG_ASSERT( m_SendCryptoStorage == NULL );
  645. DBG_ASSERT( m_ReceiveCryptoStorage == NULL );
  646. //
  647. // Setup locals so we know how to cleanup on exit.
  648. //
  649. keyExchangeClient = NULL;
  650. clientKeyExchangeKeyBlob = NULL;
  651. clientSignatureKeyBlob = NULL;
  652. clientSessionKeyBlob = NULL;
  653. clientHashBlob = NULL;
  654. serverKeyExchangeKeyBlob = NULL;
  655. serverSignatureKeyBlob = NULL;
  656. serverSessionKeyBlob = NULL;
  657. serverHashBlob = NULL;
  658. HANDLE hToken = NULL;
  659. if (OpenThreadToken( GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hToken ) ) {
  660. RevertToSelf();
  661. }
  662. //
  663. // Get the crypto provider to use.
  664. //
  665. DBG_CODE( prov = CRYPT_NULL );
  666. result = GetClientCryptoProvider( &prov );
  667. if( FAILED(result) ) {
  668. goto cleanup;
  669. }
  670. DBG_ASSERT( prov != CRYPT_NULL );
  671. //
  672. // Create & initialize the client-side key exchange object.
  673. //
  674. // N.B. Do not set the m_KeyExchangeClient to a non-NULL value
  675. // until key exchange is complete.
  676. //
  677. keyExchangeClient = new IIS_CRYPTO_EXCHANGE_CLIENT;
  678. if( keyExchangeClient == NULL ) {
  679. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  680. goto cleanup;
  681. }
  682. result = keyExchangeClient->Initialize(
  683. prov, // hProv
  684. CRYPT_NULL, // hKeyExchangeKey
  685. CRYPT_NULL, // hSignatureKey
  686. TRUE // fUseMachineKeyset was FALSE before fix for 213126
  687. );
  688. if( FAILED(result) ) {
  689. goto cleanup;
  690. }
  691. //
  692. // Phase 1: Get the client's key exchange and signature key blobs,
  693. // send them to the server, and get the server's key exchange,
  694. // signature, and session key blobs.
  695. //
  696. result = keyExchangeClient->ClientPhase1(
  697. &clientKeyExchangeKeyBlob,
  698. &clientSignatureKeyBlob
  699. );
  700. if( FAILED(result) ) {
  701. goto cleanup;
  702. }
  703. result = IMSAdminBaseW_R_KeyExchangePhase1_Proxy(
  704. (IMSAdminBaseW *)Object,
  705. clientKeyExchangeKeyBlob,
  706. clientSignatureKeyBlob,
  707. &serverKeyExchangeKeyBlob,
  708. &serverSignatureKeyBlob,
  709. &serverSessionKeyBlob
  710. );
  711. if( FAILED(result) ) {
  712. goto cleanup;
  713. }
  714. //
  715. // Phase 2: Import the server's key exchange, signature, and session
  716. // key blobs, get the client's session key and hash blobs, send them
  717. // to the server, and get the server's hash blob.
  718. //
  719. result = keyExchangeClient->ClientPhase2(
  720. serverKeyExchangeKeyBlob,
  721. serverSignatureKeyBlob,
  722. serverSessionKeyBlob,
  723. &clientSessionKeyBlob,
  724. &clientHashBlob
  725. );
  726. if( FAILED(result) ) {
  727. goto cleanup;
  728. }
  729. result = IMSAdminBaseW_R_KeyExchangePhase2_Proxy(
  730. (IMSAdminBaseW *)Object,
  731. clientSessionKeyBlob,
  732. clientHashBlob,
  733. &serverHashBlob
  734. );
  735. if( FAILED(result) ) {
  736. goto cleanup;
  737. }
  738. //
  739. // Phase 3: Import the server's hash blob.
  740. //
  741. result = keyExchangeClient->ClientPhase3(
  742. serverHashBlob
  743. );
  744. if( FAILED(result) ) {
  745. goto cleanup;
  746. }
  747. //
  748. // OK, the key exchange is complete. We just need to create the
  749. // appropriate storage objects.
  750. //
  751. m_SendCryptoStorage = new IIS_CRYPTO_STORAGE;
  752. if( m_SendCryptoStorage == NULL ) {
  753. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  754. goto cleanup;
  755. }
  756. result = m_SendCryptoStorage->Initialize(
  757. keyExchangeClient->QueryProviderHandle(), // hProv
  758. keyExchangeClient->AssumeClientSessionKey(), // hSessionKey
  759. CRYPT_NULL, // hKeyExchangeKey
  760. CRYPT_NULL, // hSignatureKey
  761. TRUE // fUseMachineKeyset was FALSE before fix for 213126
  762. );
  763. if( FAILED(result) ) {
  764. goto cleanup;
  765. }
  766. m_ReceiveCryptoStorage = new IIS_CRYPTO_STORAGE;
  767. if( m_ReceiveCryptoStorage == NULL ) {
  768. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  769. goto cleanup;
  770. }
  771. result = m_ReceiveCryptoStorage->Initialize(
  772. keyExchangeClient->QueryProviderHandle(), // hProv
  773. keyExchangeClient->AssumeServerSessionKey(), // hSessionKey
  774. CRYPT_NULL, // hKeyExchangeKey
  775. keyExchangeClient->AssumeServerSignatureKey(), // hSignatureKey
  776. TRUE // fUseMachineKeyset was FALSE before fix for 213126
  777. );
  778. if( FAILED(result) ) {
  779. goto cleanup;
  780. }
  781. //
  782. // Success!
  783. //
  784. m_KeyExchangeClient = keyExchangeClient;
  785. cleanup:
  786. //
  787. // Free any blobs we allocated.
  788. //
  789. FREE_BLOB( clientKeyExchangeKeyBlob );
  790. FREE_BLOB( clientSignatureKeyBlob );
  791. FREE_BLOB( clientSessionKeyBlob );
  792. FREE_BLOB( clientHashBlob );
  793. FREE_BLOB( serverKeyExchangeKeyBlob );
  794. FREE_BLOB( serverSignatureKeyBlob );
  795. FREE_BLOB( serverSessionKeyBlob );
  796. FREE_BLOB( serverHashBlob );
  797. //
  798. // If we're failing the call, then free the associated objects we
  799. // created.
  800. //
  801. if( FAILED(result) ) {
  802. delete keyExchangeClient;
  803. CleanupCryptoData();
  804. }
  805. if (hToken) {
  806. if( ImpersonateLoggedOnUser( hToken ) )
  807. {
  808. // Nothing needs to be done here
  809. }
  810. CloseHandle(hToken);
  811. hToken = NULL;
  812. }
  813. return result;
  814. } // ADM_SECURE_DATA::DoClientSideKeyExchange
  815. HRESULT
  816. ADM_SECURE_DATA::DoServerSideKeyExchangePhase1(
  817. IN PIIS_CRYPTO_BLOB pClientKeyExchangeKeyBlob,
  818. IN PIIS_CRYPTO_BLOB pClientSignatureKeyBlob,
  819. OUT PIIS_CRYPTO_BLOB * ppServerKeyExchangeKeyBlob,
  820. OUT PIIS_CRYPTO_BLOB * ppServerSignatureKeyBlob,
  821. OUT PIIS_CRYPTO_BLOB * ppServerSessionKeyBlob
  822. )
  823. /*++
  824. Routine Description:
  825. Performs the first phase of server-side key exchange.
  826. Arguments:
  827. pClientKeyExchangeKeyBlob - The client-side key exchange key blob.
  828. pClientSignatureKeyBlob - The client-side signature key blob.
  829. ppServerKeyExchangeKeyBlob - Receives a pointer to the server-side
  830. key exchange key blob if successful.
  831. ppServerSignatureKeyBlob - Receives a pointer to the server-side
  832. signature key blob if successful.
  833. ppServerSessionKeyBlob - Receives a pointer to the server-side session
  834. key blob if successful.
  835. Return Value:
  836. HRESULT - 0 if successful, !0 otherwise.
  837. --*/
  838. {
  839. HRESULT result;
  840. HCRYPTPROV prov;
  841. IIS_CRYPTO_EXCHANGE_SERVER * keyExchangeServer;
  842. //
  843. // Sanity check.
  844. //
  845. DBG_ASSERT( m_Object != NULL );
  846. DBG_ASSERT( m_KeyExchangeServer == NULL );
  847. DBG_ASSERT( m_SendCryptoStorage == NULL );
  848. DBG_ASSERT( m_ReceiveCryptoStorage == NULL );
  849. DBG_ASSERT( pClientKeyExchangeKeyBlob != NULL );
  850. DBG_ASSERT( pClientSignatureKeyBlob != NULL );
  851. DBG_ASSERT( ppServerKeyExchangeKeyBlob != NULL );
  852. DBG_ASSERT( ppServerSignatureKeyBlob != NULL );
  853. DBG_ASSERT( ppServerSessionKeyBlob != NULL );
  854. HANDLE hToken = NULL;
  855. if (OpenThreadToken( GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hToken ) ) {
  856. RevertToSelf();
  857. }
  858. //
  859. // Setup locals so we know how to cleanup on exit.
  860. //
  861. keyExchangeServer = NULL;
  862. //
  863. // Get the crypto provider to use.
  864. //
  865. DBG_CODE( prov = CRYPT_NULL );
  866. result = GetServerCryptoProvider( &prov );
  867. if( FAILED(result) ) {
  868. goto cleanup;
  869. }
  870. DBG_ASSERT( prov != CRYPT_NULL );
  871. //
  872. // Create & initialize the server-side key exchange object.
  873. //
  874. // N.B. Do not set the m_KeyExchangeServer to a non-NULL value
  875. // until key exchange is complete.
  876. //
  877. keyExchangeServer = new IIS_CRYPTO_EXCHANGE_SERVER;
  878. if( keyExchangeServer == NULL ) {
  879. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  880. goto cleanup;
  881. }
  882. result = keyExchangeServer->Initialize(
  883. prov, // hProv
  884. CRYPT_NULL, // hKeyExchangeKey
  885. CRYPT_NULL, // hSignatureKey
  886. FALSE // fUseMachineKeyset
  887. );
  888. if( FAILED(result) ) {
  889. goto cleanup;
  890. }
  891. //
  892. // Do the first phase of the key exchange.
  893. //
  894. result = keyExchangeServer->ServerPhase1(
  895. pClientKeyExchangeKeyBlob,
  896. pClientSignatureKeyBlob,
  897. ppServerKeyExchangeKeyBlob,
  898. ppServerSignatureKeyBlob,
  899. ppServerSessionKeyBlob
  900. );
  901. if( FAILED(result) ) {
  902. goto cleanup;
  903. }
  904. //
  905. // Success!
  906. //
  907. m_KeyExchangeServer = keyExchangeServer;
  908. cleanup:
  909. //
  910. // If we're failing the call, then free the associated objects we
  911. // created.
  912. //
  913. if( FAILED(result) ) {
  914. delete keyExchangeServer;
  915. }
  916. if (hToken) {
  917. if( ImpersonateLoggedOnUser( hToken ) )
  918. {
  919. // Don't need to anything here
  920. }
  921. CloseHandle(hToken);
  922. hToken = NULL;
  923. }
  924. return result;
  925. } // ADM_SECURE_DATA::DoServerSideKeyExchangePhase1
  926. HRESULT
  927. ADM_SECURE_DATA::DoServerSideKeyExchangePhase2(
  928. IN PIIS_CRYPTO_BLOB pClientSessionKeyBlob,
  929. IN PIIS_CRYPTO_BLOB pClientHashBlob,
  930. OUT PIIS_CRYPTO_BLOB * ppServerHashBlob
  931. )
  932. /*++
  933. Routine Description:
  934. Performs the second phase of server-side key exchange.
  935. Arguments:
  936. pClientSessionKeyBlob - The client-side session key blob.
  937. pClientHashBlob - The client-side hash blob.
  938. ppServerHashBlob - Receives a pointer to the server-side hash blob
  939. if successful.
  940. Return Value:
  941. HRESULT - 0 if successful, !0 otherwise.
  942. --*/
  943. {
  944. HRESULT result;
  945. //
  946. // Sanity check.
  947. //
  948. DBG_ASSERT( m_Object != NULL );
  949. DBG_ASSERT( m_KeyExchangeServer != NULL );
  950. DBG_ASSERT( m_SendCryptoStorage == NULL );
  951. DBG_ASSERT( m_ReceiveCryptoStorage == NULL );
  952. DBG_ASSERT( pClientSessionKeyBlob != NULL );
  953. DBG_ASSERT( pClientHashBlob != NULL );
  954. DBG_ASSERT( ppServerHashBlob != NULL );
  955. HANDLE hToken = NULL;
  956. if (OpenThreadToken( GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hToken ) ) {
  957. RevertToSelf();
  958. }
  959. //
  960. // Do the second phase of the key exchange.
  961. //
  962. result = m_KeyExchangeServer->ServerPhase2(
  963. pClientSessionKeyBlob,
  964. pClientHashBlob,
  965. ppServerHashBlob
  966. );
  967. if( FAILED(result) ) {
  968. goto cleanup;
  969. }
  970. //
  971. // OK, the key exchange is complete. We just need to create the
  972. // appropriate storage objects.
  973. //
  974. m_SendCryptoStorage = new IIS_CRYPTO_STORAGE;
  975. if( m_SendCryptoStorage == NULL ) {
  976. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  977. goto cleanup;
  978. }
  979. result = m_SendCryptoStorage->Initialize(
  980. m_KeyExchangeServer->QueryProviderHandle(), // hProv
  981. m_KeyExchangeServer->AssumeServerSessionKey(), // hSessionKey
  982. CRYPT_NULL, // hKeyExchangeKey
  983. CRYPT_NULL, // hSignatureKey
  984. FALSE // fUseMachineKeyset
  985. );
  986. if( FAILED(result) ) {
  987. goto cleanup;
  988. }
  989. m_ReceiveCryptoStorage = new IIS_CRYPTO_STORAGE;
  990. if( m_ReceiveCryptoStorage == NULL ) {
  991. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  992. goto cleanup;
  993. }
  994. result = m_ReceiveCryptoStorage->Initialize(
  995. m_KeyExchangeServer->QueryProviderHandle(), // hProv
  996. m_KeyExchangeServer->AssumeClientSessionKey(), // hSessionKey
  997. CRYPT_NULL, // hKeyExchangeKey
  998. m_KeyExchangeServer->AssumeClientSignatureKey(), // hSignatureKey
  999. FALSE // fUseMachineKeyset
  1000. );
  1001. if( FAILED(result) ) {
  1002. goto cleanup;
  1003. }
  1004. //
  1005. // Success!
  1006. //
  1007. cleanup:
  1008. //
  1009. // If we're failing the call, then free the associated objects we
  1010. // created.
  1011. //
  1012. if( FAILED(result) ) {
  1013. CleanupCryptoData();
  1014. }
  1015. if (hToken) {
  1016. if( ImpersonateLoggedOnUser( hToken ) )
  1017. {
  1018. // Don't need to do anything here
  1019. }
  1020. CloseHandle(hToken);
  1021. hToken = NULL;
  1022. }
  1023. return result;
  1024. } // ADM_SECURE_DATA::DoServerSideKeyExchangePhase2
  1025. HRESULT
  1026. ADM_SECURE_DATA::GetCryptoProviderHelper(
  1027. OUT HCRYPTPROV * UserProvider,
  1028. OUT HCRYPTPROV * CachedProvider,
  1029. IN LPTSTR ContainerName,
  1030. IN DWORD CryptoFlags
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Helper routine for GetServerCryptoProvider and GetClientCryptoProvider().
  1035. Provides necessary locking to ensure exactly one provider of each type
  1036. is opened.
  1037. Arguments:
  1038. UserProvider - Receives the handle to the provider.
  1039. CachedProvider - Also receives the handle to the provider.
  1040. ContainerName - The name of the container to open/create.
  1041. CryptoFlags - Flags to pass into IISCryptoGetStandardContainer().
  1042. Return Value:
  1043. HRESULT - 0 if successful, !0 otherwise.
  1044. --*/
  1045. {
  1046. HRESULT result = NO_ERROR;
  1047. HCRYPTPROV hprov;
  1048. //
  1049. // Sanity check.
  1050. //
  1051. DBG_ASSERT( UserProvider != NULL );
  1052. DBG_ASSERT( CachedProvider != NULL );
  1053. LockThis();
  1054. //
  1055. // Recheck the provider handle under the guard of the lock, just
  1056. // in case another thread has already created it.
  1057. //
  1058. hprov = *CachedProvider;
  1059. if( hprov == CRYPT_NULL ) {
  1060. //
  1061. // Open/create the container.
  1062. //
  1063. result = IIS_CRYPTO_BASE::GetCryptoContainerByName(
  1064. &hprov,
  1065. ContainerName,
  1066. CryptoFlags,
  1067. FALSE // fApplyAcl
  1068. );
  1069. }
  1070. if( SUCCEEDED(result) ) {
  1071. DBG_ASSERT( hprov != CRYPT_NULL );
  1072. *CachedProvider = hprov;
  1073. *UserProvider = hprov;
  1074. }
  1075. UnlockThis();
  1076. return result;
  1077. } // ADM_SECURE_DATA::GetCryptoProviderHelper
  1078. VOID
  1079. ADM_SECURE_DATA::CleanupCryptoData()
  1080. /*++
  1081. Routine Description:
  1082. Frees any crypto data associated with the current object.
  1083. Arguments:
  1084. None.
  1085. Return Value:
  1086. None.
  1087. --*/
  1088. {
  1089. delete m_KeyExchangeClient;
  1090. m_KeyExchangeClient = NULL;
  1091. delete m_KeyExchangeServer;
  1092. m_KeyExchangeServer = NULL;
  1093. delete m_SendCryptoStorage;
  1094. m_SendCryptoStorage = NULL;
  1095. delete m_ReceiveCryptoStorage;
  1096. m_ReceiveCryptoStorage = NULL;
  1097. } // ADM_SECURE_DATA::CleanupCryptoData
  1098. HRESULT
  1099. ADM_SECURE_DATA::GetClientCryptoProvider(
  1100. OUT HCRYPTPROV * Provider
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. This method calls down to GetCryptoProviderHelper to create key
  1105. and before that it prepares a name for key container
  1106. Arguments:
  1107. Provider - returns handle to provider
  1108. Return Value:
  1109. HRESULT error code if fail
  1110. --*/
  1111. {
  1112. HRESULT retVal = NO_ERROR;
  1113. if( sm_ClientCryptoProvider != CRYPT_NULL ) {
  1114. *Provider = sm_ClientCryptoProvider;
  1115. return retVal;
  1116. }
  1117. //
  1118. // Previously each user had a unique container name generated
  1119. // and keys would be stored persistently.
  1120. // Currently temporary container will be created to store temporary
  1121. // keys. This way the race condition will be prevented where multiple
  1122. // processes running under the same user identity would try to create
  1123. // container of the same name (and one would eventually fail)
  1124. //
  1125. retVal = GetCryptoProviderHelper( Provider,
  1126. &sm_ClientCryptoProvider,
  1127. NULL, // CREATE temporary container
  1128. 0
  1129. );
  1130. return retVal;
  1131. }
  1132. #define BUFSIZE_FOR_TOKEN 256
  1133. HRESULT
  1134. ADM_SECURE_DATA::GenerateNameForContainer(
  1135. IN OUT PCHAR pszContainerName,
  1136. IN DWORD dwBufferLen
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This method generates the name for crypoto container by taking some string
  1141. which has 'IIS client ' appending that with suer name and user SID for uniqueness
  1142. Arguments:
  1143. pszContainerName - pointer to a buffer which will receive a generated string
  1144. dwBufferLen - size of buffer suplied for receiving string
  1145. Return Value:
  1146. HRESULT
  1147. --*/
  1148. {
  1149. HANDLE hToken;
  1150. BYTE buf[BUFSIZE_FOR_TOKEN];
  1151. PTOKEN_USER ptgUser = (PTOKEN_USER)buf;
  1152. DWORD cbBuffer=BUFSIZE_FOR_TOKEN;
  1153. DWORD dwLenOfBuffer, dwLenOfBuffAvailable;
  1154. BOOL bSuccess;
  1155. PCHAR pszPlaceToAppend;
  1156. DWORD dwError;
  1157. //
  1158. // initialize string with some name for IIS client container
  1159. //
  1160. if (sizeof (DCOM_CLIENT_CONTAINER) >= dwBufferLen)
  1161. {
  1162. return RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
  1163. }
  1164. strcpy (pszContainerName, DCOM_CLIENT_CONTAINER);
  1165. dwLenOfBuffer = (DWORD)strlen(pszContainerName);
  1166. pszPlaceToAppend = pszContainerName + dwLenOfBuffer;
  1167. dwLenOfBuffAvailable = dwBufferLen - dwLenOfBuffer;
  1168. if ( !GetUserName(pszPlaceToAppend,&dwLenOfBuffAvailable) )
  1169. {
  1170. return RETURNCODETOHRESULT(GetLastError());
  1171. }
  1172. dwLenOfBuffer += dwLenOfBuffAvailable;
  1173. pszPlaceToAppend = pszContainerName + dwLenOfBuffer - 1;
  1174. dwLenOfBuffAvailable = dwBufferLen - dwLenOfBuffer - 1;
  1175. //
  1176. // obtain current process token
  1177. //
  1178. if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken ))
  1179. {
  1180. if(GetLastError() != ERROR_NO_TOKEN)
  1181. {
  1182. return RETURNCODETOHRESULT(GetLastError());
  1183. }
  1184. //
  1185. // retry against process token if no thread token exists
  1186. //
  1187. if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  1188. {
  1189. return RETURNCODETOHRESULT(GetLastError());
  1190. }
  1191. }
  1192. //
  1193. // obtain user identified by current process' access token
  1194. //
  1195. bSuccess = GetTokenInformation( hToken, // identifies access token
  1196. TokenUser, // TokenUser info type
  1197. ptgUser, // retrieved info buffer
  1198. cbBuffer, // size of buffer passed-in
  1199. &cbBuffer // required buffer size
  1200. );
  1201. if (!bSuccess)
  1202. {
  1203. dwError= GetLastError();
  1204. // close token handle. do this even if error above
  1205. CloseHandle(hToken);
  1206. return RETURNCODETOHRESULT(dwError);
  1207. }
  1208. // close token handle
  1209. CloseHandle(hToken);
  1210. //
  1211. // obtain the textual representaion of the Sid
  1212. //
  1213. return GetTextualSid( ptgUser->User.Sid, // user binary Sid
  1214. pszPlaceToAppend, // buffer for TextualSid
  1215. &dwLenOfBuffAvailable // size/required buffer
  1216. );
  1217. }
  1218. HRESULT
  1219. ADM_SECURE_DATA::GetTextualSid(
  1220. PSID pSid, // binary Sid
  1221. LPTSTR TextualSid, // buffer for Textual representaion of Sid
  1222. LPDWORD cchSidSize // required/provided TextualSid buffersize
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. Thsi method converts bianry SID to text representation
  1227. Arguments:
  1228. pSid - binary SID
  1229. TextualSid - buffer for Textual representaiton of SID
  1230. cchSidSize - required/provided TextualSid buffersize
  1231. Return Value:
  1232. HRESULT
  1233. --*/
  1234. {
  1235. PSID_IDENTIFIER_AUTHORITY psia;
  1236. DWORD dwSubAuthorities;
  1237. DWORD dwCounter;
  1238. DWORD cchSidCopy;
  1239. //
  1240. // test if Sid passed in is valid
  1241. //
  1242. if(!IsValidSid(pSid))
  1243. {
  1244. return RETURNCODETOHRESULT(ERROR_INVALID_SID);
  1245. }
  1246. // obtain SidIdentifierAuthority
  1247. psia = GetSidIdentifierAuthority(pSid);
  1248. // obtain sidsubauthority count
  1249. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  1250. //
  1251. // compute approximate buffer length
  1252. // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
  1253. //
  1254. cchSidCopy = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
  1255. //
  1256. // check provided buffer length.
  1257. // If not large enough, indicate proper size and setlasterror
  1258. //
  1259. if(*cchSidSize < cchSidCopy)
  1260. {
  1261. *cchSidSize = cchSidCopy;
  1262. return RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER);
  1263. }
  1264. //
  1265. // prepare S-SID_REVISION-
  1266. //
  1267. cchSidCopy = wsprintf(TextualSid, "S-%lu-", SID_REVISION );
  1268. //
  1269. // prepare SidIdentifierAuthority
  1270. //
  1271. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
  1272. {
  1273. cchSidCopy += wsprintf(TextualSid + cchSidCopy,
  1274. "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  1275. (USHORT)psia->Value[0],
  1276. (USHORT)psia->Value[1],
  1277. (USHORT)psia->Value[2],
  1278. (USHORT)psia->Value[3],
  1279. (USHORT)psia->Value[4],
  1280. (USHORT)psia->Value[5]);
  1281. }
  1282. else
  1283. {
  1284. cchSidCopy += wsprintf(TextualSid + cchSidCopy,
  1285. "%lu",
  1286. (ULONG)(psia->Value[5] ) +
  1287. (ULONG)(psia->Value[4] << 8) +
  1288. (ULONG)(psia->Value[3] << 16) +
  1289. (ULONG)(psia->Value[2] << 24) );
  1290. }
  1291. //
  1292. // loop through SidSubAuthorities
  1293. //
  1294. for(dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++)
  1295. {
  1296. cchSidCopy += wsprintf(TextualSid + cchSidCopy, "-%lu",
  1297. *GetSidSubAuthority(pSid, dwCounter) );
  1298. }
  1299. //
  1300. // tell the caller how many chars we provided, not including NULL
  1301. //
  1302. *cchSidSize = cchSidCopy;
  1303. return NO_ERROR;
  1304. }
  1305. ADM_GUID_MAP::ADM_GUID_MAP(
  1306. IN IUnknown * Object,
  1307. IN GUID guidServer
  1308. ):m_Object( Object ),
  1309. m_ReferenceCount( 1 ),
  1310. m_guidServer(guidServer)
  1311. /*++
  1312. Routine Description:
  1313. ADM_GUID_MAP object constructor.
  1314. Arguments:
  1315. Object - Pointer to the object to associate.
  1316. Return Value:
  1317. None.
  1318. --*/
  1319. {
  1320. //
  1321. // Sanity check.
  1322. //
  1323. DBG_ASSERT( Object != NULL );
  1324. DBG_ASSERT( guidServer != GUID_NULL );
  1325. //
  1326. // Initialize any complex data members.
  1327. //
  1328. INITIALIZE_CRITICAL_SECTION( &m_ObjectLock );
  1329. //
  1330. // Put ourselves on the list.
  1331. //
  1332. AcquireDataLock();
  1333. InsertHeadList( &sm_GuidMapListHead, &m_GuidMapListEntry );
  1334. ReleaseDataLock();
  1335. } // ADM_GUID_MAP::ADM_GUID_MAP
  1336. ADM_GUID_MAP::~ADM_GUID_MAP()
  1337. /*++
  1338. Routine Description:
  1339. ADM_SECURE_DATA object destructor.
  1340. Arguments:
  1341. None.
  1342. Return Value:
  1343. None.
  1344. --*/
  1345. {
  1346. //
  1347. // Sanity check.
  1348. //
  1349. DBG_ASSERT( m_ReferenceCount == 0 );
  1350. //
  1351. // AddRef the ADM_SECURE_DATA
  1352. // Do this here instead of constructor to
  1353. // all handing of errors.
  1354. //
  1355. ADM_SECURE_DATA *psecdatData;
  1356. psecdatData = ADM_SECURE_DATA::FindAndReferenceClientSecureData( this );
  1357. if (psecdatData != NULL) {
  1358. psecdatData->Dereference();
  1359. psecdatData->Dereference();
  1360. }
  1361. //
  1362. // Cleanup.
  1363. //
  1364. AcquireDataLock();
  1365. RemoveEntryList( &m_GuidMapListEntry );
  1366. ReleaseDataLock();
  1367. DeleteCriticalSection( &m_ObjectLock );
  1368. } // ADM_SECURE_DATA::~ADM_SECURE_DATA
  1369. VOID
  1370. ADM_GUID_MAP::Initialize( VOID
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. Initializes static global data private to ADM_SECURE_DATA.
  1375. Arguments:
  1376. hDll - Handle to this DLL.
  1377. Return Value:
  1378. None.
  1379. --*/
  1380. {
  1381. INITIALIZE_CRITICAL_SECTION( &sm_GuidMapDataLock );
  1382. #if DBG
  1383. sm_GuidMapLockOwner = 0;
  1384. sm_RefTraceLog = CreateRefTraceLog( 1024, 0 );
  1385. #endif
  1386. InitializeListHead( &sm_GuidMapListHead );
  1387. } // ADM_SECURE_DATA::Initialize
  1388. VOID
  1389. ADM_GUID_MAP::Terminate()
  1390. {
  1391. PLIST_ENTRY entry;
  1392. ADM_GUID_MAP * data;
  1393. //
  1394. // Free any secure data objects on our list.
  1395. //
  1396. AcquireDataLock();
  1397. entry = sm_GuidMapListHead.Flink;
  1398. while( entry != &sm_GuidMapListHead ) {
  1399. data = CONTAINING_RECORD(
  1400. entry,
  1401. ADM_GUID_MAP,
  1402. m_GuidMapListEntry
  1403. );
  1404. data->Dereference();
  1405. entry = sm_GuidMapListHead.Flink;
  1406. }
  1407. ReleaseDataLock();
  1408. DBG_ASSERT( IsListEmpty( &sm_GuidMapListHead ) );
  1409. //
  1410. // Final cleanup.
  1411. //
  1412. DeleteCriticalSection( &sm_GuidMapDataLock );
  1413. #if DBG
  1414. if( sm_RefTraceLog != NULL ) {
  1415. DestroyRefTraceLog( sm_RefTraceLog );
  1416. }
  1417. #endif
  1418. }
  1419. //
  1420. // Find and reference the ADM_GUID_MAP object associatd with the
  1421. // given object; create if not found.
  1422. //
  1423. ADM_GUID_MAP *
  1424. ADM_GUID_MAP::FindAndReferenceGuidMap(
  1425. IN IUnknown *Object )
  1426. {
  1427. PLIST_ENTRY entry;
  1428. ADM_GUID_MAP *pguidmapData;
  1429. AcquireDataLock();
  1430. for( entry = sm_GuidMapListHead.Flink ;
  1431. entry != &sm_GuidMapListHead ;
  1432. entry = entry->Flink )
  1433. {
  1434. pguidmapData = CONTAINING_RECORD( entry,
  1435. ADM_GUID_MAP,
  1436. m_GuidMapListEntry );
  1437. if( pguidmapData->m_Object == Object )
  1438. {
  1439. pguidmapData->Reference();
  1440. goto exit;
  1441. }
  1442. }
  1443. pguidmapData = NULL;
  1444. exit:
  1445. ReleaseDataLock();
  1446. return pguidmapData;
  1447. }