//--------------------------------------------------------------------------- // // 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; ieKind != 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; // 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; // // AddRef the DSSearch interface. If the CreateRowProvider function fails // then it releases the interface, otherwise it just stores it. // _pDSSearch->AddRef(); 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) || !(*ppStringBuffer)) { if (*prgInfo) { _pIMalloc->Free(*prgInfo); *prgInfo = NULL; } if (*ppStringBuffer) { _pIMalloc->Free(*ppStringBuffer); *ppStringBuffer = 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 *pRow = NULL; auto_rel pSession; auto_rel pRowDelete; HRESULT hr = S_OK; hr = CComObject::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 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 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 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 pDBProp; auto_rel pPathParent; auto_rel 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; icProperties; 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 ); }