Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

832 lines
33 KiB

  1. /*======================================================================================//
  2. | //
  3. |Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated. All rights reserved. //
  4. | //
  5. |Description: //
  6. | //
  7. |---------------------------------------------------------------------------------------//
  8. | This file contains utility functions: error reporting, etc. //
  9. |---------------------------------------------------------------------------------------//
  10. | //
  11. |Created: //
  12. | //
  13. | Jarl McDonald 04-99 (from earlier code in ProcCon service //
  14. | //
  15. |Revision History: //
  16. | //
  17. | Jarl McDonald 03-00 Look up Administrators Name rather than use hard-coded //
  18. | Paul Skoglund 04-01 Add formatting functions to support logging of rule edits //
  19. | //
  20. |=======================================================================================*/
  21. #include "..\SERVICE\ProcConSvc.h"
  22. #include <aclapi.h>
  23. //--------------------------------------------------------------------------------//
  24. // Globals //
  25. //--------------------------------------------------------------------------------//
  26. TCHAR PROCCON_SVC_DISP_NAME[128]
  27. = { TEXT("Process Control") }; // Service display name
  28. TCHAR PROCCON_MEDIATOR_DISP_NAME[128]
  29. = { TEXT("Process Control Mediator") }; // Mediator display name
  30. TCHAR PROCCON_UNKNOWN_PROCESS[32]
  31. = { TEXT("unknown") }; // Name used for the already terminated process
  32. TCHAR PROCCON_SERVICE_DESCRIPTION[256]
  33. = { TEXT("Provides control and grouping of running processes.") };
  34. TCHAR PROCCON_DEFAULT_NAMERULE_DESC[NAME_DESCRIPTION_LEN + 1]
  35. = { TEXT("---Default Alias Rule---") }; // Default alias rule desc
  36. TCHAR PROCCON_FLAG_ON[32]
  37. = { TEXT("on") }; // Name used to indicate rule option is on
  38. TCHAR PROCCON_FLAG_OFF[32]
  39. = { TEXT("off") }; // Name used to indicate rule option is off
  40. TCHAR PROCCON_SYSTEM_PROCESS[32]
  41. = { TEXT("System") }; // Name used for the 'System' process
  42. TCHAR PROCCON_SYSTEM_IDLE[64]
  43. = { TEXT("System Idle Process") }; // Name used for the 'System Idle Process'
  44. TCHAR PROCCON_SERVICE_USAGE[256]
  45. #ifdef _DEBUG
  46. = { TEXT("Usage: proccsvc [-install user_password] [-reinstall user_password] [-remove] [-noService]\n") } // Debug usage message
  47. #else
  48. = { TEXT("Usage: proccsvc [-install user_password] [-reinstall user_password] [-remove]\n") } // Regular usage message
  49. #endif
  50. ;
  51. //=======================================================================================//
  52. // Function to load our strings.
  53. //
  54. // Input: none
  55. // Returns: nothing -- if loads fail default values are set
  56. //
  57. void PCLoadStrings( void ) {
  58. static struct {
  59. PCULONG32 stringId;
  60. TCHAR *stringLoc;
  61. PCULONG32 stringLen;
  62. } ourStrings[] = {
  63. { IDS_SERVICE_DISP_NAME, PROCCON_SVC_DISP_NAME, ENTRY_COUNT(PROCCON_SVC_DISP_NAME) },
  64. { IDS_SERVICE_DESCRIPTION, PROCCON_SERVICE_DESCRIPTION, ENTRY_COUNT(PROCCON_SERVICE_DESCRIPTION) },
  65. { IDS_MEDIATOR_DISP_NAME, PROCCON_MEDIATOR_DISP_NAME, ENTRY_COUNT(PROCCON_MEDIATOR_DISP_NAME) },
  66. { IDS_UNKNOWN_PROCESS, PROCCON_UNKNOWN_PROCESS, ENTRY_COUNT(PROCCON_UNKNOWN_PROCESS) },
  67. { IDS_DEFAULT_NAMERULE, PROCCON_DEFAULT_NAMERULE_DESC, ENTRY_COUNT(PROCCON_DEFAULT_NAMERULE_DESC) },
  68. { IDS_FLAG_ON, PROCCON_FLAG_ON, ENTRY_COUNT(PROCCON_FLAG_ON) },
  69. { IDS_FLAG_OFF, PROCCON_FLAG_OFF, ENTRY_COUNT(PROCCON_FLAG_OFF) },
  70. { IDS_SYSTEM_PROCESS, PROCCON_SYSTEM_PROCESS, ENTRY_COUNT(PROCCON_SYSTEM_PROCESS) },
  71. { IDS_SYSTEM_IDLE, PROCCON_SYSTEM_IDLE, ENTRY_COUNT(PROCCON_SYSTEM_IDLE) },
  72. { IDS_SERVICE_USAGE, PROCCON_SERVICE_USAGE, ENTRY_COUNT(PROCCON_SERVICE_USAGE) },
  73. };
  74. for ( int i = 0; i < ENTRY_COUNT(ourStrings); ++i ) {
  75. LoadString( GetModuleHandle( NULL ), ourStrings[i].stringId,
  76. ourStrings[i].stringLoc, ourStrings[i].stringLen );
  77. }
  78. }
  79. //=======================================================================================//
  80. // Function to test if we are running on Windows 2000 Datacenter Server.
  81. //
  82. // Input: none
  83. // Returns: TRUE if we are on Windows 2000 Datacenter Server, else FALSE
  84. //
  85. BOOL PCTestOSVersion( void ) {
  86. OSVERSIONINFOEX version;
  87. memset( &version, 0, sizeof( version ) ); // needed due to bug in Beta 3
  88. version.dwOSVersionInfoSize = sizeof( version );
  89. DWORDLONG condition = 0;
  90. VER_SET_CONDITION( condition, VER_PLATFORMID, VER_EQUAL );
  91. VER_SET_CONDITION( condition, VER_MAJORVERSION, VER_GREATER_EQUAL );
  92. VER_SET_CONDITION( condition, VER_SUITENAME, VER_AND );
  93. version.dwPlatformId = VER_PLATFORM_WIN32_NT;
  94. version.dwMajorVersion = 5;
  95. version.wSuiteMask = VER_SUITE_DATACENTER;
  96. return VerifyVersionInfo( &version, VER_PLATFORMID + VER_MAJORVERSION + VER_SUITENAME, condition );
  97. }
  98. //=======================================================================================//
  99. // Function to test if an instance of the passed name is running (exists)
  100. //
  101. // Input: name of exclusion object, display name of requestor or NULL
  102. // Returns: TRUE if an instance of the object exists
  103. // FALSE if the object was newly created
  104. //
  105. BOOL PCTestIsRunning( const TCHAR *who, const TCHAR *dispName ) {
  106. HANDLE hEvent = OpenEvent( EVENT_ALL_ACCESS, FALSE, who );
  107. DWORD rc = GetLastError();
  108. if ( hEvent ) CloseHandle( hEvent );
  109. if ( !hEvent && rc != ERROR_FILE_NOT_FOUND && dispName ) {
  110. SetLastError( rc ) ;
  111. PCLogUnExError( who, TEXT("OpenExclEvent") );
  112. }
  113. return hEvent != NULL;
  114. }
  115. //=======================================================================================//
  116. // Function to set exclusive access to the name (via an event)
  117. //
  118. // Input: name of exclusion object, display name of requestor or NULL
  119. // Returns: TRUE if an instance of an exclusive instance of the object was created
  120. // FALSE if the object already existed
  121. //
  122. BOOL PCSetIsRunning( const TCHAR *who, const TCHAR *dispName ) {
  123. DWORD rc = TRUE;
  124. HANDLE hEvent;
  125. SECURITY_ATTRIBUTES secAttr;
  126. if ( !PCBuildNullSecAttr( secAttr ) ) { // Everybody can access -- we want universal exclusion
  127. PCLogUnExError( who, TEXT("BuildNullSecAttr") );
  128. rc = FALSE;
  129. }
  130. else {
  131. hEvent = CreateEvent( &secAttr, TRUE, FALSE, who );
  132. if ( !hEvent ) {
  133. PCLogUnExError( who, TEXT("CreateExclEvent") );
  134. rc = FALSE;
  135. }
  136. else if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
  137. if ( dispName ) PCLogMessage( PC_PROCESS_ALREADY_RUNNING, EVENTLOG_ERROR_TYPE, 1, dispName );
  138. CloseHandle( hEvent );
  139. rc = FALSE;
  140. }
  141. }
  142. PCFreeSecAttr( secAttr );
  143. return rc;
  144. }
  145. //=======================================================================================//
  146. // Functions to build our registry keys.
  147. //
  148. // Input: location to build key
  149. // Returns: nothing
  150. //
  151. void PCBuildBaseKey( TCHAR *key ) {
  152. _tcscpy( key, PROCCON_REG_SERVICE_BASE );
  153. _tcscat( key, PROCCON_SVC_NAME );
  154. }
  155. void PCBuildMsgKey( TCHAR *key ) {
  156. _tcscpy( key, PROCCON_REG_SERVICE_BASE );
  157. _tcscat( key, PROCCON_REG_EVENTLOG_SUBKEY );
  158. _tcscat( key, PROCCON_SVC_NAME );
  159. }
  160. void PCBuildParmKey( TCHAR *key ) {
  161. PCBuildBaseKey( key );
  162. _tcscat( key, TEXT("\\") );
  163. _tcscat( key, PROCCON_REG_PARMS_SUBKEY );
  164. }
  165. //=======================================================================================//
  166. // Functions to verify a name, type, etc.
  167. //
  168. //
  169. #define TBLANK L' '
  170. BOOL PCValidName( const TCHAR *name, const PCULONG32 len, const BOOL nullOK ) {
  171. for ( PCULONG32 i = 0; i < len; ++i ) {
  172. // hit terminator -- verify whole name: no leading or trailing blanks, not NULL unless OKed
  173. if ( !name[i] ) {
  174. if ( i ) {
  175. if ( name[0] == TBLANK || name[i - 1] == TBLANK ) return FALSE; // leading/trailing blnk
  176. else return TRUE;
  177. }
  178. else return nullOK; // name is null
  179. }
  180. if ( _tcschr( TEXT("\\,\""), name[i] ) ) return FALSE; // hit invalid character
  181. }
  182. return FALSE; // no terminator
  183. }
  184. BOOL PCValidMatchType( const TCHAR type ) {
  185. return type == MATCH_PGM || type == MATCH_DIR || type == MATCH_ANY;
  186. }
  187. //=======================================================================================//
  188. // Function to locate first occurrence of one string in another without regard to case.
  189. //
  190. // Input: location of string to search (here), location of string to find (it)
  191. // Returns: location of first match or NULL
  192. //
  193. const TCHAR *PCiStrStr( const TCHAR *here, const TCHAR *it ) {
  194. const TCHAR firstchar = _totupper( *it );
  195. PCULONG32 len = _tcslen( it );
  196. for ( const TCHAR *at = here; ; ++at ) {
  197. while ( *at && firstchar != _totupper( *at ) ) ++at;
  198. if ( !*at ) return firstchar? NULL : at;
  199. if ( !_tcsnicmp( at, it, len ) ) return at;
  200. }
  201. }
  202. //=======================================================================================//
  203. // Functions to convert a hex or decimal number to a PCULONG32 or __int64.
  204. //
  205. // Input: location of data, location to set to end of data
  206. // Returns: converted number
  207. //
  208. __int64 PCGetParmValue64( TCHAR *loc, TCHAR **end ) {
  209. PCULONG32 base = 10;
  210. if ( *(loc + 1) == TEXT('x') || *(loc + 1) == TEXT('X') ) {
  211. base = 16;
  212. loc += 2;
  213. }
  214. for ( __int64 result = 0; ; ++loc ) {
  215. TCHAR c = _totupper(*loc);
  216. if ( c >= TEXT('0') && c <= TEXT('9') )
  217. result = result * base + c - TEXT('0');
  218. else if ( base == 16 && c >= TEXT('A') && c <= TEXT('F') )
  219. result = result * base + 10 + c - TEXT('A');
  220. else {
  221. *end = loc;
  222. break;
  223. }
  224. }
  225. return result;
  226. }
  227. PCULONG32 PCGetParmValue( TCHAR *loc, TCHAR **end ) {
  228. return (PCULONG32) PCGetParmValue64( loc, end );
  229. }
  230. //=======================================================================================//
  231. // Function to test sign of __int64.
  232. //
  233. // Input: integer to test
  234. // Returns: +1, -1, or 0 depending on if integer is greater, less, or equal zero
  235. //
  236. int PCSignof64(__int64 x ) {
  237. return (x > 0)? 1 : (x < 0)? -1 : 0;
  238. }
  239. //=======================================================================================//
  240. // Functions to report one of our errors in the Win2K event log.
  241. //
  242. // Input: log message parameters: code, type, string count, string ptr, data len, data ptr
  243. // Returns: nothing
  244. //
  245. void PCLogMessage( const PCULONG32 msgCode,
  246. const WORD msgType,
  247. WORD numStrings,
  248. const void *msgStrings,
  249. ULONG lenData,
  250. void *msgData ) {
  251. // If no message data, use NT error as data
  252. PCULONG32 NTError;
  253. if ( !lenData && msgType != EVENTLOG_INFORMATION_TYPE ) {
  254. NTError = GetLastError();
  255. lenData = sizeof( NTError );
  256. msgData = &NTError;
  257. }
  258. // Make sure we successfully register...
  259. HANDLE hErrLog = RegisterEventSource( NULL, PROCCON_SVC_NAME );
  260. if ( !hErrLog ) return;
  261. // Prepare insertion argument list...
  262. const TCHAR *strings[64];
  263. // Make a local copy of string args to allow us to extend it.
  264. // For a single string just set up single entry table,
  265. // For a multi-entry table use the passed array.
  266. if ( numStrings == 1 )
  267. strings[0] = (TCHAR *) msgStrings;
  268. else
  269. memcpy( strings, msgStrings, sizeof(TCHAR *) * numStrings );
  270. // For error meassages add the NT error description to the argument list...
  271. TCHAR err[1024];
  272. if ( msgType == EVENTLOG_ERROR_TYPE ) {
  273. PCNTErrorText( *(PCULONG32 *)msgData, err, ENTRY_COUNT(err) );
  274. strings[numStrings++] = err;
  275. }
  276. // Report the desired event...
  277. ReportEvent( hErrLog, msgType, 0, msgCode, NULL,
  278. numStrings, lenData, strings, msgData );
  279. // de-register...
  280. DeregisterEventSource( hErrLog );
  281. }
  282. // Handle unexpected NT error by:
  283. // 1. Setting up two strings -- an operand and an operation.
  284. // 2. Getting the NT error.
  285. // 3. Calling standard error fcn with strings and NT error.
  286. void PCLogUnExError( const TCHAR *who, const TCHAR *what ) {
  287. const TCHAR *strings[2] = { who, what };
  288. DWORD err = GetLastError();
  289. PCLogMessage( PC_UNEXPECTED_NT_ERROR, EVENTLOG_ERROR_TYPE,
  290. ENTRY_COUNT(strings), strings, sizeof(err), &err );
  291. }
  292. // Handle PID-based unexpected NT error by:
  293. // 1. Setting up two strings -- an operand as "PID nnn" and an operation.
  294. // 2. Getting the NT error.
  295. // 3. Calling standard error fcn with strings and NT error.
  296. void PCLogUnExError( const __int64 pid, const TCHAR *what ) {
  297. TCHAR pidString[16];
  298. const TCHAR *strings[2] = { pidString, what };
  299. DWORD err = GetLastError();
  300. _tcscpy( pidString, TEXT("PID ") );
  301. _i64tot( pid, pidString + _tcslen(pidString), 10 );
  302. PCLogMessage( PC_UNEXPECTED_NT_ERROR, EVENTLOG_ERROR_TYPE,
  303. ENTRY_COUNT(strings), strings, sizeof(err), &err );
  304. }
  305. // Handle insufficient memory by:
  306. // 1. Setting up two strings -- a size string and the passed identifying string.
  307. // 2. Setting an NT error of ERROR_NOT_ENOUGH_MEMORY (no error set by new).
  308. // 3. Calling standard error fcn with strings and NT error.
  309. PCULONG32 PCLogNoMemory( const TCHAR *string, const PCULONG32 len ) {
  310. TCHAR size[1024];
  311. const TCHAR *strings[2] = { size, string };
  312. DWORD err = ERROR_NOT_ENOUGH_MEMORY;
  313. _stprintf( size, TEXT("0x%lx"), len );
  314. PCLogMessage( PC_CANT_GET_MEMORY, EVENTLOG_ERROR_TYPE,
  315. ENTRY_COUNT(strings), strings, sizeof(err), &err );
  316. return PC_CANT_GET_MEMORY;
  317. }
  318. //=======================================================================================//
  319. // Function to get text for a Win2K error
  320. //
  321. // Input: error, buffer pointer, buffer length
  322. // Returns: pointer to buffer
  323. // Note: trailing returns are stripped from the message.
  324. //
  325. LPTSTR PCNTErrorText( PCULONG32 error, LPTSTR buf, PCULONG32 size )
  326. {
  327. PCULONG32 dwRet = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
  328. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  329. FORMAT_MESSAGE_IGNORE_INSERTS,
  330. NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, size, NULL );
  331. if (!dwRet) {
  332. if (size)
  333. buf[size - 1] = 0;
  334. _sntprintf( buf, size - 1, TEXT("0x%lx"), error );
  335. }
  336. else {
  337. while ( --dwRet && (buf[dwRet] == TEXT('\n') || buf[dwRet] == TEXT('\r')) )
  338. buf[dwRet] = TEXT('\0');
  339. }
  340. return buf;
  341. }
  342. //=======================================================================================//
  343. // Functions to determine if management behavior is requested in a process/job definition
  344. //
  345. // Input: ref to management definition
  346. // Returns: TRUE if any management behavior would be applied, else FALSE
  347. //
  348. BOOL PCIsProcManaged( MGMT_PARMS &def, JOB_NAME *job ) {
  349. if ( def.mFlags & PCMFLAG_APPLY_JOB_MEMBERSHIP && job[0] ) return TRUE;
  350. else if ( def.mFlags & PCMFLAG_APPLY_AFFINITY && def.affinity ) return TRUE;
  351. else if ( def.mFlags & PCMFLAG_APPLY_PRIORITY && def.priority ) return TRUE;
  352. else if ( def.mFlags & PCMFLAG_APPLY_WS_MINMAX && def.minWS && def.maxWS ) return TRUE;
  353. return FALSE;
  354. }
  355. BOOL PCIsJobManaged( MGMT_PARMS &def ) {
  356. if ( def.mFlags & (PCMFLAG_SET_PROC_BREAKAWAY_OK |
  357. PCMFLAG_SET_SILENT_BREAKAWAY |
  358. PCMFLAG_SET_DIE_ON_UH_EXCEPTION) ) return TRUE;
  359. else if ( def.mFlags & PCMFLAG_APPLY_AFFINITY && def.affinity ) return TRUE;
  360. else if ( def.mFlags & PCMFLAG_APPLY_PRIORITY && def.priority ) return TRUE;
  361. else if ( def.mFlags & PCMFLAG_APPLY_WS_MINMAX && def.minWS && def.maxWS ) return TRUE;
  362. else if ( def.mFlags & PCMFLAG_APPLY_SCHEDULING_CLASS && def.schedClass < 10 ) return TRUE;
  363. else if ( def.mFlags & PCMFLAG_APPLY_PROC_MEMORY_LIMIT && def.procMemoryLimit ) return TRUE;
  364. else if ( def.mFlags & PCMFLAG_APPLY_JOB_MEMORY_LIMIT && def.jobMemoryLimit ) return TRUE;
  365. else if ( def.mFlags & PCMFLAG_APPLY_JOB_TIME_LIMIT && def.jobTimeLimitCNS ) return TRUE;
  366. else if ( def.mFlags & PCMFLAG_APPLY_PROC_TIME_LIMIT && def.procTimeLimitCNS ) return TRUE;
  367. else if ( def.mFlags & PCMFLAG_APPLY_PROC_COUNT_LIMIT && def.procCountLimit ) return TRUE;
  368. return FALSE;
  369. }
  370. //=======================================================================================//
  371. // Function to return a string representing if a flag is set:
  372. //
  373. // Input: field and flag value for the field in question
  374. // Returns: string representation of if a flag is set
  375. LPCTSTR PCIsSetToStr(PC_MGMT_FLAGS field, PCMgmtFlags flag)
  376. {
  377. if (field & flag)
  378. return TEXT("+");
  379. else
  380. return TEXT("-");
  381. }
  382. //=======================================================================================//
  383. // Functions to determine if one flag setting is opposite another flag setting:
  384. //
  385. // Input: flag field and flag value for the two fields in question
  386. // Returns: 1 if first flag is set and second flag is unset
  387. // -1 if first flag is unset and second flag is set
  388. // 0 if both flags are set or unset
  389. //
  390. int PCTestSetUnset( DWORD field1, DWORD flag1, DWORD field2, DWORD flag2 ) {
  391. if ( field1 & flag1 && !(field2 & flag2) ) return 1;
  392. if ( !(field1 & flag1) && field2 & flag2 ) return -1;
  393. return 0;
  394. }
  395. //=======================================================================================//
  396. // Functions to map PC priority (same as toolhelp priority) to NT priority and back
  397. //
  398. // Input: priority to map
  399. // Returns: mapped priority
  400. //
  401. PCULONG32 PCMapPriorityToNT( PRIORITY prio ) {
  402. if ( prio > 15 ) return REALTIME_PRIORITY_CLASS; // 16 and above
  403. else if ( prio > 11 ) return HIGH_PRIORITY_CLASS; // 12-15
  404. else if ( prio > 9 ) return ABOVE_NORMAL_PRIORITY_CLASS; // 10-11
  405. else if ( prio > 7 ) return NORMAL_PRIORITY_CLASS; // 8-9
  406. else if ( prio > 5 ) return BELOW_NORMAL_PRIORITY_CLASS; // 6-7
  407. else if ( prio > 0 ) return IDLE_PRIORITY_CLASS; // 1-5
  408. return 0;
  409. }
  410. PRIORITY PCMapPriorityToPC( PCULONG32 prio ) {
  411. if ( prio & REALTIME_PRIORITY_CLASS ) return PCPrioRealTime;
  412. else if ( prio & HIGH_PRIORITY_CLASS ) return PCPrioHigh;
  413. else if ( prio & ABOVE_NORMAL_PRIORITY_CLASS ) return PCPrioAboveNormal;
  414. else if ( prio & NORMAL_PRIORITY_CLASS ) return PCPrioNormal;
  415. else if ( prio & BELOW_NORMAL_PRIORITY_CLASS ) return PCPrioBelowNormal;
  416. else if ( prio & IDLE_PRIORITY_CLASS ) return PCPrioIdle;
  417. return 0;
  418. }
  419. PRIORITY PCMapPriorityForAPI( PRIORITY prio ) {
  420. if ( prio > 15 ) return PCPrioRealTime;
  421. else if ( prio > 11 ) return PCPrioHigh;
  422. else if ( prio > 9 ) return PCPrioAboveNormal;
  423. else if ( prio > 7 ) return PCPrioNormal;
  424. else if ( prio > 5 ) return PCPrioBelowNormal;
  425. else if ( prio > 0 ) return PCPrioIdle;
  426. return 0;
  427. }
  428. //=======================================================================================//
  429. // Functions to map NT defined long numbers to int 64's
  430. //
  431. // Input: numeric field format to convert
  432. // Returns: int64 version of data
  433. //
  434. __int64 PCLargeIntToInt64( LARGE_INTEGER &in ) {
  435. return in.QuadPart;
  436. }
  437. __int64 PCFileTimeToInt64( FILETIME &in ) {
  438. return ((__int64) in.dwHighDateTime << 32) + (__int64) in.dwLowDateTime;
  439. }
  440. //=======================================================================================//
  441. // Function to delete a registry key by deleting all subkeys first
  442. //
  443. // Input: handle to open key, name of subkey tree to delete
  444. // Returns: NT return code
  445. //
  446. PCULONG32 PCDeleteKeyTree( HKEY hKey, const TCHAR *keyName ) {
  447. PCULONG32 rc, ourCount;
  448. HKEY ourKey;
  449. // Open the key at top of tree...
  450. rc = RegOpenKeyEx( hKey, keyName, NULL, KEY_READ + KEY_WRITE, &ourKey );
  451. if ( rc == ERROR_FILE_NOT_FOUND || rc == ERROR_KEY_DELETED ) // nothing to do
  452. return ERROR_SUCCESS;
  453. else if ( rc != ERROR_SUCCESS ) {
  454. SetLastError( rc );
  455. PCLogUnExError( keyName, TEXT("RegOpenKeyEx") );
  456. return rc;
  457. }
  458. // Determine how many subkeys we have...
  459. rc = RegQueryInfoKey( ourKey, NULL, NULL, NULL, &ourCount,
  460. NULL, NULL, NULL, NULL, NULL, NULL, NULL );
  461. if ( rc != ERROR_SUCCESS ) { // Should never happen
  462. SetLastError( rc );
  463. PCLogUnExError( keyName, TEXT("RegQueryInfoKey") );
  464. return rc;
  465. }
  466. // For each sub-key delete its sub-tree...
  467. for ( PCULONG32 i = 0; rc == ERROR_SUCCESS && i < ourCount; ++i ) {
  468. // Get next subkey...
  469. TCHAR name[MAX_PATH];
  470. FILETIME keyLastWrite;
  471. PCULONG32 nameLen = ENTRY_COUNT(name);
  472. rc = RegEnumKeyEx( ourKey, ourCount - 1 - i, name, &nameLen, NULL, NULL, NULL, &keyLastWrite );
  473. if ( rc == ERROR_NO_MORE_ITEMS ) {
  474. rc = ERROR_SUCCESS;
  475. break;
  476. }
  477. if ( rc != ERROR_SUCCESS ) { // Should never happen
  478. SetLastError( rc );
  479. PCLogUnExError( keyName, TEXT("RegEnumKeyEx") );
  480. return rc;
  481. }
  482. rc = PCDeleteKeyTree( ourKey, name );
  483. }
  484. // Close the key at top of tree and delete it...
  485. RegCloseKey( ourKey );
  486. if ( rc == ERROR_SUCCESS )
  487. rc = RegDeleteKey( hKey, keyName );
  488. return rc == ERROR_KEY_DELETED? ERROR_SUCCESS : rc;
  489. }
  490. //=======================================================================================//
  491. // Function to enable/disable an NT user privilege
  492. //
  493. // Input: ptr to name of privilege, enable/disable flag
  494. // Returns: TRUE if successful, else FALSE
  495. //
  496. BOOL PCSetPrivilege( TCHAR *privilege, BOOL enable ) {
  497. HANDLE hTok = NULL;
  498. BOOL ok = TRUE;
  499. // Build token to enable or disable the privilege...
  500. TOKEN_PRIVILEGES priv;
  501. priv.PrivilegeCount = 1;
  502. priv.Privileges[0].Attributes = enable? SE_PRIVILEGE_ENABLED : 0;
  503. // Get access token handle...
  504. if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hTok ) ) {
  505. PCLogUnExError( privilege, TEXT("OpenProcessToken") );
  506. ok = FALSE;
  507. }
  508. // Look up privilege to set local ID...
  509. else if ( !LookupPrivilegeValue( NULL, privilege, &priv.Privileges[0].Luid ) ) {
  510. PCLogUnExError( privilege, TEXT("LookupPrivilegeValue") );
  511. ok = FALSE;
  512. }
  513. // Update privilege...
  514. else if ( !AdjustTokenPrivileges( hTok, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), NULL, NULL ) ) {
  515. PCLogUnExError( privilege, TEXT("Adjustprivileges") );
  516. ok = FALSE;
  517. }
  518. if ( hTok ) CloseHandle( hTok );
  519. return ok;
  520. }
  521. //=======================================================================================//
  522. // Function to create a security attributes with NULL security descriptor
  523. //
  524. // Input: reference to security attribue structure to build
  525. // Returns: TRUE if successful, else FALSE
  526. //
  527. PCULONG32 PCBuildNullSecAttr( SECURITY_ATTRIBUTES &secAttr ) {
  528. BOOL ok = TRUE;
  529. // Init passed attributes struct...
  530. secAttr.nLength = sizeof(secAttr);
  531. secAttr.lpSecurityDescriptor = new char[SECURITY_DESCRIPTOR_MIN_LENGTH];
  532. secAttr.bInheritHandle = TRUE;
  533. if ( !secAttr.lpSecurityDescriptor ) {
  534. PCLogNoMemory( TEXT("AllocSecurityDesc"), SECURITY_DESCRIPTOR_MIN_LENGTH );
  535. ok = FALSE;
  536. }
  537. else if ( !InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) ) {
  538. PCLogUnExError( TEXT("NullAttr"), TEXT("InitializeSecurityDescriptor") );
  539. ok = FALSE;
  540. }
  541. // add a NULL discretionary ACL...
  542. else if ( !SetSecurityDescriptorDacl(secAttr.lpSecurityDescriptor, TRUE, NULL, FALSE) ) {
  543. PCLogUnExError( TEXT("NullAttr"), TEXT("SetSecurityDescriptorDacl") );
  544. ok = FALSE;
  545. }
  546. if ( !ok && secAttr.lpSecurityDescriptor ) {
  547. delete [] secAttr.lpSecurityDescriptor;
  548. secAttr.lpSecurityDescriptor = NULL;
  549. }
  550. return ok;
  551. }
  552. //=======================================================================================//
  553. // Function to create a security attributes with ADMINISTRATORS security descriptor
  554. //
  555. // Input: reference to security attribue structure to build
  556. // Returns: TRUE if successful, else FALSE
  557. //
  558. PCULONG32 PCBuildAdminSecAttr( SECURITY_ATTRIBUTES &secAttr ) {
  559. #define ADMIN_NAME_LEN 256
  560. BOOL ok = TRUE;
  561. TCHAR AdminName[ADMIN_NAME_LEN+1];
  562. PCULONG32 AdminNameLen = ADMIN_NAME_LEN;
  563. // Init passed attributes struct...
  564. secAttr.nLength = sizeof(secAttr);
  565. secAttr.lpSecurityDescriptor = new char[SECURITY_DESCRIPTOR_MIN_LENGTH];
  566. secAttr.bInheritHandle = FALSE;
  567. if ( !secAttr.lpSecurityDescriptor ) {
  568. PCLogNoMemory( TEXT("AllocSecurityDesc"), SECURITY_DESCRIPTOR_MIN_LENGTH );
  569. ok = FALSE;
  570. }
  571. else if ( !InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) ) {
  572. PCLogUnExError( TEXT("AdminAttr"), TEXT("InitializeSecurityDescriptor") );
  573. ok = FALSE;
  574. }
  575. else if( !PCGetAdminGroupName( AdminName, &AdminNameLen) )
  576. ok = FALSE;
  577. else {
  578. EXPLICIT_ACCESS adminAccess[2];
  579. ACL *adminACL = NULL;
  580. BuildExplicitAccessWithName( &adminAccess[0],
  581. TEXT("SYSTEM"), // access is for system
  582. STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, // access is for all rights
  583. GRANT_ACCESS, // ace grants access
  584. OBJECT_INHERIT_ACE ); // objects inherit access
  585. BuildExplicitAccessWithName( &adminAccess[1],
  586. AdminName, // access is for admins
  587. STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, // access is for all rights
  588. GRANT_ACCESS, // ace grants access
  589. OBJECT_INHERIT_ACE ); // objects inherit access
  590. if ( ERROR_SUCCESS != SetEntriesInAcl( 2, adminAccess, NULL, &adminACL ) ) {
  591. PCLogUnExError( TEXT("AdminAttr"), TEXT("SetEntriesInAcl") );
  592. ok = FALSE;
  593. }
  594. else if ( !SetSecurityDescriptorDacl( secAttr.lpSecurityDescriptor, TRUE, adminACL, FALSE ) ) {
  595. PCLogUnExError( TEXT("AdminAttr"), TEXT("SetSecurityDescriptorDacl") );
  596. ok = FALSE;
  597. }
  598. }
  599. if ( !ok && secAttr.lpSecurityDescriptor ) {
  600. delete [] secAttr.lpSecurityDescriptor;
  601. secAttr.lpSecurityDescriptor = NULL;
  602. }
  603. return ok;
  604. }
  605. void PCFreeSecAttr( SECURITY_ATTRIBUTES &secAttr ) {
  606. if ( secAttr.lpSecurityDescriptor ) {
  607. if ( ((SECURITY_DESCRIPTOR *)(secAttr.lpSecurityDescriptor))->Dacl )
  608. LocalFree( ((SECURITY_DESCRIPTOR *)(secAttr.lpSecurityDescriptor))->Dacl );
  609. delete [] secAttr.lpSecurityDescriptor;
  610. secAttr.lpSecurityDescriptor = NULL;
  611. }
  612. }
  613. //=======================================================================================//
  614. // Function to look up local name of ADMINISTRATORS group
  615. //
  616. // Input: Pointers to name and name length
  617. // Returns: TRUE on success, FALSE on failure with error message logged
  618. //
  619. BOOL PCGetAdminGroupName( TCHAR *Name, PCULONG32 *NameLen ) {
  620. #define DOMAIN_NAME_LEN 256
  621. SID_IDENTIFIER_AUTHORITY SidIdAuthority = SECURITY_NT_AUTHORITY;
  622. SID_NAME_USE SidNameUse;
  623. PSID pSid;
  624. TCHAR DomainName[DOMAIN_NAME_LEN+1];
  625. PCULONG32 DomainNameLen = DOMAIN_NAME_LEN;
  626. BOOL ok = FALSE;
  627. if ( !AllocateAndInitializeSid( &SidIdAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  628. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid) )
  629. PCLogUnExError( TEXT("AdminAttr"), TEXT("AllocateAdminSid") );
  630. else {
  631. if ( !LookupAccountSid( NULL, pSid, Name, NameLen, DomainName, &DomainNameLen, &SidNameUse ) )
  632. PCLogUnExError( TEXT("AdminAttr"), TEXT("LookupAdminSid") );
  633. else
  634. ok = TRUE;
  635. FreeSid(pSid);
  636. }
  637. return ok;
  638. }
  639. //=======================================================================================//
  640. // Functions to help format management attributes for use in log, these functions
  641. // format the values as limits with
  642. // '+' => on, enabled, or applied
  643. // '-' => off, disabed, or not applied
  644. // the value follows the on/off indicator in square brackets "[]"
  645. //
  646. // Input: buffer, buffer length in CHARACTERS, management parmaters
  647. // Returns: buffer with string form of attribute
  648. //
  649. void PCFormatAffinityLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  650. {
  651. Buffer[BufferLength - 1] = 0;
  652. _sntprintf(Buffer, BufferLength - 1, TEXT("%s[0x%I64X]"),
  653. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_AFFINITY),
  654. def.affinity );
  655. }
  656. void PCFormatPriorityLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  657. {
  658. Buffer[BufferLength - 1] = 0;
  659. _sntprintf(Buffer, BufferLength - 1, TEXT("%s[%lu]"),
  660. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PRIORITY),
  661. def.priority );
  662. }
  663. void PCFormatWorkingSetLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  664. {
  665. Buffer[BufferLength - 1] = 0;
  666. _sntprintf(Buffer, BufferLength - 1, TEXT("%s[%I64u,%I64u]"),
  667. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_WS_MINMAX),
  668. def.minWS,
  669. def.maxWS );
  670. }
  671. void PCFormatSchedClassLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  672. {
  673. Buffer[BufferLength - 1] = 0;
  674. _sntprintf(Buffer, BufferLength - 1, TEXT("%s[%lu]"),
  675. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_SCHEDULING_CLASS),
  676. def.schedClass );
  677. }
  678. void PCFormatProcessCountLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  679. {
  680. Buffer[BufferLength - 1] = 0;
  681. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%lu]"),
  682. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PROC_COUNT_LIMIT),
  683. def.procCountLimit );
  684. }
  685. void PCFormatProcTimeLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  686. {
  687. Buffer[BufferLength - 1] = 0;
  688. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64d]"),
  689. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PROC_TIME_LIMIT),
  690. def.procTimeLimitCNS / 10000 );
  691. }
  692. void PCFormatJobTimeLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  693. {
  694. Buffer[BufferLength - 1] = 0;
  695. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64d]"),
  696. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_JOB_TIME_LIMIT),
  697. def.jobTimeLimitCNS / 10000 );
  698. }
  699. void PCFormatProcMemLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  700. {
  701. Buffer[BufferLength - 1] = 0;
  702. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64u]"),
  703. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_PROC_MEMORY_LIMIT),
  704. def.procMemoryLimit );
  705. }
  706. void PCFormatJobMemLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  707. {
  708. Buffer[BufferLength - 1] = 0;
  709. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%I64u]"),
  710. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_JOB_MEMORY_LIMIT),
  711. def.jobMemoryLimit );
  712. }
  713. void PCFormatEndofJobAction(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def)
  714. {
  715. Buffer[BufferLength - 1] = 0;
  716. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s[%s]"),
  717. PCIsSetToStr(def.mFlags, PCMFLAG_APPLY_JOB_TIME_LIMIT),
  718. (def.mFlags & PCMFLAG_MSG_ON_JOB_TIME_LIMIT_HIT) ? PROCCON_FLAG_ON : PROCCON_FLAG_OFF);
  719. }
  720. void PCFormatOnOrOffLimit(TCHAR *Buffer, UINT BufferLength, const MGMT_PARMS &def, PCMgmtFlags flag)
  721. {
  722. Buffer[BufferLength - 1] = 0;
  723. _sntprintf(Buffer, BufferLength - 1 , TEXT("%s"),
  724. (def.mFlags & flag) ? PROCCON_FLAG_ON : PROCCON_FLAG_OFF);
  725. }
  726. // End of PCUtility.cpp
  727. //============================================================================J McDonald fecit====//