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.

616 lines
18 KiB

  1. //Copyright (c) 1998 - 1999 Microsoft Corporation
  2. /******************************************************************************
  3. *
  4. * QPROCESS.C
  5. *
  6. * query process information
  7. *
  8. *
  9. *******************************************************************************/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. // #include <ntddkbd.h>
  15. // #include <ntddmou.h>
  16. #include <winstaw.h>
  17. #include <assert.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <time.h>
  21. #include <locale.h>
  22. #include <utilsub.h>
  23. #include <process.h>
  24. #include <string.h>
  25. #include <malloc.h>
  26. #include <printfoa.h>
  27. #include <allproc.h>
  28. #include "qprocess.h"
  29. HANDLE hServerName = SERVERNAME_CURRENT;
  30. WCHAR ServerName[MAX_IDS_LEN+1];
  31. WCHAR match_string[MAX_IDS_LEN+2];
  32. USHORT help_flag = FALSE;
  33. USHORT system_flag = FALSE;
  34. ULONG ArgLogonId = (ULONG)(-1);
  35. BOOLEAN MatchedOne = FALSE;
  36. TOKMAP ptm[] = {
  37. {L" ", TMFLAG_OPTIONAL, TMFORM_STRING, MAX_IDS_LEN,
  38. match_string},
  39. {L"/server", TMFLAG_OPTIONAL, TMFORM_STRING, MAX_IDS_LEN,
  40. ServerName},
  41. {L"/system", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT),
  42. &system_flag},
  43. {L"/?", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT),
  44. &help_flag},
  45. {L"/ID", TMFLAG_OPTIONAL, TMFORM_ULONG, sizeof(ULONG),
  46. &ArgLogonId },
  47. {0, 0, 0, 0, 0}
  48. };
  49. // From pstat.c
  50. #define BUFFER_SIZE 32*1024
  51. //
  52. // This table contains common NT system programs that we do not want to display
  53. // unless the user specifies /SYSTEM.
  54. //
  55. WCHAR *SysProcTable[] = {
  56. L"csrss.exe",
  57. L"smss.exe",
  58. L"screg.exe",
  59. L"lsass.exe",
  60. L"spoolss.exe",
  61. L"EventLog.exe",
  62. L"netdde.exe",
  63. L"clipsrv.exe",
  64. L"lmsvcs.exe",
  65. L"MsgSvc.exe",
  66. L"winlogon.exe",
  67. L"NETSTRS.EXE",
  68. L"nddeagnt.exe",
  69. L"wfshell.exe",
  70. L"chgcdm.exe",
  71. L"userinit.exe",
  72. NULL
  73. };
  74. WCHAR *Empty = L" ";
  75. /*
  76. * Local function prototypes
  77. */
  78. VOID FormatAndDisplayProcessInfo( HANDLE hServer,
  79. PTS_SYS_PROCESS_INFORMATION ProcessInfo,
  80. PSID pUserSid,
  81. ULONG LogonId,
  82. ULONG CurrentLogonId);
  83. BOOLEAN IsSystemProcess( PTS_SYS_PROCESS_INFORMATION,
  84. PWCHAR );
  85. BOOLEAN SystemProcess( INT,
  86. PTS_SYS_PROCESS_INFORMATION,
  87. PWCHAR );
  88. void Usage( BOOLEAN bError );
  89. /*******************************************************************************
  90. *
  91. * main
  92. *
  93. ******************************************************************************/
  94. int __cdecl
  95. main(INT argc, CHAR **argv)
  96. {
  97. int rc;
  98. // WCHAR CurrWinStationName[WINSTATIONNAME_LENGTH]; -- not used.
  99. WCHAR CurrUserName[USERNAME_LENGTH];
  100. WCHAR **argvW;
  101. DWORD CurrentPid;
  102. ULONG LogonId, CurrentLogonId;
  103. PSID pUserSid;
  104. PTS_SYS_PROCESS_INFORMATION ProcessInfo;
  105. PCITRIX_PROCESS_INFORMATION CitrixInfo;
  106. PBYTE pBuffer;
  107. ULONG ByteCount;
  108. NTSTATUS status;
  109. ULONG NumberOfProcesses,j;
  110. PTS_ALL_PROCESSES_INFO ProcessArray = NULL;
  111. int i;
  112. ULONG TotalOffset;
  113. DWORD dwError;
  114. setlocale(LC_ALL, ".OCP");
  115. /*
  116. * Massage the command line.
  117. */
  118. argvW = MassageCommandLine((DWORD)argc);
  119. if (argvW == NULL) {
  120. ErrorPrintf(IDS_ERROR_MALLOC);
  121. return(FAILURE);
  122. }
  123. /*
  124. * parse the cmd line without parsing the program name (argc-1, argv+1)
  125. */
  126. match_string[0] = L'\0';
  127. rc = ParseCommandLine(argc-1, argvW+1, ptm, PCL_FLAG_NO_CLEAR_MEMORY);
  128. /*
  129. * Check for error from ParseCommandLine
  130. */
  131. if ( help_flag || (rc && !(rc & PARSE_FLAG_NO_PARMS)) ) {
  132. if ( !help_flag ) {
  133. Usage(TRUE);
  134. return(FAILURE);
  135. } else {
  136. Usage(FALSE);
  137. return(SUCCESS);
  138. }
  139. }
  140. // If no remote server was specified, then check if we are running under Terminal Server
  141. if ((!IsTokenPresent(ptm, L"/server") ) && (!AreWeRunningTerminalServices()))
  142. {
  143. ErrorPrintf(IDS_ERROR_NOT_TS);
  144. return(FAILURE);
  145. }
  146. /*
  147. * Open the specified server
  148. */
  149. if( ServerName[0] ) {
  150. hServerName = WinStationOpenServer( ServerName );
  151. if( hServerName == NULL ) {
  152. StringErrorPrintf(IDS_ERROR_SERVER,ServerName);
  153. PutStdErr( GetLastError(), 0 );
  154. return(FAILURE);
  155. }
  156. }
  157. /*
  158. * Get the current users name
  159. */
  160. GetCurrentUserName( CurrUserName, USERNAME_LENGTH );
  161. _wcslwr( CurrUserName );
  162. OEM2ANSIW(CurrUserName, (USHORT)wcslen(CurrUserName));
  163. /*
  164. * Get current processes pid
  165. */
  166. CurrentPid = GetCurrentProcessId();
  167. /*
  168. * Get current WinStation name.
  169. GetCurrentWinStationName( CurrWinStationName, WINSTATIONNAME_LENGTH );
  170. _wcslwr( CurrWinStationName );
  171. OEM2ANSIW(CurrWinStationName, (USHORT)wcslen(CurrWinStationName));
  172. */
  173. /*
  174. * Get current LogonId.
  175. */
  176. CurrentLogonId = GetCurrentLogonId();
  177. /*
  178. * If no "match_string" input, then default to all processes for LoginId
  179. * (if /ID: switch specified) or user logged into current WinStation.
  180. */
  181. if ( !(*match_string) ) {
  182. if( ArgLogonId != (-1) ) {
  183. wsprintf( match_string, L"%d", ArgLogonId );
  184. }
  185. else
  186. wcscpy( match_string, CurrUserName );
  187. }
  188. /*
  189. * Make match name lower case
  190. */
  191. _wcslwr( match_string );
  192. SetFileApisToOEM();
  193. /*
  194. * Enumerate all processes on the server.
  195. */
  196. //
  197. // Try the new interface first (NT5 server ?)
  198. //
  199. if (WinStationGetAllProcesses( hServerName,
  200. GAP_LEVEL_BASIC,
  201. &NumberOfProcesses,
  202. &ProcessArray) )
  203. {
  204. for (j=0; j<NumberOfProcesses; j++)
  205. {
  206. ProcessInfo = (PTS_SYS_PROCESS_INFORMATION )(ProcessArray[j].pTsProcessInfo);
  207. pUserSid = ProcessArray[j].pSid;
  208. LogonId = ProcessInfo->SessionId;
  209. FormatAndDisplayProcessInfo(hServerName,
  210. ProcessInfo,
  211. pUserSid,
  212. LogonId,
  213. CurrentLogonId);
  214. }
  215. //
  216. // Free ppProcessArray and all child pointers allocated by the client stub.
  217. //
  218. WinStationFreeGAPMemory(GAP_LEVEL_BASIC, ProcessArray, NumberOfProcesses);
  219. }
  220. else // Maybe a Hydra 4 server ?
  221. {
  222. //
  223. // Check the return code indicating that the interface is not available.
  224. //
  225. dwError = GetLastError();
  226. if (dwError != RPC_S_PROCNUM_OUT_OF_RANGE)
  227. {
  228. ErrorPrintf(IDS_ERROR_ENUMERATE_PROCESSES);
  229. return(FAILURE);
  230. }
  231. else
  232. {
  233. //
  234. // The new interface is not known
  235. // It must be a Hydra 4 server
  236. // Let's try the old interface
  237. //
  238. if ( !WinStationEnumerateProcesses( hServerName, &pBuffer) ) {
  239. ErrorPrintf(IDS_ERROR_ENUMERATE_PROCESSES);
  240. return(FAILURE);
  241. }
  242. /*
  243. * Loop through all processes. Output those that match desired
  244. * criteria.
  245. */
  246. ProcessInfo = (PTS_SYS_PROCESS_INFORMATION)pBuffer;
  247. TotalOffset = 0;
  248. rc = 0;
  249. for(;;)
  250. {
  251. /*
  252. * Get the CITRIX_INFORMATION which follows the Threads
  253. */
  254. CitrixInfo = (PCITRIX_PROCESS_INFORMATION)
  255. (((PUCHAR)ProcessInfo) +
  256. SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION +
  257. (SIZEOF_TS4_SYSTEM_THREAD_INFORMATION * (int)ProcessInfo->NumberOfThreads));
  258. if( CitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) {
  259. LogonId = CitrixInfo->LogonId;
  260. pUserSid = CitrixInfo->ProcessSid;
  261. }
  262. else
  263. {
  264. LogonId = (ULONG)(-1);
  265. pUserSid = NULL;
  266. }
  267. FormatAndDisplayProcessInfo( hServerName,
  268. ProcessInfo,
  269. pUserSid,
  270. LogonId,
  271. CurrentLogonId);
  272. if( ProcessInfo->NextEntryOffset == 0 ) {
  273. break;
  274. }
  275. TotalOffset += ProcessInfo->NextEntryOffset;
  276. ProcessInfo = (PTS_SYS_PROCESS_INFORMATION)&pBuffer[TotalOffset];
  277. }
  278. /*
  279. * free buffer
  280. */
  281. WinStationFreeMemory( pBuffer );
  282. }
  283. }
  284. /*
  285. * Check for at least one match
  286. */
  287. if ( !MatchedOne ) {
  288. StringErrorPrintf(IDS_ERROR_PROCESS_NOT_FOUND, match_string);
  289. return(FAILURE);
  290. }
  291. return(SUCCESS);
  292. } /* main() */
  293. /******************************************************************************
  294. *
  295. * FormatAndDisplayProcessInfo
  296. *
  297. *
  298. *****************************************************************************/
  299. VOID
  300. FormatAndDisplayProcessInfo(
  301. HANDLE hServer,
  302. PTS_SYS_PROCESS_INFORMATION ProcessInfo,
  303. PSID pUserSid,
  304. ULONG LogonId,
  305. ULONG CurrentLogonId)
  306. {
  307. WCHAR WinStationName[WINSTATIONNAME_LENGTH];
  308. WCHAR UserName[USERNAME_LENGTH];
  309. WCHAR ImageName[ MAXNAME + 2 ];
  310. ULONG MaxLen;
  311. ImageName[MAXNAME+1] = 0; // Force NULL termination
  312. /*
  313. * Convert the counted string into a buffer
  314. */
  315. if( ProcessInfo->ImageName.Length > MAXNAME * 2)
  316. {
  317. wcsncpy(ImageName, ProcessInfo->ImageName.Buffer, MAXNAME);
  318. }
  319. else if( ProcessInfo->ImageName.Length == 0 )
  320. {
  321. ImageName[0] = 0;
  322. }
  323. else
  324. {
  325. wcsncpy(ImageName, ProcessInfo->ImageName.Buffer, ProcessInfo->ImageName.Length/2);
  326. ImageName[ProcessInfo->ImageName.Length/2] = 0;
  327. }
  328. // get remote winstation name
  329. if ( (LogonId == (ULONG)(-1)) ||
  330. !xxxGetWinStationNameFromId( hServer,
  331. LogonId,
  332. WinStationName,
  333. WINSTATIONNAME_LENGTH ) ) {
  334. if (GetUnknownString())
  335. {
  336. wsprintf( WinStationName, L"(%s)", GetUnknownString() );
  337. }
  338. else
  339. {
  340. wcscpy( WinStationName, L"(Unknown)" );
  341. }
  342. }
  343. OEM2ANSIW(WinStationName, (USHORT)wcslen(WinStationName));
  344. /*
  345. * Get the User name for the SID of the process.
  346. */
  347. MaxLen = USERNAME_LENGTH;
  348. GetUserNameFromSid( pUserSid, UserName, &MaxLen);
  349. OEM2ANSIW(UserName, (USHORT)wcslen(UserName));
  350. /*
  351. * Call the general process object match function
  352. */
  353. if ( SystemProcess( system_flag, ProcessInfo, UserName ) &&
  354. ProcessObjectMatch(
  355. UlongToPtr(ProcessInfo->UniqueProcessId),
  356. LogonId,
  357. ((ArgLogonId == (-1)) ? FALSE : TRUE),
  358. match_string,
  359. WinStationName,
  360. UserName,
  361. ImageName ) ) {
  362. /*
  363. * Match: truncate and lower case the names in preparation for
  364. * output.
  365. */
  366. TruncateString( _wcslwr(WinStationName), 12 );
  367. TruncateString( _wcslwr(UserName), 18 );
  368. TruncateString( _wcslwr(ImageName), 15);
  369. /*
  370. * If first time - output header
  371. */
  372. if ( !MatchedOne ) {
  373. Message(IDS_HEADER);
  374. MatchedOne = TRUE;
  375. }
  376. /*
  377. * identify all processes belonging to current user.
  378. */
  379. if ( (hServerName == SERVERNAME_CURRENT) && (LogonId == CurrentLogonId ) )
  380. wprintf( L">" );
  381. else
  382. wprintf( L" " );
  383. {
  384. #define MAX_PRINTFOA_BUFFER_SIZE 1024
  385. char pUserName[MAX_PRINTFOA_BUFFER_SIZE];
  386. char pWinStationName[MAX_PRINTFOA_BUFFER_SIZE];
  387. char pImageName[MAX_PRINTFOA_BUFFER_SIZE];
  388. WideCharToMultiByte(CP_OEMCP, 0,
  389. UserName, -1,
  390. pUserName, sizeof(pUserName),
  391. NULL, NULL);
  392. WideCharToMultiByte(CP_OEMCP, 0,
  393. WinStationName, -1,
  394. pWinStationName, sizeof(pWinStationName),
  395. NULL, NULL);
  396. WideCharToMultiByte(CP_OEMCP, 0,
  397. ImageName, -1,
  398. pImageName, sizeof(pImageName),
  399. NULL, NULL);
  400. fprintf( stdout,
  401. FORMAT,
  402. pUserName,
  403. pWinStationName,
  404. LogonId,
  405. // ProgramState,
  406. ProcessInfo->UniqueProcessId,
  407. pImageName );
  408. }
  409. }
  410. }
  411. /******************************************************************************
  412. *
  413. * SystemProcess
  414. *
  415. * Returns TRUE if the process should be displayed depending on the
  416. * supplied flag and the result from IsSystemProcess().
  417. *
  418. * ENTRY:
  419. * SystemFlag
  420. * TRUE if caller wants 'system' processes displayed.
  421. * FALSE to display only normal 'user' processes.
  422. * pProcessInfo (input)
  423. * Pointer to an NT SYSTEM_PROCESS_INFORMATION structure for a single
  424. * process.
  425. * pUserName (input)
  426. * Pointer to the user name associated with the process for checking
  427. * against the 'system' user name.
  428. *
  429. * EXIT:
  430. * TRUE if this process should be displayed; FALSE if not.
  431. *
  432. *****************************************************************************/
  433. BOOLEAN
  434. SystemProcess( int SystemFlag,
  435. PTS_SYS_PROCESS_INFORMATION pSys,
  436. PWCHAR pUserName )
  437. {
  438. if( SystemFlag )
  439. return( TRUE );
  440. return( !IsSystemProcess( pSys, pUserName ) );
  441. } /* SystemProcess() */
  442. /******************************************************************************
  443. *
  444. * IsSystemProcess
  445. *
  446. * Return whether the given process described by SYSTEM_PROCESS_INFORMATION
  447. * is an NT "system" process, and not a user program.
  448. *
  449. * ENTRY:
  450. * pProcessInfo (input)
  451. * Pointer to an NT SYSTEM_PROCESS_INFORMATION structure for a single
  452. * process.
  453. * pUserName (input)
  454. * Pointer to the user name associated with the process for checking
  455. * against the 'system' user name.
  456. *
  457. * EXIT:
  458. * TRUE if this is an NT system process; FALSE if a general user process.
  459. *
  460. *****************************************************************************/
  461. BOOLEAN
  462. IsSystemProcess( PTS_SYS_PROCESS_INFORMATION pSysProcessInfo,
  463. PWCHAR pUserName )
  464. {
  465. int i;
  466. /*
  467. * If the processes' UserName is 'system', treat this as a system process.
  468. */
  469. if ( !_wcsicmp( pUserName, L"system" ) )
  470. return(TRUE);
  471. /*
  472. * Compare its image name against some well known system image names.
  473. */
  474. for( i=0; SysProcTable[i]; i++) {
  475. if ( !_wcsnicmp( pSysProcessInfo->ImageName.Buffer,
  476. SysProcTable[i],
  477. pSysProcessInfo->ImageName.Length) ) {
  478. return(TRUE);
  479. }
  480. }
  481. return(FALSE);
  482. } /* IsSystemProcess() */
  483. /*******************************************************************************
  484. *
  485. * Usage
  486. *
  487. * Output the usage message for this utility.
  488. *
  489. * ENTRY:
  490. * bError (input)
  491. * TRUE if the 'invalid parameter(s)' message should preceed the usage
  492. * message and the output go to stderr; FALSE for no such error
  493. * string and output goes to stdout.
  494. *
  495. * EXIT:
  496. *
  497. *
  498. ******************************************************************************/
  499. void
  500. Usage( BOOLEAN bError )
  501. {
  502. if ( bError ) {
  503. ErrorPrintf(IDS_ERROR_INVALID_PARAMETERS);
  504. ErrorPrintf(IDS_HELP_USAGE1);
  505. ErrorPrintf(IDS_HELP_USAGE2);
  506. ErrorPrintf(IDS_HELP_USAGE3);
  507. ErrorPrintf(IDS_HELP_USAGE40);
  508. ErrorPrintf(IDS_HELP_USAGE4);
  509. ErrorPrintf(IDS_HELP_USAGE5);
  510. ErrorPrintf(IDS_HELP_USAGE6);
  511. ErrorPrintf(IDS_HELP_USAGE7);
  512. ErrorPrintf(IDS_HELP_USAGE8);
  513. ErrorPrintf(IDS_HELP_USAGE9);
  514. ErrorPrintf(IDS_HELP_USAGE10);
  515. } else {
  516. Message(IDS_HELP_USAGE1);
  517. Message(IDS_HELP_USAGE2);
  518. Message(IDS_HELP_USAGE3);
  519. Message(IDS_HELP_USAGE40);
  520. Message(IDS_HELP_USAGE4);
  521. Message(IDS_HELP_USAGE5);
  522. Message(IDS_HELP_USAGE6);
  523. Message(IDS_HELP_USAGE7);
  524. Message(IDS_HELP_USAGE8);
  525. Message(IDS_HELP_USAGE9);
  526. Message(IDS_HELP_USAGE10);
  527. }
  528. } /* Usage() */