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.

957 lines
29 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: session.cxx
  7. //
  8. // Contents: TSession interfaces.
  9. //
  10. // History: 3-30-97 MohamedN Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #define DBINITCONSTANTS
  16. #include <mparser.h>
  17. #undef DBINITCONSTANTS
  18. #include <session.hxx>
  19. #include <stdqspec.hxx> // CQuerySpec
  20. // Constants -----------------------------------------------------------------
  21. // Session object interfaces that support ISupportErrorInfo
  22. static const GUID* apSessionErrInt[] =
  23. {
  24. &IID_IDBCreateCommand,
  25. &IID_IGetDataSource,
  26. &IID_IOpenRowset,
  27. &IID_ISessionProperties,
  28. };
  29. static const ULONG cSessionErrInt = NUMELEM( apSessionErrInt );
  30. //+---------------------------------------------------------------------------
  31. //
  32. // Class: CDBSession::CDBSession
  33. //
  34. // Purpose: ctor
  35. //
  36. // History: 3-30-97 MohamedN Created
  37. //
  38. // Notes:
  39. //
  40. //----------------------------------------------------------------------------
  41. CDBSession::CDBSession( CDataSrc & dataSrc,
  42. IUnknown * pUnkOuter,
  43. IUnknown ** ppUnkInner,
  44. IParserSession * pIPSession,
  45. HANDLE hToken ) :
  46. _dataSrc(dataSrc),
  47. #pragma warning(disable : 4355) // 'this' in ctor
  48. _impIUnknown(this),
  49. _ErrorInfo( * ((IUnknown *) (IOpenRowset *) this), _mtxSess ),
  50. #pragma warning(default : 4355) // 'this' in ctor.
  51. _xSessionToken( hToken )
  52. {
  53. _pUnkOuter = pUnkOuter ? pUnkOuter : (IUnknown *) &_impIUnknown;
  54. _ErrorInfo.SetInterfaceArray( cSessionErrInt, apSessionErrInt );
  55. _dataSrc.AddRef();
  56. _dataSrc.IncSessionCount();
  57. //
  58. // SQL Text Parser
  59. //
  60. Win4Assert( pIPSession );
  61. _xIPSession.Set( pIPSession );
  62. _xIPSession->AddRef();
  63. *ppUnkInner = (IUnknown *) &_impIUnknown;
  64. (*ppUnkInner)->AddRef();
  65. }
  66. //+---------------------------------------------------------------------------
  67. //
  68. // Class: CDBSession::~CDBSession
  69. //
  70. // Purpose: dtor
  71. //
  72. // History: 3-30-97 MohamedN Created
  73. //
  74. // Notes:
  75. //
  76. //----------------------------------------------------------------------------
  77. CDBSession::~CDBSession()
  78. {
  79. _dataSrc.DecSessionCount();
  80. _dataSrc.Release();
  81. }
  82. //+---------------------------------------------------------------------------
  83. //
  84. // Member: CDBSession::RealQueryInterface
  85. //
  86. // Synopsis: Supports IID_IUnknown,
  87. // IID_IGetDataSource,
  88. // IID_IOpenRowset,
  89. // IID_ISessionProperties,
  90. // IID_IDBCreateCommand
  91. // IID_ISupportErrorInfo
  92. //
  93. // History: 03-30-97 mohamedn created
  94. // 10-18-97 danleg added ISupportErrorInfo Support
  95. // 01-29-98 danleg non delegating QI when not aggregated
  96. //----------------------------------------------------------------------------
  97. STDMETHODIMP CDBSession::RealQueryInterface(REFIID riid, void **ppvObj )
  98. {
  99. SCODE sc = S_OK;
  100. if ( !ppvObj )
  101. return E_INVALIDARG;
  102. *ppvObj = 0;
  103. if ( riid == IID_IUnknown )
  104. {
  105. *ppvObj = (void *) ( (IUnknown *) (IOpenRowset *) this );
  106. }
  107. else if ( riid == IID_IGetDataSource )
  108. {
  109. *ppvObj = (void *) (IGetDataSource *) this;
  110. }
  111. else if ( riid == IID_ISessionProperties )
  112. {
  113. *ppvObj = (void *) (ISessionProperties *) this;
  114. }
  115. else if ( riid == IID_IOpenRowset )
  116. {
  117. *ppvObj = (void *) (IOpenRowset *) this;
  118. }
  119. else if ( riid == IID_IDBCreateCommand )
  120. {
  121. *ppvObj = (void *) (IDBCreateCommand *) this;
  122. }
  123. else if ( riid == IID_ISupportErrorInfo )
  124. {
  125. *ppvObj = (void *) ((IUnknown *) (ISupportErrorInfo *) &_ErrorInfo);
  126. }
  127. else
  128. {
  129. *ppvObj = 0;
  130. sc = E_NOINTERFACE;
  131. }
  132. return sc;
  133. } //RealQueryInterface
  134. //+---------------------------------------------------------------------------
  135. //
  136. // Method: CDBSession::GetDataSource
  137. //
  138. // Synopsis: obtains the owning data source object
  139. //
  140. // Arguments: [riid] - interface to bind
  141. // [ppDataSource] - interface returned here
  142. //
  143. // returns: S_OK, E_NOINTERFACE
  144. //
  145. // History: 3-30-97 mohamedn Created
  146. // 11-20-97 danleg QI on OuterUnk
  147. // Notes:
  148. //
  149. //----------------------------------------------------------------------------
  150. STDMETHODIMP CDBSession::GetDataSource( REFIID riid, IUnknown ** ppDataSource )
  151. {
  152. SCODE sc = S_OK;
  153. // Clear previous Error Object for this thread
  154. _ErrorInfo.ClearErrorInfo();
  155. // Check Function Arguments
  156. if ( 0 == ppDataSource )
  157. return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IGetDataSource );
  158. TRANSLATE_EXCEPTIONS;
  159. TRY
  160. {
  161. CLock lck( _mtxSess );
  162. *ppDataSource = 0;
  163. sc = (_dataSrc.GetOuterUnk())->QueryInterface( riid, (void **)ppDataSource );
  164. if ( FAILED(sc) )
  165. THROW( CException(sc) );
  166. }
  167. CATCH( CException, e )
  168. {
  169. sc = _ErrorInfo.PostHResult( e, IID_IGetDataSource );
  170. }
  171. END_CATCH;
  172. UNTRANSLATE_EXCEPTIONS;
  173. return sc;
  174. }
  175. //+-------------------------------------------------------------------------
  176. //
  177. // Function: CDBSession::GetProperties
  178. //
  179. // Synopsis: gets ISessionProperties
  180. //
  181. // Arguments: [cPropertyIDSets] - number of desired property set IDs or 0
  182. // [pPropIDSets] - array of desired property set IDs or NULL
  183. // [pcPropertySets] - number of property sets returned
  184. // [prgPropertySets] - array of returned property sets
  185. //
  186. // Returns: SCODE - result code indicating error return status. One of
  187. // S_OK, DB_S_ERRORSOCCURRED, E_INVALIDARG.
  188. //
  189. // History: 03-30-97 mohamedn Created
  190. // 10-30-97 danleg Changed to use common property code
  191. //--------------------------------------------------------------------------
  192. STDMETHODIMP CDBSession::GetProperties(ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
  193. ULONG* pcProperties, DBPROPSET** prgProperties)
  194. {
  195. SCODE sc = S_OK;
  196. // Clear previous Error Object for this thread
  197. _ErrorInfo.ClearErrorInfo();
  198. TRANSLATE_EXCEPTIONS;
  199. TRY
  200. {
  201. CLock lck( _mtxSess );
  202. _UtlProps.GetPropertiesArgChk( cPropertySets,
  203. rgPropertySets,
  204. pcProperties,
  205. prgProperties );
  206. sc = _UtlProps.GetProperties( cPropertySets,
  207. rgPropertySets,
  208. pcProperties,
  209. prgProperties );
  210. if ( FAILED(sc) )
  211. THROW( CException(sc) );
  212. }
  213. CATCH( CException, e )
  214. {
  215. sc = _ErrorInfo.PostHResult( e, IID_ISessionProperties );
  216. }
  217. END_CATCH;
  218. UNTRANSLATE_EXCEPTIONS;
  219. return sc;
  220. }
  221. //+---------------------------------------------------------------------------
  222. //
  223. // Function: CDBSession::SetProperties
  224. //
  225. // Synopsis: sets ISessionProperties
  226. //
  227. // Arguments: [cPropertySets] - number of property sets
  228. // [rgPropertySets] - array of property sets
  229. //
  230. // Returns: SCODE - result code indicating error return status. One of
  231. // S_OK, DB_S_ERRORSOCCURRED, E_INVALIDARG.
  232. //
  233. // History: 03-30-97 mohamedn created
  234. // 10-28-97 danleg Changed to use common property code
  235. //----------------------------------------------------------------------------
  236. STDMETHODIMP CDBSession::SetProperties(ULONG cPropertySets, DBPROPSET rgPropertySets[])
  237. {
  238. SCODE sc = S_OK;
  239. // Win4Assert( _pCUtlProps );
  240. // Clear previous Error Object for this thread
  241. _ErrorInfo.ClearErrorInfo();
  242. // Quick return if the Count of Properties is 0
  243. if( cPropertySets == 0 )
  244. return S_OK;
  245. TRANSLATE_EXCEPTIONS;
  246. TRY
  247. {
  248. CLock lck( _mtxSess );
  249. _UtlProps.SetPropertiesArgChk( cPropertySets, rgPropertySets );
  250. sc = _UtlProps.SetProperties( cPropertySets,
  251. rgPropertySets);
  252. if ( FAILED(sc) )
  253. THROW( CException(sc) );
  254. }
  255. CATCH( CException, e )
  256. {
  257. sc = _ErrorInfo.PostHResult( e, IID_ISessionProperties );
  258. }
  259. END_CATCH;
  260. UNTRANSLATE_EXCEPTIONS;
  261. return sc;
  262. }
  263. //+---------------------------------------------------------------------------
  264. //
  265. // Method: CDBSession::CreateCommand
  266. //
  267. // Synopsis: Creates an ICommand object
  268. //
  269. // Arguments: [pUnkOuter] -- 'Outer' IUnknown
  270. // [riid] -- Interface to bind
  271. // [ppCommand] -- Interface returned here
  272. //
  273. //
  274. // returns: SCODE of success or failure.
  275. //
  276. // History: 03-30-97 mohamedn Created
  277. // 11-03-97 danleg Aggregation support & error posting
  278. //
  279. // Notes:
  280. //
  281. //----------------------------------------------------------------------------
  282. STDMETHODIMP CDBSession::CreateCommand
  283. (
  284. IUnknown * pUnkOuter,
  285. REFIID riid,
  286. IUnknown ** ppCommand
  287. )
  288. {
  289. // Clear previous Error Object for this thread
  290. _ErrorInfo.ClearErrorInfo();
  291. // Check Function Arguments
  292. if ( 0 == ppCommand )
  293. return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBCreateCommand );
  294. if (0 != pUnkOuter && riid != IID_IUnknown)
  295. return _ErrorInfo.PostHResult( DB_E_NOAGGREGATION, IID_IDBCreateCommand );
  296. *ppCommand = 0;
  297. SCODE sc = S_OK;
  298. CQuerySpec * pQuery = 0;
  299. TRANSLATE_EXCEPTIONS;
  300. TRY
  301. {
  302. IUnknown * pUnkInner = 0;
  303. // Serialize access to this object.
  304. CLock lck( _mtxSess );
  305. pQuery = new CQuerySpec( pUnkOuter, &pUnkInner, this );
  306. XInterface<IUnknown> xUnkInner( pUnkInner );
  307. if ( IID_IUnknown == riid )
  308. {
  309. *ppCommand = pUnkInner;
  310. }
  311. else
  312. {
  313. sc = pUnkInner->QueryInterface( riid, (void **)ppCommand );
  314. if ( FAILED(sc) )
  315. {
  316. Win4Assert( 0 == *ppCommand );
  317. THROW( CException(sc) );
  318. }
  319. }
  320. }
  321. CATCH( CException, e )
  322. {
  323. sc = _ErrorInfo.PostHResult( e, IID_IDBCreateCommand );
  324. }
  325. END_CATCH;
  326. UNTRANSLATE_EXCEPTIONS;
  327. return sc;
  328. } //CreateCommand
  329. //
  330. // Constants used by OpenRowset
  331. //
  332. static const WCHAR BASE_SELECT[] = L"SELECT Path, FileName, Size, Write,"\
  333. L"Attrib, DocTitle, DocAuthor, DocSubject,"\
  334. L"DocKeywords, Characterization FROM "\
  335. L"SCOPE('SHALLOW TRAVERSAL OF %s')";
  336. //Approx. size (Includes space for NULL-TERMINATOR, do not subtract this out)
  337. const ULONG APPROX_CCH_BASE_SELECT = sizeof(BASE_SELECT) / sizeof(WCHAR);
  338. //+---------------------------------------------------------------------------
  339. //
  340. // Method: CDBSession::OpenRowset
  341. //
  342. // Synopsis: Opens and returns a rowset that includes all rows from
  343. // a single base table
  344. //
  345. // Arguments: [pUnkOuter] - Controlling unknown, if any
  346. // [pTableID] - Table to open
  347. // [pIndexID] - DBID of the index
  348. // [riid] - Interface to return
  349. // [cPropertySets] - Count of properties
  350. // [rgPropertySets] - Array of property values
  351. // [ppRowset] - Where to return interface
  352. //
  353. // Returns: S_OK - The method succeeded
  354. // E_INVALIDARG - pTableID and pIndexId were NULL
  355. // E_FAIL - Provider-specific error
  356. // DB_E_NOTABLE - Specified table does not exist in current Data
  357. // Data Source object
  358. // E_OUTOFMEMORY - Out of memory
  359. // E_NOINTERFACE - The requested interface was not available
  360. //
  361. // History: 10-26-97 danelg Created from Monarch
  362. //
  363. //----------------------------------------------------------------------------
  364. STDMETHODIMP CDBSession::OpenRowset
  365. (
  366. IUnknown * pUnkOuter,
  367. DBID * pTableID,
  368. DBID * pIndexID,
  369. REFIID riid,
  370. ULONG cPropertySets,
  371. DBPROPSET rgPropertySets[],
  372. IUnknown ** ppRowset
  373. )
  374. {
  375. ULONG ul, ul2;
  376. SCODE sc = S_OK;
  377. SCODE scProp = S_OK;
  378. // Clear previous Error Object for this thread
  379. _ErrorInfo.ClearErrorInfo();
  380. // Intialize Buffer
  381. if( ppRowset )
  382. *ppRowset = NULL;
  383. if ( 0 != pUnkOuter && IID_IUnknown != riid )
  384. return _ErrorInfo.PostHResult( DB_E_NOAGGREGATION, IID_IOpenRowset );
  385. // Check Arguments
  386. if( (!pTableID && !pIndexID) )
  387. return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IOpenRowset );
  388. // We only accept NULL for pIndexID
  389. if( pIndexID )
  390. return _ErrorInfo.PostHResult( DB_E_NOINDEX, IID_IOpenRowset );
  391. // If the eKind is not known to use, basically it
  392. // means we have no table identifier
  393. if( (!pTableID) ||
  394. (pTableID->eKind != DBKIND_NAME) ||
  395. ((pTableID->eKind == DBKIND_NAME) && (!(pTableID->uName.pwszName))) ||
  396. (wcslen(pTableID->uName.pwszName) == 0) )
  397. return _ErrorInfo.PostHResult( DB_E_NOTABLE, IID_IOpenRowset );
  398. // We do not allow the riid to be IID_NULL
  399. if( riid == IID_NULL )
  400. return _ErrorInfo.PostHResult( E_NOINTERFACE, IID_IOpenRowset );
  401. TRANSLATE_EXCEPTIONS;
  402. TRY
  403. {
  404. // Serialize access to this object.
  405. CLock lck( _mtxSess );
  406. XInterface<ICommandText> xICmdText;
  407. IUnknown * pUnkInner;
  408. // Check Arguments for use by properties
  409. CUtlProps::SetPropertiesArgChk( cPropertySets, rgPropertySets );
  410. //
  411. // pUnkOuter is the outer unkown from the user on the Session
  412. // object. Don't use pUnkOuter for the Command object here.
  413. //
  414. XInterface<CQuerySpec> xQuery(
  415. new CQuerySpec(0, &pUnkInner, this) );
  416. // Tell the command object to post errors as IOpenRowset
  417. xQuery->ImpersonateOpenRowset();
  418. // Construct and set Command. Allocate buffer for SQL Statement
  419. XArray<WCHAR> xwszBuff( wcslen(pTableID->uName.pwszName) + APPROX_CCH_BASE_SELECT );
  420. //@devnote: swprintf not supported on win95?
  421. swprintf( xwszBuff.Get(), BASE_SELECT, pTableID->uName.pwszName );
  422. sc = pUnkInner->QueryInterface( IID_ICommandText,
  423. xICmdText.GetQIPointer() );
  424. if( SUCCEEDED(sc) )
  425. {
  426. Win4Assert( !xICmdText.IsNull() );
  427. sc = xICmdText->SetCommandText( DBGUID_SQL, xwszBuff.Get() );
  428. // Process properties
  429. if ( SUCCEEDED(sc) && cPropertySets > 0)
  430. {
  431. sc = SetOpenRowsetProperties(xICmdText.GetPointer(),
  432. cPropertySets, rgPropertySets);
  433. scProp = sc; // Save this retcode.
  434. }
  435. // Execute the SQL Statement if we were given a ppRowset
  436. if ( SUCCEEDED(sc) && ppRowset )
  437. {
  438. sc = xICmdText->Execute( pUnkOuter, riid, 0, 0, ppRowset );
  439. if ( DB_E_ERRORSOCCURRED == sc && (cPropertySets > 0) )
  440. {
  441. sc = MarkOpenRowsetProperties((xICmdText.GetPointer()),
  442. cPropertySets, rgPropertySets);
  443. }
  444. }
  445. }
  446. sc = (sc == S_OK) ? scProp : sc;
  447. if ( FAILED(sc) )
  448. THROW( CException(sc) );
  449. }
  450. CATCH( CException, e )
  451. {
  452. sc = _ErrorInfo.PostHResult( e, IID_IOpenRowset );
  453. }
  454. END_CATCH;
  455. UNTRANSLATE_EXCEPTIONS;
  456. return sc;
  457. }
  458. //+---------------------------------------------------------------------------
  459. //
  460. // Member: CDBSession::SetOpenRowsetProperties, private
  461. //
  462. // Synopsis: Loop through the passed in properties andmark those in error.
  463. // Used by OpenRowset()
  464. //
  465. // History: 10-31-97 briants Created
  466. //
  467. //----------------------------------------------------------------------------
  468. SCODE CDBSession::SetOpenRowsetProperties(
  469. ICommandText* pICmdText,
  470. ULONG cPropertySets,
  471. DBPROPSET rgPropertySets[]
  472. )
  473. {
  474. Win4Assert( pICmdText != NULL );
  475. XInterface<ICommandProperties> xICmdProp;
  476. SCODE sc = pICmdText->QueryInterface( IID_ICommandProperties,
  477. (void **) xICmdProp.GetQIPointer() );
  478. if( SUCCEEDED(sc) )
  479. {
  480. Win4Assert( !xICmdProp.IsNull() );
  481. sc = xICmdProp->SetProperties( cPropertySets, rgPropertySets );
  482. if ( (DB_E_ERRORSOCCURRED == sc) || (DB_S_ERRORSOCCURRED == sc) )
  483. {
  484. // If all the properties set were OPTIONAL then we can set our status to
  485. // DB_S_ERRORSOCCURED and continue
  486. for(ULONG ul=0;ul<cPropertySets; ul++)
  487. {
  488. for(ULONG ul2=0;ul2<rgPropertySets[ul].cProperties; ul2++)
  489. {
  490. // Check for a required property that failed, if found, we must return
  491. // DB_E_ERRORSOCCURRED
  492. if( (rgPropertySets[ul].rgProperties[ul2].dwStatus != DBPROPSTATUS_OK) &&
  493. (rgPropertySets[ul].rgProperties[ul2].dwOptions != DBPROPOPTIONS_OPTIONAL) )
  494. return DB_E_ERRORSOCCURRED;
  495. }
  496. }
  497. sc = DB_S_ERRORSOCCURRED;
  498. }
  499. }
  500. return sc;
  501. }
  502. //+---------------------------------------------------------------------------
  503. //
  504. // Member: CDBSession::MarkOpenRowsetProperties, private
  505. //
  506. // Synopsis: Loop through the passed in properties andmark those in error.
  507. // Used by OpenRowset()
  508. //
  509. // History: 10-31-97 briants Created
  510. //
  511. //----------------------------------------------------------------------------
  512. SCODE CDBSession::MarkOpenRowsetProperties(
  513. ICommandText* pICmdText,
  514. ULONG cPropertySets,
  515. DBPROPSET rgPropertySets[]
  516. )
  517. {
  518. Win4Assert( pICmdText != NULL );
  519. XInterface<ICommandProperties> xICmdProp;
  520. DBPROPSET * pPropSets = 0;
  521. ULONG cPropSets = 0;
  522. DBPROPIDSET dbPropIdSet[1];
  523. dbPropIdSet[0].guidPropertySet = DBPROPSET_PROPERTIESINERROR;
  524. dbPropIdSet[0].cPropertyIDs = 0;
  525. dbPropIdSet[0].rgPropertyIDs = 0;
  526. SCODE sc = pICmdText->QueryInterface( IID_ICommandProperties,
  527. (void **) xICmdProp.GetQIPointer() );
  528. if( SUCCEEDED(sc) )
  529. {
  530. Win4Assert( !xICmdProp.IsNull() );
  531. sc = xICmdProp->GetProperties( 1,
  532. dbPropIdSet,
  533. &cPropSets,
  534. &pPropSets );
  535. if( SUCCEEDED(sc) )
  536. {
  537. XArrayOLEInPlace<CDbPropSet> xPropSets;
  538. xPropSets.Set( cPropSets, (CDbPropSet *)pPropSets );
  539. // Loop through all the properties in error and see if one
  540. // of the passed in properties matches. If it matches, then
  541. // transfer the in error status.
  542. for(ULONG iSet=0; iSet<cPropSets; iSet++)
  543. {
  544. if( 0 == xPropSets[iSet].rgProperties ||
  545. 0 == xPropSets[iSet].cProperties )
  546. continue;
  547. for(ULONG iProp=0; iProp<xPropSets[iSet].cProperties; iProp++)
  548. {
  549. MarkPropInError( cPropertySets,
  550. rgPropertySets,
  551. &(xPropSets[iSet].guidPropertySet),
  552. &(xPropSets[iSet].rgProperties[iProp]) );
  553. // Clear variant value
  554. VariantClear(&(xPropSets[iSet].rgProperties[iProp].vValue));
  555. }
  556. // Free the memory as we go through them
  557. // CoTaskMemFree(xPropSets[iSet].rgProperties);
  558. }
  559. }
  560. }
  561. return sc;
  562. }
  563. //+---------------------------------------------------------------------------
  564. //
  565. // Member: CDBSession::MarkPropInError, private
  566. //
  567. // Synopsis: Loop through the passed in properties andmark those in error.
  568. // Used by OpenRowset()
  569. //
  570. // History: 10-31-97 danleg Created
  571. //
  572. //----------------------------------------------------------------------------
  573. void CDBSession::MarkPropInError
  574. (
  575. ULONG cPropertySets,
  576. DBPROPSET* rgPropertySets,
  577. GUID* pguidPropSet,
  578. DBPROP* pProp
  579. )
  580. {
  581. ULONG iSet, iProp;
  582. Win4Assert( rgPropertySets );
  583. for(iSet=0; iSet<cPropertySets; iSet++)
  584. {
  585. if( (rgPropertySets[iSet].guidPropertySet != *pguidPropSet) ||
  586. (0 == rgPropertySets[iSet].rgProperties) ||
  587. (0 == rgPropertySets[iSet].cProperties) )
  588. continue;
  589. for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
  590. {
  591. if( (rgPropertySets[iSet].rgProperties[iProp].dwPropertyID == pProp->dwPropertyID) &&
  592. (rgPropertySets[iSet].rgProperties[iProp].dwStatus == DBPROPSTATUS_OK) )
  593. {
  594. rgPropertySets[iSet].rgProperties[iProp].dwStatus = pProp->dwStatus;
  595. }
  596. }
  597. }
  598. }
  599. //+---------------------------------------------------------------------------
  600. //
  601. // Member: CImpersonateSessionUser::CImpersonateSessionUser, public
  602. //
  603. // Purpose: ctor
  604. //
  605. // History: 01-23-99 danleg Created
  606. //
  607. //----------------------------------------------------------------------------
  608. CImpersonateSessionUser::CImpersonateSessionUser( HANDLE hToken ) :
  609. _fImpersonated( FALSE ),
  610. _xSessionToken( INVALID_HANDLE_VALUE ),
  611. _xPrevToken( INVALID_HANDLE_VALUE )
  612. {
  613. if ( INVALID_HANDLE_VALUE != hToken )
  614. {
  615. HANDLE hTempToken = DupToken( hToken );
  616. if ( INVALID_HANDLE_VALUE != hTempToken )
  617. _xSessionToken.Set( hTempToken );
  618. CachePrevToken();
  619. Impersonate();
  620. }
  621. } //CImpersonateSessionUser
  622. //+---------------------------------------------------------------------------
  623. //
  624. // Member: CImpersonateSessionUser::~CImpersonateSessionUser, public
  625. //
  626. // Synopsis: dtor
  627. //
  628. // History: 01-23-99 danleg Created
  629. //
  630. //----------------------------------------------------------------------------
  631. CImpersonateSessionUser::~CImpersonateSessionUser()
  632. {
  633. TRY
  634. {
  635. Revert();
  636. }
  637. CATCH( CException, e )
  638. {
  639. //
  640. // Ignore failures in unwind paths -- the query will fail. If we
  641. // can't revert here the ole db client has to realize the thread
  642. // may be in a bad state after a query failure.
  643. //
  644. }
  645. END_CATCH
  646. BOOL fSuccess = TRUE;
  647. } //~CImpersonateSessionUser
  648. //+---------------------------------------------------------------------------
  649. //
  650. // Member: CImpersonateSessionUser::Revert, public
  651. //
  652. // Synopsis: Reverts the thread to the original state
  653. //
  654. // History: 02-11-02 dlee Created from ~, so we have a form that
  655. // can fail.
  656. //
  657. //----------------------------------------------------------------------------
  658. void CImpersonateSessionUser::Revert()
  659. {
  660. BOOL fSuccess = TRUE;
  661. if ( INVALID_HANDLE_VALUE == _xPrevToken.Get() )
  662. {
  663. //
  664. // There is no need to revert to self here if we didn't impersonate
  665. // in the first place -- if there was no token or there was no
  666. // session object. If you revert here then IIS threads become
  667. // system.
  668. //
  669. if ( _fImpersonated )
  670. {
  671. fSuccess = RevertToSelf();
  672. if ( fSuccess )
  673. _fImpersonated = FALSE;
  674. }
  675. }
  676. else
  677. {
  678. fSuccess = ImpersonateLoggedOnUser( _xPrevToken.Get() );
  679. _xPrevToken.Free();
  680. }
  681. if ( !fSuccess )
  682. {
  683. DWORD dwError = GetLastError();
  684. vqDebugOut(( DEB_ERROR,
  685. "CImpersonateSessionUser::Revert: Impersonation failed with error %d\n",
  686. dwError ));
  687. THROW( CException( HRESULT_FROM_WIN32( dwError ) ) );
  688. }
  689. } //Revert
  690. //+---------------------------------------------------------------------------
  691. //
  692. // Member: CImpersonateSessionUser:: DupToken, private
  693. //
  694. // Synopsis: Duplicate the session token for the current thread
  695. //
  696. // History: 01-23-99 danleg Created
  697. //
  698. //----------------------------------------------------------------------------
  699. HANDLE CImpersonateSessionUser::DupToken( HANDLE hToken )
  700. {
  701. SECURITY_QUALITY_OF_SERVICE qos;
  702. qos.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  703. qos.ImpersonationLevel = SecurityImpersonation;
  704. qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  705. qos.EffectiveOnly = FALSE;
  706. OBJECT_ATTRIBUTES ObjAttr;
  707. InitializeObjectAttributes( &ObjAttr,
  708. NULL,
  709. 0,
  710. NULL,
  711. NULL );
  712. ObjAttr.SecurityQualityOfService = &qos;
  713. HANDLE hNewToken = INVALID_HANDLE_VALUE;
  714. NTSTATUS status = NtDuplicateToken( hToken,
  715. TOKEN_IMPERSONATE|TOKEN_QUERY,
  716. &ObjAttr,
  717. FALSE,
  718. TokenImpersonation,
  719. &hNewToken );
  720. if ( !NT_SUCCESS(status) )
  721. {
  722. vqDebugOut(( DEB_ERROR,
  723. "DupToken failed to duplicate token, %x\n",
  724. status ));
  725. THROW( CException( status ) );
  726. }
  727. return hNewToken;
  728. } //DupToken
  729. //+---------------------------------------------------------------------------
  730. //
  731. // Member: CImpersonateSessionUser:: CachePrevToken, private
  732. //
  733. // Synopsis: If the current thread is already impersonated, cache its
  734. // impersonation token so it can be restored later.
  735. //
  736. // History: 01-23-99 danleg Created
  737. //
  738. //----------------------------------------------------------------------------
  739. void CImpersonateSessionUser::CachePrevToken()
  740. {
  741. DWORD dwLength;
  742. TOKEN_STATISTICS TokenInformation;
  743. HANDLE hToken = INVALID_HANDLE_VALUE;
  744. NTSTATUS status = NtOpenThreadToken( GetCurrentThread(),
  745. TOKEN_QUERY |
  746. TOKEN_DUPLICATE |
  747. TOKEN_IMPERSONATE,
  748. TRUE,
  749. &hToken);
  750. if ( NT_SUCCESS(status) )
  751. {
  752. SHandle xHandle( hToken );
  753. //
  754. // If this thread is already impersonated, cache its impersonation
  755. // token and impersonate using the session (i.e. logon) token
  756. //
  757. status = NtQueryInformationToken ( hToken,
  758. TokenStatistics,
  759. (LPVOID)&TokenInformation,
  760. sizeof TokenInformation,
  761. &dwLength);
  762. if ( NT_SUCCESS(status) )
  763. {
  764. if ( TokenInformation.TokenType == TokenImpersonation )
  765. {
  766. HANDLE hTempToken = DupToken( hToken );
  767. if ( INVALID_HANDLE_VALUE != hTempToken )
  768. _xPrevToken.Set( hTempToken );
  769. }
  770. }
  771. else // NtQueryInformation failed
  772. {
  773. vqDebugOut(( DEB_ERROR,
  774. "CImpersonateSessionUser failed to query token information, %x\n",
  775. status ));
  776. THROW( CException( status ) );
  777. }
  778. }
  779. else // NtOpenThreadToken failed
  780. {
  781. //
  782. // If it's STATUS_NO_TOKEN then there isn't anything to capture and we
  783. // can ignore impersonation for this query.
  784. //
  785. if ( STATUS_NO_TOKEN != status )
  786. {
  787. vqDebugOut(( DEB_ERROR,
  788. "CImpersonateSessionUser failed to open thread token, %x\n",
  789. status ));
  790. THROW( CException( status ) );
  791. }
  792. }
  793. } //CachePrevToken
  794. //+---------------------------------------------------------------------------
  795. //
  796. // Member: CImpersonateSessionUser::Impersonate, private
  797. //
  798. // Synopsis: Impersonate the user who created the OLE DB session.
  799. //
  800. // History: 01-23-99 danleg Created
  801. //
  802. //----------------------------------------------------------------------------
  803. void CImpersonateSessionUser::Impersonate()
  804. {
  805. if ( INVALID_HANDLE_VALUE == _xSessionToken.Get() )
  806. return;
  807. BOOL fSuccess = ImpersonateLoggedOnUser( _xSessionToken.Get() );
  808. if ( fSuccess )
  809. _fImpersonated = TRUE;
  810. else
  811. {
  812. DWORD dwError = GetLastError();
  813. vqDebugOut(( DEB_ERROR,
  814. "CImpersonateSessionUser failed to impersonate, %d\n",
  815. dwError ));
  816. THROW( CException( HRESULT_FROM_WIN32( dwError ) ) );
  817. }
  818. } //Impersonate