Leaked source code of windows server 2003
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.

493 lines
14 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 <winnlsp.h>
  29. #include "qprocess.h"
  30. // max length of the locale string
  31. #define MAX_LOCALE_STRING 64
  32. HANDLE hServerName = SERVERNAME_CURRENT;
  33. WCHAR ServerName[MAX_IDS_LEN+1];
  34. WCHAR match_string[MAX_IDS_LEN+2];
  35. USHORT help_flag = FALSE;
  36. ULONG ArgLogonId = (ULONG)(-1);
  37. BOOLEAN MatchedOne = FALSE;
  38. TOKMAP ptm[] = {
  39. {L" ", TMFLAG_OPTIONAL, TMFORM_STRING, MAX_IDS_LEN, match_string},
  40. {L"/server", TMFLAG_OPTIONAL, TMFORM_STRING, MAX_IDS_LEN,ServerName},
  41. {L"/?", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT),&help_flag},
  42. {L"/ID", TMFLAG_OPTIONAL, TMFORM_ULONG, sizeof(ULONG),&ArgLogonId },
  43. {0, 0, 0, 0, 0}
  44. };
  45. // From pstat.c
  46. #define BUFFER_SIZE 32*1024
  47. /*
  48. * Local function prototypes
  49. */
  50. VOID FormatAndDisplayProcessInfo( HANDLE hServer,
  51. PTS_SYS_PROCESS_INFORMATION ProcessInfo,
  52. PSID pUserSid,
  53. ULONG LogonId,
  54. ULONG CurrentLogonId);
  55. void Usage( BOOLEAN bError );
  56. /*******************************************************************************
  57. *
  58. * main
  59. *
  60. ******************************************************************************/
  61. int __cdecl
  62. main(INT argc, CHAR **argv)
  63. {
  64. int rc;
  65. // WCHAR CurrWinStationName[WINSTATIONNAME_LENGTH]; -- not used.
  66. WCHAR CurrUserName[USERNAME_LENGTH];
  67. WCHAR **argvW;
  68. DWORD CurrentPid;
  69. ULONG LogonId, CurrentLogonId;
  70. PSID pUserSid;
  71. WCHAR wszString[MAX_LOCALE_STRING + 1];
  72. PTS_SYS_PROCESS_INFORMATION ProcessInfo;
  73. PCITRIX_PROCESS_INFORMATION CitrixInfo;
  74. PBYTE pBuffer;
  75. ULONG ByteCount;
  76. NTSTATUS status;
  77. ULONG NumberOfProcesses,j;
  78. PTS_ALL_PROCESSES_INFO ProcessArray = NULL;
  79. int i;
  80. ULONG TotalOffset;
  81. DWORD dwError;
  82. setlocale(LC_ALL, ".OCP");
  83. // We don't want LC_CTYPE set the same as the others or else we will see
  84. // garbage output in the localized version, so we need to explicitly
  85. // set it to correct console output code page
  86. _snwprintf(wszString, sizeof(wszString)/sizeof(WCHAR), L".%d", GetConsoleOutputCP());
  87. wszString[sizeof(wszString)/sizeof(WCHAR) - 1] = L'\0';
  88. _wsetlocale(LC_CTYPE, wszString);
  89. SetThreadUILanguage(0);
  90. /*
  91. * Massage the command line.
  92. */
  93. argvW = MassageCommandLine((DWORD)argc);
  94. if (argvW == NULL) {
  95. ErrorPrintf(IDS_ERROR_MALLOC);
  96. return(FAILURE);
  97. }
  98. /*
  99. * parse the cmd line without parsing the program name (argc-1, argv+1)
  100. */
  101. match_string[0] = L'\0';
  102. rc = ParseCommandLine(argc-1, argvW+1, ptm, PCL_FLAG_NO_CLEAR_MEMORY);
  103. /*
  104. * Check for error from ParseCommandLine
  105. */
  106. if ( help_flag || (rc && !(rc & PARSE_FLAG_NO_PARMS)) ) {
  107. if ( !help_flag ) {
  108. Usage(TRUE);
  109. return(FAILURE);
  110. } else {
  111. Usage(FALSE);
  112. return(SUCCESS);
  113. }
  114. }
  115. // If no remote server was specified, then check if we are running under Terminal Server
  116. if ((!IsTokenPresent(ptm, L"/server") ) && (!AreWeRunningTerminalServices()))
  117. {
  118. ErrorPrintf(IDS_ERROR_NOT_TS);
  119. return(FAILURE);
  120. }
  121. /*
  122. * Open the specified server
  123. */
  124. if( ServerName[0] ) {
  125. hServerName = WinStationOpenServer( ServerName );
  126. if( hServerName == NULL ) {
  127. StringErrorPrintf(IDS_ERROR_SERVER,ServerName);
  128. PutStdErr( GetLastError(), 0 );
  129. return(FAILURE);
  130. }
  131. }
  132. /*
  133. * Get the current users name
  134. */
  135. GetCurrentUserName( CurrUserName, USERNAME_LENGTH );
  136. _wcslwr( CurrUserName );
  137. OEM2ANSIW(CurrUserName, (USHORT)wcslen(CurrUserName));
  138. /*
  139. * Get current processes pid
  140. */
  141. CurrentPid = GetCurrentProcessId();
  142. /*
  143. * Get current WinStation name.
  144. GetCurrentWinStationName( CurrWinStationName, WINSTATIONNAME_LENGTH );
  145. _wcslwr( CurrWinStationName );
  146. OEM2ANSIW(CurrWinStationName, (USHORT)wcslen(CurrWinStationName));
  147. */
  148. /*
  149. * Get current LogonId.
  150. */
  151. CurrentLogonId = GetCurrentLogonId();
  152. /*
  153. * If no "match_string" input, then default to all processes for LoginId
  154. * (if /ID: switch specified) or user logged into current WinStation.
  155. */
  156. if ( !(*match_string) ) {
  157. if( ArgLogonId != (-1) ) {
  158. wsprintf( match_string, L"%d", ArgLogonId );
  159. }
  160. else
  161. wcscpy( match_string, CurrUserName );
  162. }
  163. /*
  164. * Make match name lower case
  165. */
  166. _wcslwr( match_string );
  167. SetFileApisToOEM();
  168. /*
  169. * Enumerate all processes on the server.
  170. */
  171. //
  172. // Try the new interface first (NT5 server ?)
  173. //
  174. if (WinStationGetAllProcesses( hServerName,
  175. GAP_LEVEL_BASIC,
  176. &NumberOfProcesses,
  177. &ProcessArray) )
  178. {
  179. for (j=0; j<NumberOfProcesses; j++)
  180. {
  181. ProcessInfo = (PTS_SYS_PROCESS_INFORMATION )(ProcessArray[j].pTsProcessInfo);
  182. pUserSid = ProcessArray[j].pSid;
  183. LogonId = ProcessInfo->SessionId;
  184. FormatAndDisplayProcessInfo(hServerName,
  185. ProcessInfo,
  186. pUserSid,
  187. LogonId,
  188. CurrentLogonId);
  189. }
  190. //
  191. // Free ppProcessArray and all child pointers allocated by the client stub.
  192. //
  193. WinStationFreeGAPMemory(GAP_LEVEL_BASIC, ProcessArray, NumberOfProcesses);
  194. }
  195. else // Maybe a Hydra 4 server ?
  196. {
  197. //
  198. // Check the return code indicating that the interface is not available.
  199. //
  200. dwError = GetLastError();
  201. if (dwError != RPC_S_PROCNUM_OUT_OF_RANGE)
  202. {
  203. ErrorPrintf(IDS_ERROR_ENUMERATE_PROCESSES);
  204. return(FAILURE);
  205. }
  206. else
  207. {
  208. //
  209. // The new interface is not known
  210. // It must be a Hydra 4 server
  211. // Let's try the old interface
  212. //
  213. if ( !WinStationEnumerateProcesses( hServerName, &pBuffer) ) {
  214. ErrorPrintf(IDS_ERROR_ENUMERATE_PROCESSES);
  215. return(FAILURE);
  216. }
  217. /*
  218. * Loop through all processes. Output those that match desired
  219. * criteria.
  220. */
  221. ProcessInfo = (PTS_SYS_PROCESS_INFORMATION)pBuffer;
  222. TotalOffset = 0;
  223. rc = 0;
  224. for(;;)
  225. {
  226. /*
  227. * Get the CITRIX_INFORMATION which follows the Threads
  228. */
  229. CitrixInfo = (PCITRIX_PROCESS_INFORMATION)
  230. (((PUCHAR)ProcessInfo) +
  231. SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION +
  232. (SIZEOF_TS4_SYSTEM_THREAD_INFORMATION * (int)ProcessInfo->NumberOfThreads));
  233. if( CitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) {
  234. LogonId = CitrixInfo->LogonId;
  235. pUserSid = CitrixInfo->ProcessSid;
  236. }
  237. else
  238. {
  239. LogonId = (ULONG)(-1);
  240. pUserSid = NULL;
  241. }
  242. FormatAndDisplayProcessInfo( hServerName,
  243. ProcessInfo,
  244. pUserSid,
  245. LogonId,
  246. CurrentLogonId);
  247. if( ProcessInfo->NextEntryOffset == 0 ) {
  248. break;
  249. }
  250. TotalOffset += ProcessInfo->NextEntryOffset;
  251. ProcessInfo = (PTS_SYS_PROCESS_INFORMATION)&pBuffer[TotalOffset];
  252. }
  253. /*
  254. * free buffer
  255. */
  256. WinStationFreeMemory( pBuffer );
  257. }
  258. }
  259. /*
  260. * Check for at least one match
  261. */
  262. if ( !MatchedOne ) {
  263. StringErrorPrintf(IDS_ERROR_PROCESS_NOT_FOUND, match_string);
  264. return(FAILURE);
  265. }
  266. return(SUCCESS);
  267. } /* main() */
  268. /******************************************************************************
  269. *
  270. * FormatAndDisplayProcessInfo
  271. *
  272. *
  273. *****************************************************************************/
  274. VOID
  275. FormatAndDisplayProcessInfo(
  276. HANDLE hServer,
  277. PTS_SYS_PROCESS_INFORMATION ProcessInfo,
  278. PSID pUserSid,
  279. ULONG LogonId,
  280. ULONG CurrentLogonId)
  281. {
  282. WCHAR WinStationName[WINSTATIONNAME_LENGTH];
  283. WCHAR UserName[USERNAME_LENGTH];
  284. WCHAR ImageName[ MAXNAME + 2 ];
  285. ULONG MaxLen;
  286. ImageName[MAXNAME+1] = 0; // Force NULL termination
  287. // Convert the counted string into a buffer
  288. if( ProcessInfo->ImageName.Length > MAXNAME * 2)
  289. {
  290. wcsncpy(ImageName, ProcessInfo->ImageName.Buffer, MAXNAME);
  291. }
  292. else if( ProcessInfo->ImageName.Length == 0 )
  293. {
  294. ImageName[0] = 0;
  295. }
  296. else
  297. {
  298. wcsncpy(ImageName, ProcessInfo->ImageName.Buffer, ProcessInfo->ImageName.Length/2);
  299. ImageName[ProcessInfo->ImageName.Length/2] = 0;
  300. }
  301. // get remote winstation name
  302. if ( (LogonId == (ULONG)(-1)) ||
  303. !xxxGetWinStationNameFromId( hServer,
  304. LogonId,
  305. WinStationName,
  306. WINSTATIONNAME_LENGTH ) ) {
  307. if (GetUnknownString())
  308. {
  309. wsprintf( WinStationName, L"(%s)", GetUnknownString() );
  310. }
  311. else
  312. {
  313. wcscpy( WinStationName, L"(Unknown)" );
  314. }
  315. }
  316. OEM2ANSIW(WinStationName, (USHORT)wcslen(WinStationName));
  317. // Get the User name for the SID of the process.
  318. MaxLen = USERNAME_LENGTH;
  319. GetUserNameFromSid( pUserSid, UserName, &MaxLen);
  320. OEM2ANSIW(UserName, (USHORT)wcslen(UserName));
  321. // Call the general process object match function
  322. if ( ProcessObjectMatch(UlongToPtr(ProcessInfo->UniqueProcessId),
  323. LogonId,
  324. ((ArgLogonId == (-1)) ? FALSE : TRUE),
  325. match_string,
  326. WinStationName,
  327. UserName,
  328. ImageName ) ){
  329. // Match: truncate and lower case the names in preparation for output.
  330. TruncateString( _wcslwr(WinStationName), 12 );
  331. TruncateString( _wcslwr(UserName), 18 );
  332. TruncateString( _wcslwr(ImageName), 15);
  333. // If first time - output header
  334. if ( !MatchedOne ) {
  335. Message(IDS_HEADER);
  336. MatchedOne = TRUE;
  337. }
  338. // identify all processes belonging to current user.
  339. if ( (hServerName == SERVERNAME_CURRENT) && (LogonId == CurrentLogonId ) )
  340. wprintf( L">" );
  341. else
  342. wprintf( L" " );
  343. {
  344. #define MAX_PRINTFOA_BUFFER_SIZE 1024
  345. char pUserName[MAX_PRINTFOA_BUFFER_SIZE];
  346. char pWinStationName[MAX_PRINTFOA_BUFFER_SIZE];
  347. char pImageName[MAX_PRINTFOA_BUFFER_SIZE];
  348. WideCharToMultiByte(CP_OEMCP, 0,
  349. UserName, -1,
  350. pUserName, sizeof(pUserName),
  351. NULL, NULL);
  352. WideCharToMultiByte(CP_OEMCP, 0,
  353. WinStationName, -1,
  354. pWinStationName, sizeof(pWinStationName),
  355. NULL, NULL);
  356. WideCharToMultiByte(CP_OEMCP, 0,
  357. ImageName, -1,
  358. pImageName, sizeof(pImageName),
  359. NULL, NULL);
  360. fprintf( stdout,
  361. FORMAT,
  362. pUserName,
  363. pWinStationName,
  364. LogonId,
  365. // ProgramState,
  366. ProcessInfo->UniqueProcessId,
  367. pImageName );
  368. }
  369. }
  370. }
  371. /*******************************************************************************
  372. *
  373. * Usage
  374. *
  375. * Output the usage message for this utility.
  376. *
  377. * ENTRY:
  378. * bError (input)
  379. * TRUE if the 'invalid parameter(s)' message should preceed the usage
  380. * message and the output go to stderr; FALSE for no such error
  381. * string and output goes to stdout.
  382. *
  383. * EXIT:
  384. *
  385. *
  386. ******************************************************************************/
  387. void
  388. Usage( BOOLEAN bError )
  389. {
  390. if ( bError ) {
  391. ErrorPrintf(IDS_ERROR_INVALID_PARAMETERS);
  392. ErrorPrintf(IDS_HELP_USAGE1);
  393. ErrorPrintf(IDS_HELP_USAGE2);
  394. ErrorPrintf(IDS_HELP_USAGE3);
  395. ErrorPrintf(IDS_HELP_USAGE40);
  396. ErrorPrintf(IDS_HELP_USAGE4);
  397. ErrorPrintf(IDS_HELP_USAGE5);
  398. ErrorPrintf(IDS_HELP_USAGE6);
  399. ErrorPrintf(IDS_HELP_USAGE7);
  400. ErrorPrintf(IDS_HELP_USAGE8);
  401. ErrorPrintf(IDS_HELP_USAGE9);
  402. } else {
  403. Message(IDS_HELP_USAGE1);
  404. Message(IDS_HELP_USAGE2);
  405. Message(IDS_HELP_USAGE3);
  406. Message(IDS_HELP_USAGE40);
  407. Message(IDS_HELP_USAGE4);
  408. Message(IDS_HELP_USAGE5);
  409. Message(IDS_HELP_USAGE6);
  410. Message(IDS_HELP_USAGE7);
  411. Message(IDS_HELP_USAGE8);
  412. Message(IDS_HELP_USAGE9);
  413. }
  414. } /* Usage() */