325 lines
10 KiB
C++
325 lines
10 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
||
|
//
|
||
|
// File: process.cxx
|
||
|
//
|
||
|
// Contents: CProcess class
|
||
|
// CServiceProcess class
|
||
|
//
|
||
|
// History: 07-Jun-94 DwightKr Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <proc32.hxx>
|
||
|
#include <cievtmsg.h>
|
||
|
#include <fwevent.hxx>
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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() );
|
||
|
}
|
||
|
}
|