//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: extension.cxx // // Contents: 3rd party extension mgmt functions // // History: 25-Oct-94 KrishnaG Created. // //---------------------------------------------------------------------------- #include "iis.hxx" #pragma hdrstop LPCWSTR lpszTopLevel = L"SOFTWARE\\Microsoft\\ADs\\Providers\\IIS"; LPCWSTR lpszExtensions = L"Extensions"; PCLASS_ENTRY gpClassHead = NULL; PCLASS_ENTRY BuildClassesList() { HKEY hTopLevelKey = NULL; HKEY hExtensionKey = NULL; HKEY hExtensionRootKey = NULL; HKEY hClassKey = NULL; DWORD dwIndex = 0; WCHAR lpszClassName[MAX_PATH]; DWORD dwchClassName = 0; PCLASS_ENTRY pClassHead = NULL; PCLASS_ENTRY pClassEntry = NULL; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpszTopLevel, 0, KEY_READ, &hTopLevelKey ) != ERROR_SUCCESS) { goto CleanupAndExit; } if (RegOpenKeyEx(hTopLevelKey, lpszExtensions, 0, KEY_READ, &hExtensionRootKey ) != ERROR_SUCCESS) { goto CleanupAndExit; } memset(lpszClassName, 0, sizeof(lpszClassName)); dwchClassName = (int) (sizeof(lpszClassName) / sizeof(WCHAR)); while(RegEnumKeyEx(hExtensionRootKey, dwIndex, lpszClassName, &dwchClassName, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS) { // // Read namespace // if (RegOpenKeyEx(hExtensionRootKey, lpszClassName, 0, KEY_READ, &hClassKey ) != ERROR_SUCCESS){ goto CleanupAndExit; } pClassEntry = BuildClassEntry( lpszClassName, hClassKey ); if (pClassEntry) { pClassEntry->pNext = pClassHead; pClassHead = pClassEntry; } if (hClassKey) { CloseHandle(hClassKey); } memset(lpszClassName, 0, sizeof(lpszClassName)); dwchClassName = (int) (sizeof(lpszClassName) / sizeof(WCHAR)); dwIndex++; } CleanupAndExit: if (hExtensionRootKey) { RegCloseKey(hExtensionRootKey); } if (hTopLevelKey) { RegCloseKey(hTopLevelKey); } return(pClassHead); } VOID FreeClassesList( PCLASS_ENTRY pClassHead ) { PCLASS_ENTRY pDelete; while (pClassHead) { pDelete = pClassHead; pClassHead = pClassHead->pNext; FreeClassEntry(pDelete); } return; } PCLASS_ENTRY BuildClassEntry( LPWSTR lpszClassName, HKEY hClassKey ) { HKEY hTopLevelKey = NULL; HKEY hExtensionKey = NULL; DWORD dwIndex = 0; DWORD dwchExtensionCLSID = 0; WCHAR lpszExtensionCLSID[MAX_PATH]; PCLASS_ENTRY pClassEntry = NULL; PEXTENSION_ENTRY pExtensionHead = NULL; PEXTENSION_ENTRY pExtensionEntry = NULL; pClassEntry = (PCLASS_ENTRY)AllocADsMem(sizeof(CLASS_ENTRY)); if (!pClassEntry) { goto CleanupAndExit; } wcscpy(pClassEntry->szClassName, lpszClassName); memset(lpszExtensionCLSID, 0, sizeof(lpszExtensionCLSID)); dwchExtensionCLSID = (int) (sizeof(lpszExtensionCLSID) / sizeof(WCHAR)); while(RegEnumKeyEx(hClassKey, dwIndex, lpszExtensionCLSID, &dwchExtensionCLSID, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS) { // // Read namespace // if (RegOpenKeyEx(hClassKey, lpszExtensionCLSID, 0, KEY_READ, &hExtensionKey ) != ERROR_SUCCESS){ goto CleanupAndExit; } // // Read the Interfaces that this Extension supports // pExtensionEntry = BuildExtensionEntry( lpszExtensionCLSID, hExtensionKey ); if (pExtensionEntry) { wcscpy(pExtensionEntry->szExtensionCLSID, lpszExtensionCLSID); pExtensionEntry->pNext = pExtensionHead; pExtensionHead = pExtensionEntry; } if (hExtensionKey) { CloseHandle(hExtensionKey); } memset(lpszExtensionCLSID, 0, sizeof(lpszExtensionCLSID)); dwchExtensionCLSID = (int) (sizeof(lpszExtensionCLSID) / sizeof(WCHAR)); dwIndex++; } pClassEntry->pExtensionHead = pExtensionHead; CleanupAndExit: return(pClassEntry); } PEXTENSION_ENTRY BuildExtensionEntry( LPWSTR lpszExtensionCLSID, HKEY hExtensionKey ) { PEXTENSION_ENTRY pExtensionEntry = NULL; PINTERFACE_ENTRY pInterfaceEntry = NULL; PINTERFACE_ENTRY pInterfaceHead = NULL; WCHAR lpszInterfaces[MAX_PATH]; DWORD dwchInterfaces = 0; LPWSTR psz = NULL; WCHAR Interface[MAX_PATH]; HRESULT hr = S_OK; pExtensionEntry = (PEXTENSION_ENTRY)AllocADsMem(sizeof(EXTENSION_ENTRY)); if (!pExtensionEntry) { goto CleanupAndExit; } memset(lpszInterfaces, 0, sizeof(lpszInterfaces)); dwchInterfaces = sizeof(lpszInterfaces); RegQueryValueEx( hExtensionKey, L"Interfaces", NULL, NULL, (LPBYTE) lpszInterfaces, &dwchInterfaces ); psz = lpszInterfaces; while (psz && *psz) { lstrcpy(Interface, psz); // skip (length) + 1 // lstrlen returns length sans '\0' pInterfaceEntry = (PINTERFACE_ENTRY)AllocADsMem(sizeof(INTERFACE_ENTRY)); if (pInterfaceEntry) { wcscpy(pInterfaceEntry->szInterfaceIID, Interface); hr = IIDFromString(Interface, &(pInterfaceEntry->iid)); pInterfaceEntry->pNext = pInterfaceHead; pInterfaceHead = pInterfaceEntry; } psz = psz + lstrlen(psz) + 1; } wcscpy(pExtensionEntry->szExtensionCLSID, lpszExtensionCLSID); hr = CLSIDFromString(lpszExtensionCLSID, &(pExtensionEntry->ExtCLSID)); pExtensionEntry->pIID = pInterfaceHead; CleanupAndExit: return(pExtensionEntry); } void FreeInterfaceEntry( PINTERFACE_ENTRY pInterfaceEntry ) { if (pInterfaceEntry) { FreeADsMem(pInterfaceEntry); } } void FreeExtensionEntry( PEXTENSION_ENTRY pExtensionEntry ) { PINTERFACE_ENTRY pInterfaceEntry = NULL; PINTERFACE_ENTRY pTemp = NULL; if (pExtensionEntry) { pInterfaceEntry = pExtensionEntry->pIID; while (pInterfaceEntry) { pTemp = pInterfaceEntry->pNext; if (pInterfaceEntry) { FreeInterfaceEntry(pInterfaceEntry); } pInterfaceEntry = pTemp; } // // Now unload the Extension Object // if (pExtensionEntry->pUnknown) { // // Call non-delegating Release to release ref. count on innner // object to inner object -> inner object self destroyed. // (pExtensionEntry->pUnknown)->Release(); } FreeADsMem(pExtensionEntry); } return; } void FreeClassEntry( PCLASS_ENTRY pClassEntry ) { PEXTENSION_ENTRY pExtensionEntry = NULL; PEXTENSION_ENTRY pTemp = NULL; if (pClassEntry) { pExtensionEntry = pClassEntry->pExtensionHead; while (pExtensionEntry) { pTemp = pExtensionEntry->pNext; if (pExtensionEntry) { FreeExtensionEntry(pExtensionEntry); } pExtensionEntry = pTemp; } FreeADsMem(pClassEntry); } return; } PINTERFACE_ENTRY MakeCopyofInterfaceEntry( PINTERFACE_ENTRY pInterfaceEntry ) { PINTERFACE_ENTRY pNewInterfaceEntry = NULL; pNewInterfaceEntry = (PINTERFACE_ENTRY)AllocADsMem(sizeof(INTERFACE_ENTRY)); if (pNewInterfaceEntry) { wcscpy(pNewInterfaceEntry->szInterfaceIID, pInterfaceEntry->szInterfaceIID); memcpy(&(pNewInterfaceEntry->iid), &(pInterfaceEntry->iid), sizeof(GUID)); } return(pNewInterfaceEntry); } PEXTENSION_ENTRY MakeCopyofExtensionEntry( PEXTENSION_ENTRY pExtensionEntry ) { PEXTENSION_ENTRY pNewExtensionEntry = NULL; PINTERFACE_ENTRY pInterfaceEntry = NULL; PINTERFACE_ENTRY pNewInterfaceEntry = NULL; PINTERFACE_ENTRY pNewInterfaceHead = NULL; pInterfaceEntry = pExtensionEntry->pIID; while (pInterfaceEntry) { pNewInterfaceEntry = MakeCopyofInterfaceEntry(pInterfaceEntry); if (pNewInterfaceEntry) { pNewInterfaceEntry->pNext = pNewInterfaceHead; pNewInterfaceHead = pNewInterfaceEntry; } pInterfaceEntry = pInterfaceEntry->pNext; } pNewExtensionEntry = (PEXTENSION_ENTRY)AllocADsMem(sizeof(EXTENSION_ENTRY)); if (pNewExtensionEntry) { wcscpy( pNewExtensionEntry->szExtensionCLSID, pExtensionEntry->szExtensionCLSID ); memcpy( &(pNewExtensionEntry->ExtCLSID), &(pExtensionEntry->ExtCLSID), sizeof(GUID) ); pNewExtensionEntry->pIID = pNewInterfaceHead; // // Initialize fields we won't know the values of until an instacne of // the extension is created and aggregated (loaded). // pNewExtensionEntry->pUnknown=NULL; pNewExtensionEntry->pPrivDisp=NULL; pNewExtensionEntry->pADsExt=NULL; pNewExtensionEntry->fDisp=FALSE; pNewExtensionEntry->dwExtensionID = (DWORD) -1; //invalid dwExtensionID // // let class entry handle pNext // } return(pNewExtensionEntry); } PCLASS_ENTRY MakeCopyofClassEntry( PCLASS_ENTRY pClassEntry ) { PCLASS_ENTRY pNewClassEntry = NULL; PEXTENSION_ENTRY pExtensionEntry = NULL; PEXTENSION_ENTRY pNewExtensionEntry = NULL; PEXTENSION_ENTRY pNewExtensionHead = NULL; pExtensionEntry = pClassEntry->pExtensionHead; while (pExtensionEntry) { pNewExtensionEntry = MakeCopyofExtensionEntry(pExtensionEntry); if (pNewExtensionEntry) { pNewExtensionEntry->pNext = pNewExtensionHead; pNewExtensionHead = pNewExtensionEntry; } pExtensionEntry = pExtensionEntry->pNext; } pNewClassEntry = (PCLASS_ENTRY)AllocADsMem(sizeof(CLASS_ENTRY)); if (pNewClassEntry) { wcscpy(pNewClassEntry->szClassName, pClassEntry->szClassName); pNewClassEntry->pExtensionHead = pNewExtensionHead; } return(pNewClassEntry); } CRITICAL_SECTION g_ExtCritSect; #define ENTER_EXTENSION_CRITSECT() EnterCriticalSection(&g_ExtCritSect) #define LEAVE_EXTENSION_CRITSECT() LeaveCriticalSection(&g_ExtCritSect) HRESULT ADSIGetExtensionList( LPWSTR pszClassName, PCLASS_ENTRY * ppClassEntry ) { PCLASS_ENTRY pTempClassEntry = NULL; PCLASS_ENTRY pClassEntry = NULL; ENTER_EXTENSION_CRITSECT(); pTempClassEntry = gpClassHead; while (pTempClassEntry) { if (!_wcsicmp(pTempClassEntry->szClassName, pszClassName)) { // // Make a copy of this entire extension and // hand it over to the calling entity. // pClassEntry = MakeCopyofClassEntry(pTempClassEntry); *ppClassEntry = pClassEntry; LEAVE_EXTENSION_CRITSECT(); RRETURN(S_OK); } pTempClassEntry = pTempClassEntry->pNext; } *ppClassEntry = NULL; LEAVE_EXTENSION_CRITSECT(); RRETURN(S_OK); } // // Instantiate extension objects listed in as aggregatees of // aggregator . Initialize extensions with . // // Max Load 127 extensions. Return S_FALSE if more extension in // EXTTODO: define S_??? in future for > unloaded extension -> passed to // ADSI clients. // HRESULT ADSILoadExtensions2( IUnknown FAR * pUnkOuter, CCredentials& Credentials, PCLASS_ENTRY pClassEntry ) { 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; ASSERT(pUnkOuter); 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)) { RRETURN(S_OK); } dwAuthFlags = Credentials.GetAuthFlags(); while (pExtEntry) { // // Max # of extension have been loaded, cannot load more // if (dwExtensionID>MAX_EXTENSION_ID) { // // EXTTODO: S_FALSE for now. See hdr doc for future plan. // hr = S_FALSE; 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) // // EXTTODO: no warning to user about failure // 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 ); } } // 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) { FreeADsStr(pszPassword); } VariantClear(pvarUserName); VariantClear(pvarPassword); VariantClear(pvarAuthFlags); if (fReturnError) { RRETURN(hr); // fetal error, } else { RRETURN(S_OK); // "okay" error if any, optional support } } HRESULT ADSILoadExtensions( IUnknown FAR * pUnkOuter, CCredentials& Credentials, PCLASS_ENTRY pClassEntry, LPTSTR pszClassName ) { HRESULT hr = S_OK; PEXTENSION_ENTRY pExtensionEntry = NULL; DWORD dwExtensionID = 1; IPrivateDispatch * pPrivDisp = NULL; LPWSTR pszUserName = NULL; LPWSTR pszPassword = NULL; DWORD dwAuthFlags = 0; hr = Credentials.GetUserName(&pszUserName); if (FAILED(hr)) { RRETURN(S_OK); } hr = Credentials.GetPassword(&pszPassword); if (FAILED(hr)) { RRETURN(S_OK); } dwAuthFlags = Credentials.GetAuthFlags(); pExtensionEntry = pClassEntry->pExtensionHead; while (pExtensionEntry) { hr = CoCreateInstance( pExtensionEntry->ExtCLSID, pUnkOuter, CLSCTX_INPROC_SERVER, IID_IPrivateUnknown, (void **)&(pExtensionEntry->pUnknown) ); if (SUCCEEDED(hr)) { hr = (pExtensionEntry->pUnknown)->ADSIInitializeObject( pszUserName, pszPassword, dwAuthFlags ); pExtensionEntry->dwExtensionID = dwExtensionID; hr = (pExtensionEntry->pUnknown)->QueryInterface( IID_IPrivateDispatch, (void **)&pPrivDisp ); if (SUCCEEDED(hr)) { hr = pPrivDisp->ADSIInitializeDispatchManager(dwExtensionID); if (FAILED(hr)) { // // Remember NOT to do a Release here for IPrivateDispatch // pExtensionEntry->fDisp = FALSE; (pExtensionEntry->pUnknown)->Release(); }else { pExtensionEntry->fDisp = TRUE; pExtensionEntry->pPrivDisp = pPrivDisp; // // Now release both pointers because we don't want to // have a cyclic reference count // (pExtensionEntry->pPrivDisp)->Release(); (pExtensionEntry->pUnknown)->Release(); } }else { pExtensionEntry->fDisp = FALSE; (pExtensionEntry->pUnknown)->Release(); } } pExtensionEntry = pExtensionEntry->pNext; dwExtensionID++; } if (pszUserName) { FreeADsStr(pszUserName); } if (pszPassword) { FreeADsStr(pszPassword); } RRETURN(S_OK); }