//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000. // // File: process.cxx // // Contents: CProcess class // CServiceProcess class // // History: 07-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include //+------------------------------------------------------------------------- // // Member: CProcess::CProcess // // Purpose: Creates a process on the local machine. // // Arguments: [wcsImageName] -- name of EXE to run // [wcsCommandLine] -- command line passed to EXE // [fCreateSuspended] -- should the EXE be created suspended? // [SAProcess] -- Security context to run under // [fServiceChild] -- Flag set to TRUE if the process is a // child of a "service" process (ala CiFilter // service or W3Svc). // [pAdviseStatus] -- ICiCAdviseStatus interface, optional. // // History: 06-Jun-94 DwightKr Created // // Notes: If a system process (such as a service) spawning a process // it will always be created on the SYSTEM desktop, and never // the user's or DEFAULT desktop. System processes do not have // sufficient acccess to create windows on the user's desktop. // //-------------------------------------------------------------------------- CProcess::CProcess( const WCHAR *wcsImageName, const WCHAR *wcsCommandLine, BOOL fCreateSuspended, const SECURITY_ATTRIBUTES & SAProcess, BOOL fOFSDaemon, ICiCAdviseStatus * pAdviseStatus ) { _pAdviseStatus = pAdviseStatus; WCHAR wcsEXEName[_MAX_PATH + 1]; if ( ExpandEnvironmentStrings( wcsImageName, wcsEXEName, _MAX_PATH ) == 0 ) { THROW( CException() ); } STARTUPINFO siDefault; RtlZeroMemory( &siDefault, sizeof(siDefault) ); DWORD dwCreateFlags = 0; siDefault.cb = sizeof(STARTUPINFO); // Size of this struct if ( fOFSDaemon ) { siDefault.lpReserved = NULL; // Not used (for now) siDefault.lpDesktop = L"Default"; // Use default desktop siDefault.lpTitle = (WCHAR *) wcsImageName; // Default title siDefault.dwX = 0; // Don't specify where to siDefault.dwY = 0; // place the window siDefault.dwXSize = 0; // " " " " " siDefault.dwYSize = 0; // " " " " " siDefault.dwFlags = STARTF_USESHOWWINDOW; // Allow for minimizing siDefault.wShowWindow = SW_MINIMIZE; // Normal display siDefault.cbReserved2 = 0; // Not used (for now) siDefault.lpReserved2 = NULL; // " " " " " dwCreateFlags = CREATE_NEW_CONSOLE; } else { siDefault.lpTitle = (WCHAR *) wcsImageName; // Default title dwCreateFlags = DETACHED_PROCESS; } if ( fCreateSuspended ) dwCreateFlags |= CREATE_SUSPENDED; if ( !CreateProcess( fOFSDaemon ? (WCHAR *) wcsEXEName : 0, // EXE name (WCHAR *) wcsCommandLine, // Command line (SECURITY_ATTRIBUTES *) &SAProcess, // Proc sec attrib NULL, // Thread sec attrib fOFSDaemon, // Inherit handles dwCreateFlags, // Creation flags NULL, // Environment NULL, // Startup directory &siDefault, // Startup Info &_piProcessInfo ) ) // Process handles { DWORD dwLastError = GetLastError(); if ( ERROR_FILE_NOT_FOUND == dwLastError && _pAdviseStatus ) { CFwEventItem item( EVENTLOG_AUDIT_FAILURE, MSG_CI_FILE_NOT_FOUND, 1 ); item.AddArg( wcsEXEName ); item.ReportEvent(*_pAdviseStatus); } THROW( CException( HRESULT_FROM_WIN32( dwLastError) ) ); } // // Only AddRef() once we get to a point where the constructor can // no longer fail (and the destructor is guaranteed to be called) // if (_pAdviseStatus) _pAdviseStatus->AddRef(); } //CProcess //+------------------------------------------------------------------------- // // Member: CProcess::~CProcess // // Purpose: destructor // // History: 06-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- CProcess::~CProcess() { if ( 0 != _pAdviseStatus ) _pAdviseStatus->Release(); Terminate(); WaitForDeath(); } //+------------------------------------------------------------------------- // // Member: CProcess::Resume, public // // Purpose: Continue a suspended thread // // History: 06-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- void CProcess::Resume() { ResumeThread( _piProcessInfo.hThread ); } //+------------------------------------------------------------------------- // // Member: CProcess::WaitForDeath // // Purpose: Blocks until the process has been terminated. // // History: 06-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- void CProcess::WaitForDeath( DWORD dwTimeout ) { DWORD res = WaitForSingleObject ( _piProcessInfo.hProcess, dwTimeout ); #if 0 if ( WAIT_FAILED == res ) { Win4Assert( !"Are we leaking a handle" ); } #endif // 0 CloseHandle(_piProcessInfo.hThread); CloseHandle(_piProcessInfo.hProcess); // if ( WAIT_FAILED == res ) // { // THROW( CException() ); // } } //+------------------------------------------------------------------------- // // Member: CProcess::GetProcessToken, private // // Purpose: Returns the process token for the process // // History: 06-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- HANDLE CProcess::GetProcessToken() { HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, _piProcessInfo.dwProcessId ); if ( NULL == hProcess ) { THROW( CException() ); } SWin32Handle process(hProcess); // Save in smart pointer HANDLE hProcessToken = 0; if ( !OpenProcessToken( hProcess, TOKEN_ADJUST_DEFAULT | TOKEN_QUERY, &hProcessToken ) ) { THROW( CException() ); } return hProcessToken; } //+------------------------------------------------------------------------- // // Member: CProcess::AddDacl, public // // Purpose: Adds the access specified onto the Dacl on the process. // // Arguments: [dwAccessMask] -- Any combination of the Win32 ACCESS_MASK bits // // History: 06-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- void CProcess::AddDacl( DWORD dwAccessMask ) { HANDLE hProcessToken = GetProcessToken(); SWin32Handle processToken( hProcessToken ); // // Create a SID that gives everyone access. We want to allow anyone // to synchronize on the objects created in this process (if they // can get a handle to the object to synchronize on). // SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_WORLD_SID_AUTHORITY; CSid WorldSid( NtAuthority, SECURITY_WORLD_RID ); // // Read the current Dacl. This requires two steps. The current // Dacl size is not known, the 1st call determines its current size. // DWORD cbRequired; if ( !GetTokenInformation( hProcessToken, TokenDefaultDacl, 0, 0, &cbRequired ) ) { if ( ERROR_INSUFFICIENT_BUFFER != GetLastError() ) THROW( CException() ); } else { ciDebugOut(( DEB_WARN, "No default dacl(1), invalid CI configuration\n" )); THROW( CException( STATUS_INVALID_PARAMETER ) ); } // // Create a buffer of the size requested to store the Dacl on the next // call to GetTokenInformation(). Add additional space for the new // synchronize-all Ace to be appended later. // cbRequired += sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( WorldSid ); TOKEN_DEFAULT_DACL *pDacl = (TOKEN_DEFAULT_DACL *) new BYTE[cbRequired]; SDacl SDacl(pDacl); // Save in smart pointer if ( !GetTokenInformation( hProcessToken, TokenDefaultDacl, pDacl, cbRequired, &cbRequired ) ) { THROW( CException() ); } // // pDacl->DefaultDacl will be 0 if cisvc is started in windbg // with pipes preconfigured. Don't do that -- we don't support it. // if ( 0 == pDacl->DefaultDacl ) { ciDebugOut(( DEB_WARN, "No default dacl(2), invalid CI configuration\n" )); THROW( CException( STATUS_INVALID_PARAMETER ) ); } pDacl->DefaultDacl->AclSize += (USHORT)(sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( WorldSid ) - sizeof(ULONG)); // // Append synchronize access onto the Dacl. // if ( !AddAccessAllowedAce( pDacl->DefaultDacl, // On to this acl, ACL_REVISION, // built for version X, dwAccessMask, // allow synchronize, WorldSid ) ) // for these objects. { THROW( CException() ); } #if CIDBG == 1 if ( !IsValidAcl( pDacl->DefaultDacl ) ) { Win4Assert(!"Invalid Acl"); } #endif // // Update the process's Dacl. // if ( !SetTokenInformation( hProcessToken, TokenDefaultDacl, &pDacl->DefaultDacl, pDacl->DefaultDacl->AclSize ) ) { THROW( CException() ); } }