WindowsXP-SP1/termsrv/wtsapi/process.c

765 lines
24 KiB
C

/*******************************************************************************
* process.c
*
* Published Terminal Server APIs
*
* - process routines
*
* Copyright 1998, Citrix Systems Inc.
* Copyright (C) 1997-1999 Microsoft Corp.
/******************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntddkbd.h>
#include <ntddmou.h>
#include <windows.h>
#include <winbase.h>
#include <winerror.h>
#include <allproc.h>
#if(WINVER >= 0x0500)
#include <ntstatus.h>
#include <winsta.h>
#else
#include <citrix\cxstatus.h>
#include <citrix\winsta.h>
#endif
#include <utildll.h>
#include <stdio.h>
#include <stdarg.h>
#include <wtsapi32.h>
/*=============================================================================
== External procedures defined
=============================================================================*/
BOOL WINAPI WTSEnumerateProcessesW( HANDLE, DWORD, DWORD, PWTS_PROCESS_INFOW *, DWORD * );
BOOL WINAPI WTSEnumerateProcessesA( HANDLE, DWORD, DWORD, PWTS_PROCESS_INFOA *, DWORD * );
BOOL WINAPI WTSTerminateProcess( HANDLE, DWORD, DWORD );
/*=============================================================================
== Procedures used
=============================================================================*/
VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
/*=============================================================================
* Internal function
=============================================================================*/
BOOL
GetProcessSid(HANDLE Server,
HANDLE hUniqueProcessId,
LARGE_INTEGER ProcessStartTime,
PBYTE * pProcessUserSid //Return the SID (allocated here..)
);
/*=======================================================================
* Private structure definitions
*=========================================================================*/
typedef struct _SID_INFO {
struct _SID_INFO * pNext;
PBYTE pSid;
} SID_INFO;
/****************************************************************************
*
* WTSEnumerateProcessesW (UNICODE)
*
* Returns a list of Terminal Server Processes on the specified server
*
* ENTRY:
* hServer (input)
* Handle to a Terminal server (or WTS_CURRENT_SERVER)
* Reserved (input)
* Must be zero
* Version (input)
* Version of the enumeration request (must be 1)
* ppProcessInfo (output)
* Points to the address of a variable to receive the enumeration results,
* which are returned as an array of WTS_PROCESS_INFO structures. The
* buffer is allocated within this API and is disposed of using
* WTSFreeMemory.
* pCount (output)
* Points to the address of a variable to receive the number of
* WTS_PROCESS_INFO structures returned
*
* EXIT:
*
* TRUE -- The enumerate operation succeeded.
*
* FALSE -- The operation failed. Extended error status is available
* using GetLastError.
*
****************************************************************************/
#if(WINVER >= 0x0500)
BOOL
WINAPI
WTSEnumerateProcessesW(
IN HANDLE hServer,
IN DWORD Reserved,
IN DWORD Version,
OUT PWTS_PROCESS_INFOW * ppProcessInfo,
OUT DWORD * pCount
)
{
PBYTE pProcessBuffer = NULL;
PTS_SYS_PROCESS_INFORMATION pProcessInfo;
PCITRIX_PROCESS_INFORMATION pCitrixInfo;
ULONG ProcessCount;
ULONG Offset;
ULONG DataLength;
PWTS_PROCESS_INFOW pProcessW;
PBYTE pProcessData;
ULONG i;
ULONG Length;
PTS_ALL_PROCESSES_INFO ProcessArray = NULL;
DWORD dwError;
SID_INFO sidInfoHead; //The head of the Sid temp storage
SID_INFO * pSidInfo; //Point to a list of temp storage for the
//variable length SID
sidInfoHead.pNext = NULL;
sidInfoHead.pSid = NULL;
pSidInfo = &sidInfoHead;
/*
* Validate parameters
*/
if ( Reserved != 0 || Version != 1 ) {
SetLastError( ERROR_INVALID_PARAMETER );
goto badparam;
}
if (!ppProcessInfo || !pCount) {
SetLastError( ERROR_INVALID_PARAMETER );
goto badparam;
}
//
// Try the new interface first (Windows 2000 server)
//
if (WinStationGetAllProcesses( hServer,
GAP_LEVEL_BASIC,
&ProcessCount,
&ProcessArray) )
{
DataLength = 0;
for (i=0; i<ProcessCount; i++)
{
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION)(ProcessArray[i].pTsProcessInfo);
DataLength += (pProcessInfo->ImageName.Length + sizeof(WCHAR));
if (ProcessArray[i].pSid)
{
DataLength += GetLengthSid( ProcessArray[i].pSid );
}
}
/*
* Allocate user buffer
*/
pProcessW = LocalAlloc( LPTR, (ProcessCount * sizeof(WTS_PROCESS_INFOW)) + DataLength );
if ( pProcessW == NULL ) {
SetLastError(ERROR_OUTOFMEMORY);
goto GAPErrorReturn;
}
/*
* Update user parameters
*/
*ppProcessInfo = pProcessW;
*pCount = ProcessCount;
/*
* Copy data to new buffer
*/
pProcessData = (PBYTE)pProcessW + (ProcessCount * sizeof(WTS_PROCESS_INFOW));
for ( i=0; i < ProcessCount; i++ ) {
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION)(ProcessArray[i].pTsProcessInfo);
Length = pProcessInfo->ImageName.Length; // number of bytes
pProcessW->pProcessName = (LPWSTR) pProcessData;
memcpy( pProcessData, pProcessInfo->ImageName.Buffer, Length );
*(pProcessData += Length) = (WCHAR)0;
pProcessData += sizeof(WCHAR);
pProcessW->ProcessId = (ULONG)(ULONG_PTR)pProcessInfo->UniqueProcessId;
pProcessW->SessionId = pProcessInfo->SessionId;
if (ProcessArray[i].pSid)
{
Length = GetLengthSid( ProcessArray[i].pSid );
pProcessW->pUserSid = (LPWSTR) pProcessData;
memcpy( pProcessData, ProcessArray[i].pSid, Length );
pProcessData += Length;
}
pProcessW++;
}
//
// Free ppProcessArray and all child pointers allocated by the client stub.
//
WinStationFreeGAPMemory(GAP_LEVEL_BASIC, ProcessArray, ProcessCount);
}
else // Maybe a TS 4.0 server ?
{
//
// Check the return code indicating that the interface is not available.
//
dwError = GetLastError();
if (dwError != RPC_S_PROCNUM_OUT_OF_RANGE)
{
goto badenum;
}
else
{
// It might be a TS4.0 server
// Try the old interface
//
//
// Enumerate Processes and check for an error
//
if ( !WinStationEnumerateProcesses( hServer, &pProcessBuffer ) ) {
goto badenum;
}
//
// Count the number of processes and total up the size of the data
//
ProcessCount = 0;
DataLength = 0;
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) pProcessBuffer;
Offset = 0;
do {
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) ((PBYTE)pProcessInfo + Offset);
ProcessCount++;
DataLength += (pProcessInfo->ImageName.Length + sizeof(WCHAR));
pCitrixInfo = (PCITRIX_PROCESS_INFORMATION)
(((PUCHAR)pProcessInfo) +
SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION +
(SIZEOF_TS4_SYSTEM_THREAD_INFORMATION * (int)pProcessInfo->NumberOfThreads));
if ( pCitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) {
if ( pCitrixInfo->ProcessSid )
DataLength += GetLengthSid( pCitrixInfo->ProcessSid );
}
Offset = pProcessInfo->NextEntryOffset;
} while ( Offset != 0 );
/*
* Allocate user buffer
*/
pProcessW = LocalAlloc( LPTR, (ProcessCount * sizeof(WTS_PROCESS_INFOW)) + DataLength );
if ( pProcessW == NULL ) {
SetLastError(ERROR_OUTOFMEMORY);
goto badalloc;
}
/*
* Update user parameters
*/
*ppProcessInfo = pProcessW;
*pCount = ProcessCount;
/*
* Copy data to new buffer
*/
pProcessData = (PBYTE)pProcessW + (ProcessCount * sizeof(WTS_PROCESS_INFOW));
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) pProcessBuffer;
Offset = 0;
for ( i=0; i < ProcessCount; i++ ) {
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) ((PBYTE)pProcessInfo + Offset);
Length = pProcessInfo->ImageName.Length; // number of bytes
pProcessW->pProcessName = (LPWSTR) pProcessData;
memcpy( pProcessData, pProcessInfo->ImageName.Buffer, Length );
*(pProcessData += Length) = (WCHAR)0;
pProcessData += sizeof(WCHAR);
pProcessW->ProcessId = pProcessInfo->UniqueProcessId;
/*
* Point to the CITRIX_INFORMATION which follows the Threads
*/
pCitrixInfo = (PCITRIX_PROCESS_INFORMATION)
(((PUCHAR)pProcessInfo) +
SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION +
(SIZEOF_TS4_SYSTEM_THREAD_INFORMATION * (int)pProcessInfo->NumberOfThreads));
if ( pCitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) {
pProcessW->SessionId = pCitrixInfo->LogonId;
if ( pCitrixInfo->ProcessSid ) {
Length = GetLengthSid( pCitrixInfo->ProcessSid );
pProcessW->pUserSid = (LPWSTR) pProcessData;
memcpy( pProcessData, pCitrixInfo->ProcessSid, Length );
pProcessData += Length;
}
} else {
pProcessW->SessionId = (ULONG) -1;
}
pProcessW++;
Offset = pProcessInfo->NextEntryOffset;
}
/*
* Free original Process list buffer
*/
WinStationFreeMemory( pProcessBuffer );
}
}
return( TRUE );
/*=============================================================================
== Error return
=============================================================================*/
GAPErrorReturn:
//
// Free ppProcessArray and all child pointers allocated by the client stub.
//
WinStationFreeGAPMemory(GAP_LEVEL_BASIC, ProcessArray, ProcessCount);
goto enderror;
badalloc:
WinStationFreeMemory( pProcessBuffer );
badenum:
badparam:
enderror:
if (ppProcessInfo) *ppProcessInfo = NULL;
if (pCount) *pCount = 0;
return( FALSE );
}
#else //#if(WINVER>=0x0500)
BOOL
WINAPI
WTSEnumerateProcessesW(
IN HANDLE hServer,
IN DWORD Reserved,
IN DWORD Version,
OUT PWTS_PROCESS_INFOW * ppProcessInfo,
OUT DWORD * pCount
)
{
PBYTE pProcessBuffer;
PTS_SYS_PROCESS_INFORMATION pProcessInfo;
PCITRIX_PROCESS_INFORMATION pCitrixInfo;
ULONG ProcessCount;
ULONG Offset;
ULONG DataLength;
PWTS_PROCESS_INFOW pProcessW;
PBYTE pProcessData;
ULONG i;
ULONG Length;
/*
* Validate parameters
*/
if ( Reserved != 0 || Version != 1 ) {
SetLastError( ERROR_INVALID_PARAMETER );
goto badparam;
}
if (!ppProcessInfo || !pCount) {
SetLastError( ERROR_INVALID_PARAMETER );
goto badparam;
}
/*
* Enumerate Processes and check for an error
*/
if ( !WinStationEnumerateProcesses( hServer, &pProcessBuffer ) ) {
goto badenum;
}
/*
* Count the number of processes and total up the size of the data
*/
ProcessCount = 0;
DataLength = 0;
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) pProcessBuffer;
Offset = 0;
do {
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) ((PBYTE)pProcessInfo + Offset);
ProcessCount++;
DataLength += (pProcessInfo->ImageName.Length + sizeof(WCHAR));
pCitrixInfo = (PCITRIX_PROCESS_INFORMATION)
((PBYTE)pProcessInfo +
sizeof(SYSTEM_PROCESS_INFORMATION) +
(sizeof(SYSTEM_THREAD_INFORMATION) *
pProcessInfo->NumberOfThreads));
if ( pCitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) {
if ( pCitrixInfo->ProcessSid )
DataLength += GetLengthSid( pCitrixInfo->ProcessSid );
}
Offset = pProcessInfo->NextEntryOffset;
} while ( Offset != 0 );
/*
* Allocate user buffer
*/
pProcessW = LocalAlloc( LPTR, (ProcessCount * sizeof(WTS_PROCESS_INFOW)) + DataLength );
if ( pProcessW == NULL ) {
SetLastError(ERROR_OUTOFMEMORY);
goto badalloc;
}
/*
* Update user parameters
*/
*ppProcessInfo = pProcessW;
*pCount = ProcessCount;
/*
* Copy data to new buffer
*/
pProcessData = (PBYTE)pProcessW + (ProcessCount * sizeof(WTS_PROCESS_INFOW));
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) pProcessBuffer;
Offset = 0;
for ( i=0; i < ProcessCount; i++ ) {
pProcessInfo = (PTS_SYS_PROCESS_INFORMATION) ((PBYTE)pProcessInfo + Offset);
Length = pProcessInfo->ImageName.Length; // number of bytes
pProcessW->pProcessName = (LPWSTR) pProcessData;
memcpy( pProcessData, pProcessInfo->ImageName.Buffer, Length );
*(pProcessData += Length) = (WCHAR)0;
pProcessData += sizeof(WCHAR);
pProcessW->ProcessId = (ULONG) pProcessInfo->UniqueProcessId;
/*
* Point to the CITRIX_INFORMATION which follows the Threads
*/
pCitrixInfo = (PCITRIX_PROCESS_INFORMATION)
((PBYTE)pProcessInfo +
sizeof(SYSTEM_PROCESS_INFORMATION) +
(sizeof(SYSTEM_THREAD_INFORMATION) *
pProcessInfo->NumberOfThreads));
if ( pCitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) {
pProcessW->SessionId = pCitrixInfo->LogonId;
if ( pCitrixInfo->ProcessSid ) {
Length = GetLengthSid( pCitrixInfo->ProcessSid );
pProcessW->pUserSid = (LPWSTR) pProcessData;
memcpy( pProcessData, pCitrixInfo->ProcessSid, Length );
pProcessData += Length;
}
} else {
pProcessW->SessionId = (ULONG) -1;
}
pProcessW++;
Offset = pProcessInfo->NextEntryOffset;
}
/*
* Free original Process list buffer
*/
WinStationFreeMemory( pProcessBuffer );
return( TRUE );
/*=============================================================================
== Error return
=============================================================================*/
badalloc:
WinStationFreeMemory( pProcessBuffer );
badenum:
badparam:
if (ppProcessInfo) *ppProcessInfo = NULL;
if (pCount) *pCount = 0;
return( FALSE );
}
#endif //#if(WINVER>=0x0500)
/****************************************************************************
*
* WTSEnumerateProcessesA (ANSI stub)
*
* Returns a list of Terminal Server Processes on the specified server
*
* ENTRY:
*
* see WTSEnumerateProcessesW
*
* EXIT:
*
* TRUE -- The enumerate operation succeeded.
*
* FALSE -- The operation failed. Extended error status is available
* using GetLastError.
*
****************************************************************************/
BOOL
WINAPI
WTSEnumerateProcessesA(
IN HANDLE hServer,
IN DWORD Reserved,
IN DWORD Version,
OUT PWTS_PROCESS_INFOA * ppProcessInfo,
OUT DWORD * pCount
)
{
PWTS_PROCESS_INFOW pProcessW;
PWTS_PROCESS_INFOA pProcessA;
PBYTE pProcessData;
ULONG Length;
ULONG DataLength; // number of bytes of name data
ULONG NameCount;
ULONG i;
/*
* Enumerate processes (UNICODE)
*/
if ( !WTSEnumerateProcessesW( hServer,
Reserved,
Version,
&pProcessW,
&NameCount ) ) {
goto badenum;
}
/*
* Calculate the length of the name data
*/
for ( i=0, DataLength=0; i < NameCount; i++ ) {
DataLength += (wcslen(pProcessW[i].pProcessName) + 1);
if ( pProcessW[i].pUserSid )
DataLength += GetLengthSid( pProcessW[i].pUserSid );
}
/*
* Allocate user buffer
*/
pProcessA = LocalAlloc( LPTR, (NameCount * sizeof(WTS_PROCESS_INFOA)) + DataLength );
if ( pProcessA == NULL )
goto badalloc2;
/*
* Convert unicode process list to ansi
*/
pProcessData = (PBYTE)pProcessA + (NameCount * sizeof(WTS_PROCESS_INFOA));
for ( i=0; i < NameCount; i++ ) {
pProcessA[i].SessionId = pProcessW[i].SessionId;
pProcessA[i].ProcessId = pProcessW[i].ProcessId;
Length = wcslen(pProcessW[i].pProcessName) + 1;
pProcessA[i].pProcessName = pProcessData;
UnicodeToAnsi( pProcessData, DataLength, pProcessW[i].pProcessName );
DataLength -= Length;
pProcessData += Length;
if ( pProcessW[i].pUserSid ) {
Length = GetLengthSid( pProcessW[i].pUserSid );
pProcessA[i].pUserSid = pProcessData;
memcpy( pProcessData, pProcessW[i].pUserSid, Length );
DataLength -= Length;
pProcessData += Length;
}
}
/*
* Free unicode process list buffer
*/
LocalFree( pProcessW );
/*
* Update user parameters
*/
if (ppProcessInfo) {
*ppProcessInfo = pProcessA;
} else {
SetLastError(ERROR_INVALID_USER_BUFFER);
return(FALSE);
}
if (pCount) {
*pCount = NameCount;
} else {
SetLastError(ERROR_INVALID_USER_BUFFER);
return(FALSE);
}
return( TRUE );
/*=============================================================================
== Error return
=============================================================================*/
badalloc2:
LocalFree( pProcessW );
badenum:
// make sure the passed parameter buffer pointer is not NULL
if (ppProcessInfo) *ppProcessInfo = NULL;
if (pCount) *pCount = 0;
return( FALSE );
}
/*******************************************************************************
*
* WTSTerminateProcess
*
* Terminate the specified process
*
* ENTRY:
*
* hServer (input)
* handle to Terminal server
* ProcessId (input)
* process id of the process to terminate
* ExitCode (input)
* Termination status for each thread in the process
*
*
* EXIT:
*
* TRUE -- The terminate operation succeeded.
*
* FALSE -- The operation failed. Extended error status is available
* using GetLastError.
*
******************************************************************************/
BOOL WINAPI
WTSTerminateProcess(
HANDLE hServer,
DWORD ProcessId,
DWORD ExitCode
)
{
return( WinStationTerminateProcess( hServer, ProcessId, ExitCode ) );
}
#if(WINVER >= 0x0500)
//======================================================================//
// Private functions //
//======================================================================//
BOOL
GetProcessSid(HANDLE hServer,
HANDLE hUniqueProcessId,
LARGE_INTEGER ProcessStartTime,
PBYTE * ppSid //Return the SID (allocated here..)
)
{
DWORD dwSidSize;
BYTE tmpSid[128]; //temp storage
FILETIME startTime;
dwSidSize = sizeof(tmpSid);
*ppSid = NULL;
//Convert the time format
startTime.dwLowDateTime = ProcessStartTime.LowPart;
startTime.dwHighDateTime = ProcessStartTime.HighPart;
//-------------------------------------------//
// Get the SID with the temp Sid storage //
//-------------------------------------------//
if (!WinStationGetProcessSid(hServer,
(DWORD)(ULONG_PTR)hUniqueProcessId,
startTime,
(PBYTE)&tmpSid,
&dwSidSize
)) {
//-------------------------------------------//
// Sid is too big for the temp storage //
//Get the size of the sid and do it again //
//-------------------------------------------//
NTSTATUS status;
if ((status = GetLastError()) == STATUS_BUFFER_TOO_SMALL) {
*ppSid = LocalAlloc(LPTR, dwSidSize);
if (!*ppSid) {
SetLastError(ERROR_OUTOFMEMORY);
goto ErrorReturn;
}
} else if (dwSidSize == 0) {
*ppSid = NULL;
return TRUE;
} else {
SetLastError(status);
goto ErrorReturn;
}
//-------------------------------------------//
// Call the server again to get the SID
//-------------------------------------------//
if (!WinStationGetProcessSid(hServer,
(DWORD)(ULONG_PTR)hUniqueProcessId,
startTime,
(PBYTE)ppSid,
&dwSidSize
)) {
goto ErrorReturn;
}
} else {
//-------------------------------------------//
// Temp Sid is large enough //
// Allocate the correct size and copy the //
// Sid //
//-------------------------------------------//
*ppSid = LocalAlloc(LPTR, dwSidSize);
if (*ppSid) {
memcpy(*ppSid, tmpSid, dwSidSize);
} else {
SetLastError(ERROR_OUTOFMEMORY);
goto ErrorReturn;
}
}
return TRUE;
ErrorReturn:
if (*ppSid) {
LocalFree(*ppSid);
*ppSid = NULL;
}
return FALSE;
}
#endif //#if(WINVER >= 0x0500)