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.
 
 
 
 
 
 

957 lines
30 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: session.cxx
//
// Contents: TSession interfaces.
//
// History: 3-30-97 MohamedN Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#define DBINITCONSTANTS
#include <mparser.h>
#undef DBINITCONSTANTS
#include <session.hxx>
#include <stdqspec.hxx> // CQuerySpec
// Constants -----------------------------------------------------------------
// Session object interfaces that support ISupportErrorInfo
static const GUID* apSessionErrInt[] =
{
&IID_IDBCreateCommand,
&IID_IGetDataSource,
&IID_IOpenRowset,
&IID_ISessionProperties,
};
static const ULONG cSessionErrInt = NUMELEM( apSessionErrInt );
//+---------------------------------------------------------------------------
//
// Class: CDBSession::CDBSession
//
// Purpose: ctor
//
// History: 3-30-97 MohamedN Created
//
// Notes:
//
//----------------------------------------------------------------------------
CDBSession::CDBSession( CDataSrc & dataSrc,
IUnknown * pUnkOuter,
IUnknown ** ppUnkInner,
IParserSession * pIPSession,
HANDLE hToken ) :
_dataSrc(dataSrc),
#pragma warning(disable : 4355) // 'this' in ctor
_impIUnknown(this),
_ErrorInfo( * ((IUnknown *) (IOpenRowset *) this), _mtxSess ),
#pragma warning(default : 4355) // 'this' in ctor.
_xSessionToken( hToken )
{
_pUnkOuter = pUnkOuter ? pUnkOuter : (IUnknown *) &_impIUnknown;
_ErrorInfo.SetInterfaceArray( cSessionErrInt, apSessionErrInt );
_dataSrc.AddRef();
_dataSrc.IncSessionCount();
//
// SQL Text Parser
//
Win4Assert( pIPSession );
_xIPSession.Set( pIPSession );
_xIPSession->AddRef();
*ppUnkInner = (IUnknown *) &_impIUnknown;
(*ppUnkInner)->AddRef();
}
//+---------------------------------------------------------------------------
//
// Class: CDBSession::~CDBSession
//
// Purpose: dtor
//
// History: 3-30-97 MohamedN Created
//
// Notes:
//
//----------------------------------------------------------------------------
CDBSession::~CDBSession()
{
_dataSrc.DecSessionCount();
_dataSrc.Release();
}
//+---------------------------------------------------------------------------
//
// Member: CDBSession::RealQueryInterface
//
// Synopsis: Supports IID_IUnknown,
// IID_IGetDataSource,
// IID_IOpenRowset,
// IID_ISessionProperties,
// IID_IDBCreateCommand
// IID_ISupportErrorInfo
//
// History: 03-30-97 mohamedn created
// 10-18-97 danleg added ISupportErrorInfo Support
// 01-29-98 danleg non delegating QI when not aggregated
//----------------------------------------------------------------------------
STDMETHODIMP CDBSession::RealQueryInterface(REFIID riid, void **ppvObj )
{
SCODE sc = S_OK;
if ( !ppvObj )
return E_INVALIDARG;
*ppvObj = 0;
if ( riid == IID_IUnknown )
{
*ppvObj = (void *) ( (IUnknown *) (IOpenRowset *) this );
}
else if ( riid == IID_IGetDataSource )
{
*ppvObj = (void *) (IGetDataSource *) this;
}
else if ( riid == IID_ISessionProperties )
{
*ppvObj = (void *) (ISessionProperties *) this;
}
else if ( riid == IID_IOpenRowset )
{
*ppvObj = (void *) (IOpenRowset *) this;
}
else if ( riid == IID_IDBCreateCommand )
{
*ppvObj = (void *) (IDBCreateCommand *) this;
}
else if ( riid == IID_ISupportErrorInfo )
{
*ppvObj = (void *) ((IUnknown *) (ISupportErrorInfo *) &_ErrorInfo);
}
else
{
*ppvObj = 0;
sc = E_NOINTERFACE;
}
return sc;
} //RealQueryInterface
//+---------------------------------------------------------------------------
//
// Method: CDBSession::GetDataSource
//
// Synopsis: obtains the owning data source object
//
// Arguments: [riid] - interface to bind
// [ppDataSource] - interface returned here
//
// returns: S_OK, E_NOINTERFACE
//
// History: 3-30-97 mohamedn Created
// 11-20-97 danleg QI on OuterUnk
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CDBSession::GetDataSource( REFIID riid, IUnknown ** ppDataSource )
{
SCODE sc = S_OK;
// Clear previous Error Object for this thread
_ErrorInfo.ClearErrorInfo();
// Check Function Arguments
if ( 0 == ppDataSource )
return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IGetDataSource );
TRANSLATE_EXCEPTIONS;
TRY
{
CLock lck( _mtxSess );
*ppDataSource = 0;
sc = (_dataSrc.GetOuterUnk())->QueryInterface( riid, (void **)ppDataSource );
if ( FAILED(sc) )
THROW( CException(sc) );
}
CATCH( CException, e )
{
sc = _ErrorInfo.PostHResult( e, IID_IGetDataSource );
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return sc;
}
//+-------------------------------------------------------------------------
//
// Function: CDBSession::GetProperties
//
// Synopsis: gets ISessionProperties
//
// Arguments: [cPropertyIDSets] - number of desired property set IDs or 0
// [pPropIDSets] - array of desired property set IDs or NULL
// [pcPropertySets] - number of property sets returned
// [prgPropertySets] - array of returned property sets
//
// Returns: SCODE - result code indicating error return status. One of
// S_OK, DB_S_ERRORSOCCURRED, E_INVALIDARG.
//
// History: 03-30-97 mohamedn Created
// 10-30-97 danleg Changed to use common property code
//--------------------------------------------------------------------------
STDMETHODIMP CDBSession::GetProperties(ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
ULONG* pcProperties, DBPROPSET** prgProperties)
{
SCODE sc = S_OK;
// Clear previous Error Object for this thread
_ErrorInfo.ClearErrorInfo();
TRANSLATE_EXCEPTIONS;
TRY
{
CLock lck( _mtxSess );
_UtlProps.GetPropertiesArgChk( cPropertySets,
rgPropertySets,
pcProperties,
prgProperties );
sc = _UtlProps.GetProperties( cPropertySets,
rgPropertySets,
pcProperties,
prgProperties );
if ( FAILED(sc) )
THROW( CException(sc) );
}
CATCH( CException, e )
{
sc = _ErrorInfo.PostHResult( e, IID_ISessionProperties );
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: CDBSession::SetProperties
//
// Synopsis: sets ISessionProperties
//
// Arguments: [cPropertySets] - number of property sets
// [rgPropertySets] - array of property sets
//
// Returns: SCODE - result code indicating error return status. One of
// S_OK, DB_S_ERRORSOCCURRED, E_INVALIDARG.
//
// History: 03-30-97 mohamedn created
// 10-28-97 danleg Changed to use common property code
//----------------------------------------------------------------------------
STDMETHODIMP CDBSession::SetProperties(ULONG cPropertySets, DBPROPSET rgPropertySets[])
{
SCODE sc = S_OK;
// Win4Assert( _pCUtlProps );
// Clear previous Error Object for this thread
_ErrorInfo.ClearErrorInfo();
// Quick return if the Count of Properties is 0
if( cPropertySets == 0 )
return S_OK;
TRANSLATE_EXCEPTIONS;
TRY
{
CLock lck( _mtxSess );
_UtlProps.SetPropertiesArgChk( cPropertySets, rgPropertySets );
sc = _UtlProps.SetProperties( cPropertySets,
rgPropertySets);
if ( FAILED(sc) )
THROW( CException(sc) );
}
CATCH( CException, e )
{
sc = _ErrorInfo.PostHResult( e, IID_ISessionProperties );
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return sc;
}
//+---------------------------------------------------------------------------
//
// Method: CDBSession::CreateCommand
//
// Synopsis: Creates an ICommand object
//
// Arguments: [pUnkOuter] -- 'Outer' IUnknown
// [riid] -- Interface to bind
// [ppCommand] -- Interface returned here
//
//
// returns: SCODE of success or failure.
//
// History: 03-30-97 mohamedn Created
// 11-03-97 danleg Aggregation support & error posting
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CDBSession::CreateCommand
(
IUnknown * pUnkOuter,
REFIID riid,
IUnknown ** ppCommand
)
{
// Clear previous Error Object for this thread
_ErrorInfo.ClearErrorInfo();
// Check Function Arguments
if ( 0 == ppCommand )
return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBCreateCommand );
if (0 != pUnkOuter && riid != IID_IUnknown)
return _ErrorInfo.PostHResult( DB_E_NOAGGREGATION, IID_IDBCreateCommand );
*ppCommand = 0;
SCODE sc = S_OK;
CQuerySpec * pQuery = 0;
TRANSLATE_EXCEPTIONS;
TRY
{
IUnknown * pUnkInner = 0;
// Serialize access to this object.
CLock lck( _mtxSess );
pQuery = new CQuerySpec( pUnkOuter, &pUnkInner, this );
XInterface<IUnknown> xUnkInner( pUnkInner );
if ( IID_IUnknown == riid )
{
*ppCommand = pUnkInner;
}
else
{
sc = pUnkInner->QueryInterface( riid, (void **)ppCommand );
if ( FAILED(sc) )
{
Win4Assert( 0 == *ppCommand );
THROW( CException(sc) );
}
}
}
CATCH( CException, e )
{
sc = _ErrorInfo.PostHResult( e, IID_IDBCreateCommand );
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return sc;
} //CreateCommand
//
// Constants used by OpenRowset
//
static const WCHAR BASE_SELECT[] = L"SELECT Path, FileName, Size, Write,"\
L"Attrib, DocTitle, DocAuthor, DocSubject,"\
L"DocKeywords, Characterization FROM "\
L"SCOPE('SHALLOW TRAVERSAL OF %s')";
//Approx. size (Includes space for NULL-TERMINATOR, do not subtract this out)
const ULONG APPROX_CCH_BASE_SELECT = sizeof(BASE_SELECT) / sizeof(WCHAR);
//+---------------------------------------------------------------------------
//
// Method: CDBSession::OpenRowset
//
// Synopsis: Opens and returns a rowset that includes all rows from
// a single base table
//
// Arguments: [pUnkOuter] - Controlling unknown, if any
// [pTableID] - Table to open
// [pIndexID] - DBID of the index
// [riid] - Interface to return
// [cPropertySets] - Count of properties
// [rgPropertySets] - Array of property values
// [ppRowset] - Where to return interface
//
// Returns: S_OK - The method succeeded
// E_INVALIDARG - pTableID and pIndexId were NULL
// E_FAIL - Provider-specific error
// DB_E_NOTABLE - Specified table does not exist in current Data
// Data Source object
// E_OUTOFMEMORY - Out of memory
// E_NOINTERFACE - The requested interface was not available
//
// History: 10-26-97 danelg Created from Monarch
//
//----------------------------------------------------------------------------
STDMETHODIMP CDBSession::OpenRowset
(
IUnknown * pUnkOuter,
DBID * pTableID,
DBID * pIndexID,
REFIID riid,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
IUnknown ** ppRowset
)
{
ULONG ul, ul2;
SCODE sc = S_OK;
SCODE scProp = S_OK;
// Clear previous Error Object for this thread
_ErrorInfo.ClearErrorInfo();
// Intialize Buffer
if( ppRowset )
*ppRowset = NULL;
if ( 0 != pUnkOuter && IID_IUnknown != riid )
return _ErrorInfo.PostHResult( DB_E_NOAGGREGATION, IID_IOpenRowset );
// Check Arguments
if( (!pTableID && !pIndexID) )
return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IOpenRowset );
// We only accept NULL for pIndexID
if( pIndexID )
return _ErrorInfo.PostHResult( DB_E_NOINDEX, IID_IOpenRowset );
// If the eKind is not known to use, basically it
// means we have no table identifier
if( (!pTableID) ||
(pTableID->eKind != DBKIND_NAME) ||
((pTableID->eKind == DBKIND_NAME) && (!(pTableID->uName.pwszName))) ||
(wcslen(pTableID->uName.pwszName) == 0) )
return _ErrorInfo.PostHResult( DB_E_NOTABLE, IID_IOpenRowset );
// We do not allow the riid to be IID_NULL
if( riid == IID_NULL )
return _ErrorInfo.PostHResult( E_NOINTERFACE, IID_IOpenRowset );
TRANSLATE_EXCEPTIONS;
TRY
{
// Serialize access to this object.
CLock lck( _mtxSess );
XInterface<ICommandText> xICmdText;
IUnknown * pUnkInner;
// Check Arguments for use by properties
CUtlProps::SetPropertiesArgChk( cPropertySets, rgPropertySets );
//
// pUnkOuter is the outer unkown from the user on the Session
// object. Don't use pUnkOuter for the Command object here.
//
XInterface<CQuerySpec> xQuery(
new CQuerySpec(0, &pUnkInner, this) );
// Tell the command object to post errors as IOpenRowset
xQuery->ImpersonateOpenRowset();
// Construct and set Command. Allocate buffer for SQL Statement
XArray<WCHAR> xwszBuff( wcslen(pTableID->uName.pwszName) + APPROX_CCH_BASE_SELECT );
//@devnote: swprintf not supported on win95?
swprintf( xwszBuff.Get(), BASE_SELECT, pTableID->uName.pwszName );
sc = pUnkInner->QueryInterface( IID_ICommandText,
xICmdText.GetQIPointer() );
if( SUCCEEDED(sc) )
{
Win4Assert( !xICmdText.IsNull() );
sc = xICmdText->SetCommandText( DBGUID_SQL, xwszBuff.Get() );
// Process properties
if ( SUCCEEDED(sc) && cPropertySets > 0)
{
sc = SetOpenRowsetProperties(xICmdText.GetPointer(),
cPropertySets, rgPropertySets);
scProp = sc; // Save this retcode.
}
// Execute the SQL Statement if we were given a ppRowset
if ( SUCCEEDED(sc) && ppRowset )
{
sc = xICmdText->Execute( pUnkOuter, riid, 0, 0, ppRowset );
if ( DB_E_ERRORSOCCURRED == sc && (cPropertySets > 0) )
{
sc = MarkOpenRowsetProperties((xICmdText.GetPointer()),
cPropertySets, rgPropertySets);
}
}
}
sc = (sc == S_OK) ? scProp : sc;
if ( FAILED(sc) )
THROW( CException(sc) );
}
CATCH( CException, e )
{
sc = _ErrorInfo.PostHResult( e, IID_IOpenRowset );
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CDBSession::SetOpenRowsetProperties, private
//
// Synopsis: Loop through the passed in properties andmark those in error.
// Used by OpenRowset()
//
// History: 10-31-97 briants Created
//
//----------------------------------------------------------------------------
SCODE CDBSession::SetOpenRowsetProperties(
ICommandText* pICmdText,
ULONG cPropertySets,
DBPROPSET rgPropertySets[]
)
{
Win4Assert( pICmdText != NULL );
XInterface<ICommandProperties> xICmdProp;
SCODE sc = pICmdText->QueryInterface( IID_ICommandProperties,
(void **) xICmdProp.GetQIPointer() );
if( SUCCEEDED(sc) )
{
Win4Assert( !xICmdProp.IsNull() );
sc = xICmdProp->SetProperties( cPropertySets, rgPropertySets );
if ( (DB_E_ERRORSOCCURRED == sc) || (DB_S_ERRORSOCCURRED == sc) )
{
// If all the properties set were OPTIONAL then we can set our status to
// DB_S_ERRORSOCCURED and continue
for(ULONG ul=0;ul<cPropertySets; ul++)
{
for(ULONG ul2=0;ul2<rgPropertySets[ul].cProperties; ul2++)
{
// Check for a required property that failed, if found, we must return
// DB_E_ERRORSOCCURRED
if( (rgPropertySets[ul].rgProperties[ul2].dwStatus != DBPROPSTATUS_OK) &&
(rgPropertySets[ul].rgProperties[ul2].dwOptions != DBPROPOPTIONS_OPTIONAL) )
return DB_E_ERRORSOCCURRED;
}
}
sc = DB_S_ERRORSOCCURRED;
}
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CDBSession::MarkOpenRowsetProperties, private
//
// Synopsis: Loop through the passed in properties andmark those in error.
// Used by OpenRowset()
//
// History: 10-31-97 briants Created
//
//----------------------------------------------------------------------------
SCODE CDBSession::MarkOpenRowsetProperties(
ICommandText* pICmdText,
ULONG cPropertySets,
DBPROPSET rgPropertySets[]
)
{
Win4Assert( pICmdText != NULL );
XInterface<ICommandProperties> xICmdProp;
DBPROPSET * pPropSets = 0;
ULONG cPropSets = 0;
DBPROPIDSET dbPropIdSet[1];
dbPropIdSet[0].guidPropertySet = DBPROPSET_PROPERTIESINERROR;
dbPropIdSet[0].cPropertyIDs = 0;
dbPropIdSet[0].rgPropertyIDs = 0;
SCODE sc = pICmdText->QueryInterface( IID_ICommandProperties,
(void **) xICmdProp.GetQIPointer() );
if( SUCCEEDED(sc) )
{
Win4Assert( !xICmdProp.IsNull() );
sc = xICmdProp->GetProperties( 1,
dbPropIdSet,
&cPropSets,
&pPropSets );
if( SUCCEEDED(sc) )
{
XArrayOLEInPlace<CDbPropSet> xPropSets;
xPropSets.Set( cPropSets, (CDbPropSet *)pPropSets );
// Loop through all the properties in error and see if one
// of the passed in properties matches. If it matches, then
// transfer the in error status.
for(ULONG iSet=0; iSet<cPropSets; iSet++)
{
if( 0 == xPropSets[iSet].rgProperties ||
0 == xPropSets[iSet].cProperties )
continue;
for(ULONG iProp=0; iProp<xPropSets[iSet].cProperties; iProp++)
{
MarkPropInError( cPropertySets,
rgPropertySets,
&(xPropSets[iSet].guidPropertySet),
&(xPropSets[iSet].rgProperties[iProp]) );
// Clear variant value
VariantClear(&(xPropSets[iSet].rgProperties[iProp].vValue));
}
// Free the memory as we go through them
// CoTaskMemFree(xPropSets[iSet].rgProperties);
}
}
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CDBSession::MarkPropInError, private
//
// Synopsis: Loop through the passed in properties andmark those in error.
// Used by OpenRowset()
//
// History: 10-31-97 danleg Created
//
//----------------------------------------------------------------------------
void CDBSession::MarkPropInError
(
ULONG cPropertySets,
DBPROPSET* rgPropertySets,
GUID* pguidPropSet,
DBPROP* pProp
)
{
ULONG iSet, iProp;
Win4Assert( rgPropertySets );
for(iSet=0; iSet<cPropertySets; iSet++)
{
if( (rgPropertySets[iSet].guidPropertySet != *pguidPropSet) ||
(0 == rgPropertySets[iSet].rgProperties) ||
(0 == rgPropertySets[iSet].cProperties) )
continue;
for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
{
if( (rgPropertySets[iSet].rgProperties[iProp].dwPropertyID == pProp->dwPropertyID) &&
(rgPropertySets[iSet].rgProperties[iProp].dwStatus == DBPROPSTATUS_OK) )
{
rgPropertySets[iSet].rgProperties[iProp].dwStatus = pProp->dwStatus;
}
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CImpersonateSessionUser::CImpersonateSessionUser, public
//
// Purpose: ctor
//
// History: 01-23-99 danleg Created
//
//----------------------------------------------------------------------------
CImpersonateSessionUser::CImpersonateSessionUser( HANDLE hToken ) :
_fImpersonated( FALSE ),
_xSessionToken( INVALID_HANDLE_VALUE ),
_xPrevToken( INVALID_HANDLE_VALUE )
{
if ( INVALID_HANDLE_VALUE != hToken )
{
HANDLE hTempToken = DupToken( hToken );
if ( INVALID_HANDLE_VALUE != hTempToken )
_xSessionToken.Set( hTempToken );
CachePrevToken();
Impersonate();
}
} //CImpersonateSessionUser
//+---------------------------------------------------------------------------
//
// Member: CImpersonateSessionUser::~CImpersonateSessionUser, public
//
// Synopsis: dtor
//
// History: 01-23-99 danleg Created
//
//----------------------------------------------------------------------------
CImpersonateSessionUser::~CImpersonateSessionUser()
{
TRY
{
Revert();
}
CATCH( CException, e )
{
//
// Ignore failures in unwind paths -- the query will fail. If we
// can't revert here the ole db client has to realize the thread
// may be in a bad state after a query failure.
//
}
END_CATCH
BOOL fSuccess = TRUE;
} //~CImpersonateSessionUser
//+---------------------------------------------------------------------------
//
// Member: CImpersonateSessionUser::Revert, public
//
// Synopsis: Reverts the thread to the original state
//
// History: 02-11-02 dlee Created from ~, so we have a form that
// can fail.
//
//----------------------------------------------------------------------------
void CImpersonateSessionUser::Revert()
{
BOOL fSuccess = TRUE;
if ( INVALID_HANDLE_VALUE == _xPrevToken.Get() )
{
//
// There is no need to revert to self here if we didn't impersonate
// in the first place -- if there was no token or there was no
// session object. If you revert here then IIS threads become
// system.
//
if ( _fImpersonated )
{
fSuccess = RevertToSelf();
if ( fSuccess )
_fImpersonated = FALSE;
}
}
else
{
fSuccess = ImpersonateLoggedOnUser( _xPrevToken.Get() );
_xPrevToken.Free();
}
if ( !fSuccess )
{
DWORD dwError = GetLastError();
vqDebugOut(( DEB_ERROR,
"CImpersonateSessionUser::Revert: Impersonation failed with error %d\n",
dwError ));
THROW( CException( HRESULT_FROM_WIN32( dwError ) ) );
}
} //Revert
//+---------------------------------------------------------------------------
//
// Member: CImpersonateSessionUser:: DupToken, private
//
// Synopsis: Duplicate the session token for the current thread
//
// History: 01-23-99 danleg Created
//
//----------------------------------------------------------------------------
HANDLE CImpersonateSessionUser::DupToken( HANDLE hToken )
{
SECURITY_QUALITY_OF_SERVICE qos;
qos.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
qos.ImpersonationLevel = SecurityImpersonation;
qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
qos.EffectiveOnly = FALSE;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes( &ObjAttr,
NULL,
0,
NULL,
NULL );
ObjAttr.SecurityQualityOfService = &qos;
HANDLE hNewToken = INVALID_HANDLE_VALUE;
NTSTATUS status = NtDuplicateToken( hToken,
TOKEN_IMPERSONATE|TOKEN_QUERY,
&ObjAttr,
FALSE,
TokenImpersonation,
&hNewToken );
if ( !NT_SUCCESS(status) )
{
vqDebugOut(( DEB_ERROR,
"DupToken failed to duplicate token, %x\n",
status ));
THROW( CException( status ) );
}
return hNewToken;
} //DupToken
//+---------------------------------------------------------------------------
//
// Member: CImpersonateSessionUser:: CachePrevToken, private
//
// Synopsis: If the current thread is already impersonated, cache its
// impersonation token so it can be restored later.
//
// History: 01-23-99 danleg Created
//
//----------------------------------------------------------------------------
void CImpersonateSessionUser::CachePrevToken()
{
DWORD dwLength;
TOKEN_STATISTICS TokenInformation;
HANDLE hToken = INVALID_HANDLE_VALUE;
NTSTATUS status = NtOpenThreadToken( GetCurrentThread(),
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE,
TRUE,
&hToken);
if ( NT_SUCCESS(status) )
{
SHandle xHandle( hToken );
//
// If this thread is already impersonated, cache its impersonation
// token and impersonate using the session (i.e. logon) token
//
status = NtQueryInformationToken ( hToken,
TokenStatistics,
(LPVOID)&TokenInformation,
sizeof TokenInformation,
&dwLength);
if ( NT_SUCCESS(status) )
{
if ( TokenInformation.TokenType == TokenImpersonation )
{
HANDLE hTempToken = DupToken( hToken );
if ( INVALID_HANDLE_VALUE != hTempToken )
_xPrevToken.Set( hTempToken );
}
}
else // NtQueryInformation failed
{
vqDebugOut(( DEB_ERROR,
"CImpersonateSessionUser failed to query token information, %x\n",
status ));
THROW( CException( status ) );
}
}
else // NtOpenThreadToken failed
{
//
// If it's STATUS_NO_TOKEN then there isn't anything to capture and we
// can ignore impersonation for this query.
//
if ( STATUS_NO_TOKEN != status )
{
vqDebugOut(( DEB_ERROR,
"CImpersonateSessionUser failed to open thread token, %x\n",
status ));
THROW( CException( status ) );
}
}
} //CachePrevToken
//+---------------------------------------------------------------------------
//
// Member: CImpersonateSessionUser::Impersonate, private
//
// Synopsis: Impersonate the user who created the OLE DB session.
//
// History: 01-23-99 danleg Created
//
//----------------------------------------------------------------------------
void CImpersonateSessionUser::Impersonate()
{
if ( INVALID_HANDLE_VALUE == _xSessionToken.Get() )
return;
BOOL fSuccess = ImpersonateLoggedOnUser( _xSessionToken.Get() );
if ( fSuccess )
_fImpersonated = TRUE;
else
{
DWORD dwError = GetLastError();
vqDebugOut(( DEB_ERROR,
"CImpersonateSessionUser failed to impersonate, %d\n",
dwError ));
THROW( CException( HRESULT_FROM_WIN32( dwError ) ) );
}
} //Impersonate