/* IisRsta.cpp Implementation of WinMain for COM IIisServiceControl handler FILE HISTORY: Phillich 06-Oct-1998 Created */ #include "stdafx.h" #include "resource.h" #include #include "iisrsta.h" #include #include #include "IisRestart.h" const DWORD dwTimeOut = 5000; // time for EXE to be idle before shutting down const DWORD dwPause = 1000; // time to wait for threads to finish up HRESULT AddLaunchPermissionsAcl( PSECURITY_DESCRIPTOR pSD ); // Passed to CreateThread to monitor the shutdown event static DWORD WINAPI MonitorProc(void* pv) { CExeModule* p = (CExeModule*)pv; p->MonitorShutdown(); return 0; } LONG CExeModule::Unlock() { LONG l = CComModule::Unlock(); if (l == 0) { bActivity = true; SetEvent(hEventShutdown); // tell monitor that we transitioned to zero } return l; } //Monitors the shutdown event void CExeModule::MonitorShutdown() { while (1) { WaitForSingleObject(hEventShutdown, INFINITE); DWORD dwWait=0; do { bActivity = false; dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut); } while (dwWait == WAIT_OBJECT_0); // timed out if (!bActivity && m_nLockCnt == 0) // if no activity let's really bail { break; } } CloseHandle(hEventShutdown); PostThreadMessage(dwThreadID, WM_QUIT, 0, 0); } bool CExeModule::StartMonitor() { hEventShutdown = CreateEvent(NULL, false, false, NULL); if (hEventShutdown == NULL) return false; DWORD dwThreadID; HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID); return (h != NULL); } CExeModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_IisServiceControl, CIisRestart) END_OBJECT_MAP() LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) { while (p1 != NULL && *p1 != NULL) { LPCTSTR p = p2; while (p != NULL && *p != NULL) { if (*p1 == *p) return CharNext(p1); p = CharNext(p); } p1 = CharNext(p1); } return NULL; } ///////////////////////////////////////////////////////////////////////////// // int _cdecl main( int, char ) { LPTSTR lpCmdLine = GetCommandLine(); // necessary for minimal CRT HRESULT hRes = S_OK; DWORD dwErr = ERROR_SUCCESS; PSID psidAdmin = NULL; PACL pACL = NULL; EXPLICIT_ACCESS ea; SECURITY_DESCRIPTOR sd = {0}; BOOL fCoInitialized = FALSE; hRes = CoInitializeEx(NULL,COINIT_MULTITHREADED); if (FAILED(hRes)) { goto exit; } fCoInitialized = TRUE; // // Get a sid that represents the Administrators group. // dwErr = AllocateAndCreateWellKnownSid( WinBuiltinAdministratorsSid, &psidAdmin ); if ( dwErr != ERROR_SUCCESS ) { hRes = HRESULT_FROM_WIN32(dwErr); goto exit; } // Initialize an EXPLICIT_ACCESS structure for an ACE. SecureZeroMemory(&ea, sizeof(ea)); // // Setup Administrators for read access. // SetExplicitAccessSettings( &ea, COM_RIGHTS_EXECUTE, SET_ACCESS, psidAdmin ); // // Create a new ACL that contains the new ACEs. // dwErr = SetEntriesInAcl(sizeof(ea)/sizeof(EXPLICIT_ACCESS), &ea, NULL, &pACL); if ( dwErr != ERROR_SUCCESS ) { hRes = HRESULT_FROM_WIN32(dwErr); goto exit; } if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { hRes = HRESULT_FROM_WIN32(GetLastError()); goto exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, // fDaclPresent flag pACL, FALSE)) // not a default DACL { hRes = HRESULT_FROM_WIN32(GetLastError()); goto exit; } if (!SetSecurityDescriptorOwner(&sd, psidAdmin, // fDaclPresent flag FALSE)) // not a default DACL { hRes = HRESULT_FROM_WIN32(GetLastError()); goto exit; } if (!SetSecurityDescriptorGroup(&sd, psidAdmin, // fDaclPresent flag FALSE)) // not a default DACL { hRes = HRESULT_FROM_WIN32(GetLastError()); goto exit; } hRes = CoInitializeSecurity( &sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_ANONYMOUS, NULL, EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL, NULL ); if (FAILED(hRes)) { goto exit; } _ASSERTE(SUCCEEDED(hRes)); _Module.Init(ObjectMap,GetModuleHandle(NULL)); _Module.dwThreadID = GetCurrentThreadId(); TCHAR szTokens[] = _T("-/"); BOOL bRun = TRUE; LPCTSTR lpszToken = FindOneOf(lpCmdLine,szTokens); while (lpszToken != NULL) { #pragma prefast(push) #pragma prefast(disable:400, "Don't complain about case insensitive compares") if (lstrcmpi(lpszToken, _T("UnregServer"))==0) { _Module.UpdateRegistryFromResource(IDR_IISRESTART, FALSE); bRun = FALSE; break; } if (lstrcmpi(lpszToken, _T("RegServer"))==0) { _Module.UpdateRegistryFromResource(IDR_IISRESTART, TRUE); // we need to do the Module.Terminate so we // will just flow on with a bad hresult, however // it will end up getting returned to the user // so it is ok. hRes = AddLaunchPermissionsAcl(&sd); bRun = FALSE; break; } lpszToken = FindOneOf(lpszToken, szTokens); #pragma prefast(pop) } if (bRun) { _Module.StartMonitor(); hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE); _ASSERTE(SUCCEEDED(hRes)); MSG msg; while (GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } _Module.RevokeClassObjects(); Sleep(dwPause); //wait for any threads to finish } _Module.Term(); exit: FreeWellKnownSid(&psidAdmin); if (pACL) { LocalFree(pACL); pACL = NULL; } if ( fCoInitialized ) { CoUninitialize(); } return (hRes); } HRESULT AddLaunchPermissionsAcl( PSECURITY_DESCRIPTOR pSD ) { DWORD Win32Error = NO_ERROR; HRESULT hr = S_OK; HKEY KeyHandle = NULL; PSECURITY_DESCRIPTOR pSDRelative = NULL; DWORD dwBytesNeeded = 0; if ( MakeSelfRelativeSD( pSD, pSDRelative, &dwBytesNeeded ) ) { // If this passes, then there is a real problem because // we didn't give it anywhere to copy to. So // we fail here. return E_FAIL; } Win32Error = GetLastError(); if ( Win32Error != ERROR_INSUFFICIENT_BUFFER ) { return HRESULT_FROM_WIN32(Win32Error); } // At this point we know the size of the data // that we are going to receive, so we can allocated // enough space. pSDRelative = ( PSECURITY_DESCRIPTOR ) new BYTE[ dwBytesNeeded ]; if ( pSDRelative == NULL ) { return E_OUTOFMEMORY; } if ( !MakeSelfRelativeSD( pSD, pSDRelative, &dwBytesNeeded ) ) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } Win32Error = RegOpenKeyEx( HKEY_CLASSES_ROOT, L"AppID\\{E8FB8615-588F-11D2-9D61-00C04F79C5FE}", NULL, KEY_WRITE, &KeyHandle ); if ( Win32Error != NO_ERROR ) { hr = HRESULT_FROM_WIN32( Win32Error ); goto exit; } Win32Error = RegSetValueEx( KeyHandle, L"LaunchPermission", NULL, REG_BINARY, reinterpret_cast( pSDRelative ), dwBytesNeeded ); if ( Win32Error != NO_ERROR ) { hr = HRESULT_FROM_WIN32( Win32Error ); goto exit; } exit: if ( KeyHandle != NULL ) { RegCloseKey( KeyHandle ); } if ( pSDRelative != NULL ) { delete [] pSDRelative; } return hr; }