//--------------------------------------------------------------------- // Copyright (C)1998 Microsoft Corporation, All Rights Reserved. // // registry.cpp // //--------------------------------------------------------------------- #define UNICODE #define INITGUID #include #include #include #include // for: SELFREG_E_CLASS #include // COM Interface header #include // MD_ & IIS_MD_ #defines #include #include #include #include #include #include #include #include #include #include #include #include #include #include // uncomment to debug setup problems /* #ifndef DBG_REG #define DBG_REG 1 #endif // DBG_REG #define DBG_ERROR 1 */ // this defines control whether we will compile for the IIS security // console or for the lockdown list. #define IIS_SEC_CONSOLE 1 //#define IIS_LOCKDOWN_LIST //---------------------------------------------------------------- // Globals: //---------------------------------------------------------------- const rpcconn_tunnel_settings EchoRTS = { { OSF_RPC_V20_VERS, OSF_RPC_V20_VERS_MINOR, rpc_rts, PFC_FIRST_FRAG | PFC_LAST_FRAG, { NDR_LOCAL_CHAR_DREP | NDR_LOCAL_INT_DREP, NDR_LOCAL_FP_DREP, 0, 0 }, FIELD_OFFSET(rpcconn_tunnel_settings, Cmd) + ConstPadN(FIELD_OFFSET(rpcconn_tunnel_settings, Cmd), 4), 0, 0 }, RTS_FLAG_ECHO, 0 }; const BYTE *GetEchoRTS ( OUT ULONG *EchoRTSSize ) { *EchoRTSSize = FIELD_OFFSET(rpcconn_tunnel_settings, Cmd) + ConstPadN(FIELD_OFFSET(rpcconn_tunnel_settings, Cmd), 4); return (const BYTE *)&EchoRTS; } HMODULE g_hInst = NULL; //---------------------------------------------------------------- // AnsiToUnicode() // // Convert an ANSI string to a UNICODE string. //---------------------------------------------------------------- DWORD AnsiToUnicode( IN UCHAR *pszString, IN ULONG ulStringLen, OUT WCHAR *pwsString ) { if (!pszString) { if (!pwsString) { return NO_ERROR; } else { pwsString[0] = 0; return NO_ERROR; } } if (!MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (char*)pszString, 1+ulStringLen, pwsString, 1+ulStringLen )) { return ERROR_NO_UNICODE_TRANSLATION; } return NO_ERROR; } //--------------------------------------------------------------------- // RegSetKeyAndValueIfDontExist() // // Private helper function for SetupRegistry() that checks if a key exists, // and if not, creates a key, sets a value, then closes the key. If key // exists, it is not touched. // // Parameters: // pwsKey WCHAR* The name of the key // pwsSubkey WCHAR* The name of a subkey // pwsValueName WCHAR* The value name. // pwsValue WCHAR* The data value to store // dwType The type for the new registry value. // dwDataSize The size for non-REG_SZ registry entry types. // // Return: // BOOL TRUE if successful, FALSE otherwise. //--------------------------------------------------------------------- BOOL RegSetKeyAndValueIfDontExist( const WCHAR *pwsKey, const WCHAR *pwsSubKey, const WCHAR *pwsValueName, const WCHAR *pwsValue, const DWORD dwType = REG_SZ, DWORD dwDataSize = 0 ) { HKEY hKey; DWORD dwSize = 0; WCHAR *pwsCompleteKey; DWORD dwTypeFound; long Error; if (pwsKey) dwSize = wcslen(pwsKey); if (pwsSubKey) dwSize += wcslen(pwsSubKey); dwSize = (1+1+dwSize)*sizeof(WCHAR); // Extra +1 for the backslash... pwsCompleteKey = (WCHAR*)_alloca(dwSize); wcscpy(pwsCompleteKey,pwsKey); if (NULL!=pwsSubKey) { wcscat(pwsCompleteKey, TEXT("\\")); wcscat(pwsCompleteKey, pwsSubKey); } if ((Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pwsCompleteKey, 0, KEY_WRITE | KEY_QUERY_VALUE, &hKey) ) == ERROR_SUCCESS ) { if (( Error = RegQueryValueEx( hKey, pwsValueName, 0, &dwTypeFound, NULL, NULL ) ) == ERROR_SUCCESS ) { RegCloseKey(hKey); return TRUE; } // the key exists, but the value does not. Fall through to // create it } else { if (ERROR_SUCCESS != RegCreateKeyEx( HKEY_LOCAL_MACHINE, pwsCompleteKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)) { return FALSE; } } if (pwsValue) { if ((dwType == REG_SZ)||(dwType == REG_EXPAND_SZ)) dwDataSize = (1+wcslen(pwsValue))*sizeof(WCHAR); RegSetValueEx( hKey, pwsValueName, 0, dwType, (BYTE *)pwsValue, dwDataSize ); } else { RegSetValueEx( hKey, pwsValueName, 0, dwType, (BYTE *)pwsValue, 0 ); } RegCloseKey(hKey); return TRUE; } const WCHAR * const EVENT_LOG_SOURCE_NAME = L"RPC Proxy"; const WCHAR * const EVENT_LOG_KEY_NAME = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\RPC Proxy"; const ULONG EVENT_LOG_CATEGORY_COUNT = 1; HRESULT RegisterEventLog() { HKEY EventLogKey = NULL; DWORD Disposition; LONG Result = RegCreateKeyEx( HKEY_LOCAL_MACHINE, // handle to open key EVENT_LOG_KEY_NAME, // subkey name 0, // reserved NULL, // class string 0, // special options KEY_ALL_ACCESS, // desired security access NULL, // inheritance &EventLogKey, // key handle &Disposition // disposition value buffer ); if ( Result ) { #if DBG DbgPrint("RPCProxy: Can't create Eventlog key: %X\n", GetLastError()); #endif // DBG return HRESULT_FROM_WIN32( Result ); } DWORD Value = EVENT_LOG_CATEGORY_COUNT; Result = RegSetValueEx( EventLogKey, // handle to key L"CategoryCount", // value name 0, // reserved REG_DWORD, // value type (BYTE*)&Value, // value data sizeof(Value) // size of value data ); if ( Result ) { #if DBG DbgPrint("RPCProxy: Can't set CategoryCount value: %X\n", GetLastError()); #endif // DBG goto error; } const WCHAR MessageFileName[] = L"%SystemRoot%\\system32\\rpcproxy\\rpcproxy.dll"; const DWORD MessageFileNameSize = sizeof( MessageFileName ); Result = RegSetValueEx( EventLogKey, // handle to key L"CategoryMessageFile", // value name 0, // reserved REG_EXPAND_SZ, // value type (const BYTE*)MessageFileName, // value data MessageFileNameSize // size of value data ); if ( Result ) { #if DBG DbgPrint("RPCProxy: Can't set CategoryMessageFile value: %X\n", GetLastError()); #endif // DBG goto error; } Result = RegSetValueEx( EventLogKey, // handle to key L"EventMessageFile", // value name 0, // reserved REG_EXPAND_SZ, // value type (const BYTE*)MessageFileName, // value data MessageFileNameSize // size of value data ); if ( Result ) { #if DBG DbgPrint("RPCProxy: Can't set EventMessageFile value: %X\n", GetLastError()); #endif // DBG goto error; } Value = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; Result = RegSetValueEx( EventLogKey, // handle to key L"TypesSupported", // value name 0, // reserved REG_DWORD, // value type (BYTE*)&Value, // value data sizeof(Value) // size of value data ); if ( Result ) { #if DBG DbgPrint("RPCProxy: Can't set TypesSupported value: %X\n", GetLastError()); #endif // DBG goto error; } RegCloseKey( EventLogKey ); EventLogKey = NULL; return S_OK; error: if ( EventLogKey ) { RegCloseKey( EventLogKey ); EventLogKey = NULL; } if ( REG_CREATED_NEW_KEY == Disposition ) { RegDeleteKey( HKEY_LOCAL_MACHINE, EVENT_LOG_KEY_NAME ); } return HRESULT_FROM_WIN32( Result ); } HRESULT UnRegisterEventLog() { RegDeleteKey( HKEY_LOCAL_MACHINE, EVENT_LOG_KEY_NAME ); return S_OK; } HRESULT RPCProxyGetStartupInfo( LPSTARTUPINFOA lpStartupInfo ) { __try { GetStartupInfoA( lpStartupInfo ); } __except( EXCEPTION_EXECUTE_HANDLER ) { return E_OUTOFMEMORY; } return S_OK; } BOOL RegisterOutOfProc(void) { // // Runs a child process // STARTUPINFOA StartupInfo; HRESULT Hr = RPCProxyGetStartupInfo( &StartupInfo ); if ( FAILED( Hr ) ) { SetLastError( Hr ); return FALSE; } PROCESS_INFORMATION ProcessInfo; CHAR sApplicationPath[MAX_PATH]; CHAR *pApplicationName = NULL; CHAR sCmdLine[MAX_PATH]; DWORD dwLen = MAX_PATH; DWORD dwCount; dwCount = SearchPathA(NULL, // Search Path, NULL is PATH "regsvr32.exe", // Application NULL, // Extension (already specified) dwLen, // Length (char's) of sApplicationPath sApplicationPath, // Path + Name for application &pApplicationName ); // File part of sApplicationPath if (dwCount == 0) { return FALSE; } if (dwCount > dwLen) { SetLastError( ERROR_BUFFER_OVERFLOW ); return FALSE; } strcpy(sCmdLine, "regsvr32 /s rpcproxy.dll"); BOOL RetVal = CreateProcessA( sApplicationPath, // name of executable module sCmdLine, // command line string NULL, // SD NULL, // SD FALSE, // handle inheritance option CREATE_NO_WINDOW, // creation flags NULL, // new environment block NULL, // current directory name &StartupInfo, // startup information &ProcessInfo // process information ); if ( !RetVal ) return FALSE; WaitForSingleObject( ProcessInfo.hProcess, INFINITE ); DWORD Status; GetExitCodeProcess( ProcessInfo.hProcess, &Status ); CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread ); if ( ERROR_SUCCESS == Status ) return TRUE; SetLastError( Status ); return FALSE; } //--------------------------------------------------------------------- // SetupRegistry() // // Add RPC proxy specific registry entries to contol its operation. // // \HKEY_LOCAL_MACHINE // \Software // \Microsoft // \Rpc // \RpcProxy // \Enabled:REG_DWORD:0x00000001 // \ValidPorts:REG_SZ::1-5000 // //--------------------------------------------------------------------- HRESULT SetupRegistry() { DWORD dwEnabled = 0x01; DWORD dwSize; DWORD dwStatus; WCHAR *pwsValidPorts = 0; char szHostName[MAX_TCPIP_HOST_NAME]; HRESULT hr; // Note that gethostname() is an ANSI (non-unicode) function: if (SOCKET_ERROR == gethostname(szHostName,sizeof(szHostName))) { dwStatus = WSAGetLastError(); return SELFREG_E_CLASS; } dwSize = 1 + _mbstrlen(szHostName); pwsValidPorts = (WCHAR*)MemAllocate( sizeof(WCHAR) * (dwSize + wcslen(REG_PORT_RANGE)) ); if (!pwsValidPorts) { return E_OUTOFMEMORY; } dwStatus = AnsiToUnicode((unsigned char*)szHostName,dwSize,pwsValidPorts); if (dwStatus != NO_ERROR) { MemFree(pwsValidPorts); return SELFREG_E_CLASS; } wcscat(pwsValidPorts,REG_PORT_RANGE); if ( !RegSetKeyAndValueIfDontExist( REG_RPC_PATH, REG_RPCPROXY, REG_ENABLED, (unsigned short *)&dwEnabled, REG_DWORD, sizeof(DWORD)) || !RegSetKeyAndValueIfDontExist( REG_RPC_PATH, REG_RPCPROXY, REG_VALID_PORTS, pwsValidPorts, REG_SZ) ) { MemFree(pwsValidPorts); return SELFREG_E_CLASS; } MemFree(pwsValidPorts); hr = RegisterEventLog (); return hr; } //--------------------------------------------------------------------- // CleanupRegistry() // // Delete the RpcProxy specific registry entries. //--------------------------------------------------------------------- HRESULT CleanupRegistry() { HRESULT hr; LONG lStatus; DWORD dwLength = sizeof(WCHAR) + sizeof(REG_RPC_PATH) + sizeof(REG_RPCPROXY); WCHAR *pwsSubKey; pwsSubKey = (WCHAR*)_alloca(sizeof(WCHAR)*dwLength); wcscpy(pwsSubKey,REG_RPC_PATH); wcscat(pwsSubKey,TEXT("\\")); wcscat(pwsSubKey,REG_RPCPROXY); lStatus = RegDeleteKey( HKEY_LOCAL_MACHINE, pwsSubKey ); (void) UnRegisterEventLog (); return S_OK; } //--------------------------------------------------------------------- // GetMetaBaseString() // // Retrieve a string value from the metabase. //--------------------------------------------------------------------- HRESULT GetMetaBaseString( IN IMSAdminBase *pIMeta, IN METADATA_HANDLE hMetaBase, IN WCHAR *pwsKeyPath, IN DWORD dwIdent, OUT WCHAR *pwsBuffer, IN OUT DWORD *pdwBufferSize ) { HRESULT hr; DWORD dwSize; METADATA_RECORD *pmbRecord; dwSize = sizeof(METADATA_RECORD); pmbRecord = (METADATA_RECORD*)MemAllocate(dwSize); if (!pmbRecord) { return ERROR_OUTOFMEMORY; } memset(pmbRecord,0,dwSize); pmbRecord->dwMDIdentifier = dwIdent; pmbRecord->dwMDAttributes = 0; // METADATA_INHERIT; pmbRecord->dwMDUserType = IIS_MD_UT_SERVER; pmbRecord->dwMDDataType = STRING_METADATA; pmbRecord->dwMDDataLen = *pdwBufferSize; pmbRecord->pbMDData = (BYTE*)pwsBuffer; hr = pIMeta->GetData( hMetaBase, pwsKeyPath, pmbRecord, &dwSize ); #ifdef DBG_REG if (FAILED(hr)) { DbgPrint("pIMeta->GetData(): Failed: 0x%x\n",hr); } #endif MemFree(pmbRecord); return hr; } //--------------------------------------------------------------------- // SetMetaBaseString() // // Store a string value into the metabase. //--------------------------------------------------------------------- HRESULT SetMetaBaseString( IMSAdminBase *pIMeta, METADATA_HANDLE hMetaBase, WCHAR *pwsKeyPath, DWORD dwIdent, WCHAR *pwsBuffer, DWORD dwAttributes, DWORD dwUserType ) { HRESULT hr; METADATA_RECORD MbRecord; memset(&MbRecord,0,sizeof(MbRecord)); MbRecord.dwMDIdentifier = dwIdent; MbRecord.dwMDAttributes = dwAttributes; MbRecord.dwMDUserType = dwUserType; MbRecord.dwMDDataType = STRING_METADATA; MbRecord.dwMDDataLen = sizeof(WCHAR) * (1 + wcslen(pwsBuffer)); MbRecord.pbMDData = (BYTE*)pwsBuffer; hr = pIMeta->SetData( hMetaBase, pwsKeyPath, &MbRecord ); return hr; } #if IIS_LOCKDOWN_LIST HRESULT AddDllToIISList( SAFEARRAY* Array ) { // // Add the ISAPI to the IIS list. // HRESULT Hr; WCHAR ExtensionPath[ MAX_PATH ]; DWORD dwRet = GetModuleFileNameW( g_hInst, ExtensionPath, MAX_PATH ); if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() ); // Search for the DLL. If its already in the list, do nothing Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr; for ( unsigned int i = Array->rgsabound[0].lLbound; i < Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; i++ ) { VARIANT & IElem = ((VARIANT*)Array->pvData)[i]; if ( _wcsicmp( (WCHAR*)IElem.bstrVal, ExtensionPath ) == 0 ) { SafeArrayUnlock( Array ); return S_OK; } } // Need to add the DLL SAFEARRAYBOUND SafeBounds; SafeBounds.lLbound = Array->rgsabound[0].lLbound; SafeBounds.cElements = Array->rgsabound[0].cElements+1; SafeArrayUnlock( Array ); Hr = SafeArrayRedim( Array, &SafeBounds ); if ( FAILED( Hr ) ) return Hr; VARIANT bstrvar; VariantInit( &bstrvar ); bstrvar.vt = VT_BSTR; bstrvar.bstrVal = SysAllocString( ExtensionPath ); long Index = SafeBounds.lLbound + SafeBounds.cElements - 1; Hr = SafeArrayPutElement( Array, &Index, (void*)&bstrvar ); VariantClear( &bstrvar ); if ( FAILED( Hr ) ) return Hr; return S_OK; } HRESULT RemoveDllFromIISList( SAFEARRAY *Array ) { // Remove the DLL from the IIS list HRESULT Hr; WCHAR ExtensionPath[ MAX_PATH ]; DWORD dwRet = GetModuleFileNameW( g_hInst, ExtensionPath, MAX_PATH ); if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() ); Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr; ULONG NewSize = 0; SIZE_T j = Array->rgsabound[0].lLbound; SIZE_T k = Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; while( j < k ) { VARIANT & JElem = ((VARIANT*)Array->pvData)[j]; // This element is fine, keep it if ( 0 != _wcsicmp( (WCHAR*)JElem.bstrVal, ExtensionPath ) ) { NewSize++; j++; } else { // find a suitable element to replace the bad element with while( j < --k ) { VARIANT & KElem = ((VARIANT*)Array->pvData)[k]; if ( 0 != _wcsicmp( (WCHAR*)KElem.bstrVal, ExtensionPath ) ) { // found element. move it VARIANT temp = JElem; JElem = KElem; KElem = temp; break; } } } } SAFEARRAYBOUND ArrayBounds; ArrayBounds = Array->rgsabound[0]; ArrayBounds.cElements = NewSize; SafeArrayUnlock( Array ); Hr = SafeArrayRedim( Array, &ArrayBounds ); if ( FAILED( Hr ) ) return Hr; return S_OK; } #endif // #if #if IIS_LOCKDOWN_LIST #if IIS_SEC_CONSOLE HRESULT EnableRpcProxyExtension ( void ) /*++ Routine Description: Enables the rpc proxy extension in the list of IIS ISAPI extensions. Arguments: Return Value: Standard HRESULT --*/ { HRESULT hr; WCHAR* wszRootWeb6 = L"IIS://LOCALHOST/W3SVC"; IISWebService * pWeb = NULL; VARIANT var1,var2; BSTR ExtensionPath = NULL; BSTR ExtensionGroup = NULL; BSTR ExtensionDescription = NULL; WCHAR FilterPath[ MAX_PATH + 1 ]; WCHAR ExtensionNameBuffer[ MAX_PATH ]; DWORD dwRet; hr = ADsGetObject(wszRootWeb6, IID_IISWebService, (void**)&pWeb); if (SUCCEEDED(hr) && NULL != pWeb) { VariantInit(&var1); VariantInit(&var2); var1.vt = VT_BOOL; var1.boolVal = VARIANT_TRUE; var2.vt = VT_BOOL; var2.boolVal = VARIANT_TRUE; dwRet = GetModuleFileNameW( g_hInst, FilterPath, MAX_PATH ); if ( (dwRet > 0) && (dwRet != MAX_PATH)) { FilterPath[MAX_PATH] = '\0'; ASSERT(GetLastError() == NO_ERROR); } else { ASSERT(GetLastError() != NO_ERROR); hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanupAndExit; } if (! LoadStringW(g_hInst, // handle to resource module IDS_EXTENSION_NAME, // resource identifier ExtensionNameBuffer, // resource buffer MAX_PATH ) ) // size of buffer { hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanupAndExit; } ExtensionPath = SysAllocString(FilterPath); if (ExtensionPath == NULL) { hr = E_OUTOFMEMORY; goto CleanupAndExit; } ExtensionGroup = SysAllocString(L"RPCProxy"); if (ExtensionGroup == NULL) { hr = E_OUTOFMEMORY; goto CleanupAndExit; } ExtensionDescription = SysAllocString(ExtensionNameBuffer); if (ExtensionDescription == NULL) { hr = E_OUTOFMEMORY; goto CleanupAndExit; } // During an upgrade the extension will already exist, so the API will fail. hr = pWeb->AddExtensionFile(ExtensionPath, var1, ExtensionGroup, var2, ExtensionDescription); if (SUCCEEDED(hr)) { hr = pWeb->AddDependency(ExtensionPath, ExtensionGroup); if (SUCCEEDED(hr)) { hr = S_OK; } } else { if (HRESULT_CODE(hr) == ERROR_DUP_NAME) { hr = S_OK; } else { #ifdef DBG_ERROR DbgPrint("pWeb->AddExtensionFile failed: %X\r\n", hr); #endif // fall through with hr } } VariantClear(&var1); VariantClear(&var2); pWeb->Release(); } else { #ifdef DBG_ERROR DbgPrint("FAIL:no object: %X\r\n", hr); #endif // fall through with hr } CleanupAndExit: if (ExtensionPath != NULL) SysFreeString(ExtensionPath); if (ExtensionGroup != NULL) SysFreeString(ExtensionGroup); if (ExtensionDescription != NULL) SysFreeString(ExtensionDescription); return hr; } HRESULT DisableRpcProxyExtension ( void ) /*++ Routine Description: Disables the rpc proxy extension in the list of IIS ISAPI extensions. Arguments: Return Value: Standard HRESULT --*/ { BSTR ExtensionPath = NULL; HRESULT hr; WCHAR* wszRootWeb6 = L"IIS://LOCALHOST/W3SVC"; IISWebService * pWeb = NULL; DWORD dwRet; WCHAR FilterPath[ MAX_PATH + 1 ]; hr = ADsGetObject(wszRootWeb6, IID_IISWebService, (void**)&pWeb); if (SUCCEEDED(hr) && NULL != pWeb) { dwRet = GetModuleFileNameW( g_hInst, FilterPath, MAX_PATH ); if ( (dwRet > 0) && (dwRet != MAX_PATH)) { FilterPath[MAX_PATH] = '\0'; ASSERT(GetLastError() == NO_ERROR); } else { ASSERT(GetLastError() != NO_ERROR); hr = HRESULT_FROM_WIN32( GetLastError() ); goto CleanupAndExit; } ExtensionPath = SysAllocString(FilterPath); if (ExtensionPath == NULL) { hr = E_OUTOFMEMORY; goto CleanupAndExit; } // Call DeleteExtensionFileRecord for each of the DLLs you are removing // from the system. This removes entries from WSERL. hr = pWeb->DeleteExtensionFileRecord(ExtensionPath); if (SUCCEEDED(hr)) { // Call RemoveApplication (pYourAppName) - this removes your entry from // ApplicationDependencies hr = pWeb->RemoveApplication(ExtensionPath); // fall through with the hr } else { #ifdef DBG_ERROR DbgPrint("pWeb->DeleteExtensionFileRecord failed: %X\r\n", hr); #endif // fall through with the hr } } else { // fall through with the hr } CleanupAndExit: if (ExtensionPath != NULL) SysFreeString(ExtensionPath); return hr; } #endif // #if IIS_SEC_CONSOLE #if IIS_LOCKDOWN_LIST HRESULT ModifyLockdownList( bool Add ) { // Toplevel function to modify the IIS lockdown list. // If Add is 1, then the ISAPI is added. If Add is 0, then the ISAPI is removed. HRESULT Hr; IADs *Service = NULL; SAFEARRAY* Array = NULL; bool ArrayLocked = false; VARIANT var; VariantInit( &var ); Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC" ), __uuidof( IADs ), (void**)&Service ); if ( FAILED( Hr ) ) return Hr; Hr = Service->Get( BSTR( L"IsapiRestrictionList" ), &var ); if ( FAILED(Hr) ) { // This property doesn't exist on IIS5 or IIS5.1 don't install it Hr = S_OK; goto cleanup; } Array = var.parray; Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) goto cleanup; ArrayLocked = true; if ( !Array->rgsabound[0].cElements ) { // The array has no elements which means no restrictions. Hr = S_OK; goto cleanup; } VARIANT & FirstElem = ((VARIANT*)Array->pvData)[ Array->rgsabound[0].lLbound ]; if ( _wcsicmp(L"0", (WCHAR*)FirstElem.bstrVal ) == 0 ) { // // According to the IIS6 spec, a 0 means that all ISAPIs are denied except // those that are explicitly listed. // // If installing: add to the list. // If uninstalling: remove from the list // SafeArrayUnlock( Array ); ArrayLocked = false; if ( Add ) Hr = AddDllToIISList( Array ); else Hr = RemoveDllFromIISList( Array ); if ( FAILED( Hr ) ) goto cleanup; } else if ( _wcsicmp( L"1", (WCHAR*)FirstElem.bstrVal ) == 0 ) { // // According to the IIS6 spec, a 1 means that all ISAPIs are allowed except // those that are explicitly denied. // // If installing: remove from the list // If uninstalling: Do nothing // SafeArrayUnlock( Array ); ArrayLocked = false; if ( Add ) { Hr = RemoveDllFromIISList( Array ); if ( FAILED( Hr ) ) goto cleanup; } } else { Hr = E_FAIL; goto cleanup; } Hr = Service->Put( BSTR( L"IsapiRestrictionList" ), var ); if ( FAILED( Hr ) ) goto cleanup; Hr = Service->SetInfo(); if ( FAILED( Hr ) ) goto cleanup; Hr = S_OK; cleanup: if ( Array && ArrayLocked ) SafeArrayUnlock( Array ); if ( Service ) Service->Release(); VariantClear( &var ); return Hr; } HRESULT AddToLockdownListDisplayPutString( SAFEARRAY *Array, unsigned long Position, const WCHAR *String ) { HRESULT Hr; VARIANT Var; VariantInit( &Var ); Var.vt = VT_BSTR; Var.bstrVal = SysAllocString( String ); if ( !Var.bstrVal ) return E_OUTOFMEMORY; long Index = (unsigned long)Position; Hr = SafeArrayPutElement( Array, &Index, (void*)&Var ); VariantClear( &Var ); return Hr; } HRESULT AddToLockdownListDisplay( SAFEARRAY *Array ) { HRESULT Hr; WCHAR FilterPath[ MAX_PATH ]; DWORD dwRet = GetModuleFileNameW( g_hInst, FilterPath, MAX_PATH ); if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() ); WCHAR ExtensionName[ MAX_PATH ]; if (! LoadStringW(g_hInst, // handle to resource module IDS_EXTENSION_NAME, // resource identifier ExtensionName, // resource buffer MAX_PATH ) ) // size of buffer return HRESULT_FROM_WIN32( GetLastError() ); // // Check to see if the ISAPI is already in the list. If it is, don't modify // list. // Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr; for( unsigned long i = Array->rgsabound[0].lLbound; i < Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; i++ ) { VARIANT & CurrentElement = ((VARIANT*)Array->pvData)[ i ]; BSTR BSTRString = CurrentElement.bstrVal; if ( _wcsicmp( (WCHAR*)BSTRString, FilterPath ) == 0 ) { // ISAPI is already in the list, don't do anything SafeArrayUnlock( Array ); return S_OK; } } SAFEARRAYBOUND SafeArrayBound = Array->rgsabound[0]; unsigned long OldSize = SafeArrayBound.cElements; SafeArrayBound.cElements += 3; SafeArrayUnlock( Array ); Hr = SafeArrayRedim( Array, &SafeArrayBound ); if ( FAILED( Hr ) ) return Hr; Hr = AddToLockdownListDisplayPutString( Array, OldSize, L"1" ); if ( FAILED( Hr ) ) return Hr; Hr = AddToLockdownListDisplayPutString( Array, OldSize + 1, FilterPath ); if ( FAILED( Hr ) ) return Hr; Hr = AddToLockdownListDisplayPutString( Array, OldSize + 2, ExtensionName ); if ( FAILED( Hr ) ) return Hr; return S_OK; } HRESULT SafeArrayRemoveSlice( SAFEARRAY *Array, unsigned long lBound, unsigned long uBound ) { // Remove a slice of an array. SIZE_T ElementsToRemove = uBound - lBound + 1; HRESULT Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr; if ( uBound + 1 < Array->rgsabound[0].cElements ) { // At least one element exists above this element // Step 1, move slice to temp storage VARIANT *Temp = (VARIANT*)_alloca( sizeof(VARIANT) * ElementsToRemove ); memcpy( Temp, &((VARIANT*)Array->pvData)[ lBound ], sizeof(VARIANT)*ElementsToRemove ); // Step 2, collapse hole left by slice memmove( &((VARIANT*)Array->pvData)[ lBound ], &((VARIANT*)Array->pvData)[ uBound + 1 ], sizeof(VARIANT) * ( Array->rgsabound[0].cElements - ( uBound + 1 ) ) ); // Step 3, move slice to end of array memcpy( &((VARIANT*)Array->pvData)[ Array->rgsabound[0].cElements - ElementsToRemove ], Temp, sizeof(VARIANT)*ElementsToRemove ); } SAFEARRAYBOUND SafeArrayBound = Array->rgsabound[0]; SafeArrayBound.cElements -= (ULONG)ElementsToRemove; SafeArrayUnlock( Array ); return SafeArrayRedim( Array, &SafeArrayBound ); } HRESULT RemoveFromLockdownListDisplay( SAFEARRAY *Array ) { HRESULT Hr; WCHAR FilterPath[ MAX_PATH ]; DWORD dwRet = GetModuleFileNameW( g_hInst, FilterPath, MAX_PATH ); if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() ); Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr; for( unsigned int i = Array->rgsabound[0].lLbound; i < Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; i++ ) { VARIANT & CurrentElement = ((VARIANT*)Array->pvData)[ i ]; BSTR BSTRString = CurrentElement.bstrVal; if ( _wcsicmp( (WCHAR*)BSTRString, FilterPath ) == 0 ) { // ISAPI is in the list, remove it Hr = SafeArrayUnlock( Array ); if ( FAILED( Hr ) ) return Hr; Hr = SafeArrayRemoveSlice( Array, (i == 0) ? 0 : i - 1, min( i + 1, Array->rgsabound[0].cElements - 1 ) ); return Hr; } } // ISAPI wasn't found. Nothing to do. SafeArrayUnlock( Array ); return S_OK; } HRESULT ModifyLockdownListDisplay( bool Add ) { HRESULT Hr; SAFEARRAY* Array = NULL; IADs *Service = NULL; VARIANT var; VariantInit( &var ); Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC" ), __uuidof( IADs ), (void**)&Service ); if ( FAILED( Hr ) ) { #ifdef DBG_REG DbgPrint("RpcProxy: ADsGetObject(): Failed: 0x%x (%d)\n", Hr, Hr ); #endif return Hr; } Hr = Service->Get( BSTR( L"RestrictionListCustomDesc" ), &var ); if ( FAILED(Hr) ) { #ifdef DBG_REG DbgPrint("RpcProxy: Service->Get(): Failed: 0x%x (%d)\n", Hr, Hr ); #endif // This property doesn't exist on IIS5 or IIS5.1 don't install or uninstall it Hr = S_OK; goto cleanup; } Array = var.parray; if ( Add ) Hr = AddToLockdownListDisplay( Array ); else Hr = RemoveFromLockdownListDisplay( Array ); if ( FAILED( Hr ) ) { #ifdef DBG_REG DbgPrint("RpcProxy: AddToLockdownListDisplay/RemoveFromLockdownListDisplay(): Failed: 0x%x (%d)\n", Hr, Hr ); #endif goto cleanup; } Hr = Service->Put( BSTR( L"RestrictionListCustomDesc" ), var ); if ( FAILED( Hr ) ) { #ifdef DBG_REG DbgPrint("RpcProxy: Service->Put(): Failed: 0x%x (%d)\n", Hr, Hr ); #endif goto cleanup; } Hr = Service->SetInfo(); if ( FAILED( Hr ) ) { #ifdef DBG_REG DbgPrint("RpcProxy: Service->SetInfo(): Failed: 0x%x (%d)\n", Hr, Hr ); #endif goto cleanup; } cleanup: VariantClear( &var ); if ( Service ) Service->Release(); return Hr; } #endif // #if IIS_LOCKDOWN_LIST //--------------------------------------------------------------------- // GetMetaBaseDword() // // Get a DWORD value from the metabase. //--------------------------------------------------------------------- HRESULT GetMetaBaseDword( IMSAdminBase *pIMeta, METADATA_HANDLE hMetaBase, WCHAR *pwsKeyPath, DWORD dwIdent, DWORD *pdwValue ) { HRESULT hr; DWORD dwSize; METADATA_RECORD MbRecord; memset(&MbRecord,0,sizeof(MbRecord)); *pdwValue = 0; MbRecord.dwMDIdentifier = dwIdent; MbRecord.dwMDAttributes = 0; MbRecord.dwMDUserType = IIS_MD_UT_SERVER; MbRecord.dwMDDataType = DWORD_METADATA; MbRecord.dwMDDataLen = sizeof(DWORD); MbRecord.pbMDData = (unsigned char *)pdwValue; hr = pIMeta->GetData( hMetaBase, pwsKeyPath, &MbRecord, &dwSize ); return hr; } //--------------------------------------------------------------------- // SetMetaBaseDword() // // Store a DWORD value into the metabase. //--------------------------------------------------------------------- HRESULT SetMetaBaseDword( IMSAdminBase *pIMeta, METADATA_HANDLE hMetaBase, WCHAR *pwsKeyPath, DWORD dwIdent, DWORD dwValue, DWORD dwAttributes, DWORD dwUserType ) { HRESULT hr; DWORD dwSize; METADATA_RECORD MbRecord; memset(&MbRecord,0,sizeof(MbRecord)); MbRecord.dwMDIdentifier = dwIdent; MbRecord.dwMDAttributes = dwAttributes; MbRecord.dwMDUserType = dwUserType; MbRecord.dwMDDataType = DWORD_METADATA; MbRecord.dwMDDataLen = sizeof(DWORD); MbRecord.pbMDData = (unsigned char *)&dwValue; hr = pIMeta->SetData( hMetaBase, pwsKeyPath, &MbRecord ); return hr; } RPC_STATUS GetIISConnectionTimeout ( OUT ULONG *ConnectionTimeout ) /*++ Routine Description: Retrieve the connection timeout for IIS: W3Svc/1/ROOT/Rpc/ConnectionTimeout Arguments: ConnectionTimeout - the connection timeout in seconds. Undefined on failure Return Value: RPC_S_OK or RPC_S_* for error --*/ { HRESULT hr = 0; DWORD dwValue = 0; DWORD dwSize = 0; IMSAdminBase *pIMeta = NULL; BOOL CoInitSucceeded = FALSE; hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) { #ifdef DBG_ERROR DbgPrint("GetIISConnectionTimeout: CoInitializeEx failed: Error: %X\n", hr); #endif goto MapErrorAndExit; } CoInitSucceeded = TRUE; hr = CoCreateInstance( CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **)&pIMeta ); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("CoCreateInstance(): Failed: 0x%x\n",hr); #endif goto MapErrorAndExit; } // // Get: /W3Svc/1/ROOT/rpc/ConnectionTimeout // hr = GetMetaBaseDword( pIMeta, METADATA_MASTER_ROOT_HANDLE, TEXT("/lm/w3svc/1/ROOT/Rpc"), MD_CONNECTION_TIMEOUT, ConnectionTimeout); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("GetMetaBaseDword: Failed: 0x%x\n",hr); #endif // couldn't read at the site level - try the root // // Get: /W3Svc/ConnectionTimeout // hr = GetMetaBaseDword( pIMeta, METADATA_MASTER_ROOT_HANDLE, TEXT("/lm/w3svc"), MD_CONNECTION_TIMEOUT, ConnectionTimeout); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("GetMetaBaseDword: Failed: 0x%x\n",hr); #endif } } MapErrorAndExit: if (pIMeta != NULL) pIMeta->Release(); if (CoInitSucceeded) CoUninitialize(); if (FAILED(hr)) return RPC_S_OUT_OF_MEMORY; else return RPC_S_OK; } //--------------------------------------------------------------------- // SetupMetaBase() // // Setup entries in the metabase for both the filter and ISAPI parts // of the RPC proxy. Note that these entries used to be in the registry. // // W3Svc/Filters/FilterLoadOrder "...,RpcProxy" // W3Svc/Filters/RpcProxy/FilterImagePath "%SystemRoot%\System32\RpcProxy" // W3Svc/Filters/RpcProxy/KeyType "IIsFilter" // W3Svc/Filters/RpcProxy/FilterDescription "Microsoft RPC Proxy Filter, v1.0" // // W3Svc/1/ROOT/Rpc/KeyType "IIsWebVirtualDir" // W3Svc/1/ROOT/Rpc/VrPath "%SystemRoot%\System32\RpcProxy" // W3Svc/1/ROOT/Rpc/AccessPerm 0x205 // W3Svc/1/ROOT/Rpc/Win32Error 0x0 // W3Svc/1/ROOT/Rpc/DirectoryBrowsing 0x4000001E // W3Svc/1/ROOT/Rpc/AppIsolated 0x0 // W3Svc/1/ROOT/Rpc/AppRoot "/LM/W3SVC/1/Root/rpc" // W3Svc/1/ROOT/Rpc/AppWamClsid "{BF285648-0C5C-11D2-A476-0000F8080B50}" // W3Svc/1/ROOT/Rpc/AppFriendlyName "rpc" // //--------------------------------------------------------------------- HRESULT SetupMetaBase() { HRESULT hr = 0; DWORD dwValue = 0; DWORD dwSize = 0; DWORD dwBufferSize = sizeof(WCHAR) * ORIGINAL_BUFFER_SIZE; WCHAR *pwsBuffer = (WCHAR*)MemAllocate(dwBufferSize); WCHAR *pwsSystemRoot = _wgetenv(SYSTEM_ROOT); WCHAR wsPath[METADATA_MAX_NAME_LEN]; IMSAdminBase *pIMeta; METADATA_HANDLE hMetaBase; // // Name of this DLL (and where it is): // // WCHAR wszModule[256]; // // if (!GetModuleFileName( g_hInst, wszModule, // sizeof(wszModule)/sizeof(WCHAR))) // { // return SELFREG_E_CLASS; // } if (!pwsBuffer) { return E_OUTOFMEMORY; } hr = CoCreateInstance( CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **)&pIMeta ); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("CoCreateInstance(): Failed: 0x%x\n",hr); #endif MemFree(pwsBuffer); return hr; } // Get a handle to the Web service: hr = pIMeta->OpenKey( METADATA_MASTER_ROOT_HANDLE, LOCAL_MACHINE_W3SVC, (METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE), 20, &hMetaBase ); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("pIMeta->OpenKey(): Failed: 0x%x\n",hr); #endif MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // IIS Filter: FilterLoadOrder // dwSize = dwBufferSize; hr = GetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS, // See iiscnfg.h MD_FILTER_LOAD_ORDER, // See iiscnfg.h pwsBuffer, &dwSize ); if (FAILED(hr) && (hr != MD_ERROR_DATA_NOT_FOUND)) { #ifdef DBG_REG DbgPrint("GetMetaBaseString(): Failed: 0x%x\n",hr); #endif MemFree(pwsBuffer); pIMeta->Release(); return hr; } if (hr == MD_ERROR_DATA_NOT_FOUND) pwsBuffer[0] = '\0'; // Check whether too much of the buffer has been used up. pwsBuffer[ORIGINAL_BUFFER_SIZE-1] = '\0'; if (wcslen(pwsBuffer) > MAX_USED_BUFFER_SIZE) { ASSERT(0); MemFree(pwsBuffer); pIMeta->Release(); return E_UNEXPECTED; } if (!wcsstr(pwsBuffer,RPCPROXY)) { // RpcProxy is not in FilterLoadOrder, so add it (if there were // previous elements). if (hr != MD_ERROR_DATA_NOT_FOUND) { wcscat(pwsBuffer,TEXT(",")); } wcscat(pwsBuffer,RPCPROXY); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS, MD_FILTER_LOAD_ORDER, pwsBuffer, 0, IIS_MD_UT_SERVER ); } if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // IIS Filter: RpcProxy/FilterImagePath // hr = pIMeta->AddKey( hMetaBase, MD_KEY_FILTERS_RPCPROXY ); if ( (FAILED(hr)) && (hr != 0x800700b7)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } wcscpy(pwsBuffer,pwsSystemRoot); wcscat(pwsBuffer,RPCPROXY_PATH); wcscat(pwsBuffer,TEXT("\\")); wcscat(pwsBuffer,RPCPROXY_DLL); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS_RPCPROXY, MD_FILTER_IMAGE_PATH, pwsBuffer, 0, IIS_MD_UT_SERVER ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // IIS Filter: Filters/RpcProxy/KeyType // wcscpy(pwsBuffer,IISFILTER); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS_RPCPROXY, MD_KEY_TYPE, pwsBuffer, 0, IIS_MD_UT_SERVER ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } wcscpy(pwsBuffer, FILTER_DESCRIPTION_W); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS_RPCPROXY, MD_FILTER_DESCRIPTION, pwsBuffer, 0, IIS_MD_UT_SERVER ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // We do not write the events we subscribe for to the metabase. We have // already advertised our presence and in IIS 5 mode IIS will load us, // ask for the events, and write them for us in the metabase // // Set: /W3Svc/1/ROOT/rpc/AccessPerm // dwValue = ACCESS_PERM_FLAGS; hr = SetMetaBaseDword( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_ACCESS_PERM, dwValue, METADATA_INHERIT, IIS_MD_UT_FILE ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Disable entity body preload for this ISAPI // dwValue = 0; hr = SetMetaBaseDword( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_UPLOAD_READAHEAD_SIZE, dwValue, METADATA_INHERIT, IIS_MD_UT_FILE ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/Win32Error // dwValue = 0; hr = SetMetaBaseDword( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_WIN32_ERROR, dwValue, METADATA_INHERIT, IIS_MD_UT_SERVER ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/DirectroyBrowsing // dwValue = DIRECTORY_BROWSING_FLAGS; hr = SetMetaBaseDword( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_DIRECTORY_BROWSING, dwValue, METADATA_INHERIT, IIS_MD_UT_FILE ); if (FAILED(hr)) { pIMeta->Release(); CoUninitialize(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/KeyType // wcscpy(pwsBuffer,IIS_WEB_VIRTUAL_DIR); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_KEY_TYPE, pwsBuffer, 0, IIS_MD_UT_SERVER ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/VrPath // wcscpy(pwsBuffer,pwsSystemRoot); wcscat(pwsBuffer,RPCPROXY_PATH); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_VR_PATH, pwsBuffer, METADATA_INHERIT, IIS_MD_UT_FILE ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } #if FALSE // // Set: /W3Svc/1/ROOT/rpc/AppIsolated // dwValue = 0; hr = SetMetaBaseDword( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_APP_ISOLATED, dwValue, METADATA_INHERIT, IIS_MD_UT_WAM ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/AppRoot // wcscpy(pwsBuffer,APP_ROOT_PATH); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_APP_ROOT, pwsBuffer, METADATA_INHERIT, IIS_MD_UT_FILE ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/AppWamClsid // wcscpy(pwsBuffer,APP_WAM_CLSID); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_APP_WAM_CLSID, pwsBuffer, METADATA_INHERIT, IIS_MD_UT_WAM ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Set: /W3Svc/1/ROOT/rpc/AppFriendlyName // wcscpy(pwsBuffer,APP_FRIENDLY_NAME); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_ROOT_RPC, MD_APP_FRIENDLY_NAME, pwsBuffer, METADATA_INHERIT, IIS_MD_UT_WAM ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } #endif // // Release the handle and buffer: // MemFree(pwsBuffer); pIMeta->CloseKey(hMetaBase); pIMeta->Release(); CoUninitialize(); return 0; } //--------------------------------------------------------------------- // CleanupMetaBase() // //--------------------------------------------------------------------- HRESULT CleanupMetaBase() { HRESULT hr = 0; DWORD dwSize = 0; WCHAR *pwsRpcProxy; WCHAR *pws; DWORD dwBufferSize = sizeof(WCHAR) * ORIGINAL_BUFFER_SIZE; WCHAR *pwsBuffer = (WCHAR*)MemAllocate(dwBufferSize); // CComPtr pIMeta; IMSAdminBase *pIMeta; METADATA_HANDLE hMetaBase; if (!pwsBuffer) { return ERROR_OUTOFMEMORY; } hr = CoCreateInstance( CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **)&pIMeta ); if (FAILED(hr)) { MemFree(pwsBuffer); return hr; } // // Get a handle to the Web service: // hr = pIMeta->OpenKey( METADATA_MASTER_ROOT_HANDLE, TEXT("/LM/W3SVC"), (METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE), 20, &hMetaBase ); if (FAILED(hr)) { MemFree(pwsBuffer); pIMeta->Release(); return hr; } // // Remove the RpcProxy reference from the FilterLoadOrder value: // dwSize = dwBufferSize; hr = GetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS, MD_FILTER_LOAD_ORDER, pwsBuffer, &dwSize ); if (!FAILED(hr)) { // Check whether too much of the buffer has been used up. pwsBuffer[ORIGINAL_BUFFER_SIZE-1] = '\0'; if (wcslen(pwsBuffer) > MAX_USED_BUFFER_SIZE) { ASSERT(0); MemFree(pwsBuffer); pIMeta->Release(); return E_UNEXPECTED; } if (pwsRpcProxy=wcsstr(pwsBuffer,RPCPROXY)) { // "RpcProxy" is in FilterLoadOrder, so remove it: // Check to see if RpcProxy is at the start of the list: if (pwsRpcProxy != pwsBuffer) { pwsRpcProxy--; // Want to remove the comma before... dwSize = sizeof(RPCPROXY); } else { dwSize = sizeof(RPCPROXY) - 1; } pws = pwsRpcProxy + dwSize; memcpy(pwsRpcProxy,pws,sizeof(WCHAR)*(1+wcslen(pws))); hr = SetMetaBaseString( pIMeta, hMetaBase, MD_KEY_FILTERS, MD_FILTER_LOAD_ORDER, pwsBuffer, 0, IIS_MD_UT_SERVER ); } } // // Delete: /W3Svc/Filters/RpcProxy // hr = pIMeta->DeleteKey( hMetaBase, MD_KEY_FILTERS_RPCPROXY ); // // Delete: /W3Svc/1/ROOT/Rpc // hr = pIMeta->DeleteKey( hMetaBase, MD_KEY_FILTERS_RPCPROXY ); // // Release the handle and buffer: // MemFree(pwsBuffer); pIMeta->CloseKey(hMetaBase); pIMeta->Release(); return S_OK; } const WCHAR InetInfoName[] = L"inetinfo.exe"; const ULONG InetInfoNameLength = sizeof(InetInfoName) / sizeof(WCHAR) - 1; // in characters without terminating NULL BOOL UpdateIsIISInCompatibilityMode ( void ) /*++ Routine Description: Reads the compatibility mode state. It used to read it from the metabase, but after repeated problems in compatibility mode, WadeH suggested a simpler approach - check whether we run in inetinfo. If yet, we're in compatibility mode. Arguments: Return Value: non-zero if the variable is correctly updated. 0 otherwise --*/ { WCHAR ExtensionPath[ MAX_PATH + 1 ]; ULONG ModuleFileNameLength; // in characters without terminating NULL DWORD dwRet = GetModuleFileNameW( GetModuleHandle(NULL), ExtensionPath, MAX_PATH ); if ( (dwRet > 0) && (dwRet != MAX_PATH)) { ExtensionPath[MAX_PATH] = '\0'; ASSERT(GetLastError() == NO_ERROR); } else { ASSERT(GetLastError() != NO_ERROR); return FALSE; } ModuleFileNameLength = wcslen(ExtensionPath); if (ModuleFileNameLength < InetInfoNameLength) { fIsIISInCompatibilityMode = FALSE; } if (_wcsicmp(ExtensionPath + ModuleFileNameLength - InetInfoNameLength, InetInfoName) == 0) { fIsIISInCompatibilityMode = TRUE; } else { fIsIISInCompatibilityMode = FALSE; } return TRUE; } //--------------------------------------------------------------------- // DllRegisterServer() // // Setup the Registry and MetaBase for the RPC proxy. //--------------------------------------------------------------------- const char ChildProcessVar[] = "__RPCPROXY_CHILD_PROCESS"; const char ChildProcessVarValue[] = "__FROM_SETUP"; HRESULT DllRegisterServer() { HRESULT hr; WORD wVersion = MAKEWORD(1,1); WSADATA wsaData; char EnvironmentVarBuffer[MAX_PATH]; DWORD Temp; BOOL Result; DWORD LastError; #ifdef DBG_REG DbgPrint("RpcProxy: DllRegisterServer(): Start\n"); #endif // check if we are have already been called from the RPCProxy DllRegister routine Temp = GetEnvironmentVariableA(ChildProcessVar, EnvironmentVarBuffer, MAX_PATH); #ifdef DBG_REG DbgPrint("RpcProxy: Result of looking for environment variable - %d\n", Temp); #endif // GetEnvironmentVariable does not count the terminating NULL. if (Temp < sizeof(ChildProcessVarValue) - 1) { #ifdef DBG_REG DbgPrint("RpcProxy: Not a child process - spawning one\n"); #endif // we didn't find the variable. Add it and spawn ourselves to register out of proc Result = SetEnvironmentVariableA (ChildProcessVar, ChildProcessVarValue); if (Result == FALSE) return E_OUTOFMEMORY; Result = RegisterOutOfProc(); if (Result == FALSE) { // capture the last error before we call SetEnvironmentVariable LastError = GetLastError(); } // before processing the result, remove the environment variable. If this fails, there // isn't much we can do. Fortunately, failure to delete is completely benign (void) SetEnvironmentVariableA (ChildProcessVar, NULL); if (Result == FALSE) { return HRESULT_FROM_WIN32(LastError); } return S_OK; } if (WSAStartup(wVersion,&wsaData)) { return SELFREG_E_CLASS; } hr = CoInitializeEx(0,COINIT_MULTITHREADED); if (FAILED(hr)) { hr = CoInitializeEx(0,COINIT_APARTMENTTHREADED); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: CoInitialize(): Failed: 0x%x\n", hr ); #endif return hr; } } hr = SetupRegistry(); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: SetupRegistry(): Failed: 0x%x (%d)\n", hr, hr ); #endif goto CleanupAndExit; } hr = SetupMetaBase(); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: SetupMetaBase(): Failed: 0x%x (%d)\n", hr, hr ); #endif goto CleanupAndExit; } #if IIS_LOCKDOWN_LIST hr = ModifyLockdownList( true ); #endif // #if IIS_LOCKDOWN_LIST #if IIS_SEC_CONSOLE hr = EnableRpcProxyExtension(); #endif // #if IIS_SEC_CONSOLE if ( FAILED( hr ) ) { #ifdef DBG_REG DbgPrint("RpcProxy: ModifyLockdownList(): Failed: 0x%x (%d)\n", hr, hr ); #endif goto CleanupAndExit; } #if IIS_LOCKDOWN_LIST hr = ModifyLockdownListDisplay( true ); #ifdef DBG_REG if ( FAILED( hr ) ) { DbgPrint("RpcProxy: ModifyLockdownListDisplay(): Failed: 0x%x (%d)\n", hr, hr ); } #endif #endif // #if IIS_LOCKDOWN_LIST CleanupAndExit: CoUninitialize(); #ifdef DBG_REG DbgPrint("RpcProxy: DllRegisterServer(): End: hr: 0x%x\n",hr); #endif return hr; } //--------------------------------------------------------------------- // DllUnregisterServer() // // Uninstall Registry and MetaBase values used by the RPC proxy. // // Modified to mostly return S_Ok, even if a problem occurs. This is // done so that the uninstall will complete even if there is a problem // in the un-register. //--------------------------------------------------------------------- HRESULT DllUnregisterServer() { HRESULT hr; WORD wVersion = MAKEWORD(1,1); WSADATA wsaData; #ifdef DBG_REG DbgPrint("RpcProxy: DllUnregisterServer(): Start\n"); #endif if (WSAStartup(wVersion,&wsaData)) { return SELFREG_E_CLASS; } hr = CoInitializeEx(0,COINIT_MULTITHREADED); if (FAILED(hr)) { hr = CoInitializeEx(0,COINIT_APARTMENTTHREADED); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: CoInitializeEx() Failed: 0x%x\n",hr); #endif return S_OK; } } #if IIS_SEC_CONSOLE hr = DisableRpcProxyExtension(); #endif // #if IIS_SEC_CONSOLE #if IIS_LOCKDOWN_LIST hr = ModifyLockdownList( false ); #endif // #if IIS_LOCKDOWN_LIST if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: ModifyLockdownList() Failed: 0x%x (%d)\n",hr,hr); #endif return S_OK; } #if IIS_LOCKDOWN_LIST hr = ModifyLockdownListDisplay( false ); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: ModifyLockdownListDisplay() Failed: 0x%x (%d)\n",hr,hr); #endif return S_OK; } #endif // #if IIS_LOCKDOWN_LIST hr = CleanupRegistry(); if (FAILED(hr)) { #ifdef DBG_REG DbgPrint("RpcProxy: CleanupRegistry() Failed: 0x%x (%d)\n",hr,hr); #endif return S_OK; } hr = CleanupMetaBase(); #ifdef DBG_REG if (FAILED(hr)) { DbgPrint("RpcProxy: CleanupMetaBase() Failed: 0x%x (%d)\n",hr,hr); } #endif CoUninitialize(); #ifdef DBG_REG DbgPrint("RpcProxy: DllUnregisterServer(): Start\n"); #endif return S_OK; } //-------------------------------------------------------------------- // DllMain() // //-------------------------------------------------------------------- BOOL WINAPI DllMain( HINSTANCE hInst, ULONG ulReason, LPVOID pvReserved ) { BOOL fInitialized = TRUE; switch (ulReason) { case DLL_PROCESS_ATTACH: if (!DisableThreadLibraryCalls(hInst)) { fInitialized = FALSE; } else { g_hInst = hInst; } break; case DLL_PROCESS_DETACH: FreeServerInfo(&g_pServerInfo); break; case DLL_THREAD_ATTACH: // Not used. Disabled. break; case DLL_THREAD_DETACH: // Not used. Disabled. break; } return fInitialized; }