833 lines
33 KiB
C++
833 lines
33 KiB
C++
|
/*======================================================================================//
|
||
|
| //
|
||
|
|Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated. All rights reserved. //
|
||
|
| //
|
||
|
|Description: //
|
||
|
| //
|
||
|
|---------------------------------------------------------------------------------------//
|
||
|
| This file contains utility functions: error reporting, etc. //
|
||
|
|---------------------------------------------------------------------------------------//
|
||
|
| //
|
||
|
|Created: //
|
||
|
| //
|
||
|
| Jarl McDonald 04-99 (from earlier code in ProcCon service //
|
||
|
| //
|
||
|
|Revision History: //
|
||
|
| //
|
||
|
| Jarl McDonald 03-00 Look up Administrators Name rather than use hard-coded //
|
||
|
| Paul Skoglund 04-01 Add formatting functions to support logging of rule edits //
|
||
|
| //
|
||
|
|=======================================================================================*/
|
||
|
#include "..\SERVICE\ProcConSvc.h"
|
||
|
#include <aclapi.h>
|
||
|
|
||
|
//--------------------------------------------------------------------------------//
|
||
|
// Globals //
|
||
|
//--------------------------------------------------------------------------------//
|
||
|
TCHAR PROCCON_SVC_DISP_NAME[128]
|
||
|
= { TEXT("Process Control") }; // Service display name
|
||
|
TCHAR PROCCON_MEDIATOR_DISP_NAME[128]
|
||
|
= { TEXT("Process Control Mediator") }; // Mediator display name
|
||
|
TCHAR PROCCON_UNKNOWN_PROCESS[32]
|
||
|
= { TEXT("unknown") }; // Name used for the already terminated process
|
||
|
TCHAR PROCCON_SERVICE_DESCRIPTION[256]
|
||
|
= { TEXT("Provides control and grouping of running processes.") };
|
||
|
TCHAR PROCCON_DEFAULT_NAMERULE_DESC[NAME_DESCRIPTION_LEN + 1]
|
||
|
= { TEXT("---Default Alias Rule---") }; // Default alias rule desc
|
||
|
TCHAR PROCCON_FLAG_ON[32]
|
||
|
= { TEXT("on") }; // Name used to indicate rule option is on
|
||
|
TCHAR PROCCON_FLAG_OFF[32]
|
||
|
= { TEXT("off") }; // Name used to indicate rule option is off
|
||
|
TCHAR PROCCON_SYSTEM_PROCESS[32]
|
||
|
= { TEXT("System") }; // Name used for the 'System' process
|
||
|
TCHAR PROCCON_SYSTEM_IDLE[64]
|
||
|
= { TEXT("System Idle Process") }; // Name used for the 'System Idle Process'
|
||
|
TCHAR PROCCON_SERVICE_USAGE[256]
|
||
|
#ifdef _DEBUG
|
||
|
= { TEXT("Usage: proccsvc [-install user_password] [-reinstall user_password] [-remove] [-noService]\n") } // Debug usage message
|
||
|
#else
|
||
|
= { TEXT("Usage: proccsvc [-install user_password] [-reinstall user_password] [-remove]\n") } // Regular usage message
|
||
|
#endif
|
||
|
;
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to load our strings.
|
||
|
//
|
||
|
// Input: none
|
||
|
// Returns: nothing -- if loads fail default values are set
|
||
|
//
|
||
|
void PCLoadStrings( void ) {
|
||
|
|
||
|
static struct {
|
||
|
PCULONG32 stringId;
|
||
|
TCHAR *stringLoc;
|
||
|
PCULONG32 stringLen;
|
||
|
} ourStrings[] = {
|
||
|
{ IDS_SERVICE_DISP_NAME, PROCCON_SVC_DISP_NAME, ENTRY_COUNT(PROCCON_SVC_DISP_NAME) },
|
||
|
{ IDS_SERVICE_DESCRIPTION, PROCCON_SERVICE_DESCRIPTION, ENTRY_COUNT(PROCCON_SERVICE_DESCRIPTION) },
|
||
|
{ IDS_MEDIATOR_DISP_NAME, PROCCON_MEDIATOR_DISP_NAME, ENTRY_COUNT(PROCCON_MEDIATOR_DISP_NAME) },
|
||
|
{ IDS_UNKNOWN_PROCESS, PROCCON_UNKNOWN_PROCESS, ENTRY_COUNT(PROCCON_UNKNOWN_PROCESS) },
|
||
|
{ IDS_DEFAULT_NAMERULE, PROCCON_DEFAULT_NAMERULE_DESC, ENTRY_COUNT(PROCCON_DEFAULT_NAMERULE_DESC) },
|
||
|
{ IDS_FLAG_ON, PROCCON_FLAG_ON, ENTRY_COUNT(PROCCON_FLAG_ON) },
|
||
|
{ IDS_FLAG_OFF, PROCCON_FLAG_OFF, ENTRY_COUNT(PROCCON_FLAG_OFF) },
|
||
|
{ IDS_SYSTEM_PROCESS, PROCCON_SYSTEM_PROCESS, ENTRY_COUNT(PROCCON_SYSTEM_PROCESS) },
|
||
|
{ IDS_SYSTEM_IDLE, PROCCON_SYSTEM_IDLE, ENTRY_COUNT(PROCCON_SYSTEM_IDLE) },
|
||
|
{ IDS_SERVICE_USAGE, PROCCON_SERVICE_USAGE, ENTRY_COUNT(PROCCON_SERVICE_USAGE) },
|
||
|
};
|
||
|
|
||
|
for ( int i = 0; i < ENTRY_COUNT(ourStrings); ++i ) {
|
||
|
LoadString( GetModuleHandle( NULL ), ourStrings[i].stringId,
|
||
|
ourStrings[i].stringLoc, ourStrings[i].stringLen );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to test if we are running on Windows 2000 Datacenter Server.
|
||
|
//
|
||
|
// Input: none
|
||
|
// Returns: TRUE if we are on Windows 2000 Datacenter Server, else FALSE
|
||
|
//
|
||
|
BOOL PCTestOSVersion( void ) {
|
||
|
|
||
|
OSVERSIONINFOEX version;
|
||
|
memset( &version, 0, sizeof( version ) ); // needed due to bug in Beta 3
|
||
|
version.dwOSVersionInfoSize = sizeof( version );
|
||
|
|
||
|
DWORDLONG condition = 0;
|
||
|
VER_SET_CONDITION( condition, VER_PLATFORMID, VER_EQUAL );
|
||
|
VER_SET_CONDITION( condition, VER_MAJORVERSION, VER_GREATER_EQUAL );
|
||
|
VER_SET_CONDITION( condition, VER_SUITENAME, VER_AND );
|
||
|
|
||
|
version.dwPlatformId = VER_PLATFORM_WIN32_NT;
|
||
|
version.dwMajorVersion = 5;
|
||
|
version.wSuiteMask = VER_SUITE_DATACENTER;
|
||
|
|
||
|
return VerifyVersionInfo( &version, VER_PLATFORMID + VER_MAJORVERSION + VER_SUITENAME, condition );
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to test if an instance of the passed name is running (exists)
|
||
|
//
|
||
|
// Input: name of exclusion object, display name of requestor or NULL
|
||
|
// Returns: TRUE if an instance of the object exists
|
||
|
// FALSE if the object was newly created
|
||
|
//
|
||
|
BOOL PCTestIsRunning( const TCHAR *who, const TCHAR *dispName ) {
|
||
|
|
||
|
HANDLE hEvent = OpenEvent( EVENT_ALL_ACCESS, FALSE, who );
|
||
|
DWORD rc = GetLastError();
|
||
|
|
||
|
if ( hEvent ) CloseHandle( hEvent );
|
||
|
|
||
|
if ( !hEvent && rc != ERROR_FILE_NOT_FOUND && dispName ) {
|
||
|
SetLastError( rc ) ;
|
||
|
PCLogUnExError( who, TEXT("OpenExclEvent") );
|
||
|
}
|
||
|
|
||
|
return hEvent != NULL;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to set exclusive access to the name (via an event)
|
||
|
//
|
||
|
// Input: name of exclusion object, display name of requestor or NULL
|
||
|
// Returns: TRUE if an instance of an exclusive instance of the object was created
|
||
|
// FALSE if the object already existed
|
||
|
//
|
||
|
BOOL PCSetIsRunning( const TCHAR *who, const TCHAR *dispName ) {
|
||
|
|
||
|
DWORD rc = TRUE;
|
||
|
HANDLE hEvent;
|
||
|
SECURITY_ATTRIBUTES secAttr;
|
||
|
|
||
|
if ( !PCBuildNullSecAttr( secAttr ) ) { // Everybody can access -- we want universal exclusion
|
||
|
PCLogUnExError( who, TEXT("BuildNullSecAttr") );
|
||
|
rc = FALSE;
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
hEvent = CreateEvent( &secAttr, TRUE, FALSE, who );
|
||
|
if ( !hEvent ) {
|
||
|
PCLogUnExError( who, TEXT("CreateExclEvent") );
|
||
|
rc = FALSE;
|
||
|
}
|
||
|
else if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
|
||
|
if ( dispName ) PCLogMessage( PC_PROCESS_ALREADY_RUNNING, EVENTLOG_ERROR_TYPE, 1, dispName );
|
||
|
CloseHandle( hEvent );
|
||
|
rc = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PCFreeSecAttr( secAttr );
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to build our registry keys.
|
||
|
//
|
||
|
// Input: location to build key
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
void PCBuildBaseKey( TCHAR *key ) {
|
||
|
_tcscpy( key, PROCCON_REG_SERVICE_BASE );
|
||
|
_tcscat( key, PROCCON_SVC_NAME );
|
||
|
}
|
||
|
|
||
|
void PCBuildMsgKey( TCHAR *key ) {
|
||
|
_tcscpy( key, PROCCON_REG_SERVICE_BASE );
|
||
|
_tcscat( key, PROCCON_REG_EVENTLOG_SUBKEY );
|
||
|
_tcscat( key, PROCCON_SVC_NAME );
|
||
|
}
|
||
|
|
||
|
void PCBuildParmKey( TCHAR *key ) {
|
||
|
PCBuildBaseKey( key );
|
||
|
_tcscat( key, TEXT("\\") );
|
||
|
_tcscat( key, PROCCON_REG_PARMS_SUBKEY );
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to verify a name, type, etc.
|
||
|
//
|
||
|
//
|
||
|
#define TBLANK L' '
|
||
|
BOOL PCValidName( const TCHAR *name, const PCULONG32 len, const BOOL nullOK ) {
|
||
|
for ( PCULONG32 i = 0; i < len; ++i ) {
|
||
|
// hit terminator -- verify whole name: no leading or trailing blanks, not NULL unless OKed
|
||
|
if ( !name[i] ) {
|
||
|
if ( i ) {
|
||
|
if ( name[0] == TBLANK || name[i - 1] == TBLANK ) return FALSE; // leading/trailing blnk
|
||
|
else return TRUE;
|
||
|
}
|
||
|
else return nullOK; // name is null
|
||
|
}
|
||
|
if ( _tcschr( TEXT("\\,\""), name[i] ) ) return FALSE; // hit invalid character
|
||
|
}
|
||
|
return FALSE; // no terminator
|
||
|
}
|
||
|
|
||
|
BOOL PCValidMatchType( const TCHAR type ) {
|
||
|
return type == MATCH_PGM || type == MATCH_DIR || type == MATCH_ANY;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to locate first occurrence of one string in another without regard to case.
|
||
|
//
|
||
|
// Input: location of string to search (here), location of string to find (it)
|
||
|
// Returns: location of first match or NULL
|
||
|
//
|
||
|
const TCHAR *PCiStrStr( const TCHAR *here, const TCHAR *it ) {
|
||
|
const TCHAR firstchar = _totupper( *it );
|
||
|
PCULONG32 len = _tcslen( it );
|
||
|
|
||
|
for ( const TCHAR *at = here; ; ++at ) {
|
||
|
while ( *at && firstchar != _totupper( *at ) ) ++at;
|
||
|
if ( !*at ) return firstchar? NULL : at;
|
||
|
if ( !_tcsnicmp( at, it, len ) ) return at;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to convert a hex or decimal number to a PCULONG32 or __int64.
|
||
|
//
|
||
|
// Input: location of data, location to set to end of data
|
||
|
// Returns: converted number
|
||
|
//
|
||
|
__int64 PCGetParmValue64( TCHAR *loc, TCHAR **end ) {
|
||
|
PCULONG32 base = 10;
|
||
|
if ( *(loc + 1) == TEXT('x') || *(loc + 1) == TEXT('X') ) {
|
||
|
base = 16;
|
||
|
loc += 2;
|
||
|
}
|
||
|
for ( __int64 result = 0; ; ++loc ) {
|
||
|
TCHAR c = _totupper(*loc);
|
||
|
if ( c >= TEXT('0') && c <= TEXT('9') )
|
||
|
result = result * base + c - TEXT('0');
|
||
|
else if ( base == 16 && c >= TEXT('A') && c <= TEXT('F') )
|
||
|
result = result * base + 10 + c - TEXT('A');
|
||
|
else {
|
||
|
*end = loc;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
PCULONG32 PCGetParmValue( TCHAR *loc, TCHAR **end ) {
|
||
|
return (PCULONG32) PCGetParmValue64( loc, end );
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to test sign of __int64.
|
||
|
//
|
||
|
// Input: integer to test
|
||
|
// Returns: +1, -1, or 0 depending on if integer is greater, less, or equal zero
|
||
|
//
|
||
|
int PCSignof64(__int64 x ) {
|
||
|
return (x > 0)? 1 : (x < 0)? -1 : 0;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to report one of our errors in the Win2K event log.
|
||
|
//
|
||
|
// Input: log message parameters: code, type, string count, string ptr, data len, data ptr
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
void PCLogMessage( const PCULONG32 msgCode,
|
||
|
const WORD msgType,
|
||
|
WORD numStrings,
|
||
|
const void *msgStrings,
|
||
|
ULONG lenData,
|
||
|
void *msgData ) {
|
||
|
|
||
|
// If no message data, use NT error as data
|
||
|
PCULONG32 NTError;
|
||
|
if ( !lenData && msgType != EVENTLOG_INFORMATION_TYPE ) {
|
||
|
NTError = GetLastError();
|
||
|
lenData = sizeof( NTError );
|
||
|
msgData = &NTError;
|
||
|
}
|
||
|
|
||
|
// Make sure we successfully register...
|
||
|
HANDLE hErrLog = RegisterEventSource( NULL, PROCCON_SVC_NAME );
|
||
|
if ( !hErrLog ) return;
|
||
|
|
||
|
// Prepare insertion argument list...
|
||
|
const TCHAR *strings[64];
|
||
|
// Make a local copy of string args to allow us to extend it.
|
||
|
// For a single string just set up single entry table,
|
||
|
// For a multi-entry table use the passed array.
|
||
|
if ( numStrings == 1 )
|
||
|
strings[0] = (TCHAR *) msgStrings;
|
||
|
else
|
||
|
memcpy( strings, msgStrings, sizeof(TCHAR *) * numStrings );
|
||
|
|
||
|
// For error meassages add the NT error description to the argument list...
|
||
|
TCHAR err[1024];
|
||
|
if ( msgType == EVENTLOG_ERROR_TYPE ) {
|
||
|
PCNTErrorText( *(PCULONG32 *)msgData, err, ENTRY_COUNT(err) );
|
||
|
strings[numStrings++] = err;
|
||
|
}
|
||
|
|
||
|
// Report the desired event...
|
||
|
ReportEvent( hErrLog, msgType, 0, msgCode, NULL,
|
||
|
numStrings, lenData, strings, msgData );
|
||
|
|
||
|
// de-register...
|
||
|
DeregisterEventSource( hErrLog );
|
||
|
}
|
||
|
|
||
|
// Handle unexpected NT error by:
|
||
|
// 1. Setting up two strings -- an operand and an operation.
|
||
|
// 2. Getting the NT error.
|
||
|
// 3. Calling standard error fcn with strings and NT error.
|
||
|
void PCLogUnExError( const TCHAR *who, const TCHAR *what ) {
|
||
|
const TCHAR *strings[2] = { who, what };
|
||
|
DWORD err = GetLastError();
|
||
|
|
||
|
PCLogMessage( PC_UNEXPECTED_NT_ERROR, EVENTLOG_ERROR_TYPE,
|
||
|
ENTRY_COUNT(strings), strings, sizeof(err), &err );
|
||
|
}
|
||
|
|
||
|
// Handle PID-based unexpected NT error by:
|
||
|
// 1. Setting up two strings -- an operand as "PID nnn" and an operation.
|
||
|
// 2. Getting the NT error.
|
||
|
// 3. Calling standard error fcn with strings and NT error.
|
||
|
void PCLogUnExError( const __int64 pid, const TCHAR *what ) {
|
||
|
TCHAR pidString[16];
|
||
|
const TCHAR *strings[2] = { pidString, what };
|
||
|
DWORD err = GetLastError();
|
||
|
|
||
|
_tcscpy( pidString, TEXT("PID ") );
|
||
|
_i64tot( pid, pidString + _tcslen(pidString), 10 );
|
||
|
|
||
|
PCLogMessage( PC_UNEXPECTED_NT_ERROR, EVENTLOG_ERROR_TYPE,
|
||
|
ENTRY_COUNT(strings), strings, sizeof(err), &err );
|
||
|
}
|
||
|
|
||
|
// Handle insufficient memory by:
|
||
|
// 1. Setting up two strings -- a size string and the passed identifying string.
|
||
|
// 2. Setting an NT error of ERROR_NOT_ENOUGH_MEMORY (no error set by new).
|
||
|
// 3. Calling standard error fcn with strings and NT error.
|
||
|
PCULONG32 PCLogNoMemory( const TCHAR *string, const PCULONG32 len ) {
|
||
|
TCHAR size[1024];
|
||
|
const TCHAR *strings[2] = { size, string };
|
||
|
DWORD err = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
_stprintf( size, TEXT("0x%lx"), len );
|
||
|
|
||
|
PCLogMessage( PC_CANT_GET_MEMORY, EVENTLOG_ERROR_TYPE,
|
||
|
ENTRY_COUNT(strings), strings, sizeof(err), &err );
|
||
|
|
||
|
return PC_CANT_GET_MEMORY;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to get text for a Win2K error
|
||
|
//
|
||
|
// Input: error, buffer pointer, buffer length
|
||
|
// Returns: pointer to buffer
|
||
|
// Note: trailing returns are stripped from the message.
|
||
|
//
|
||
|
LPTSTR PCNTErrorText( PCULONG32 error, LPTSTR buf, PCULONG32 size )
|
||
|
{
|
||
|
PCULONG32 dwRet = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
|
||
|
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
|
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, size, NULL );
|
||
|
if (!dwRet) {
|
||
|
if (size)
|
||
|
buf[size - 1] = 0;
|
||
|
_sntprintf( buf, size - 1, TEXT("0x%lx"), error );
|
||
|
}
|
||
|
else {
|
||
|
while ( --dwRet && (buf[dwRet] == TEXT('\n') || buf[dwRet] == TEXT('\r')) )
|
||
|
buf[dwRet] = TEXT('\0');
|
||
|
}
|
||
|
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to determine if management behavior is requested in a process/job definition
|
||
|
//
|
||
|
// Input: ref to management definition
|
||
|
// Returns: TRUE if any management behavior would be applied, else FALSE
|
||
|
//
|
||
|
BOOL PCIsProcManaged( MGMT_PARMS &def, JOB_NAME *job ) {
|
||
|
if ( def.mFlags & PCMFLAG_APPLY_JOB_MEMBERSHIP && job[0] ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_AFFINITY && def.affinity ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_PRIORITY && def.priority ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_WS_MINMAX && def.minWS && def.maxWS ) return TRUE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL PCIsJobManaged( MGMT_PARMS &def ) {
|
||
|
if ( def.mFlags & (PCMFLAG_SET_PROC_BREAKAWAY_OK |
|
||
|
PCMFLAG_SET_SILENT_BREAKAWAY |
|
||
|
PCMFLAG_SET_DIE_ON_UH_EXCEPTION) ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_AFFINITY && def.affinity ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_PRIORITY && def.priority ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_WS_MINMAX && def.minWS && def.maxWS ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_SCHEDULING_CLASS && def.schedClass < 10 ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_PROC_MEMORY_LIMIT && def.procMemoryLimit ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_JOB_MEMORY_LIMIT && def.jobMemoryLimit ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_JOB_TIME_LIMIT && def.jobTimeLimitCNS ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_PROC_TIME_LIMIT && def.procTimeLimitCNS ) return TRUE;
|
||
|
else if ( def.mFlags & PCMFLAG_APPLY_PROC_COUNT_LIMIT && def.procCountLimit ) return TRUE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to return a string representing if a flag is set:
|
||
|
//
|
||
|
// Input: field and flag value for the field in question
|
||
|
// Returns: string representation of if a flag is set
|
||
|
LPCTSTR PCIsSetToStr(PC_MGMT_FLAGS field, PCMgmtFlags flag)
|
||
|
{
|
||
|
if (field & flag)
|
||
|
return TEXT("+");
|
||
|
else
|
||
|
return TEXT("-");
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to determine if one flag setting is opposite another flag setting:
|
||
|
//
|
||
|
// Input: flag field and flag value for the two fields in question
|
||
|
// Returns: 1 if first flag is set and second flag is unset
|
||
|
// -1 if first flag is unset and second flag is set
|
||
|
// 0 if both flags are set or unset
|
||
|
//
|
||
|
int PCTestSetUnset( DWORD field1, DWORD flag1, DWORD field2, DWORD flag2 ) {
|
||
|
if ( field1 & flag1 && !(field2 & flag2) ) return 1;
|
||
|
if ( !(field1 & flag1) && field2 & flag2 ) return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to map PC priority (same as toolhelp priority) to NT priority and back
|
||
|
//
|
||
|
// Input: priority to map
|
||
|
// Returns: mapped priority
|
||
|
//
|
||
|
PCULONG32 PCMapPriorityToNT( PRIORITY prio ) {
|
||
|
if ( prio > 15 ) return REALTIME_PRIORITY_CLASS; // 16 and above
|
||
|
else if ( prio > 11 ) return HIGH_PRIORITY_CLASS; // 12-15
|
||
|
else if ( prio > 9 ) return ABOVE_NORMAL_PRIORITY_CLASS; // 10-11
|
||
|
else if ( prio > 7 ) return NORMAL_PRIORITY_CLASS; // 8-9
|
||
|
else if ( prio > 5 ) return BELOW_NORMAL_PRIORITY_CLASS; // 6-7
|
||
|
else if ( prio > 0 ) return IDLE_PRIORITY_CLASS; // 1-5
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PRIORITY PCMapPriorityToPC( PCULONG32 prio ) {
|
||
|
if ( prio & REALTIME_PRIORITY_CLASS ) return PCPrioRealTime;
|
||
|
else if ( prio & HIGH_PRIORITY_CLASS ) return PCPrioHigh;
|
||
|
else if ( prio & ABOVE_NORMAL_PRIORITY_CLASS ) return PCPrioAboveNormal;
|
||
|
else if ( prio & NORMAL_PRIORITY_CLASS ) return PCPrioNormal;
|
||
|
else if ( prio & BELOW_NORMAL_PRIORITY_CLASS ) return PCPrioBelowNormal;
|
||
|
else if ( prio & IDLE_PRIORITY_CLASS ) return PCPrioIdle;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PRIORITY PCMapPriorityForAPI( PRIORITY prio ) {
|
||
|
if ( prio > 15 ) return PCPrioRealTime;
|
||
|
else if ( prio > 11 ) return PCPrioHigh;
|
||
|
else if ( prio > 9 ) return PCPrioAboveNormal;
|
||
|
else if ( prio > 7 ) return PCPrioNormal;
|
||
|
else if ( prio > 5 ) return PCPrioBelowNormal;
|
||
|
else if ( prio > 0 ) return PCPrioIdle;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to map NT defined long numbers to int 64's
|
||
|
//
|
||
|
// Input: numeric field format to convert
|
||
|
// Returns: int64 version of data
|
||
|
//
|
||
|
__int64 PCLargeIntToInt64( LARGE_INTEGER &in ) {
|
||
|
return in.QuadPart;
|
||
|
}
|
||
|
__int64 PCFileTimeToInt64( FILETIME &in ) {
|
||
|
return ((__int64) in.dwHighDateTime << 32) + (__int64) in.dwLowDateTime;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to delete a registry key by deleting all subkeys first
|
||
|
//
|
||
|
// Input: handle to open key, name of subkey tree to delete
|
||
|
// Returns: NT return code
|
||
|
//
|
||
|
PCULONG32 PCDeleteKeyTree( HKEY hKey, const TCHAR *keyName ) {
|
||
|
PCULONG32 rc, ourCount;
|
||
|
HKEY ourKey;
|
||
|
|
||
|
// Open the key at top of tree...
|
||
|
rc = RegOpenKeyEx( hKey, keyName, NULL, KEY_READ + KEY_WRITE, &ourKey );
|
||
|
if ( rc == ERROR_FILE_NOT_FOUND || rc == ERROR_KEY_DELETED ) // nothing to do
|
||
|
return ERROR_SUCCESS;
|
||
|
else if ( rc != ERROR_SUCCESS ) {
|
||
|
SetLastError( rc );
|
||
|
PCLogUnExError( keyName, TEXT("RegOpenKeyEx") );
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
// Determine how many subkeys we have...
|
||
|
rc = RegQueryInfoKey( ourKey, NULL, NULL, NULL, &ourCount,
|
||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL );
|
||
|
if ( rc != ERROR_SUCCESS ) { // Should never happen
|
||
|
SetLastError( rc );
|
||
|
PCLogUnExError( keyName, TEXT("RegQueryInfoKey") );
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
// For each sub-key delete its sub-tree...
|
||
|
for ( PCULONG32 i = 0; rc == ERROR_SUCCESS && i < ourCount; ++i ) {
|
||
|
|
||
|
// Get next subkey...
|
||
|
TCHAR name[MAX_PATH];
|
||
|
FILETIME keyLastWrite;
|
||
|
PCULONG32 nameLen = ENTRY_COUNT(name);
|
||
|
rc = RegEnumKeyEx( ourKey, ourCount - 1 - i, name, &nameLen, NULL, NULL, NULL, &keyLastWrite );
|
||
|
if ( rc == ERROR_NO_MORE_ITEMS ) {
|
||
|
rc = ERROR_SUCCESS;
|
||
|
break;
|
||
|
}
|
||
|
if ( rc != ERROR_SUCCESS ) { // Should never happen
|
||
|
SetLastError( rc );
|
||
|
PCLogUnExError( keyName, TEXT("RegEnumKeyEx") );
|
||
|
return rc;
|
||
|
}
|
||
|
rc = PCDeleteKeyTree( ourKey, name );
|
||
|
}
|
||
|
|
||
|
// Close the key at top of tree and delete it...
|
||
|
RegCloseKey( ourKey );
|
||
|
if ( rc == ERROR_SUCCESS )
|
||
|
rc = RegDeleteKey( hKey, keyName );
|
||
|
|
||
|
return rc == ERROR_KEY_DELETED? ERROR_SUCCESS : rc;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to enable/disable an NT user privilege
|
||
|
//
|
||
|
// Input: ptr to name of privilege, enable/disable flag
|
||
|
// Returns: TRUE if successful, else FALSE
|
||
|
//
|
||
|
BOOL PCSetPrivilege( TCHAR *privilege, BOOL enable ) {
|
||
|
|
||
|
HANDLE hTok = NULL;
|
||
|
BOOL ok = TRUE;
|
||
|
|
||
|
// Build token to enable or disable the privilege...
|
||
|
TOKEN_PRIVILEGES priv;
|
||
|
priv.PrivilegeCount = 1;
|
||
|
priv.Privileges[0].Attributes = enable? SE_PRIVILEGE_ENABLED : 0;
|
||
|
|
||
|
// Get access token handle...
|
||
|
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hTok ) ) {
|
||
|
PCLogUnExError( privilege, TEXT("OpenProcessToken") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
|
||
|
// Look up privilege to set local ID...
|
||
|
else if ( !LookupPrivilegeValue( NULL, privilege, &priv.Privileges[0].Luid ) ) {
|
||
|
PCLogUnExError( privilege, TEXT("LookupPrivilegeValue") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
|
||
|
// Update privilege...
|
||
|
else if ( !AdjustTokenPrivileges( hTok, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), NULL, NULL ) ) {
|
||
|
PCLogUnExError( privilege, TEXT("Adjustprivileges") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
|
||
|
if ( hTok ) CloseHandle( hTok );
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to create a security attributes with NULL security descriptor
|
||
|
//
|
||
|
// Input: reference to security attribue structure to build
|
||
|
// Returns: TRUE if successful, else FALSE
|
||
|
//
|
||
|
PCULONG32 PCBuildNullSecAttr( SECURITY_ATTRIBUTES &secAttr ) {
|
||
|
|
||
|
BOOL ok = TRUE;
|
||
|
|
||
|
// Init passed attributes struct...
|
||
|
secAttr.nLength = sizeof(secAttr);
|
||
|
secAttr.lpSecurityDescriptor = new char[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
||
|
secAttr.bInheritHandle = TRUE;
|
||
|
|
||
|
if ( !secAttr.lpSecurityDescriptor ) {
|
||
|
PCLogNoMemory( TEXT("AllocSecurityDesc"), SECURITY_DESCRIPTOR_MIN_LENGTH );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
else if ( !InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) ) {
|
||
|
PCLogUnExError( TEXT("NullAttr"), TEXT("InitializeSecurityDescriptor") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
|
||
|
// add a NULL discretionary ACL...
|
||
|
else if ( !SetSecurityDescriptorDacl(secAttr.lpSecurityDescriptor, TRUE, NULL, FALSE) ) {
|
||
|
PCLogUnExError( TEXT("NullAttr"), TEXT("SetSecurityDescriptorDacl") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ok && secAttr.lpSecurityDescriptor ) {
|
||
|
delete [] secAttr.lpSecurityDescriptor;
|
||
|
secAttr.lpSecurityDescriptor = NULL;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Function to create a security attributes with ADMINISTRATORS security descriptor
|
||
|
//
|
||
|
// Input: reference to security attribue structure to build
|
||
|
// Returns: TRUE if successful, else FALSE
|
||
|
//
|
||
|
PCULONG32 PCBuildAdminSecAttr( SECURITY_ATTRIBUTES &secAttr ) {
|
||
|
|
||
|
#define ADMIN_NAME_LEN 256
|
||
|
BOOL ok = TRUE;
|
||
|
TCHAR AdminName[ADMIN_NAME_LEN+1];
|
||
|
PCULONG32 AdminNameLen = ADMIN_NAME_LEN;
|
||
|
|
||
|
// Init passed attributes struct...
|
||
|
secAttr.nLength = sizeof(secAttr);
|
||
|
secAttr.lpSecurityDescriptor = new char[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
||
|
secAttr.bInheritHandle = FALSE;
|
||
|
|
||
|
if ( !secAttr.lpSecurityDescriptor ) {
|
||
|
PCLogNoMemory( TEXT("AllocSecurityDesc"), SECURITY_DESCRIPTOR_MIN_LENGTH );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
else if ( !InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) ) {
|
||
|
PCLogUnExError( TEXT("AdminAttr"), TEXT("InitializeSecurityDescriptor") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
else if( !PCGetAdminGroupName( AdminName, &AdminNameLen) )
|
||
|
ok = FALSE;
|
||
|
else {
|
||
|
EXPLICIT_ACCESS adminAccess[2];
|
||
|
ACL *adminACL = NULL;
|
||
|
|
||
|
BuildExplicitAccessWithName( &adminAccess[0],
|
||
|
TEXT("SYSTEM"), // access is for system
|
||
|
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, // access is for all rights
|
||
|
GRANT_ACCESS, // ace grants access
|
||
|
OBJECT_INHERIT_ACE ); // objects inherit access
|
||
|
BuildExplicitAccessWithName( &adminAccess[1],
|
||
|
AdminName, // access is for admins
|
||
|
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, // access is for all rights
|
||
|
GRANT_ACCESS, // ace grants access
|
||
|
OBJECT_INHERIT_ACE ); // objects inherit access
|
||
|
if ( ERROR_SUCCESS != SetEntriesInAcl( 2, adminAccess, NULL, &adminACL ) ) {
|
||
|
PCLogUnExError( TEXT("AdminAttr"), TEXT("SetEntriesInAcl") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
else if ( !SetSecurityDescriptorDacl( secAttr.lpSecurityDescriptor, TRUE, adminACL, FALSE ) ) {
|
||
|
PCLogUnExError( TEXT("AdminAttr"), TEXT("SetSecurityDescriptorDacl") );
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !ok && secAttr.lpSecurityDescriptor ) {
|
||
|
delete [] secAttr.lpSecurityDescriptor;
|
||
|
secAttr.lpSecurityDescriptor = NULL;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
void PCFreeSecAttr( SECURITY_ATTRIBUTES &secAttr ) {
|
||
|
if ( secAttr.lpSecurityDescriptor ) {
|
||
|
if ( ((SECURITY_DESCRIPTOR *)(secAttr.lpSecurityDescriptor))->Dacl )
|
||
|
LocalFree( ((SECURITY_DESCRIPTOR *)(secAttr.lpSecurityDescriptor))->Dacl );
|
||
|
delete [] secAttr.lpSecurityDescriptor;
|
||
|
secAttr.lpSecurityDescriptor = NULL;
|
||
|
}
|
||
|
}
|
||
|
//=======================================================================================//
|
||
|
// Function to look up local name of ADMINISTRATORS group
|
||
|
//
|
||
|
// Input: Pointers to name and name length
|
||
|
// Returns: TRUE on success, FALSE on failure with error message logged
|
||
|
//
|
||
|
BOOL PCGetAdminGroupName( TCHAR *Name, PCULONG32 *NameLen ) {
|
||
|
|
||
|
#define DOMAIN_NAME_LEN 256
|
||
|
SID_IDENTIFIER_AUTHORITY SidIdAuthority = SECURITY_NT_AUTHORITY;
|
||
|
SID_NAME_USE SidNameUse;
|
||
|
PSID pSid;
|
||
|
TCHAR DomainName[DOMAIN_NAME_LEN+1];
|
||
|
PCULONG32 DomainNameLen = DOMAIN_NAME_LEN;
|
||
|
BOOL ok = FALSE;
|
||
|
|
||
|
if ( !AllocateAndInitializeSid( &SidIdAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
||
|
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid) )
|
||
|
PCLogUnExError( TEXT("AdminAttr"), TEXT("AllocateAdminSid") );
|
||
|
else {
|
||
|
if ( !LookupAccountSid( NULL, pSid, Name, NameLen, DomainName, &DomainNameLen, &SidNameUse ) )
|
||
|
PCLogUnExError( TEXT("AdminAttr"), TEXT("LookupAdminSid") );
|
||
|
else
|
||
|
ok = TRUE;
|
||
|
FreeSid(pSid);
|
||
|
}
|
||
|
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// Functions to help format management attributes for use in log, these functions
|
||
|
// format the values as limits with
|
||
|
// '+' => on, enabled, or applied
|
||
|
// '-' => off, disabed, or not applied
|
||
|
// the value follows the on/off indicator in square brackets "[]"
|
||
|
//
|
||
|
// Input: buffer, buffer length in CHARACTERS, management parmaters
|
||
|
// Returns: buffer with string form of attribute
|
||
|
//
|
||
|
void PCFormatAffinityLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1, TEXT("%s[0x%I64X]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_AFFINITY),
|
||
|
def.affinity );
|
||
|
}
|
||
|
|
||
|
void PCFormatPriorityLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1, TEXT("%s[%lu]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PRIORITY),
|
||
|
def.priority );
|
||
|
}
|
||
|
|
||
|
void PCFormatWorkingSetLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1, TEXT("%s[%I64u,%I64u]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_WS_MINMAX),
|
||
|
def.minWS,
|
||
|
def.maxWS );
|
||
|
}
|
||
|
|
||
|
void PCFormatSchedClassLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1, TEXT("%s[%lu]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_SCHEDULING_CLASS),
|
||
|
def.schedClass );
|
||
|
}
|
||
|
|
||
|
void PCFormatProcessCountLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%lu]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PROC_COUNT_LIMIT),
|
||
|
def.procCountLimit );
|
||
|
}
|
||
|
|
||
|
void PCFormatProcTimeLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64d]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PROC_TIME_LIMIT),
|
||
|
def.procTimeLimitCNS / 10000 );
|
||
|
}
|
||
|
|
||
|
void PCFormatJobTimeLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64d]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_JOB_TIME_LIMIT),
|
||
|
def.jobTimeLimitCNS / 10000 );
|
||
|
}
|
||
|
|
||
|
void PCFormatProcMemLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64u]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PROC_MEMORY_LIMIT),
|
||
|
def.procMemoryLimit );
|
||
|
}
|
||
|
|
||
|
void PCFormatJobMemLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64u]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_JOB_MEMORY_LIMIT),
|
||
|
def.jobMemoryLimit );
|
||
|
}
|
||
|
|
||
|
void PCFormatEndofJobAction(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%s]"),
|
||
|
PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_JOB_TIME_LIMIT),
|
||
|
(def.mFlags & PCMFLAG_MSG_ON_JOB_TIME_LIMIT_HIT) ? PROCCON_FLAG_ON : PROCCON_FLAG_OFF);
|
||
|
}
|
||
|
|
||
|
void PCFormatOnOrOffLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def, PCMgmtFlags flag)
|
||
|
{
|
||
|
Buffer[BufferLength - 1] = 0;
|
||
|
_sntprintf(Buffer, BufferLength - 1 , TEXT("%s"),
|
||
|
(def.mFlags & flag) ? PROCCON_FLAG_ON : PROCCON_FLAG_OFF);
|
||
|
}
|
||
|
|
||
|
// End of PCUtility.cpp
|
||
|
//============================================================================J McDonald fecit====//
|
||
|
|