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.
 
 
 
 
 
 

1609 lines
45 KiB

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: csession.cxx
//
// Contents: Microsoft OleDB/OleDS Session object for ADSI
//
//
// History: 08-01-96 shanksh Created.
//
//----------------------------------------------------------------------------
#include "oleds.hxx"
#pragma hdrstop
#include "atl.h"
#include "row.hxx"
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::GetDataSource
//
// Synopsis: Retrieve an interface pointer on the session object
//
// Arguments:
// riid, IID desired
// ppDSO ptr to interface
//
//
// Returns:
// S_OK Session Object Interface returned
// E_INVALIDARG ppDSO was NULL
// E_NOINTERFACE IID not supported
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::GetDataSource (
REFIID riid,
IUnknown ** ppDSO
)
{
//
// Asserts
//
ADsAssert(_pDSO);
if( ppDSO == NULL )
RRETURN( E_INVALIDARG );
RRETURN( _pDSO->QueryInterface(riid, (LPVOID*)ppDSO) );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::GetDataSource
//
// Synopsis: Retrieve an interface pointer on the session object
//
// Arguments:
// riid, IID desired
// ppDSO ptr to interface
//
//
// Returns:
// S_OK Session Object Interface returned
// E_INVALIDARG ppDSO was NULL
// E_NOINTERFACE IID not supported
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::OpenRowset(
IUnknown * pUnkOuter,
DBID * pTableID,
DBID * pIndexID,
REFIID riid,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
IUnknown ** ppRowset
)
{
// Don't pass any credentials (NULL)
RRETURN( OpenRowsetWithCredentials(
pUnkOuter,
pTableID,
pIndexID,
riid,
cPropertySets,
rgPropertySets,
NULL,
ppRowset) );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::OpenRowsetWithCredentials
//
// Synopsis: Opens a rowset. Similar to OpenRowset but takes extra argument
// CCredentials. This function is used when consumer calls
// IBindResource::Bind requesting a rowset.
//
// Returns : HRESULT
//
//----------------------------------------------------------------------------
HRESULT
CSessionObject::OpenRowsetWithCredentials (
IUnknown * pUnkOuter,
DBID * pTableID,
DBID * pIndexID,
REFIID riid,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
CCredentials * pCredentials,
IUnknown ** ppRowset
)
{
BOOL fWarning = FALSE;
CRowProvider *pRowProvider = NULL;
DWORD cAttrs = 1;
BOOL *pbMultiValue = NULL;
LPWSTR *pAttrs = NULL;
//
// Check in-params and NULL out-params in case of error
//
if( ppRowset )
*ppRowset = NULL;
if( !pTableID && !pIndexID )
RRETURN( E_INVALIDARG );
if( pIndexID )
RRETURN( DB_E_NOINDEX );
//
// Check the PropertySets
//
if( cPropertySets > 0 && !rgPropertySets )
RRETURN ( E_INVALIDARG );
for(ULONG i=0; i<cPropertySets; i++) {
if( rgPropertySets[i].cProperties && !rgPropertySets[i].rgProperties )
RRETURN ( E_INVALIDARG );
}
//
// pwszName field represents the ADsPath of the Directory we have to open;
// Make sure pwszName is meaningful
//
if( !pTableID || pTableID->eKind != DBKIND_NAME ||
!pTableID->uName.pwszName || !(*(pTableID->uName.pwszName)) )
RRETURN( DB_E_NOTABLE );
if( pUnkOuter )//&& !InlineIsEqualGUID(riid, IID_IUnknown) )
RRETURN( DB_E_NOAGGREGATION );
if( riid == IID_NULL )
RRETURN( E_NOINTERFACE );
//
// By default, we use credentials stored in member variable _Credentials
// for binding. Buf if caller passed any credentials through pCredentials,
// these take precedence. This also means that we need to store these
// credentials in the CRowProvider object for future use -
// e.g. GetRowFromHRow will use these credentials.
//
CCredentials * pCreds = &_Credentials;
if( pCredentials )
pCreds = pCredentials;
//
// If integrated security is being used, impersonate the caller
//
BOOL fImpersonating;
fImpersonating = FALSE;
if(_pDSO->IsIntegratedSecurity())
{
HANDLE ThreadToken = _pDSO->GetThreadToken();
ASSERT(ThreadToken != NULL);
if (ThreadToken)
{
if (!ImpersonateLoggedOnUser(ThreadToken))
RRETURN(E_FAIL);
fImpersonating = TRUE;
}
else
RRETURN(E_FAIL);
}
HRESULT hr = GetDSInterface(
pTableID->uName.pwszName,
*pCreds,
IID_IDirectorySearch,
(void **)&_pDSSearch);
if (fImpersonating)
{
RevertToSelf();
fImpersonating = FALSE;
}
if( FAILED(hr) )
RRETURN( hr );
//
// Get ColumnsInfo based on the list of attributes that we want to be
// returned. GetDefaultColumnInfo cleansup memory on failure.
//
ULONG cColumns = 0;
DBCOLUMNINFO * prgInfo = NULL;
WCHAR * pStringBuffer = NULL;
hr = GetDefaultColumnInfo(&cColumns, &prgInfo, &pStringBuffer);
if( FAILED(hr) )
RRETURN( hr );
// Store the properties (which must be in the rowset property group) in
// the property object. OpenRowset is different from methods like
// ICOmmand::SetProperties and ISessionProperties::SetProperties in that
// it returns DB_E_ERROSOCCURRED if any property which is REQUIRED could
// not be set and DB_S_ERROROCCURRED if any property that is OPTIONAL
// could not be set. ICommand::SetProperties returns DB_E_ERROSOCCURRED
// if all properties could not be set and DB_S_ERROSOCCURRED if some
// property could not be set i.e, DBPROPOPTIONS (REQUIRED or OPTIONAL) is
// ignored.
// Use PROPSET_COMMAND as the bitmask below since the properties that are
// going to be set are in the rowset property group. These properties that
// are stored in the property object cannot be retrieved by the client
// since GetProperties on a session object will only return properties in
// the session property group.
hr = _pUtilProp->SetProperties(
cPropertySets,
rgPropertySets,
PROPSET_COMMAND
);
if( (DB_E_ERRORSOCCURRED == hr) || (DB_S_ERRORSOCCURRED == hr) )
// check if a required property could not be set
{
ULONG i, j;
for(i = 0; i < cPropertySets; i++)
for(j = 0; j < rgPropertySets[i].cProperties; j++)
if( rgPropertySets[i].rgProperties[j].dwStatus !=
DBPROPSTATUS_OK )
if( rgPropertySets[i].rgProperties[j].dwOptions !=
DBPROPOPTIONS_OPTIONAL )
{
BAIL_ON_FAILURE( hr = DB_E_ERRORSOCCURRED );
}
else
fWarning = TRUE;
// if we get here, then there was all required properties were set
// successfully. However, hr could still be DB_ERRORSOCCURRED if all
// properties were optional and all of them could not be set. This
// condition is not an error for OpenRowset as noted in the comment
// above. Hence reset hr to S_OK.
hr = S_OK;
}
// we still need to catch other errors like E_INAVLIDARG
BAIL_ON_FAILURE(hr);
hr = SetSearchPrefs();
BAIL_ON_FAILURE( hr );
//
// Create RowProvider object to pass to rowset code
//
pbMultiValue = (BOOL *)AllocADsMem(sizeof(BOOL));
pAttrs = (LPWSTR *)AllocADsMem(cAttrs * sizeof(LPWSTR));
if( pAttrs )
pAttrs[0] = AllocADsStr(L"ADsPath");
if( !pAttrs || !pAttrs[0] || !pbMultiValue )
BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
*pbMultiValue = FALSE;
_pDSSearch->AddRef();
// Is this an NDS path? If so, set filter appropriately. Fix for #286560.
WCHAR lpszProgId[MAX_PATH];
BOOL fIsNds;
hr = CopyADsProgId(pTableID->uName.pwszName, lpszProgId);
BAIL_ON_FAILURE( hr );
if( !wcscmp(L"NDS", lpszProgId) )
fIsNds = TRUE;
else
fIsNds = FALSE;
hr = CRowProvider::CreateRowProvider(
_pDSSearch,
NULL,
pAttrs,
cAttrs,
cColumns,
prgInfo,
pStringBuffer,
IID_IRowProvider,
pbMultiValue,
TRUE,
pCreds,
(void **) &pRowProvider
);
BAIL_ON_FAILURE( hr );
//
// RowProvider responsible for deallocation
//
pbMultiValue = NULL;
hr= CRowset::CreateRowset(
pRowProvider,
(LPUNKNOWN)(IAccessor FAR *)this ,
this,
NULL,
cPropertySets,
rgPropertySets,
0,
NULL,
TRUE, // ADsPath is requested
FALSE, // not all attributes are requested
riid,
ppRowset
);
BAIL_ON_FAILURE( hr );
error:
if( _pDSSearch ) {
_pDSSearch->Release();
_pDSSearch = NULL;
}
if( pRowProvider )
pRowProvider->Release();
if( prgInfo )
_pIMalloc->Free(prgInfo);
if( pStringBuffer )
_pIMalloc->Free(pStringBuffer);
if( pbMultiValue )
FreeADsMem(pbMultiValue);
if (pAttrs)
{
for (i = 0; i < cAttrs; i++)
{
if (pAttrs[i])
FreeADsStr(pAttrs[0]);
}
FreeADsMem(pAttrs);
}
if( FAILED(hr) )
RRETURN( hr );
else if( fWarning )
RRETURN( DB_S_ERRORSOCCURRED );
else
RRETURN( hr );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::GetProperties
//
// Synopsis: Returns current settings of all properties in the DBPROPFLAGS_SESSION property
// group
//
// Arguments:
// cPropertySets count of restiction guids
// rgPropertySets restriction guids
// pcProperties count of properties returned
// prgProperties property information returned
//
// Returns:
// S_OK Session Object Interface returned
// E_INVALIDARG pcProperties or prgPropertyInfo was NULL
// E_OUTOFMEMORY Out of memory
//
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::GetProperties(
ULONG cPropIDSets,
const DBPROPIDSET rgPropIDSets[],
ULONG * pcPropSets,
DBPROPSET ** pprgPropSets
)
{
//
// Asserts
//
ADsAssert(_pUtilProp);
//
// Check in-params and NULL out-params in case of error
//
HRESULT hr = _pUtilProp->GetPropertiesArgChk(
cPropIDSets,
rgPropIDSets,
pcPropSets,
pprgPropSets,
PROPSET_SESSION);
if( FAILED(hr) )
RRETURN( hr );
//
// Just pass this call on to the utility object that manages our properties
//
RRETURN( _pUtilProp->GetProperties(
cPropIDSets,
rgPropIDSets,
pcPropSets,
pprgPropSets,
PROPSET_SESSION) );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::SetProperties
//
// Synopsis: Set properties in the DBPROPFLAGS_SESSION property group
//
// Arguments:
// cProperties
// rgProperties
//
// Returns:
// S_OK Session Object Interface returned
// E_INVALIDARG pcProperties or prgPropertyInfo was NULL
// E_OUTOFMEMORY Out of memory
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::SetProperties(
ULONG cPropertySets,
DBPROPSET rgPropertySets[]
)
{
//
// Asserts
//
ADsAssert(_pUtilProp);
//
// Just pass this call on to the utility object that manages our properties
//
RRETURN( _pUtilProp->SetProperties(
cPropertySets,
rgPropertySets,
PROPSET_SESSION) );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::CreateCommand
//
// Synopsis: Creates a brand new command and returns requested interface
//
// Arguments:
// pUnkOuter outer Unknown
// riid, IID desired
// ppCommand ptr to interface
//
//
// Returns:
// S_OK Command Object Interface returned
// E_INVALIDARG ppCommand was NULL
// E_NOINTERFACE IID not supported
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::CreateCommand(
IUnknown * pUnkOuter,
REFIID riid,
IUnknown ** ppCommand
)
{
CCommandObject* pCommand = NULL;
HRESULT hr;
//
// check in-params and NULL out-params in case of error
//
if( ppCommand )
*ppCommand = NULL;
else
RRETURN( E_INVALIDARG );
if( pUnkOuter )//&& !InlineIsEqualGUID(riid, IID_IUnknown) )
RRETURN( DB_E_NOAGGREGATION );
//
// open a CCommand object
//
pCommand = new CCommandObject(pUnkOuter);
if( !pCommand )
RRETURN( E_OUTOFMEMORY );
//
// initialize the object
//
if( !pCommand->FInit(this, _Credentials) ) {
delete pCommand;
RRETURN( E_OUTOFMEMORY );
}
//
// get requested interface pointer on DBSession
//
hr = pCommand->QueryInterface(riid, (void **)ppCommand);
if( FAILED( hr ) ) {
delete pCommand;
RRETURN( hr );
}
pCommand->Release();
//
// all went well
//
RRETURN( S_OK );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::GetDefaultColumnInfo
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::GetDefaultColumnInfo(
ULONG * pcColumns,
DBCOLUMNINFO ** prgInfo,
OLECHAR ** ppStringBuffer
)
{
//
// Asserts
//
ADsAssert(_pIMalloc);
ADsAssert(pcColumns);
ADsAssert(prgInfo);
ADsAssert(ppStringBuffer);
//
// Allcoate memory for the Bookmark and ADsPath column
//
*prgInfo = (DBCOLUMNINFO*)_pIMalloc->Alloc(2 * sizeof(DBCOLUMNINFO));
*ppStringBuffer = (WCHAR*)_pIMalloc->Alloc((wcslen(L"ADsPath") + 1) * sizeof(WCHAR));
//
// Free memory on a failure
//
if( !(*prgInfo) )
RRETURN( E_OUTOFMEMORY );
if( !(*ppStringBuffer) ) {
_pIMalloc->Free(*prgInfo);
*prgInfo = NULL;
RRETURN( E_OUTOFMEMORY );
}
//
// Initialize the memory
//
ZeroMemory(*prgInfo, 2 * sizeof(DBCOLUMNINFO));
ZeroMemory(*ppStringBuffer, (wcslen(L"ADsPath") + 1) * sizeof(WCHAR));
wcscpy(*ppStringBuffer, OLESTR("ADsPath"));
//
// Fill up the Bookmark column
//
*pcColumns = 2;
(*prgInfo)[0].pwszName = NULL;
(*prgInfo)[0].pTypeInfo = NULL;
(*prgInfo)[0].iOrdinal = 0;
(*prgInfo)[0].ulColumnSize = sizeof(ULONG);
(*prgInfo)[0].wType = DBTYPE_UI4;
(*prgInfo)[0].bPrecision = 10;
(*prgInfo)[0].bScale = (BYTE) ~ 0;
(*prgInfo)[0].columnid.eKind = DBKIND_GUID_PROPID;
(*prgInfo)[0].columnid.uGuid.guid = DBCOL_SPECIALCOL;
(*prgInfo)[0].columnid.uName.ulPropid = 2;
(*prgInfo)[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK |
DBCOLUMNFLAGS_ISFIXEDLENGTH;
//
// Fill up the ADsPath column
//
(*prgInfo)[1].pwszName = *ppStringBuffer;
(*prgInfo)[1].pTypeInfo = NULL;
(*prgInfo)[1].iOrdinal = 1;
(*prgInfo)[1].ulColumnSize = (ULONG)256;
(*prgInfo)[1].wType = DBTYPE_WSTR|DBTYPE_BYREF;
(*prgInfo)[1].bPrecision = (BYTE) ~ 0;
(*prgInfo)[1].bScale = (BYTE) ~ 0;
(*prgInfo)[1].columnid.eKind = DBKIND_NAME;
(*prgInfo)[1].columnid.uName.pwszName = *ppStringBuffer;
(*prgInfo)[1].columnid.uGuid.guid = GUID_NULL;
(*prgInfo)[1].dwFlags = DBCOLUMNFLAGS_ISNULLABLE;
RRETURN( S_OK );
}
#if (!defined(BUILD_FOR_NT40))
//IBindResource::Bind
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::CSessionObject
//
// Synopsis: Constructor
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 09-17-1998 mgorti Created.
//
//----------------------------------------------------------------------------
HRESULT CSessionObject::Bind(
IUnknown * punkOuter,
LPCOLESTR pwszURL,
DBBINDURLFLAG dwBindFlags,
REFGUID rguid,
REFIID riid,
IAuthenticate * pAuthenticate,
DBIMPLICITSESSION * pImplSession,
DWORD * pdwBindStatus,
IUnknown ** ppUnk
)
{
HRESULT hr = S_OK;
CComBSTR bstrNewURL;
TRYBLOCK
//Initialize return arguments
if (pdwBindStatus)
*pdwBindStatus = 0;
if (ppUnk)
*ppUnk = NULL;
if (pImplSession)
pImplSession->pSession = NULL;
//if caller passed a null value for dwBindFlags,
//get them from initialization properties.
if (dwBindFlags == 0)
dwBindFlags = BindFlagsFromDbProps();
//Generic argument validation
hr = ValidateBindArgs(punkOuter,
pwszURL,
dwBindFlags,
rguid,
riid,
pAuthenticate,
pImplSession,
pdwBindStatus,
ppUnk);
BAIL_ON_FAILURE(hr);
//Fill in the pImplSession struct.
if (pImplSession)
{
// Our session doesn't support aggregation.
if (pImplSession->pUnkOuter != NULL)
BAIL_ON_FAILURE(hr = DB_E_NOAGGREGATION);
hr = QueryInterface(*pImplSession->piid,
(void**)&(pImplSession->pSession));
if (FAILED(hr))
BAIL_ON_FAILURE(hr = E_NOINTERFACE );
}
//Specific validation checks
//We are currently a read-only provider
if (dwBindFlags & DBBINDURLFLAG_WRITE)
BAIL_ON_FAILURE(hr = DB_E_READONLY);
//We currently don't support aggregation
if (punkOuter != NULL)
BAIL_ON_FAILURE (hr = DB_E_NOAGGREGATION);
//We don't support the following flags
if (dwBindFlags & DBBINDURLFLAG_ASYNCHRONOUS)
BAIL_ON_FAILURE(hr = DB_E_ASYNCNOTSUPPORTED);
if (dwBindFlags & DBBINDURLFLAG_OUTPUT ||
dwBindFlags & DBBINDURLFLAG_RECURSIVE ||
dwBindFlags & DBBINDURLFLAG_DELAYFETCHSTREAM ||
dwBindFlags & DBBINDURLFLAG_DELAYFETCHCOLUMNS)
BAIL_ON_FAILURE(hr = E_INVALIDARG);
//Now Try to Bind.
if (InlineIsEqualGUID(rguid, DBGUID_ROW) ||
InlineIsEqualGUID(rguid, DBGUID_ROWSET))
{
//If the URL is not absolute, build the absolute URL
//using the DBPROP_INIT_PROVIDERSTRING.
if (! bIsAbsoluteURL(pwszURL))
{
hr = BuildAbsoluteURL (pwszURL, bstrNewURL);
if (FAILED(hr))
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
else
bstrNewURL = pwszURL;
if ( InlineIsEqualGUID(rguid, DBGUID_ROW) )
{
hr = BindToRow(punkOuter,
(PWCHAR)bstrNewURL,
pAuthenticate,
dwBindFlags,
riid,
ppUnk);
}
else
{
hr = BindToRowset(punkOuter,
(PWCHAR)bstrNewURL,
pAuthenticate,
dwBindFlags,
riid,
ppUnk);
}
BAIL_ON_FAILURE(hr);
}
else if (InlineIsEqualGUID(rguid, DBGUID_DSO))
{
ADsAssert(_pDSO);
hr = BindToDataSource(
punkOuter,
pwszURL,
pAuthenticate,
dwBindFlags,
riid,
ppUnk
);
BAIL_ON_FAILURE (hr);
}
else if (InlineIsEqualGUID(rguid, DBGUID_SESSION))
{
hr = QueryInterface(riid, (void**)ppUnk);
BAIL_ON_FAILURE (hr);
}
else
BAIL_ON_FAILURE(hr = E_INVALIDARG);
//Fix for bug Raid-X5#83386 - spec change
//If caller specified any DENY semantics,
//set warning status and return value, since
//we don't support these.
if (dwBindFlags & DBBINDURLFLAG_SHARE_DENY_READ ||
dwBindFlags & DBBINDURLFLAG_SHARE_DENY_WRITE ||
dwBindFlags & DBBINDURLFLAG_SHARE_EXCLUSIVE)
{
if (pdwBindStatus)
*pdwBindStatus = DBBINDURLSTATUS_S_DENYNOTSUPPORTED;
BAIL_ON_FAILURE (hr = DB_S_ERRORSOCCURRED);
}
CATCHBLOCKBAIL(hr)
error:
RRETURN(hr);
}
#endif
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::CSessionObject
//
// Synopsis: Constructor
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
CSessionObject::CSessionObject(
LPUNKNOWN pUnkOuter
)
{
//
// Initialize simple member vars
//
_pUnkOuter = pUnkOuter ? pUnkOuter : (IGetDataSource FAR *)this;
_cCommandsOpen = 0;
_pUtilProp = NULL;
_pDSSearch = NULL;
_pIMalloc = NULL;
_pDSO = NULL;
ENLIST_TRACKING(CSessionObject);
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::~CSessionObject
//
// Synopsis: Destructor
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
CSessionObject::~CSessionObject( )
{
//
// Free properties management object
//
delete _pUtilProp;
if( _pIMalloc )
_pIMalloc->Release();
if( _pDSO ) {
_pDSO->DecrementOpenSessions();
_pDSO->Release();
}
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::FInit
//
// Synopsis: Initialize the session Object
//
// Arguments:
//
// Returns:
// TRUE Initialization succeeded
// FALSE Initialization failed
//
// Modifies:
//
// History: 08-28-96 ShankSh Created.
//
//----------------------------------------------------------------------------
BOOL CSessionObject::FInit(
CDSOObject * pDSO,
CCredentials & Credentials
)
{
HRESULT hr;
//
// Asserts
//
ADsAssert(pDSO);
ADsAssert(&Credentials);
//
// Allocate properties management object
//
_pUtilProp = new CUtilProp();
if( !_pUtilProp )
return FALSE;
hr = _pUtilProp->FInit(&Credentials);
BAIL_ON_FAILURE(hr);
//
// IMalloc->Alloc is the way we have to allocate memory for out parameters
//
hr = CoGetMalloc(MEMCTX_TASK, &_pIMalloc);
BAIL_ON_FAILURE(hr);
//
// Establish parent object pointer
//
_pDSO = pDSO;
_Credentials = Credentials;
_pDSO->AddRef();
_pDSO->IncrementOpenSessions();
return( TRUE );
error:
RRETURN( FALSE );
}
STDMETHODIMP
CSessionObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
{
if( ppv == NULL )
RRETURN( E_INVALIDARG );
if( IsEqualIID(iid, IID_IUnknown) ) {
*ppv = (IGetDataSource FAR *) this;
}
else if( IsEqualIID(iid, IID_IGetDataSource) ) {
*ppv = (IGetDataSource FAR *) this;
}
else if( IsEqualIID(iid, IID_IOpenRowset) ) {
*ppv = (IOpenRowset FAR *) this;
}
else if( IsEqualIID(iid, IID_ISessionProperties) ) {
*ppv = (ISessionProperties FAR *) this;
}
else if( IsEqualIID(iid, IID_IDBCreateCommand) ) {
*ppv = (IDBCreateCommand FAR *) this;
}
#if (!defined(BUILD_FOR_NT40))
else if( IsEqualIID(iid, IID_IBindResource) ) {
*ppv = (IBindResource FAR *) this;
}
#endif
else {
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
#if (!defined(BUILD_FOR_NT40))
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::ValidateBindArgs
//
// Synopsis: Validates IBindResource::Bind function arguments.
//
//----------------------------------------------------------------------------
HRESULT CSessionObject::ValidateBindArgs(
IUnknown * punkOuter,
LPCOLESTR pwszURL,
DBBINDURLFLAG dwBindFlags,
REFGUID rguid,
REFIID riid,
IAuthenticate * pAuthenticate,
DBIMPLICITSESSION * pImplSession,
DWORD * pdwBindStatus,
IUnknown ** ppUnk
)
{
//General validation checks.
if (pwszURL == NULL || InlineIsEqualGUID(rguid,GUID_NULL) ||
InlineIsEqualGUID(riid, GUID_NULL) || ppUnk == NULL )
RRETURN(E_INVALIDARG);
if (pImplSession &&
(pImplSession->pUnkOuter == NULL || pImplSession->piid == NULL))
RRETURN(E_INVALIDARG);
if (punkOuter && !InlineIsEqualGUID(riid, IID_IUnknown))
RRETURN(DB_E_NOAGGREGATION);
if (pImplSession && pImplSession->pUnkOuter &&
pImplSession->piid &&
!InlineIsEqualGUID(*pImplSession->piid, IID_IUnknown))
RRETURN(DB_E_NOAGGREGATION);
if (dwBindFlags & DBBINDURLFLAG_RECURSIVE)
{
//if DBBINDURLFLAG_RECURSIVE is set, at least one of the SHARE_DENY
//flags must have been set.
if (! ( (dwBindFlags & DBBINDURLFLAG_SHARE_DENY_READ) ||
(dwBindFlags & DBBINDURLFLAG_SHARE_DENY_WRITE) ||
(dwBindFlags & DBBINDURLFLAG_SHARE_EXCLUSIVE)
)
)
RRETURN(E_INVALIDARG);
}
if (!(dwBindFlags & DBBINDURLFLAG_READ) &&
!(dwBindFlags & DBBINDURLFLAG_WRITE) ) {
// Must have either read or write access:
RRETURN(E_INVALIDARG);
}
if (InlineIsEqualGUID(rguid, DBGUID_DSO) &&
!((dwBindFlags & DBBINDURLFLAG_READ) ||
(dwBindFlags & DBBINDURLFLAG_ASYNCHRONOUS) ||
(dwBindFlags & DBBINDURLFLAG_WAITFORINIT)
)
)
//if object type is DataSource, only the above flags are allowed
RRETURN(E_INVALIDARG);
if (InlineIsEqualGUID(rguid, DBGUID_SESSION) &&
! (dwBindFlags == DBBINDURLFLAG_READ))
//if object type is Session, only DBBINDURLFLAG_READ is allowed
RRETURN(E_INVALIDARG);
if (InlineIsEqualGUID(rguid, DBGUID_ROWSET) &&
((dwBindFlags & DBBINDURLFLAG_DELAYFETCHCOLUMNS) ||
(dwBindFlags & DBBINDURLFLAG_DELAYFETCHSTREAM)
)
)
//if object type is Rowset, DELAYFETCHCOLUMNS and DELAYFETCHSTREAM
//flags are disallowed.
RRETURN ( E_INVALIDARG );
if (InlineIsEqualGUID(rguid, DBGUID_STREAM) &&
((dwBindFlags & DBBINDURLFLAG_DELAYFETCHCOLUMNS) ||
(dwBindFlags & DBBINDURLFLAG_DELAYFETCHSTREAM)
)
)
//if object type is Stream, DELAYFETCHCOLUMNS and
//DELAYFETCHSTREAM flags are disallowed.
RRETURN(E_INVALIDARG);
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::BindToRow
//
// Synopsis: Given a URL, binds to that row object and returns the requested
// interface.
//
//----------------------------------------------------------------------------
HRESULT
CSessionObject::BindToRow(
IUnknown *punkOuter,
LPCOLESTR pwszURL,
IAuthenticate *pAuthenticate,
DWORD dwBindFlags,
REFIID riid,
IUnknown** ppUnk
)
{
CComObject<CRow> *pRow = NULL;
auto_rel<IUnknown> pSession;
auto_rel<IRow> pRowDelete;
HRESULT hr = S_OK;
hr = CComObject<CRow>::CreateInstance(&pRow);
if (FAILED(hr))
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
//To make sure we delete the row object in
//case we encounter errors after this point.
//Note: this version of auto_rel doesn't addref on assignment.
pRowDelete = pRow;
pRowDelete->AddRef();
hr = QueryInterface(__uuidof(IUnknown), (void **)&pSession);
if (FAILED(hr))
BAIL_ON_FAILURE(hr = E_FAIL);
//Initialize row and bind it to a Directory Object.
hr = pRow->Initialize((PWSTR)pwszURL,
(IUnknown *)pSession,
pAuthenticate,
dwBindFlags,
FALSE, // not a tearoff
FALSE, // don't get column info. from rowset
&_Credentials,
true);
if (FAILED(hr))
{
if (INVALID_CREDENTIALS_ERROR(hr))
{
BAIL_ON_FAILURE(hr = DB_SEC_E_PERMISSIONDENIED);
}
else
{
BAIL_ON_FAILURE(hr = DB_E_NOTFOUND);
}
}
hr = pRow->QueryInterface(riid, (void**)ppUnk);
if (FAILED(hr))
BAIL_ON_FAILURE (hr = E_NOINTERFACE);
error:
RRETURN ( hr );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::BindToRowset
//
// Synopsis: Given a URL, binds to a rowset object that has all its child
// nodes as rows and returns the requested interface on the rowset.
//
//----------------------------------------------------------------------------
HRESULT
CSessionObject::BindToRowset(
IUnknown *pUnkOuter,
LPCOLESTR pwszURL,
IAuthenticate *pAuthenticate,
DWORD dwBindFlags,
REFIID riid,
IUnknown** ppUnk
)
{
HRESULT hr;
DWORD fAuthFlags;
DBID tableID;
tableID.eKind = DBKIND_NAME;
tableID.uName.pwszName = (LPWSTR) pwszURL;
//Create the rowset.
// Fix for 351040. First try explicit credentials, then session object's
// credentials, then default credentials.
if(pAuthenticate)
{
CCredentials creds;
hr = GetCredentialsFromIAuthenticate(pAuthenticate, creds);
if (FAILED(hr))
BAIL_ON_FAILURE(hr = E_INVALIDARG);
fAuthFlags = creds.GetAuthFlags();
creds.SetAuthFlags(fAuthFlags |
ADS_SECURE_AUTHENTICATION);
hr = OpenRowsetWithCredentials(pUnkOuter, &tableID, NULL, riid,
0, NULL, &creds, ppUnk);
}
if( (!pAuthenticate) || (INVALID_CREDENTIALS_ERROR(hr)) )
// try credentials in session object
hr = OpenRowset(pUnkOuter, &tableID, NULL, riid, 0, NULL, ppUnk);
if(INVALID_CREDENTIALS_ERROR(hr))
// try default credentials
{
CCredentials creds; // default credentials
fAuthFlags = creds.GetAuthFlags();
creds.SetAuthFlags(fAuthFlags |
ADS_SECURE_AUTHENTICATION);
hr = OpenRowsetWithCredentials(pUnkOuter, &tableID, NULL, riid,
0, NULL, &creds, ppUnk);
}
BAIL_ON_FAILURE(hr);
RRETURN ( S_OK );
error:
RRETURN ( hr );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::BindFlagsFromDbProps
//
// Synopsis: Synthesizes bind flags from initialization properties
// DBPROP_INIT_MODE and DBPROP_INIT_BINDFLAGS
//
//----------------------------------------------------------------------------
DWORD CSessionObject::BindFlagsFromDbProps()
{
HRESULT hr = S_OK;
auto_rel<IDBProperties> pDBProp;
ULONG i, j, cPropertySets = 0;
DWORD dwMode = 0, dwBindFlags = 0, dwBindFlagProp = 0;
DWORD dwResult = 0;
hr = GetDataSource(__uuidof(IDBProperties), (IUnknown **)&pDBProp);
BAIL_ON_FAILURE(hr);
DBPROPID propids[2];
propids[0] = DBPROP_INIT_MODE;
propids[1] = DBPROP_INIT_BINDFLAGS;
DBPROPIDSET rgPropertyIDSets[1];
rgPropertyIDSets[0].rgPropertyIDs = propids;
rgPropertyIDSets[0].cPropertyIDs = 2;
rgPropertyIDSets[0].guidPropertySet = DBPROPSET_DBINIT;
DBPROPSET *prgPropertySets;
hr = pDBProp->GetProperties(
1,
rgPropertyIDSets,
&cPropertySets,
&prgPropertySets);
if (hr == DB_E_ERRORSOCCURRED)
BAIL_ON_FAILURE(hr);
for (i = 0; i < cPropertySets; i++)
{
for (j = 0; j < prgPropertySets[i].cProperties; j++)
{
DBPROP *pProp = &prgPropertySets[i].rgProperties[j];
ADsAssert(pProp);
if (pProp->dwStatus == S_OK &&
pProp->dwPropertyID == DBPROP_INIT_MODE)
dwMode = V_I4(&pProp->vValue);
else if (pProp->dwStatus == S_OK &&
pProp->dwPropertyID == DBPROP_INIT_BINDFLAGS)
dwBindFlagProp = V_I4(&pProp->vValue);
else
continue;
}
}
//Now extract bind flags from dwMode and dwBindFlagProp
{
DWORD dwModeMask =
DB_MODE_READ |
DB_MODE_WRITE |
DB_MODE_READWRITE |
DB_MODE_SHARE_DENY_READ |
DB_MODE_SHARE_DENY_WRITE |
DB_MODE_SHARE_EXCLUSIVE |
DB_MODE_SHARE_DENY_NONE;
dwResult |= dwMode & dwModeMask;
if ( dwBindFlagProp & DB_BINDFLAGS_DELAYFETCHCOLUMNS ) {
dwBindFlags |= DBBINDURLFLAG_DELAYFETCHCOLUMNS;
}
if ( dwBindFlagProp & DB_BINDFLAGS_DELAYFETCHSTREAM ) {
dwBindFlags |= DBBINDURLFLAG_DELAYFETCHSTREAM;
}
if ( dwBindFlagProp & DB_BINDFLAGS_RECURSIVE ) {
dwBindFlags |= DBBINDURLFLAG_RECURSIVE;
}
if ( dwBindFlagProp & DB_BINDFLAGS_OUTPUT ) {
dwBindFlags |= DBBINDURLFLAG_OUTPUT;
}
dwResult |= dwBindFlagProp | dwBindFlags;
}
error:
for (i = 0; i < cPropertySets; i++)
{
for (j = 0; j < prgPropertySets[i].cProperties; j++)
{
DBPROP *pProp = &(prgPropertySets[i].rgProperties[j]);
ADsAssert(pProp);
FreeDBID(&pProp->colid);
VariantClear(&pProp->vValue);
}
CoTaskMemFree(prgPropertySets[i].rgProperties);
}
CoTaskMemFree(prgPropertySets);
RRETURN ( dwResult );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::BindToDataSource
//
// Synopsis: Initializes the DataSource object if necessary, Sets
// DBPROP_INIT_PROVIDERSTRING property and returns the requested
// interface on the datasource.
//
//----------------------------------------------------------------------------
HRESULT
CSessionObject::BindToDataSource(
IUnknown *pUnkOuter,
LPCOLESTR pwszURL,
IAuthenticate *pAuthenticate,
DWORD dwBindFlags,
REFIID riid,
IUnknown** ppUnk
)
{
HRESULT hr = S_OK;
auto_rel<IDBProperties> pDBProperties;
DBPROP props[1];
DBPROPSET rgPropertySets[1];
CComBSTR bstrURL(pwszURL);
//Initialize DBPROP_INIT_PROVIDERSTRING only if the
//URL is absolute.
if (bIsAbsoluteURL (pwszURL))
{
// Check if the datasource has already been initialized.
if (_pDSO->IsInitialized())
BAIL_ON_FAILURE(hr = DB_E_ALREADYINITIALIZED);
props[0].dwPropertyID = DBPROP_INIT_PROVIDERSTRING;
props[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
props[0].vValue.vt = VT_BSTR;
props[0].vValue.bstrVal = (PWCHAR)bstrURL;
rgPropertySets[0].rgProperties = props;
rgPropertySets[0].cProperties = 1;
rgPropertySets[0].guidPropertySet = DBPROPSET_DBINIT;
hr = GetDataSource(
__uuidof(IDBProperties),
(IUnknown **)&pDBProperties
);
BAIL_ON_FAILURE(hr);
hr = pDBProperties->SetProperties(1, rgPropertySets);
BAIL_ON_FAILURE(hr);
}
// If consumer doesn't specify DBBINDURLFLAG_WAITFORINIT, it
// means consumer wants an initialized DSO
//
if (! (dwBindFlags & DBBINDURLFLAG_WAITFORINIT))
{
auto_rel<IDBInitialize> pDBInitialize;
hr = GetDataSource(__uuidof(IDBInitialize), (IUnknown **)&pDBInitialize);
BAIL_ON_FAILURE(hr);
hr = pDBInitialize->Initialize();
BAIL_ON_FAILURE(hr);
}
//Return the requested interface on the DSO.
hr = GetDataSource(riid, ppUnk);
BAIL_ON_FAILURE(hr);
error:
RRETURN ( hr );
}
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::BuildAbsoluteURL
//
// Synopsis: Given a relative URL, builds absolute URL using the relative URL
// and the property DBPROP_INIT_PROVIDERSTRING.
//
//----------------------------------------------------------------------------
HRESULT
CSessionObject::BuildAbsoluteURL(
CComBSTR bstrLeaf,
CComBSTR& bstrAbsoluteURL
)
{
HRESULT hr = S_OK;
auto_rel<IDBProperties> pDBProp;
auto_rel<IADsPathname> pPathParent;
auto_rel<IADsPathname> pPathLeaf;
ULONG cPropertySets = 0;
long i, j, cElements = 0;
CComBSTR bstrParent;
DBPROPSET* prgPropertySets = NULL;
DBPROPID propids[1];
DBPROPIDSET rgPropertyIDSets[1];
hr = GetDataSource(__uuidof(IDBProperties), (IUnknown **)&pDBProp);
BAIL_ON_FAILURE(hr);
propids[0] = DBPROP_INIT_PROVIDERSTRING;
rgPropertyIDSets[0].rgPropertyIDs = propids;
rgPropertyIDSets[0].cPropertyIDs = 1;
rgPropertyIDSets[0].guidPropertySet = DBPROPSET_DBINIT;
hr = pDBProp->GetProperties(
1,
rgPropertyIDSets,
&cPropertySets,
&prgPropertySets);
if (SUCCEEDED(hr) && cPropertySets == 1)
{
ADsAssert(prgPropertySets != NULL);
ADsAssert(prgPropertySets[0].rgProperties != NULL);
DBPROP* pProp = & (prgPropertySets[0].rgProperties[0]);
bstrParent = pProp->vValue.bstrVal;
}
// Build Absolute Path from Parent and leaf.
hr = CPathname::CreatePathname(
__uuidof(IADsPathname),
(void **)&pPathParent
);
BAIL_ON_FAILURE(hr);
hr = pPathParent->Set(bstrParent, ADS_SETTYPE_FULL);
BAIL_ON_FAILURE(hr);
if (bstrLeaf.Length() > 0)
{
hr = CPathname::CreatePathname(
__uuidof(IADsPathname),
(void **)&pPathLeaf
);
BAIL_ON_FAILURE(hr);
hr = pPathLeaf->Set(bstrLeaf, ADS_SETTYPE_DN);
BAIL_ON_FAILURE(hr);
hr = pPathLeaf->GetNumElements(&cElements);
BAIL_ON_FAILURE(hr);
//Add leaf elements in reverse order.
//Ex: if bstrLeaf = "CN=Administrator,CN=Users",
//we add CN=Users first.
for (i = cElements-1; i >= 0; i--)
{
CComBSTR bstrElement;
hr = pPathLeaf->GetElement(i, &bstrElement);
BAIL_ON_FAILURE(hr);
hr = pPathParent->AddLeafElement(bstrElement);
BAIL_ON_FAILURE(hr);
}
}
//Read back the fully built path name
hr = pPathParent->Retrieve(ADS_FORMAT_X500, &bstrAbsoluteURL);
BAIL_ON_FAILURE(hr);
error:
// Free memory allocated by GetProperties
for (i = 0; i < cPropertySets; i++)
{
for (j = 0; j < prgPropertySets[i].cProperties; j++)
{
DBPROP *pProp = &(prgPropertySets[i].rgProperties[j]);
ADsAssert(pProp);
// We should free the DBID in pProp, but we know that
// GetProperties always returns DB_NULLID and FreeDBID doesn't
// handle DB_NULLID. So, DBID is not freed here.
VariantClear(&pProp->vValue);
}
CoTaskMemFree(prgPropertySets[i].rgProperties);
}
CoTaskMemFree(prgPropertySets);
RRETURN(hr);
}
extern PROUTER_ENTRY g_pRouterHead;
extern CRITICAL_SECTION g_csRouterHeadCritSect;
//+---------------------------------------------------------------------------
//
// Function: CSessionObject::bIsAbsoluteURL
//
// Synopsis: If the given URL starts with any of the ADS provider prefixes,
// returns true. Returns false otherwise.
//
//----------------------------------------------------------------------------
bool
CSessionObject::bIsAbsoluteURL( LPCOLESTR pwszURL)
{
if (pwszURL == NULL)
return false;
//
// Make sure the router has been initialized
//
EnterCriticalSection(&g_csRouterHeadCritSect);
if (!g_pRouterHead) {
g_pRouterHead = InitializeRouter();
}
LeaveCriticalSection(&g_csRouterHeadCritSect);
for (PROUTER_ENTRY pProvider = g_pRouterHead;
pProvider != NULL;
pProvider = pProvider->pNext)
{
if (pProvider->szProviderProgId == NULL)
continue;
size_t strSize = wcslen(pProvider->szProviderProgId);
if ( _wcsnicmp(pwszURL, pProvider->szProviderProgId, strSize) == 0 )
return true;
}
// Given URL doesn't start with any of the ADSI provider prefixes.
return false;
}
#endif
//-----------------------------------------------------------------------------
// SetSearchPrefs
//
// Sets ADSI search preferences on the property object.
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CSessionObject::SetSearchPrefs(
void
)
{
PROPSET *pPropSet;
PADS_SEARCHPREF_INFO pSearchPref = NULL;
HRESULT hr = S_OK;
ULONG i;
//
// Asserts
//
ADsAssert(_pUtilProp);
ADsAssert(_pDSSearch);
pPropSet = _pUtilProp->GetPropSetFromGuid(DBPROPSET_ADSISEARCH);
if( !pPropSet || !pPropSet->cProperties )
RRETURN( S_OK );
pSearchPref = (PADS_SEARCHPREF_INFO) AllocADsMem(
pPropSet->cProperties *
sizeof(ADS_SEARCHPREF_INFO)
);
if( !pSearchPref )
BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
for (i=0; i<pPropSet->cProperties; i++) {
hr = _pUtilProp->GetSearchPrefInfo(
pPropSet->pUPropInfo[i].dwPropertyID,
&pSearchPref[i]
);
BAIL_ON_FAILURE( hr );
}
hr = _pDSSearch->SetSearchPreference(
pSearchPref,
pPropSet->cProperties
);
_pUtilProp->FreeSearchPrefInfo(pSearchPref, pPropSet->cProperties);
BAIL_ON_FAILURE( hr );
error:
if( pSearchPref )
FreeADsMem(pSearchPref);
RRETURN( hr );
}