//---------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996 // // File: cextmgr.cxx // // Contents: LDAP ExtMgr Object // // // History: 06-15-96 yihsins Created. // //---------------------------------------------------------------------------- #include "ldap.hxx" #pragma hdrstop // Class CADsExtMgr CADsExtMgr::CADsExtMgr( IUnknown FAR * pUnkOuter ): _pUnkOuter(pUnkOuter), _pClassEntry(NULL), _pDispMgr(NULL), _pCreds(NULL), _fExtensionsLoaded(FALSE) { } // // Static create to handle multiple classes // HRESULT CADsExtMgr::CreateExtMgr( IUnknown FAR * pUnkOuter, CAggregatorDispMgr * pDispMgr, LPWSTR pszClassNames[], long lnNumClasses, CCredentials *pCreds, CADsExtMgr ** ppExtMgr ) { long lnCtr = 0; long lnInc = 1; PCLASS_ENTRY pClassEntry = NULL; CADsExtMgr FAR * pExtMgr = NULL; HRESULT hr = S_OK; pExtMgr = new CADsExtMgr(pUnkOuter); if (!pExtMgr) RRETURN(E_OUTOFMEMORY); // // Now store the DispatchMgr of the Aggregator // pExtMgr->_pDispMgr = pDispMgr; pExtMgr->_pCreds = pCreds; if (_tcsicmp(pszClassNames[lnNumClasses-1], TEXT("Top")) == 0) lnCtr = 0; else lnCtr = lnNumClasses - 1; lnInc = lnCtr ? -1 : 1; // // Read the list of extension object of the same class from registry // hr = ADSIGetExtensionList( pszClassNames[lnCtr], &(pExtMgr->_pClassEntry) ); BAIL_ON_FAILURE(hr); lnCtr += lnInc; for (; (lnInc == -1) ? (lnCtr > -1) : (lnCtr < lnNumClasses); lnCtr += lnInc) { hr = ADSIAppendToExtensionList( pszClassNames[lnCtr], &(pExtMgr->_pClassEntry) ); BAIL_ON_FAILURE(hr); } *ppExtMgr = pExtMgr; RRETURN(hr); error: *ppExtMgr = NULL; delete pExtMgr; RRETURN(hr); } CADsExtMgr::~CADsExtMgr( ) { // // Free the ClassEntry // if (_pClassEntry) { FreeClassEntry(_pClassEntry); } // // And do nothing with the DispMgr, pCreds - we just keep pointers // } // // Instantiate extension objects listed in _pClassEntry as aggregates of // aggregator _pUnkOuter. Initialize extensions with . // // Max Load 127 extensions. Extensions > 127 are silently ignored. // HRESULT CADsExtMgr::LoadExtensions( CCredentials &Credentials ) { HRESULT hr = S_OK; PEXTENSION_ENTRY pExtEntry = NULL; DWORD dwExtensionID = MIN_EXTENSION_ID; IPrivateDispatch * pPrivDisp = NULL; LPWSTR pszUserName = NULL; LPWSTR pszPassword = NULL; DWORD dwAuthFlags = 0; VARIANT varUserName; VARIANT varPassword; VARIANT varAuthFlags; PVARIANT pvarUserName = &varUserName; PVARIANT pvarPassword = &varPassword; PVARIANT pvarAuthFlags = &varAuthFlags; BOOL fReturnError = FALSE; // // Extensions (ext mgr) do(es) not exist on its own without an aggregator // ADsAssert(_pUnkOuter); // // If _pClassEntry!=NULL, pClassEntry->pExtensionHead should not // be NULL either. But just in case a user removes all extension entries // under a class key without removing the class key itself in the registry, // we will let it pass and just return S_OK here. // if (!_pClassEntry || !(pExtEntry=_pClassEntry->pExtensionHead) ) { RRETURN(S_OK); } VariantInit(pvarUserName); VariantInit(pvarPassword); VariantInit(pvarAuthFlags); hr = Credentials.GetUserName(&pszUserName); if (FAILED(hr)) { RRETURN(S_OK); } hr = Credentials.GetPassword(&pszPassword); if (FAILED(hr)) { if (pszUserName) { FreeADsStr(pszUserName); } RRETURN(S_OK); } dwAuthFlags = Credentials.GetAuthFlags(); while (pExtEntry) { // // Max # of extension have been loaded, cannot load more // if (dwExtensionID>MAX_EXTENSION_ID) { // // Terminate loading extensions. // break; } // // create extension object (aggregatee) and ask for Non-delegating // IUnknown. Ref count on extension object = 1. // hr = CoCreateInstance( pExtEntry->ExtCLSID, _pUnkOuter, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&(pExtEntry->pUnknown) ); // // if fail, go to next extesion entry s.t. bad individual extension // cannot block other extensions from loading (no clean up needed) // if (SUCCEEDED(hr)) { pExtEntry->dwExtensionID = dwExtensionID; hr = (pExtEntry->pUnknown)->QueryInterface( IID_IADsExtension, (void **) &(pExtEntry->pADsExt) ); if (FAILED(hr)) { // // extension does not support the optioanl IADsExtension -> OK. // (no clean up needed) // pExtEntry->pADsExt=NULL; pExtEntry->fDisp = FALSE; } else { // // Cache the interface ptr but call Release() immediately to // avoid aggregator having a ref count on itself // since IADsExtension inherits from delegating IUnknown. // // Note: codes still works if inherit from NonDelegatingIUknown // (pExtEntry->pADsExt)->Release() ; // // For efficiency, set this flag to FALSE on FIRST encounter of // pADsExt->PrivateGetIDsOfNames()/Invoke() returning E_NOTIMPL. // Set as TRUE now s.t. at least first encounter will happen. // pExtEntry->fDisp = TRUE; // // Pass its own credentials to extension. Ignore error if any. // hr = ADsAllocString( pszUserName, &(pvarUserName->bstrVal) ); if (FAILED(hr)) { fReturnError = TRUE; BAIL_ON_FAILURE(hr); } V_VT(pvarUserName) = VT_BSTR; hr = ADsAllocString( pszPassword, &(pvarPassword->bstrVal) ); if (FAILED(hr)) { fReturnError = TRUE; BAIL_ON_FAILURE(hr); } V_VT(pvarPassword) = VT_BSTR; V_I4(pvarAuthFlags) = dwAuthFlags; V_VT(pvarAuthFlags) = VT_I4; hr = (pExtEntry->pADsExt)->Operate( ADS_EXT_INITCREDENTIALS, varUserName, varPassword, varAuthFlags ); // // Free them as they are reused // VariantClear(pvarUserName); if(pvarPassword->bstrVal) { SecureZeroMemory(pvarPassword->bstrVal, wcslen(pvarPassword->bstrVal)*sizeof(WCHAR)); } VariantClear(pvarPassword); } } // end if CoCreateInstance() succeeded pExtEntry = pExtEntry->pNext; // // ++ extension ID even if creat'n of extension fails just to be safe // - chuck's stuff :) // dwExtensionID++; } // end while error: if (pszUserName) { FreeADsStr(pszUserName); } if (pszPassword) { SecureZeroMemory(pszPassword, wcslen(pszPassword)*sizeof(WCHAR)); FreeADsStr(pszPassword); } VariantClear(pvarUserName); if(V_VT(pvarPassword) != VT_EMPTY && pvarPassword->bstrVal) { SecureZeroMemory(pvarPassword->bstrVal, wcslen(pvarPassword->bstrVal)*sizeof(WCHAR)); VariantClear(pvarPassword); } VariantClear(pvarAuthFlags); if (fReturnError) { RRETURN(hr); // fatal error, } else { RRETURN(S_OK); // "okay" error if any, optional support } } HRESULT CADsExtMgr::LoadExtensionsIfReqd() { HRESULT hr = S_OK; if(!_fExtensionsLoaded) { hr = LoadExtensions(*_pCreds); BAIL_ON_FAILURE(hr); hr = FinalInitializeExtensions(); // this call never fails BAIL_ON_FAILURE(hr); _fExtensionsLoaded = TRUE; } RRETURN(S_OK); error: RRETURN(hr); } STDMETHODIMP CADsExtMgr::QueryInterface(REFIID iid, LPVOID FAR* ppv) { PCLASS_ENTRY pClassEntry = _pClassEntry; IUnknown * pUnknown = NULL; PINTERFACE_ENTRY pIID = NULL; PEXTENSION_ENTRY pExtensionEntry = NULL; HRESULT hr = S_OK; if (!pClassEntry) { RRETURN(E_NOINTERFACE); } pExtensionEntry = pClassEntry->pExtensionHead; while (pExtensionEntry) { pIID = pExtensionEntry->pIID; while (pIID) { if (IsEqualIID(pIID->iid, iid)) { hr = LoadExtensionsIfReqd(); if (FAILED(hr)) { RRETURN(E_NOINTERFACE); } pUnknown = pExtensionEntry->pUnknown; if (!pUnknown) { RRETURN(E_NOINTERFACE); } hr = pUnknown->QueryInterface( iid, ppv ); RRETURN(hr); } pIID = pIID->pNext; } pExtensionEntry = pExtensionEntry->pNext; } RRETURN(hr = E_NOINTERFACE); } STDMETHODIMP CADsExtMgr::GetTypeInfoCount( unsigned int FAR* pctinfo ) { RRETURN(E_NOTIMPL); } STDMETHODIMP CADsExtMgr::GetTypeInfo( unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo ) { RRETURN(E_NOTIMPL); } STDMETHODIMP CADsExtMgr::GetIDsOfNames( REFIID iid, LPWSTR FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid ) { HRESULT hr = S_OK; PEXTENSION_ENTRY pExtension = NULL; IPrivateDispatch FAR * pPrivDisp = NULL; hr = _pDispMgr->GetIDsOfNames( iid, rgszNames, cNames, lcid, rgdispid ); if (FAILED(hr)) { if (!_pClassEntry) { RRETURN(DISP_E_UNKNOWNNAME); } hr = LoadExtensionsIfReqd(); if (FAILED(hr)) { RRETURN(DISP_E_UNKNOWNNAME); } pExtension = _pClassEntry->pExtensionHead; while (pExtension) { if (pExtension->fDisp) { // // fDisp = TRUE indicates // 1) extension supports pADsExt AND // 2) either // a) PrivateGetIDsOfNames() does Not return E_NOTIMPL // OR // b) we don't know if a) is true or not yet // ADsAssert(pExtension->pADsExt); hr = (pExtension->pADsExt)->PrivateGetIDsOfNames( iid, rgszNames, cNames, lcid, rgdispid ); if (SUCCEEDED(hr)) { // // check & prefix extension id to dispid(s) returned // by extension // hr = CheckAndPrefixExtIDArray( pExtension->dwExtensionID, cNames, rgdispid ); if (SUCCEEDED(hr) ) { RRETURN(hr); } // // if cannot prefix extension id because NOT ALL // dispids returned by PrivateGetIDsOfNames() are // valid, this extension does not support this property // or method -> try next extension // } else if (hr == E_NOTIMPL) { // // extension object does not support the optional // IADsExtension::PrivateGetIDsOfNames()/PrivateInvoke() // -> remember this in cache & try next extension object // pExtension->fDisp = FALSE; } else { // // extens'n object supports PrivateGetIDsOfNames()/Invoke() // but does not know about this property or method // -> try next extension object // } } // end "if (pExtension->pADs && pExtension->fDisp)" pExtension = pExtension->pNext; } // end while } // // Unify the final error code retuned to ADSI client to DISP_E_UNKNOWNNAME // if ( FAILED(hr) && hr!=E_OUTOFMEMORY) { hr = DISP_E_UNKNOWNNAME; } RRETURN(hr); } STDMETHODIMP CADsExtMgr::Invoke( DISPID dispidMember, REFIID iid, LCID lcid, unsigned short wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, unsigned int FAR* puArgErr ) { DWORD dwExtensionId = 0; HRESULT hr = S_OK; PEXTENSION_ENTRY pExtension = NULL; IPrivateDispatch * pPrivDisp = NULL; DISPID rgExtDispid = DISPID_UNKNOWN; // // This could be a special dispatch id - pass it to // the aggregator // if (dispidMember <= 0) { hr = _pDispMgr->Invoke( dispidMember, iid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr ); RRETURN(hr); } // // It is not a special dispatch id, so compute the extension // id and pass it to the appropriate dispatch manager // dwExtensionId = EXTRACT_EXTENSION_ID(dispidMember); if (!dwExtensionId) { hr = _pDispMgr->Invoke( dispidMember, iid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr ); RRETURN(hr); } if (!_pClassEntry) { RRETURN(DISP_E_MEMBERNOTFOUND); } // // Not really neede but just in case. // hr = LoadExtensionsIfReqd(); if (FAILED(hr)) { RRETURN(DISP_E_MEMBERNOTFOUND); } pExtension = _pClassEntry->pExtensionHead; rgExtDispid = REMOVE_EXTENSION_ID(dispidMember); while (pExtension) { if (dwExtensionId == pExtension->dwExtensionID) { if (pExtension->fDisp) { // // fDisp = TRUE indicates // 1) extension supports pADsExt AND // 2) either // a) PrivateGetIDsOfNames() does Not return E_NOTIMPL // OR // b) we don't know if a) is true or not yet (client bug) // ADsAssert(pExtension->pADsExt); hr = (pExtension->pADsExt)->PrivateInvoke( rgExtDispid, iid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr ); RRETURN(hr); } else { // // A dwExtensionId match indicates THIS extens'n has returned // a valid dispid to clients thru' pADs->PrivateGetIDsOfNames. // Thus, fDisp should be TURE. // // But since dispid goes thru' clients before passed back to // PrivateInovke(), don't ASSERT in case of clients errors. // RRETURN(DISP_E_MEMBERNOTFOUND); } } pExtension = pExtension->pNext; } // end while RRETURN(DISP_E_MEMBERNOTFOUND); } HRESULT CADsExtMgr::CheckAndPrefixExtIDArray( IN DWORD dwExtensionID, IN unsigned int cDispids, IN OUT DISPID * rgDispids ) { HRESULT hrEach = S_OK; HRESULT hrAll = S_OK; ASSERT_VALID_EXTENSION_ID(dwExtensionID); for (unsigned int i = 0; i DISPID_UNKOWN // } } RRETURN(hrAll); } HRESULT CADsExtMgr::CheckAndPrefixExtID( IN DWORD dwExtensionID, IN DISPID dispid, IN OUT DISPID * pNewDispid ) { ADsAssert(pNewDispid); if ( (dispid>= ADS_EXT_MINEXTDISPID) && (dispid<= ADS_EXT_MAXEXTDISPID) ) { *pNewDispid = PREFIX_EXTENSION_ID(dwExtensionID, dispid) ; RRETURN(S_OK); } else { *pNewDispid = DISPID_UNKNOWN; RRETURN(E_FAIL); } } //+------------------------------------------------------------------------ // // Function: CADsExtMgr::FinalInitializeExtensions // // Synopsis: At this point we call Operate on all the extensions // so that they can do initialization stuff that // // // // Arguments: None // // AjayR - added on 1-27-99. //------------------------------------------------------------------------- HRESULT CADsExtMgr::FinalInitializeExtensions() { HRESULT hr = S_OK; PEXTENSION_ENTRY pExtEntry = NULL; VARIANT vDummy; VariantInit(&vDummy); // // Extensions (ext mgr) does not exist on its own without an aggregator // ADsAssert(_pUnkOuter); // // If _pClassEntry!=NULL, pClassEntry->pExtensionHead should not // be NULL either. But just in case a user removes all extension entries // under a class key without removing the class key itself in the registry, // we will let it pass and just return S_OK here. // if (!_pClassEntry || !(pExtEntry=_pClassEntry->pExtensionHead) ) { RRETURN(S_OK); } while (pExtEntry) { // // Call operate only if the extension supports the interface // if (pExtEntry->pADsExt) { hr = (pExtEntry->pADsExt)->Operate( ADS_EXT_INITIALIZE_COMPLETE, vDummy, vDummy, vDummy ); } // // we cannot really do much if there is a failure here // pExtEntry = pExtEntry->pNext; } // end while // // We need to return S_OK here as otherwise just because // the final initialization of one extension failed - we // will hold up the entire lot. // RRETURN(S_OK); } //+--------------------------------------------------------------------------- // Function: GetCLSIDForIID --- used in supporting ICustomInterfaceFactory // // Synopsis: Returns the CLSID corresponding to a given interface IID. // If the IID is one of the interfaces implemented by the // extension manager, then the extension's CLSID is returned. // // Arguments: riid - Interface ID for which we want to find the CLSID // lFlags - Reserved. Must be 0. // pCLSID - Returns the CLSID corresponding to the IID. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *pCLSID to return CLSID. // //---------------------------------------------------------------------------- STDMETHODIMP CADsExtMgr::GetCLSIDForIID( REFIID riid, long lFlags, CLSID *pCLSID ) { PCLASS_ENTRY pClassEntry = _pClassEntry; PEXTENSION_ENTRY pExtensionEntry = NULL; PINTERFACE_ENTRY pIID = NULL; HRESULT hr = S_OK; ADsAssert(!lFlags && pCLSID); if (!pClassEntry) { RRETURN(UMI_E_NOT_FOUND); } pExtensionEntry = pClassEntry->pExtensionHead; while (pExtensionEntry) { pIID = pExtensionEntry->pIID; while (pIID) { if (IsEqualIID(pIID->iid, riid)) { *pCLSID = pExtensionEntry->ExtCLSID; RRETURN(S_OK); } pIID = pIID->pNext; } pExtensionEntry = pExtensionEntry->pNext; } RRETURN(hr = UMI_E_NOT_FOUND); } //+--------------------------------------------------------------------------- // Function: GetObjectByCLSID --- Used for ICustomInterfaceFactory support. // // Synopsis: Returns a pointer to a requested interface on the object // specified by a CLSID. The object specified by the CLSID is // aggregated by the specified outer unknown on return. The // interface returned is a non-delegating interface on the object. // // Arguments: clsid - CLSID of object on which interface // should be obtained // pUnkOuter - Aggregating outer unknown // riid - Interface requested // ppInterface - Returns requested interface // // Returns: UMI_S_NO_ERROR on success. Error code otherwise. // // Modifies: *ppInterface to return requested interface // //---------------------------------------------------------------------------- STDMETHODIMP CADsExtMgr::GetObjectByCLSID( CLSID clsid, IUnknown *pUnkOuter, REFIID riid, void **ppInterface ) { PCLASS_ENTRY pClassEntry = _pClassEntry; PEXTENSION_ENTRY pExtensionEntry = NULL; HRESULT hr = S_OK; IUnknown *pPrevUnk = NULL, *pUnknown = NULL; ADsAssert(ppInterface && pUnkOuter); if (!pClassEntry) { RRETURN(UMI_E_NOT_FOUND); } pExtensionEntry = pClassEntry->pExtensionHead; while (pExtensionEntry) { if (IsEqualCLSID(pExtensionEntry->ExtCLSID, clsid)) { pPrevUnk = _pUnkOuter; _pUnkOuter = pUnkOuter; hr = LoadExtensionsIfReqd(); if (FAILED(hr)) { _pUnkOuter = pPrevUnk; BAIL_ON_FAILURE(hr = E_FAIL); } pUnknown = pExtensionEntry->pUnknown; if (!pUnknown) { BAIL_ON_FAILURE(hr = E_FAIL); } *ppInterface = pUnknown; pUnknown->AddRef(); BAIL_ON_FAILURE(hr); RRETURN(S_OK); } pExtensionEntry = pExtensionEntry->pNext; } RRETURN(UMI_E_NOT_FOUND); error: RRETURN(hr); } //+--------------------------------------------------------------------------- // Function: GetCLSIDForNames --- Used for ICustomInterfaceFactory support. // // Synopsis: Returns the CLSID of the object that supports a specified // method/property. Also returns DISPIDs for the property/method. // // Arguments: rgszNames - Names to be mapped // cNames - Number of names to be mapped // lcid - Locale in which to interpret the names // rgDispId - Returns DISPID // lFlags - Reserved. Must be 0. // pCLSID - Returns CLSID of object which supports this // property/method. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *pCLSID to return the CLSID. // *rgDispId to return the DISPIDs. // //---------------------------------------------------------------------------- STDMETHODIMP CADsExtMgr::GetCLSIDForNames( LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId, long lFlags, CLSID *pCLSID ) { HRESULT hr = S_OK; PEXTENSION_ENTRY pExtension = NULL; ADsAssert(pCLSID && !lFlags && rgszNames && rgDispId); if (!_pClassEntry) { RRETURN(DISP_E_UNKNOWNNAME); } hr = LoadExtensionsIfReqd(); if (FAILED(hr)) { RRETURN(DISP_E_UNKNOWNNAME); } pExtension = _pClassEntry->pExtensionHead; while (pExtension) { if (pExtension->fDisp) { // // fDisp = TRUE indicates // 1) extension supports pADsExt AND // 2) either // a) PrivateGetIDsOfNames() does Not return E_NOTIMPL // OR // b) we don't know if a) is true or not yet // ADsAssert(pExtension->pADsExt); hr = (pExtension->pADsExt)->PrivateGetIDsOfNames( IID_NULL, rgszNames, cNames, lcid, rgDispId ); if (SUCCEEDED(hr)) { *pCLSID = pExtension->ExtCLSID; RRETURN(S_OK); } else if (hr == E_NOTIMPL) { // // extension object does not support the optional // IADsExtension::PrivateGetIDsOfNames()/PrivateInvoke() // -> remember this in cache & try next extension object // pExtension->fDisp = FALSE; } } pExtension = pExtension->pNext; } // end while RRETURN(hr = DISP_E_UNKNOWNNAME); }