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.

3537 lines
94 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. cmd.c
  5. Abstract:
  6. This module contains the routines for handling each command.
  7. Author:
  8. Sean Selitrennikoff (v-seans) - Dec 2, 1999
  9. Revision History:
  10. --*/
  11. #include "sac.h"
  12. #include <ntddip.h>
  13. #include <ntddtcp.h>
  14. #include <tdiinfo.h>
  15. #include <ipinfo.h>
  16. #include <stdlib.h>
  17. BOOLEAN GlobalPagingNeeded = TRUE;
  18. BOOLEAN GlobalDoThreads = FALSE;
  19. // For the APC routines, a global value is better :-)
  20. IO_STATUS_BLOCK GlobalIoStatusBlock;
  21. ULONG GlobalBufferSize = 0;
  22. char *GlobalBuffer = NULL;
  23. typedef struct _SAC_RSP_TLIST {
  24. SYSTEM_BASIC_INFORMATION BasicInfo;
  25. SYSTEM_TIMEOFDAY_INFORMATION TimeOfDayInfo;
  26. SYSTEM_FILECACHE_INFORMATION FileCache;
  27. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  28. ULONG PagefileInfoOffset;
  29. ULONG ProcessInfoOffset;
  30. } SAC_RSP_TLIST, *PSAC_RSP_TLIST;
  31. WCHAR *StateTable[] = {
  32. L"Initialized",
  33. L"Ready",
  34. L"Running",
  35. L"Standby",
  36. L"Terminated",
  37. L"Wait:",
  38. L"Transition",
  39. L"Unknown",
  40. L"Unknown",
  41. L"Unknown",
  42. L"Unknown",
  43. L"Unknown"
  44. };
  45. WCHAR *WaitTable[] = {
  46. L"Executive",
  47. L"FreePage",
  48. L"PageIn",
  49. L"PoolAllocation",
  50. L"DelayExecution",
  51. L"Suspended",
  52. L"UserRequest",
  53. L"Executive",
  54. L"FreePage",
  55. L"PageIn",
  56. L"PoolAllocation",
  57. L"DelayExecution",
  58. L"Suspended",
  59. L"UserRequest",
  60. L"EventPairHigh",
  61. L"EventPairLow",
  62. L"LpcReceive",
  63. L"LpcReply",
  64. L"VirtualMemory",
  65. L"PageOut",
  66. L"Spare1",
  67. L"Spare2",
  68. L"Spare3",
  69. L"Spare4",
  70. L"Spare5",
  71. L"Spare6",
  72. L"Spare7",
  73. L"Unknown",
  74. L"Unknown",
  75. L"Unknown"
  76. };
  77. WCHAR *Empty = L" ";
  78. #define IP_LOOPBACK(x) (((x) & 0x000000ff) == 0x7f)
  79. #define IS_WHITESPACE(_ch) ((_ch == ' ') || (_ch == '\t'))
  80. #define IS_NUMBER(_ch) ((_ch >= '0') && (_ch <= '9'))
  81. #define SKIP_WHITESPACE(_pch) \
  82. while (IS_WHITESPACE(*_pch) && (*_pch != '\0')) { \
  83. _pch++; \
  84. }
  85. #define SKIP_NUMBERS(_pch) \
  86. while (IS_NUMBER(*_pch) && (*_pch != '\0')) { \
  87. _pch++; \
  88. }
  89. //
  90. // Forward declarations.
  91. //
  92. NTSTATUS
  93. GetTListInfo(
  94. OUT PSAC_RSP_TLIST ResponseBuffer,
  95. IN LONG ResponseBufferSize,
  96. OUT PULONG ResponseDataSize
  97. );
  98. VOID
  99. PrintTListInfo(
  100. IN PSAC_RSP_TLIST Buffer
  101. );
  102. VOID
  103. PutMore(
  104. OUT PBOOLEAN Stop
  105. );
  106. VOID
  107. DoGetNetInfo(
  108. IN BOOLEAN PrintToTerminal
  109. );
  110. VOID
  111. NetAPCRoutine(IN PVOID ApcContext,
  112. IN PIO_STATUS_BLOCK IoStatusBlock,
  113. IN ULONG Reserved
  114. );
  115. VOID
  116. DoHelpCommand(
  117. VOID
  118. )
  119. /*++
  120. Routine Description:
  121. This routine displays the help text on the terminal.
  122. Arguments:
  123. None.
  124. Return Value:
  125. None.
  126. --*/
  127. {
  128. SacPutSimpleMessage( SAC_HELP_D_CMD );
  129. SacPutSimpleMessage( SAC_HELP_F_CMD );
  130. SacPutSimpleMessage( SAC_HELP_HELP_CMD );
  131. SacPutSimpleMessage( SAC_HELP_I1_CMD );
  132. SacPutSimpleMessage( SAC_HELP_I2_CMD );
  133. SacPutSimpleMessage( SAC_HELP_I3_CMD );
  134. SacPutSimpleMessage( SAC_HELP_IDENTIFICATION_CMD );
  135. SacPutSimpleMessage( SAC_HELP_K_CMD );
  136. SacPutSimpleMessage( SAC_HELP_L_CMD );
  137. SacPutSimpleMessage( SAC_HELP_M_CMD );
  138. SacPutSimpleMessage( SAC_HELP_P_CMD );
  139. SacPutSimpleMessage( SAC_HELP_R_CMD );
  140. SacPutSimpleMessage( SAC_HELP_S1_CMD );
  141. SacPutSimpleMessage( SAC_HELP_S2_CMD );
  142. SacPutSimpleMessage( SAC_HELP_T_CMD );
  143. SacPutSimpleMessage( SAC_HELP_Q_CMD );
  144. SacPutSimpleMessage( SAC_HELP_RESTART_CMD );
  145. SacPutSimpleMessage( SAC_HELP_SHUTDOWN_CMD );
  146. SacPutSimpleMessage( SAC_HELP_CRASHDUMP1_CMD );
  147. SacPutSimpleMessage( SAC_HELP_CRASHDUMP2_CMD );
  148. }
  149. VOID
  150. DoFullInfoCommand(
  151. VOID
  152. )
  153. /*++
  154. Routine Description:
  155. This routine toggles on and off full thread information on tlist.
  156. Arguments:
  157. None.
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. GlobalDoThreads = (BOOLEAN)!GlobalDoThreads;
  163. if (GlobalDoThreads) {
  164. SacPutSimpleMessage(SAC_THREAD_ON);
  165. } else {
  166. SacPutSimpleMessage(SAC_THREAD_OFF);
  167. }
  168. }
  169. VOID
  170. DoPagingCommand(
  171. VOID
  172. )
  173. /*++
  174. Routine Description:
  175. This routine toggles on and off paging information on tlist.
  176. Arguments:
  177. None.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. GlobalPagingNeeded = (BOOLEAN)!GlobalPagingNeeded;
  183. if (GlobalPagingNeeded) {
  184. SacPutSimpleMessage(SAC_PAGING_ON);
  185. } else {
  186. SacPutSimpleMessage(SAC_PAGING_OFF);
  187. }
  188. }
  189. VOID
  190. DoSetTimeCommand(
  191. PUCHAR InputLine
  192. )
  193. /*++
  194. Routine Description:
  195. This routine sets the current system time.
  196. Arguments:
  197. InputLine - The users input line to parse.
  198. Return Value:
  199. None.
  200. --*/
  201. {
  202. NTSTATUS Status;
  203. PUCHAR pch = InputLine;
  204. PUCHAR pchTmp;
  205. TIME_FIELDS TimeFields;
  206. LARGE_INTEGER Time;
  207. SYSTEM_TIMEOFDAY_INFORMATION TimeOfDay;
  208. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Entering.\n")));
  209. //
  210. // Get the global buffer started so that we have room for error messages.
  211. //
  212. if (GlobalBuffer == NULL) {
  213. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  214. if (GlobalBuffer == NULL) {
  215. SacPutSimpleMessage(SAC_NO_MEMORY);
  216. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (1).\n")));
  217. return;
  218. }
  219. GlobalBufferSize = MEMORY_INCREMENT;
  220. }
  221. RtlZeroMemory(&TimeFields, sizeof(TIME_FIELDS));
  222. //
  223. // Skip the command.
  224. //
  225. pch += (sizeof(TIME_COMMAND_STRING) - sizeof(UCHAR));
  226. SKIP_WHITESPACE(pch);
  227. if (*pch == '\0') {
  228. //
  229. // This is a display time request.
  230. //
  231. Status = ZwQuerySystemInformation(SystemTimeOfDayInformation,
  232. &TimeOfDay,
  233. sizeof(TimeOfDay),
  234. NULL
  235. );
  236. if (!NT_SUCCESS(Status)) {
  237. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR ) , Status);
  238. SacPutUnicodeString((PWSTR)GlobalBuffer);
  239. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (2).\n")));
  240. return;
  241. }
  242. RtlTimeToTimeFields(&(TimeOfDay.CurrentTime), &TimeFields);
  243. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_DATETIME_FORMAT ),
  244. TimeFields.Month,
  245. TimeFields.Day,
  246. TimeFields.Year,
  247. TimeFields.Hour,
  248. TimeFields.Minute,
  249. TimeFields.Second,
  250. TimeFields.Milliseconds
  251. );
  252. SacPutUnicodeString((PWSTR)GlobalBuffer);
  253. return;
  254. }
  255. pchTmp = pch;
  256. if (!IS_NUMBER(*pchTmp)) {
  257. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  258. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (3).\n")));
  259. return;
  260. }
  261. //
  262. // Skip all the numbers.
  263. //
  264. SKIP_NUMBERS(pchTmp);
  265. SKIP_WHITESPACE(pchTmp);
  266. //
  267. // If there is something other than the divider, it is a mal-formed line.
  268. //
  269. if (*pchTmp != '/') {
  270. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  271. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (4).\n")));
  272. return;
  273. }
  274. *pchTmp = '\0';
  275. pchTmp++;
  276. TimeFields.Month = (USHORT)(atoi((LPCSTR)pch));
  277. pch = pchTmp;
  278. SKIP_WHITESPACE(pchTmp);
  279. if (!IS_NUMBER(*pchTmp)) {
  280. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  281. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (4b).\n")));
  282. return;
  283. }
  284. //
  285. // Skip all the numbers.
  286. //
  287. SKIP_NUMBERS(pchTmp);
  288. SKIP_WHITESPACE(pchTmp);
  289. //
  290. // If there is something other than the divider, it is a mal-formed line.
  291. //
  292. if (*pchTmp != '/') {
  293. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  294. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (5).\n")));
  295. return;
  296. }
  297. *pchTmp = '\0';
  298. pchTmp++;
  299. TimeFields.Day = (USHORT)(atoi((LPCSTR)pch));
  300. pch = pchTmp;
  301. SKIP_WHITESPACE(pchTmp);
  302. if (!IS_NUMBER(*pchTmp)) {
  303. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  304. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (5b).\n")));
  305. return;
  306. }
  307. //
  308. // Skip all the numbers.
  309. //
  310. SKIP_NUMBERS(pchTmp);
  311. //
  312. // If there is something other than whitespace, it is a mal-formed line.
  313. //
  314. if (!IS_WHITESPACE(*pchTmp)) {
  315. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  316. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (6).\n")));
  317. return;
  318. }
  319. *pchTmp = '\0';
  320. pchTmp++;
  321. TimeFields.Year = (USHORT)(atoi((LPCSTR)pch));
  322. if ((TimeFields.Year < 1980) || (TimeFields.Year > 2099)) {
  323. SacPutSimpleMessage(SAC_DATETIME_LIMITS);
  324. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (6b).\n")));
  325. return;
  326. }
  327. pch = pchTmp;
  328. //
  329. // Skip to the hours
  330. //
  331. SKIP_WHITESPACE(pchTmp);
  332. if (!IS_NUMBER(*pchTmp)) {
  333. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  334. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (7).\n")));
  335. return;
  336. }
  337. pch = pchTmp;
  338. SKIP_NUMBERS(pchTmp);
  339. SKIP_WHITESPACE(pchTmp);
  340. if (*pchTmp != ':') {
  341. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  342. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (8).\n")));
  343. return;
  344. }
  345. *pchTmp = '\0';
  346. pchTmp++;
  347. TimeFields.Hour = (USHORT)(atoi((LPCSTR)pch));
  348. pch = pchTmp;
  349. //
  350. // Verify nothing else on the line but numbers
  351. //
  352. SKIP_WHITESPACE(pchTmp);
  353. if (!IS_NUMBER(*pchTmp)) {
  354. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  355. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (8a).\n")));
  356. return;
  357. }
  358. SKIP_NUMBERS(pchTmp);
  359. SKIP_WHITESPACE(pchTmp);
  360. if (*pchTmp != '\0') {
  361. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  362. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (8b).\n")));
  363. return;
  364. }
  365. //
  366. // Get the minutes.
  367. //
  368. TimeFields.Minute = (USHORT)(atoi((LPCSTR)pch));
  369. if (!RtlTimeFieldsToTime(&TimeFields, &Time)) {
  370. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  371. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (9).\n")));
  372. return;
  373. }
  374. Status = ZwSetSystemTime(&Time, NULL);
  375. if (!NT_SUCCESS(Status)) {
  376. sprintf((LPSTR)GlobalBuffer, "Failed with status 0x%X.\r\n", Status);
  377. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  378. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (10).\n")));
  379. return;
  380. }
  381. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_DATETIME_FORMAT2 ),
  382. TimeFields.Month,
  383. TimeFields.Day,
  384. TimeFields.Year,
  385. TimeFields.Hour,
  386. TimeFields.Minute
  387. );
  388. SacPutUnicodeString((PWSTR)GlobalBuffer);
  389. return;
  390. }
  391. VOID
  392. DoSetIpAddressCommand(
  393. PUCHAR InputLine
  394. )
  395. /*++
  396. Routine Description:
  397. This routine sets the IP address and subnet mask.
  398. Arguments:
  399. InputLine - The users input line to parse.
  400. Return Value:
  401. None.
  402. --*/
  403. {
  404. NTSTATUS Status;
  405. PUCHAR pch = InputLine;
  406. PUCHAR pchTmp;
  407. HANDLE Handle;
  408. HANDLE EventHandle;
  409. PKEVENT Event;
  410. ULONG IpAddress;
  411. ULONG SubIpAddress;
  412. ULONG SubnetMask;
  413. ULONG NetworkNumber;
  414. LARGE_INTEGER TimeOut;
  415. IO_STATUS_BLOCK IoStatusBlock;
  416. UNICODE_STRING UnicodeString;
  417. OBJECT_ATTRIBUTES ObjectAttributes;
  418. PIP_SET_ADDRESS_REQUEST IpRequest;
  419. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Entering.\n")));
  420. //
  421. // Get the global buffer started so that we have room for error messages.
  422. //
  423. if (GlobalBuffer == NULL) {
  424. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  425. if (GlobalBuffer == NULL) {
  426. SacPutSimpleMessage(SAC_NO_MEMORY);
  427. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (1).\n")));
  428. return;
  429. }
  430. GlobalBufferSize = MEMORY_INCREMENT;
  431. }
  432. //
  433. // Skip the command.
  434. //
  435. pch += (sizeof(SETIP_COMMAND_STRING) - sizeof(UCHAR));
  436. SKIP_WHITESPACE(pch);
  437. if (*pch == '\0') {
  438. //
  439. // No other parameters, get the network numbers and their IP addresses.
  440. //
  441. DoGetNetInfo( TRUE );
  442. return;
  443. }
  444. pchTmp = pch;
  445. if (!IS_NUMBER(*pchTmp)) {
  446. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  447. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (1b).\n")));
  448. return;
  449. }
  450. SKIP_NUMBERS(pchTmp);
  451. if (!IS_WHITESPACE(*pchTmp)) {
  452. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  453. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (1c).\n")));
  454. return;
  455. }
  456. *pchTmp = '\0';
  457. pchTmp++;
  458. NetworkNumber = atoi((LPCSTR)pch);
  459. pch = pchTmp;
  460. //
  461. // Parse out the IP address.
  462. //
  463. //
  464. // Skip ahead to the divider and make it a \0.
  465. //
  466. SKIP_WHITESPACE(pchTmp);
  467. if (!IS_NUMBER(*pchTmp)) {
  468. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  469. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (2).\n")));
  470. return;
  471. }
  472. SKIP_NUMBERS(pchTmp);
  473. SKIP_WHITESPACE(pchTmp);
  474. if (*pchTmp != '.') {
  475. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  476. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (4).\n")));
  477. return;
  478. }
  479. *pchTmp = '\0';
  480. pchTmp++;
  481. SubIpAddress = atoi((LPCSTR)pch);
  482. if( SubIpAddress > 255 ) {
  483. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  484. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (4a).\n")));
  485. return;
  486. }
  487. IpAddress = SubIpAddress;
  488. //
  489. // Get 2nd part
  490. //
  491. pch = pchTmp;
  492. SKIP_WHITESPACE(pchTmp);
  493. if (!IS_NUMBER(*pchTmp)) {
  494. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  495. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (4b).\n")));
  496. return;
  497. }
  498. SKIP_NUMBERS(pchTmp);
  499. SKIP_WHITESPACE(pchTmp);
  500. if (*pchTmp != '.') {
  501. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  502. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (5).\n")));
  503. return;
  504. }
  505. *pchTmp = '\0';
  506. pchTmp++;
  507. SubIpAddress = atoi((LPCSTR)pch);
  508. if( SubIpAddress > 255 ) {
  509. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  510. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (5a).\n")));
  511. return;
  512. }
  513. IpAddress |= (SubIpAddress << 8);
  514. //
  515. // Get 3rd part
  516. //
  517. pch = pchTmp;
  518. SKIP_WHITESPACE(pchTmp);
  519. if (!IS_NUMBER(*pchTmp)) {
  520. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  521. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (5b).\n")));
  522. return;
  523. }
  524. SKIP_NUMBERS(pchTmp);
  525. SKIP_WHITESPACE(pchTmp);
  526. if (*pchTmp != '.') {
  527. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  528. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (6).\n")));
  529. return;
  530. }
  531. *pchTmp = '\0';
  532. pchTmp++;
  533. SubIpAddress = atoi((LPCSTR)pch);
  534. if( SubIpAddress > 255 ) {
  535. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  536. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (6a).\n")));
  537. return;
  538. }
  539. IpAddress |= (SubIpAddress << 16);
  540. //
  541. // Get 4th part
  542. //
  543. pch = pchTmp;
  544. SKIP_WHITESPACE(pchTmp);
  545. if (!IS_NUMBER(*pchTmp)) {
  546. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  547. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (6b).\n")));
  548. return;
  549. }
  550. SKIP_NUMBERS(pchTmp);
  551. if (!IS_WHITESPACE(*pchTmp)) {
  552. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  553. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (7).\n")));
  554. return;
  555. }
  556. *pchTmp = '\0';
  557. pchTmp++;
  558. SubIpAddress = atoi((LPCSTR)pch);
  559. if( SubIpAddress > 255 ) {
  560. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  561. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (7a).\n")));
  562. return;
  563. }
  564. IpAddress |= (SubIpAddress << 24);
  565. //
  566. //
  567. // Now onto the subnet mask.
  568. //
  569. //
  570. //
  571. // Skip ahead to the divider and make it a \0.
  572. //
  573. SKIP_WHITESPACE(pchTmp);
  574. pch = pchTmp;
  575. if (!IS_NUMBER(*pchTmp)) {
  576. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  577. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (8).\n")));
  578. return;
  579. }
  580. SKIP_NUMBERS(pchTmp);
  581. SKIP_WHITESPACE(pchTmp);
  582. if (*pchTmp != '.') {
  583. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  584. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (9).\n")));
  585. return;
  586. }
  587. *pchTmp = '\0';
  588. pchTmp++;
  589. SubIpAddress = atoi((LPCSTR)pch);
  590. if( SubIpAddress > 255 ) {
  591. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  592. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (9a).\n")));
  593. return;
  594. }
  595. SubnetMask = SubIpAddress;
  596. //
  597. // Get 2nd part
  598. //
  599. pch = pchTmp;
  600. SKIP_WHITESPACE(pchTmp);
  601. if (!IS_NUMBER(*pchTmp)) {
  602. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  603. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (9b).\n")));
  604. return;
  605. }
  606. SKIP_NUMBERS(pchTmp);
  607. SKIP_WHITESPACE(pchTmp);
  608. if (*pchTmp != '.') {
  609. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  610. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (10).\n")));
  611. return;
  612. }
  613. *pchTmp = '\0';
  614. pchTmp++;
  615. SubIpAddress = atoi((LPCSTR)pch);
  616. if( SubIpAddress > 255 ) {
  617. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  618. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (10a).\n")));
  619. return;
  620. }
  621. SubnetMask |= (SubIpAddress << 8);
  622. //
  623. // Get 3rd part
  624. //
  625. pch = pchTmp;
  626. SKIP_WHITESPACE(pchTmp);
  627. if (!IS_NUMBER(*pchTmp)) {
  628. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  629. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (10b).\n")));
  630. return;
  631. }
  632. SKIP_NUMBERS(pchTmp);
  633. SKIP_WHITESPACE(pchTmp);
  634. if (*pchTmp != '.') {
  635. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  636. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (11).\n")));
  637. return;
  638. }
  639. *pchTmp = '\0';
  640. pchTmp++;
  641. SubIpAddress = atoi((LPCSTR)pch);
  642. if( SubIpAddress > 255 ) {
  643. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  644. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (11a).\n")));
  645. return;
  646. }
  647. SubnetMask |= (SubIpAddress << 16);
  648. //
  649. // Get 4th part
  650. //
  651. pch = pchTmp;
  652. SKIP_WHITESPACE(pchTmp);
  653. if (!IS_NUMBER(*pchTmp)) {
  654. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  655. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (12).\n")));
  656. return;
  657. }
  658. SKIP_NUMBERS(pchTmp);
  659. SKIP_WHITESPACE(pchTmp);
  660. if (*pchTmp != '\0') {
  661. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  662. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (13).\n")));
  663. return;
  664. }
  665. SubIpAddress = atoi((LPCSTR)pch);
  666. if( SubIpAddress > 255 ) {
  667. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  668. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (13a).\n")));
  669. return;
  670. }
  671. SubnetMask |= (SubIpAddress << 24);
  672. //
  673. //
  674. // Now that that is done, we move onto actually doing the command.
  675. //
  676. //
  677. //
  678. // Start by opening the driver
  679. //
  680. RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
  681. InitializeObjectAttributes(&ObjectAttributes,
  682. &UnicodeString,
  683. OBJ_CASE_INSENSITIVE,
  684. NULL,
  685. NULL
  686. );
  687. Status = ZwOpenFile(&Handle,
  688. (ACCESS_MASK)FILE_GENERIC_READ,
  689. &ObjectAttributes,
  690. &IoStatusBlock,
  691. FILE_SHARE_READ | FILE_SHARE_WRITE,
  692. 0
  693. );
  694. if (!NT_SUCCESS(Status)) {
  695. SacPutSimpleMessage(SAC_IPADDRESS_SET_FAILURE);
  696. IF_SAC_DEBUG(
  697. SAC_DEBUG_FUNC_TRACE,
  698. KdPrint(("SAC DoSetIpAddressCommand: failed to open TCP device, ec = 0x%X\n",
  699. Status)));
  700. return;
  701. }
  702. //
  703. // Setup notification event
  704. //
  705. RtlInitUnicodeString(&UnicodeString, L"\\BaseNamedObjects\\SACEvent");
  706. Event = IoCreateSynchronizationEvent(&UnicodeString, &EventHandle);
  707. if (Event == NULL) {
  708. SacPutSimpleMessage(SAC_IPADDRESS_RETRIEVE_FAILURE);
  709. ZwClose(Handle);
  710. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Event is NULL.\n")));
  711. return;
  712. }
  713. //
  714. // Setup the IOCTL buffer to delete the old address.
  715. //
  716. IpRequest = (PIP_SET_ADDRESS_REQUEST)GlobalBuffer;
  717. IpRequest->Address = 0;
  718. IpRequest->SubnetMask = 0;
  719. IpRequest->Context = (USHORT)NetworkNumber;
  720. //
  721. // Submit the IOCTL
  722. //
  723. Status = NtDeviceIoControlFile(Handle,
  724. EventHandle,
  725. NULL,
  726. NULL,
  727. &IoStatusBlock,
  728. IOCTL_IP_SET_ADDRESS,
  729. IpRequest,
  730. sizeof(IP_SET_ADDRESS_REQUEST),
  731. NULL,
  732. 0
  733. );
  734. if (Status == STATUS_PENDING) {
  735. //
  736. // Wait up to 30 seconds for it to finish
  737. //
  738. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  739. Status = KeWaitForSingleObject((PVOID)Event, Executive, KernelMode, FALSE, &TimeOut);
  740. if (Status == STATUS_SUCCESS) {
  741. Status = IoStatusBlock.Status;
  742. }
  743. }
  744. if (Status != STATUS_SUCCESS) {
  745. SacPutSimpleMessage( SAC_IPADDRESS_CLEAR_FAILURE );
  746. ZwClose(EventHandle);
  747. ZwClose(Handle);
  748. IF_SAC_DEBUG(
  749. SAC_DEBUG_FUNC_TRACE,
  750. KdPrint(("SAC DoSetIpAddressCommand: Exiting because it couldn't clear existing IP Address (0x%X).\n",
  751. Status)));
  752. return;
  753. }
  754. //
  755. // Now add our address.
  756. //
  757. IpRequest = (PIP_SET_ADDRESS_REQUEST)GlobalBuffer;
  758. IpRequest->Address = IpAddress;
  759. IpRequest->SubnetMask = SubnetMask;
  760. IpRequest->Context = (USHORT)NetworkNumber;
  761. //
  762. // Submit the IOCTL
  763. //
  764. Status = NtDeviceIoControlFile(Handle,
  765. EventHandle,
  766. NULL,
  767. NULL,
  768. &IoStatusBlock,
  769. IOCTL_IP_SET_ADDRESS,
  770. IpRequest,
  771. sizeof(IP_SET_ADDRESS_REQUEST),
  772. NULL,
  773. 0
  774. );
  775. if (Status == STATUS_PENDING) {
  776. //
  777. // Wait up to 30 seconds for it to finish
  778. //
  779. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  780. Status = KeWaitForSingleObject((PVOID)Event, Executive, KernelMode, FALSE, &TimeOut);
  781. if (NT_SUCCESS(Status)) {
  782. Status = IoStatusBlock.Status;
  783. }
  784. }
  785. ZwClose(EventHandle);
  786. ZwClose(Handle);
  787. if (!NT_SUCCESS(Status)) {
  788. SacPutSimpleMessage( SAC_IPADDRESS_SET_FAILURE );
  789. IF_SAC_DEBUG(
  790. SAC_DEBUG_FUNC_TRACE,
  791. KdPrint(("SAC DoSetIpAddressCommand: Exiting because it couldn't set existing IP Address (0x%X).\n",
  792. Status)));
  793. return;
  794. }
  795. SacPutSimpleMessage( SAC_IPADDRESS_SET_SUCCESS );
  796. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting.\n")));
  797. return;
  798. }
  799. VOID
  800. DoKillCommand(
  801. PUCHAR InputLine
  802. )
  803. /*++
  804. Routine Description:
  805. This routine kill a process.
  806. Arguments:
  807. InputLine - The users input line to parse.
  808. Return Value:
  809. None.
  810. --*/
  811. {
  812. NTSTATUS Status;
  813. NTSTATUS StatusOfJobObject;
  814. HANDLE Handle = NULL;
  815. HANDLE JobHandle = NULL;
  816. PUCHAR pch = InputLine;
  817. PUCHAR pchTmp;
  818. ULONG ProcessId;
  819. OBJECT_ATTRIBUTES ObjectAttributes;
  820. UNICODE_STRING UnicodeString;
  821. CLIENT_ID ClientId;
  822. BOOLEAN TerminateJobObject;
  823. BOOLEAN TerminateProcessObject;
  824. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Entering.\n")));
  825. //
  826. // Get the global buffer started so that we have room for error messages.
  827. //
  828. if (GlobalBuffer == NULL) {
  829. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  830. if (GlobalBuffer == NULL) {
  831. SacPutSimpleMessage(SAC_NO_MEMORY);
  832. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (1).\n")));
  833. return;
  834. }
  835. GlobalBufferSize = MEMORY_INCREMENT;
  836. }
  837. //
  838. // Skip to next argument (process id)
  839. //
  840. pch += (sizeof(KILL_COMMAND_STRING) - sizeof(UCHAR));
  841. SKIP_WHITESPACE(pch);
  842. if (*pch == '\0') {
  843. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  844. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (2).\n")));
  845. return;
  846. }
  847. pchTmp = pch;
  848. if (!IS_NUMBER(*pchTmp)) {
  849. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  850. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (2b).\n")));
  851. return;
  852. }
  853. SKIP_NUMBERS(pchTmp);
  854. SKIP_WHITESPACE(pchTmp);
  855. if (*pchTmp != '\0') {
  856. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  857. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (3).\n")));
  858. return;
  859. }
  860. ProcessId = atoi((LPCSTR)pch);
  861. //
  862. // Try and open an existing job object
  863. //
  864. swprintf((PWCHAR)GlobalBuffer, L"\\BaseNamedObjects\\SAC%d", ProcessId);
  865. RtlInitUnicodeString(&UnicodeString, (PWCHAR)GlobalBuffer);
  866. InitializeObjectAttributes(&ObjectAttributes,
  867. &UnicodeString,
  868. OBJ_CASE_INSENSITIVE,
  869. NULL,
  870. NULL
  871. );
  872. StatusOfJobObject = ZwOpenJobObject(&JobHandle, MAXIMUM_ALLOWED, &ObjectAttributes);
  873. //
  874. // Also open a handle to the process itself.
  875. //
  876. InitializeObjectAttributes(&ObjectAttributes,
  877. NULL,
  878. OBJ_CASE_INSENSITIVE,
  879. NULL,
  880. NULL
  881. );
  882. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  883. ClientId.UniqueThread = NULL;
  884. Status = ZwOpenProcess(&Handle,
  885. MAXIMUM_ALLOWED,
  886. &ObjectAttributes,
  887. &ClientId
  888. );
  889. if (!NT_SUCCESS(Status) && !NT_SUCCESS(StatusOfJobObject)) {
  890. SacPutSimpleMessage(SAC_KILL_FAILURE);
  891. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  892. SacPutUnicodeString((PWSTR)GlobalBuffer);
  893. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (4).\n")));
  894. return;
  895. }
  896. //
  897. // To make the logic here more understandable, I use two booleans. We have to use
  898. // ZwIsProcessInJob because there may be a previous JobObject for a process that we
  899. // have killed, but has not yet been fully cleaned up by the system to determine if
  900. // the process we are trying to kill is, in fact, in the JobObject we have opened.
  901. //
  902. TerminateJobObject = (BOOLEAN)(NT_SUCCESS(StatusOfJobObject) &&
  903. (BOOLEAN)NT_SUCCESS(Status) &&
  904. (BOOLEAN)(ZwIsProcessInJob(Handle, JobHandle) == STATUS_PROCESS_IN_JOB)
  905. );
  906. TerminateProcessObject = !TerminateJobObject && (BOOLEAN)NT_SUCCESS(Status);
  907. if (TerminateJobObject) {
  908. Status = ZwTerminateJobObject(JobHandle, 1);
  909. //
  910. // Make the job object temporary so that when we do our close it
  911. // will remove it.
  912. //
  913. ZwMakeTemporaryObject(JobHandle);
  914. } else if (TerminateProcessObject) {
  915. Status = ZwTerminateProcess(Handle, 1);
  916. }
  917. if (JobHandle != NULL) {
  918. ZwClose(JobHandle);
  919. }
  920. if (Handle != NULL) {
  921. ZwClose(Handle);
  922. }
  923. if (!TerminateProcessObject && !TerminateJobObject) {
  924. SacPutSimpleMessage(SAC_PROCESS_STALE);
  925. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (5).\n")));
  926. return;
  927. } else if (!NT_SUCCESS(Status)) {
  928. SacPutSimpleMessage(SAC_KILL_FAILURE);
  929. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  930. SacPutUnicodeString((PWSTR)GlobalBuffer);
  931. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (6).\n")));
  932. return;
  933. }
  934. //
  935. // All done
  936. //
  937. SacPutSimpleMessage(SAC_KILL_SUCCESS);
  938. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting.\n")));
  939. return;
  940. }
  941. VOID
  942. DoLowerPriorityCommand(
  943. PUCHAR InputLine
  944. )
  945. /*++
  946. Routine Description:
  947. This routine slams the priority of a process down to the lowest possible, IDLE.
  948. Arguments:
  949. InputLine - The users input line to parse.
  950. Return Value:
  951. None.
  952. --*/
  953. {
  954. NTSTATUS Status;
  955. PUCHAR pch = InputLine;
  956. PUCHAR pchTmp;
  957. ULONG ProcessId;
  958. CLIENT_ID ClientId;
  959. OBJECT_ATTRIBUTES ObjectAttributes;
  960. HANDLE ProcessHandle = NULL;
  961. PROCESS_BASIC_INFORMATION BasicInfo;
  962. ULONG LoopCounter;
  963. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Entering.\n")));
  964. //
  965. // Get the global buffer started so that we have room for error messages.
  966. //
  967. if (GlobalBuffer == NULL) {
  968. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  969. if (GlobalBuffer == NULL) {
  970. SacPutSimpleMessage(SAC_NO_MEMORY);
  971. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (1).\n")));
  972. goto Exit;
  973. }
  974. GlobalBufferSize = MEMORY_INCREMENT;
  975. }
  976. //
  977. // Skip to next argument (process id)
  978. //
  979. pch += (sizeof(LOWER_COMMAND_STRING) - sizeof(UCHAR));
  980. SKIP_WHITESPACE(pch);
  981. if (!IS_NUMBER(*pch)) {
  982. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  983. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (2).\n")));
  984. goto Exit;
  985. }
  986. pchTmp = pch;
  987. SKIP_NUMBERS(pchTmp);
  988. SKIP_WHITESPACE(pchTmp);
  989. if (*pchTmp != '\0') {
  990. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  991. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (3).\n")));
  992. return;
  993. }
  994. ProcessId = atoi((LPCSTR)pch);
  995. //
  996. // Try to open the process
  997. //
  998. InitializeObjectAttributes(&ObjectAttributes,
  999. NULL,
  1000. OBJ_CASE_INSENSITIVE,
  1001. NULL,
  1002. NULL
  1003. );
  1004. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1005. ClientId.UniqueThread = NULL;
  1006. Status = ZwOpenProcess(&ProcessHandle,
  1007. MAXIMUM_ALLOWED,
  1008. &ObjectAttributes,
  1009. &ClientId
  1010. );
  1011. if (!NT_SUCCESS(Status)) {
  1012. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1013. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1014. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1015. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (4).\n")));
  1016. goto Exit;
  1017. }
  1018. //
  1019. // Query information on the process.
  1020. //
  1021. Status = ZwQueryInformationProcess( ProcessHandle,
  1022. ProcessBasicInformation,
  1023. &BasicInfo,
  1024. sizeof(PROCESS_BASIC_INFORMATION),
  1025. NULL );
  1026. if (!NT_SUCCESS(Status)) {
  1027. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1028. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1029. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1030. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (5).\n")));
  1031. goto Exit;
  1032. }
  1033. //
  1034. // Lower the priority and set. Keep lowering it until we fail. Remember
  1035. // that we're supposed to lower it as far as it will go.
  1036. //
  1037. Status = STATUS_SUCCESS;
  1038. LoopCounter = 0;
  1039. while( (Status == STATUS_SUCCESS) &&
  1040. (BasicInfo.BasePriority > 0) ) {
  1041. BasicInfo.BasePriority--;
  1042. Status = ZwSetInformationProcess( ProcessHandle,
  1043. ProcessBasePriority,
  1044. &BasicInfo.BasePriority,
  1045. sizeof(BasicInfo.BasePriority) );
  1046. //
  1047. // Only treat a failure on the first time through.
  1048. //
  1049. if( (!NT_SUCCESS(Status)) && (LoopCounter == 0) ) {
  1050. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1051. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1052. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1053. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (6).\n")));
  1054. goto Exit;
  1055. }
  1056. LoopCounter++;
  1057. }
  1058. //
  1059. // All done.
  1060. //
  1061. SacPutSimpleMessage(SAC_LOWERPRI_SUCCESS);
  1062. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting.\n")));
  1063. Exit:
  1064. if (ProcessHandle != NULL) {
  1065. ZwClose(ProcessHandle);
  1066. }
  1067. return;
  1068. }
  1069. VOID
  1070. DoRaisePriorityCommand(
  1071. PUCHAR InputLine
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. This routine raises the priority of a process up one increment.
  1076. Arguments:
  1077. InputLine - The users input line to parse.
  1078. Return Value:
  1079. None.
  1080. --*/
  1081. {
  1082. NTSTATUS Status;
  1083. PUCHAR pch = InputLine;
  1084. PUCHAR pchTmp;
  1085. ULONG ProcessId;
  1086. CLIENT_ID ClientId;
  1087. OBJECT_ATTRIBUTES ObjectAttributes;
  1088. HANDLE ProcessHandle = NULL;
  1089. PROCESS_BASIC_INFORMATION BasicInfo;
  1090. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Entering.\n")));
  1091. //
  1092. // Get the global buffer started so that we have room for error messages.
  1093. //
  1094. if (GlobalBuffer == NULL) {
  1095. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1096. if (GlobalBuffer == NULL) {
  1097. SacPutSimpleMessage(SAC_NO_MEMORY);
  1098. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (1).\n")));
  1099. goto Exit;
  1100. }
  1101. GlobalBufferSize = MEMORY_INCREMENT;
  1102. }
  1103. //
  1104. // Skip to next argument (process id)
  1105. //
  1106. pch += (sizeof(RAISE_COMMAND_STRING) - sizeof(UCHAR));
  1107. SKIP_WHITESPACE(pch);
  1108. if (!IS_NUMBER(*pch)) {
  1109. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1110. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (2).\n")));
  1111. goto Exit;
  1112. }
  1113. pchTmp = pch;
  1114. SKIP_NUMBERS(pchTmp);
  1115. SKIP_WHITESPACE(pchTmp);
  1116. if (*pchTmp != '\0') {
  1117. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1118. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (3).\n")));
  1119. return;
  1120. }
  1121. ProcessId = atoi((LPCSTR)pch);
  1122. //
  1123. // See if the process even exists.
  1124. //
  1125. InitializeObjectAttributes(&ObjectAttributes,
  1126. NULL,
  1127. OBJ_CASE_INSENSITIVE,
  1128. NULL,
  1129. NULL
  1130. );
  1131. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1132. ClientId.UniqueThread = NULL;
  1133. Status = ZwOpenProcess(&ProcessHandle,
  1134. MAXIMUM_ALLOWED,
  1135. &ObjectAttributes,
  1136. &ClientId
  1137. );
  1138. if (!NT_SUCCESS(Status)) {
  1139. SacPutSimpleMessage(SAC_RAISEPRI_FAILURE);
  1140. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1141. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1142. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (4).\n")));
  1143. goto Exit;
  1144. }
  1145. //
  1146. // Query information on the process.
  1147. //
  1148. Status = ZwQueryInformationProcess( ProcessHandle,
  1149. ProcessBasicInformation,
  1150. &BasicInfo,
  1151. sizeof(PROCESS_BASIC_INFORMATION),
  1152. NULL );
  1153. if (!NT_SUCCESS(Status)) {
  1154. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1155. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1156. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1157. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (5).\n")));
  1158. goto Exit;
  1159. }
  1160. //
  1161. // Lower the priority and set. Keep lowering it until we fail. Remember
  1162. // that we're supposed to lower it as far as it will go.
  1163. //
  1164. BasicInfo.BasePriority++;
  1165. Status = ZwSetInformationProcess( ProcessHandle,
  1166. ProcessBasePriority,
  1167. &BasicInfo.BasePriority,
  1168. sizeof(BasicInfo.BasePriority) );
  1169. //
  1170. // Only treat a failure on the first time through.
  1171. //
  1172. if( !NT_SUCCESS(Status) ) {
  1173. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1174. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1175. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1176. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (6).\n")));
  1177. goto Exit;
  1178. }
  1179. //
  1180. // All done.
  1181. //
  1182. SacPutSimpleMessage(SAC_RAISEPRI_SUCCESS);
  1183. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting.\n")));
  1184. Exit:
  1185. if (ProcessHandle != NULL) {
  1186. ZwClose(ProcessHandle);
  1187. }
  1188. return;
  1189. }
  1190. VOID
  1191. DoLimitMemoryCommand(
  1192. PUCHAR InputLine
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. This routine reduces the memory working set of a process to the values in
  1197. the input line given.
  1198. Arguments:
  1199. InputLine - The users input line to parse.
  1200. Return Value:
  1201. None.
  1202. --*/
  1203. {
  1204. NTSTATUS Status;
  1205. NTSTATUS StatusOfJobObject;
  1206. PUCHAR pch = InputLine;
  1207. PUCHAR pchTmp;
  1208. ULONG ProcessId;
  1209. ULONG MemoryLimit;
  1210. CLIENT_ID ClientId;
  1211. OBJECT_ATTRIBUTES ObjectAttributes;
  1212. UNICODE_STRING UnicodeString;
  1213. HANDLE JobHandle = NULL;
  1214. HANDLE ProcessHandle = NULL;
  1215. JOBOBJECT_EXTENDED_LIMIT_INFORMATION ProposedLimits;
  1216. ULONG ReturnedLength;
  1217. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Entering.\n")));
  1218. //
  1219. // Get the global buffer started so that we have room for error messages.
  1220. //
  1221. if (GlobalBuffer == NULL) {
  1222. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1223. if (GlobalBuffer == NULL) {
  1224. SacPutSimpleMessage(SAC_NO_MEMORY);
  1225. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (1).\n")));
  1226. goto Exit;
  1227. }
  1228. GlobalBufferSize = MEMORY_INCREMENT;
  1229. }
  1230. //
  1231. // Get process id
  1232. //
  1233. pch += (sizeof(LIMIT_COMMAND_STRING) - sizeof(UCHAR));
  1234. SKIP_WHITESPACE(pch);
  1235. if (!IS_NUMBER(*pch)) {
  1236. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1237. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (2).\n")));
  1238. goto Exit;
  1239. }
  1240. pchTmp = pch;
  1241. SKIP_NUMBERS(pchTmp);
  1242. if (!IS_WHITESPACE(*pchTmp)) {
  1243. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1244. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (3).\n")));
  1245. return;
  1246. }
  1247. *pchTmp = '\0';
  1248. pchTmp++;
  1249. ProcessId = atoi((LPCSTR)pch);
  1250. //
  1251. // Now get memory limit
  1252. //
  1253. SKIP_WHITESPACE(pchTmp);
  1254. if (!IS_NUMBER(*pchTmp)) {
  1255. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1256. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (4).\n")));
  1257. return;
  1258. }
  1259. pch = pchTmp;
  1260. SKIP_NUMBERS(pchTmp);
  1261. SKIP_WHITESPACE(pchTmp);
  1262. if (*pchTmp != '\0') {
  1263. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1264. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (5).\n")));
  1265. return;
  1266. }
  1267. MemoryLimit = atoi((LPCSTR)pch);
  1268. if (MemoryLimit == 0) {
  1269. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1270. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (6).\n")));
  1271. goto Exit;
  1272. }
  1273. //
  1274. // Create the name for the job object
  1275. //
  1276. swprintf((PWCHAR)GlobalBuffer, L"\\BaseNamedObjects\\SAC%d", ProcessId);
  1277. //
  1278. // Try and open the existing job object
  1279. //
  1280. RtlInitUnicodeString(&UnicodeString, (PWCHAR)GlobalBuffer);
  1281. InitializeObjectAttributes(&ObjectAttributes,
  1282. &UnicodeString,
  1283. OBJ_CASE_INSENSITIVE,
  1284. NULL,
  1285. NULL
  1286. );
  1287. StatusOfJobObject = ZwOpenJobObject(&JobHandle, MAXIMUM_ALLOWED, &ObjectAttributes);
  1288. //
  1289. // Try to open the process
  1290. //
  1291. InitializeObjectAttributes(&ObjectAttributes,
  1292. NULL,
  1293. OBJ_CASE_INSENSITIVE,
  1294. NULL,
  1295. NULL
  1296. );
  1297. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1298. ClientId.UniqueThread = NULL;
  1299. Status = ZwOpenProcess(&ProcessHandle,
  1300. MAXIMUM_ALLOWED,
  1301. &ObjectAttributes,
  1302. &ClientId
  1303. );
  1304. if (!NT_SUCCESS(Status) && !NT_SUCCESS(StatusOfJobObject)) {
  1305. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1306. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1307. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1308. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (7).\n")));
  1309. goto Exit;
  1310. }
  1311. if (NT_SUCCESS(Status) &&
  1312. NT_SUCCESS(StatusOfJobObject) &&
  1313. (ZwIsProcessInJob(ProcessHandle, JobHandle) != STATUS_PROCESS_IN_JOB)) {
  1314. SacPutSimpleMessage(SAC_DUPLICATE_PROCESS);
  1315. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (8).\n")));
  1316. goto Exit;
  1317. }
  1318. if (!NT_SUCCESS(StatusOfJobObject)) {
  1319. //
  1320. // Now try and create a job object to wrap around this process.
  1321. //
  1322. InitializeObjectAttributes(&ObjectAttributes,
  1323. &UnicodeString,
  1324. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  1325. NULL,
  1326. NULL
  1327. );
  1328. Status = ZwCreateJobObject(&JobHandle, MAXIMUM_ALLOWED, &ObjectAttributes);
  1329. if (!NT_SUCCESS(Status)) {
  1330. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1331. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1332. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1333. ZwClose(ProcessHandle);
  1334. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (8b).\n")));
  1335. goto Exit;
  1336. }
  1337. //
  1338. // Assign the process to this new job object.
  1339. //
  1340. Status = ZwAssignProcessToJobObject(JobHandle, ProcessHandle);
  1341. ZwClose(ProcessHandle);
  1342. if (!NT_SUCCESS(Status)) {
  1343. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1344. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1345. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1346. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (9).\n")));
  1347. goto Exit;
  1348. }
  1349. }
  1350. //
  1351. // Get the current set of limits
  1352. //
  1353. Status = ZwQueryInformationJobObject(JobHandle,
  1354. JobObjectExtendedLimitInformation,
  1355. &ProposedLimits,
  1356. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
  1357. &ReturnedLength
  1358. );
  1359. if (!NT_SUCCESS(Status)) {
  1360. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1361. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1362. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1363. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (10).\n")));
  1364. goto Exit;
  1365. }
  1366. //
  1367. // Change the memory limits
  1368. //
  1369. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  1370. ProposedLimits.ProcessMemoryLimit = MemoryLimit * 1024 * 1024;
  1371. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
  1372. ProposedLimits.JobMemoryLimit = MemoryLimit * 1024 * 1024;
  1373. Status = ZwSetInformationJobObject(JobHandle,
  1374. JobObjectExtendedLimitInformation,
  1375. &ProposedLimits,
  1376. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)
  1377. );
  1378. if (!NT_SUCCESS(Status)) {
  1379. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1380. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1381. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1382. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (11).\n")));\
  1383. goto Exit;
  1384. }
  1385. //
  1386. // All done.
  1387. //
  1388. SacPutSimpleMessage(SAC_LOWERMEM_SUCCESS);
  1389. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting.\n")));
  1390. Exit:
  1391. if (JobHandle != NULL) {
  1392. ZwClose(JobHandle);
  1393. }
  1394. if (ProcessHandle != NULL) {
  1395. ZwClose(ProcessHandle);
  1396. }
  1397. return;
  1398. }
  1399. VOID
  1400. DoRebootCommand(
  1401. BOOLEAN Reboot
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. This routine does a shutdown and an optional reboot.
  1406. Arguments:
  1407. Reboot - To Reboot or not to reboot, that is the question answered here.
  1408. Return Value:
  1409. None.
  1410. --*/
  1411. {
  1412. #define RESTART_DELAY_TIME (60)
  1413. NTSTATUS Status;
  1414. LARGE_INTEGER TickCount;
  1415. LARGE_INTEGER ElapsedTime;
  1416. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRebootCommand: Entering.\n")));
  1417. //
  1418. // If we attempt to shutdown the system before smss.exe has initialized
  1419. // properly, and if there's no debugger, the machine may bugcheck. Figuring
  1420. // out exactly what's going on is difficult because if we put a debugger on
  1421. // the machine, he won't repro the problem. To work around this, we're going
  1422. // to make sure the machine has had time to initialize before we tell it to
  1423. // restart/shutdown.
  1424. //
  1425. // Elapsed TickCount
  1426. KeQueryTickCount( &TickCount );
  1427. // ElapsedTime in seconds.
  1428. ElapsedTime.QuadPart = (TickCount.QuadPart)/(10000000/KeQueryTimeIncrement());
  1429. if( ElapsedTime.QuadPart < RESTART_DELAY_TIME ) {
  1430. KEVENT Event;
  1431. SacPutSimpleMessage(Reboot ? SAC_PREPARE_RESTART : SAC_PREPARE_SHUTDOWN);
  1432. // wait until the machine has been up for at least RESTART_DELAY_TIME seconds.
  1433. KeInitializeEvent( &Event,
  1434. SynchronizationEvent,
  1435. FALSE );
  1436. ElapsedTime.QuadPart = Int32x32To64((LONG)((RESTART_DELAY_TIME-ElapsedTime.LowPart)*10000), // milliseconds until we reach RESTART_DELAY_TIME
  1437. -1000);
  1438. KeWaitForSingleObject((PVOID)&Event, Executive, KernelMode, FALSE, &ElapsedTime);
  1439. }
  1440. Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff);
  1441. //
  1442. // Get the global buffer started so that we have room for error messages.
  1443. //
  1444. if (GlobalBuffer == NULL) {
  1445. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1446. if (GlobalBuffer == NULL) {
  1447. SacPutSimpleMessage(SAC_NO_MEMORY);
  1448. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRebootCommand: Exiting (1).\n")));
  1449. return;
  1450. }
  1451. GlobalBufferSize = MEMORY_INCREMENT;
  1452. }
  1453. SacPutSimpleMessage(Reboot ? SAC_RESTART_FAILURE : SAC_SHUTDOWN_FAILURE);
  1454. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1455. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1456. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRebootCommand: Exiting.\n")));
  1457. }
  1458. VOID
  1459. DoCrashCommand(
  1460. VOID
  1461. )
  1462. /*++
  1463. Routine Description:
  1464. This routine does a shutdown and bugcheck.
  1465. Arguments:
  1466. None.
  1467. Return Value:
  1468. None.
  1469. --*/
  1470. {
  1471. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCrashCommand: Entering.\n")));
  1472. //
  1473. // this call does not return
  1474. //
  1475. KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0);
  1476. // SacPutSimpleMessage( SAC_CRASHDUMP_FAILURE );
  1477. // IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCrashCommand: Exiting.\n")));
  1478. }
  1479. VOID
  1480. DoTlistCommand(
  1481. VOID
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. This routine gets a Tlist and displays it.
  1486. Arguments:
  1487. None.
  1488. Return Value:
  1489. None.
  1490. --*/
  1491. {
  1492. NTSTATUS Status;
  1493. ULONG DataLength;
  1494. PVOID NewBuffer;
  1495. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Entering.\n")));
  1496. if (GlobalBuffer == NULL) {
  1497. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1498. if (GlobalBuffer == NULL) {
  1499. SacPutSimpleMessage(SAC_NO_MEMORY);
  1500. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Exiting.\n")));
  1501. return;
  1502. }
  1503. GlobalBufferSize = MEMORY_INCREMENT;
  1504. }
  1505. RetryTList:
  1506. Status = GetTListInfo((PSAC_RSP_TLIST)GlobalBuffer,
  1507. (LONG)GlobalBufferSize,
  1508. &DataLength
  1509. );
  1510. if ((Status == STATUS_NO_MEMORY) ||
  1511. (Status == STATUS_INFO_LENGTH_MISMATCH)) {
  1512. //
  1513. // Try to get more memory, if not available, then just fail without out of memory error.
  1514. //
  1515. NewBuffer = ALLOCATE_POOL(GlobalBufferSize + MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1516. if (NewBuffer != NULL) {
  1517. FREE_POOL(&GlobalBuffer);
  1518. GlobalBuffer = NewBuffer;
  1519. GlobalBufferSize += MEMORY_INCREMENT;
  1520. goto RetryTList;
  1521. }
  1522. SacPutSimpleMessage(SAC_NO_MEMORY);
  1523. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Exiting.\n")));
  1524. return;
  1525. }
  1526. if (NT_SUCCESS(Status)) {
  1527. PrintTListInfo((PSAC_RSP_TLIST)GlobalBuffer);
  1528. } else {
  1529. SacPutSimpleMessage( SAC_TLIST_FAILURE );
  1530. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  1531. SacPutUnicodeString((PWSTR)GlobalBuffer);
  1532. }
  1533. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Exiting.\n")));
  1534. }
  1535. NTSTATUS
  1536. GetTListInfo(
  1537. OUT PSAC_RSP_TLIST ResponseBuffer,
  1538. IN LONG ResponseBufferSize,
  1539. OUT PULONG ResponseDataSize
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. This routine gets all the information necessary for the TList command.
  1544. Arguments:
  1545. ResponseBuffer - The buffer to put the results into.
  1546. ResponseBufferSize - The length of the above buffer.
  1547. ResponseDataSize - The length of the resulting buffer.
  1548. Return Value:
  1549. None.
  1550. --*/
  1551. {
  1552. NTSTATUS Status;
  1553. PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
  1554. PUCHAR DataBuffer;
  1555. PUCHAR StartProcessInfo;
  1556. LONG CurrentBufferSize;
  1557. ULONG ReturnLength;
  1558. ULONG TotalOffset;
  1559. ULONG OffsetIncrement = 0;
  1560. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  1561. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Entering.\n")));
  1562. *ResponseDataSize = 0;
  1563. if (ResponseBufferSize < sizeof(ResponseBuffer)) {
  1564. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory.\n")));
  1565. return(STATUS_NO_MEMORY);
  1566. }
  1567. DataBuffer = (PUCHAR)(ResponseBuffer + 1);
  1568. CurrentBufferSize = ResponseBufferSize - sizeof(SAC_RSP_TLIST);
  1569. if (CurrentBufferSize < 0) {
  1570. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory (2).\n")));
  1571. return STATUS_NO_MEMORY;
  1572. }
  1573. //
  1574. // Get system-wide information
  1575. //
  1576. Status = ZwQuerySystemInformation(SystemTimeOfDayInformation,
  1577. &(ResponseBuffer->TimeOfDayInfo),
  1578. sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
  1579. NULL
  1580. );
  1581. if (!NT_SUCCESS(Status)) {
  1582. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error.\n")));
  1583. return(Status);
  1584. }
  1585. Status = ZwQuerySystemInformation(SystemBasicInformation,
  1586. &(ResponseBuffer->BasicInfo),
  1587. sizeof(SYSTEM_BASIC_INFORMATION),
  1588. NULL
  1589. );
  1590. if (!NT_SUCCESS(Status)) {
  1591. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(2).\n")));
  1592. return(Status);
  1593. }
  1594. //
  1595. // Get pagefile information
  1596. //
  1597. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)DataBuffer;
  1598. Status = ZwQuerySystemInformation(SystemPageFileInformation,
  1599. PageFileInfo,
  1600. CurrentBufferSize,
  1601. &ReturnLength
  1602. );
  1603. if (NT_SUCCESS(Status) && (ReturnLength != 0)) {
  1604. ResponseBuffer->PagefileInfoOffset = ResponseBufferSize - CurrentBufferSize;
  1605. CurrentBufferSize -= ReturnLength;
  1606. DataBuffer += ReturnLength;
  1607. if (CurrentBufferSize < 0) {
  1608. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(3).\n")));
  1609. return STATUS_NO_MEMORY;
  1610. }
  1611. //
  1612. // Go thru each pagefile and fixup the names...
  1613. //
  1614. for (; ; ) {
  1615. if (PageFileInfo->PageFileName.Length > CurrentBufferSize) {
  1616. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(3).\n")));
  1617. return(STATUS_INFO_LENGTH_MISMATCH);
  1618. }
  1619. RtlCopyMemory(DataBuffer,
  1620. (PUCHAR)(PageFileInfo->PageFileName.Buffer),
  1621. PageFileInfo->PageFileName.Length
  1622. );
  1623. PageFileInfo->PageFileName.Buffer = (PWSTR)DataBuffer;
  1624. DataBuffer += PageFileInfo->PageFileName.Length;
  1625. CurrentBufferSize -= PageFileInfo->PageFileName.Length;
  1626. if (CurrentBufferSize < 0) {
  1627. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory (4).\n")));
  1628. return STATUS_NO_MEMORY;
  1629. }
  1630. if (PageFileInfo->NextEntryOffset == 0) {
  1631. break;
  1632. }
  1633. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
  1634. }
  1635. } else if (((ULONG)CurrentBufferSize) < ReturnLength) {
  1636. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(5).\n")));
  1637. return(STATUS_NO_MEMORY);
  1638. } else {
  1639. //
  1640. // Either failure or no paging file present.
  1641. //
  1642. ResponseBuffer->PagefileInfoOffset = 0;
  1643. }
  1644. //
  1645. // Get process information
  1646. //
  1647. Status = ZwQuerySystemInformation(SystemFileCacheInformation,
  1648. &(ResponseBuffer->FileCache),
  1649. sizeof(ResponseBuffer->FileCache),
  1650. NULL
  1651. );
  1652. if (!NT_SUCCESS(Status)) {
  1653. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(4).\n")));
  1654. return(Status);
  1655. }
  1656. Status = ZwQuerySystemInformation(SystemPerformanceInformation,
  1657. &(ResponseBuffer->PerfInfo),
  1658. sizeof(ResponseBuffer->PerfInfo),
  1659. NULL
  1660. );
  1661. if (!NT_SUCCESS(Status)) {
  1662. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(5).\n")));
  1663. return(Status);
  1664. }
  1665. //
  1666. // Realign DataBuffer for the next query
  1667. //
  1668. DataBuffer = ALIGN_UP_POINTER(DataBuffer, SYSTEM_PROCESS_INFORMATION);
  1669. CurrentBufferSize = (ULONG)(ResponseBufferSize - (((ULONG_PTR)DataBuffer) - ((ULONG_PTR)ResponseBuffer)));
  1670. if (CurrentBufferSize < 0) {
  1671. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory (6).\n")));
  1672. return STATUS_NO_MEMORY;
  1673. }
  1674. Status = ZwQuerySystemInformation(SystemProcessInformation,
  1675. DataBuffer,
  1676. CurrentBufferSize,
  1677. &ReturnLength
  1678. );
  1679. if (!NT_SUCCESS(Status)) {
  1680. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(6).\n")));
  1681. return(Status);
  1682. }
  1683. StartProcessInfo = DataBuffer;
  1684. ResponseBuffer->ProcessInfoOffset = ResponseBufferSize - CurrentBufferSize;
  1685. DataBuffer += ReturnLength;
  1686. CurrentBufferSize -= ReturnLength;
  1687. if (CurrentBufferSize < 0) {
  1688. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(7).\n")));
  1689. return STATUS_NO_MEMORY;
  1690. }
  1691. OffsetIncrement = 0;
  1692. TotalOffset = 0;
  1693. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)StartProcessInfo;
  1694. do {
  1695. //
  1696. // We have to take the name of each process and pack the UNICODE_STRING
  1697. // buffer in our buffer so it doesn't collide with the subsequent data
  1698. //
  1699. if (ProcessInfo->ImageName.Buffer) {
  1700. if (CurrentBufferSize < ProcessInfo->ImageName.Length ) {
  1701. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(7).\n")));
  1702. return(STATUS_INFO_LENGTH_MISMATCH);
  1703. }
  1704. RtlCopyMemory(DataBuffer, (PUCHAR)(ProcessInfo->ImageName.Buffer), ProcessInfo->ImageName.Length);
  1705. ProcessInfo->ImageName.Buffer = (PWSTR)DataBuffer;
  1706. DataBuffer += ProcessInfo->ImageName.Length;
  1707. CurrentBufferSize -= ProcessInfo->ImageName.Length;
  1708. if (CurrentBufferSize < 0) {
  1709. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(8).\n")));
  1710. return STATUS_NO_MEMORY;
  1711. }
  1712. }
  1713. if (ProcessInfo->NextEntryOffset == 0) {
  1714. break;
  1715. }
  1716. OffsetIncrement = ProcessInfo->NextEntryOffset;
  1717. TotalOffset += OffsetIncrement;
  1718. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&(StartProcessInfo[TotalOffset]);
  1719. } while( OffsetIncrement != 0 );
  1720. *ResponseDataSize = (ULONG)(ResponseBufferSize - CurrentBufferSize);
  1721. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting.\n")));
  1722. return STATUS_SUCCESS;
  1723. }
  1724. VOID
  1725. PrintTListInfo(
  1726. IN PSAC_RSP_TLIST Buffer
  1727. )
  1728. /*++
  1729. Routine Description:
  1730. This routine prints TList info to the headless terminal.
  1731. Arguments:
  1732. Buffer - The buffer with the results.
  1733. Return Value:
  1734. None.
  1735. --*/
  1736. {
  1737. LARGE_INTEGER Time;
  1738. TIME_FIELDS UserTime;
  1739. TIME_FIELDS KernelTime;
  1740. TIME_FIELDS UpTime;
  1741. ULONG TotalOffset;
  1742. ULONG OffsetIncrement = 0;
  1743. SIZE_T SumCommit;
  1744. SIZE_T SumWorkingSet;
  1745. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  1746. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  1747. PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
  1748. ULONG i;
  1749. PUCHAR ProcessInfoStart;
  1750. PUCHAR BufferStart = (PUCHAR)Buffer;
  1751. ULONG LineNumber = 0;
  1752. WCHAR OutputBuffer[200]; // should never be more than 80, but just to be safe....
  1753. UNICODE_STRING Process;
  1754. BOOLEAN Stop;
  1755. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Entering.\n")));
  1756. Time.QuadPart = Buffer->TimeOfDayInfo.CurrentTime.QuadPart - Buffer->TimeOfDayInfo.BootTime.QuadPart;
  1757. RtlTimeToElapsedTimeFields(&Time, &UpTime);
  1758. swprintf( OutputBuffer,
  1759. GetMessage( SAC_TLIST_HEADER1_FORMAT ),
  1760. Buffer->BasicInfo.NumberOfPhysicalPages * (Buffer->BasicInfo.PageSize / 1024),
  1761. UpTime.Day,
  1762. UpTime.Hour,
  1763. UpTime.Minute,
  1764. UpTime.Second,
  1765. UpTime.Milliseconds
  1766. );
  1767. SacPutUnicodeString(OutputBuffer);
  1768. LineNumber += 2;
  1769. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)(BufferStart + Buffer->PagefileInfoOffset);
  1770. //
  1771. // Print out the page file information.
  1772. //
  1773. if (Buffer->PagefileInfoOffset == 0) {
  1774. SacPutSimpleMessage(SAC_TLIST_NOPAGEFILE);
  1775. LineNumber++;
  1776. } else {
  1777. for (; ; ) {
  1778. //
  1779. // ensure that the OutputBuffer is big enough to hold the string
  1780. //
  1781. if (((wcslen(GetMessage(SAC_TLIST_PAGEFILE_NAME)) +
  1782. wcslen((PWSTR)&(PageFileInfo->PageFileName))) * sizeof(WCHAR)) > (sizeof(OutputBuffer)-2)) {
  1783. //
  1784. // Since we don't expect the pagefilename to be > 80 chars, we should stop and
  1785. // take a look at the name if this does happen
  1786. //
  1787. ASSERT(0);
  1788. //
  1789. // give up trying to print page file info
  1790. //
  1791. break;
  1792. }
  1793. swprintf( OutputBuffer,
  1794. GetMessage(SAC_TLIST_PAGEFILE_NAME),
  1795. &PageFileInfo->PageFileName);
  1796. SacPutUnicodeString(OutputBuffer);
  1797. LineNumber++;
  1798. swprintf( OutputBuffer,
  1799. GetMessage(SAC_TLIST_PAGEFILE_DATA),
  1800. PageFileInfo->TotalSize * (Buffer->BasicInfo.PageSize/1024),
  1801. PageFileInfo->TotalInUse * (Buffer->BasicInfo.PageSize/1024),
  1802. PageFileInfo->PeakUsage * (Buffer->BasicInfo.PageSize/1024)
  1803. );
  1804. SacPutUnicodeString(OutputBuffer);
  1805. LineNumber++;
  1806. if (PageFileInfo->NextEntryOffset == 0) {
  1807. break;
  1808. }
  1809. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
  1810. }
  1811. }
  1812. //
  1813. // display pmon style process output, then detailed output that includes
  1814. // per thread stuff
  1815. //
  1816. if (Buffer->ProcessInfoOffset == 0) {
  1817. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Exiting (1).\n")));
  1818. return;
  1819. }
  1820. OffsetIncrement = 0;
  1821. TotalOffset = 0;
  1822. SumCommit = 0;
  1823. SumWorkingSet = 0;
  1824. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  1825. ProcessInfoStart = (PUCHAR)ProcessInfo;
  1826. do {
  1827. SumCommit += ProcessInfo->PrivatePageCount / 1024;
  1828. SumWorkingSet += ProcessInfo->WorkingSetSize / 1024;
  1829. OffsetIncrement = ProcessInfo->NextEntryOffset;
  1830. TotalOffset += OffsetIncrement;
  1831. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart +TotalOffset);
  1832. } while( OffsetIncrement != 0 );
  1833. SumWorkingSet += Buffer->FileCache.CurrentSize/1024;
  1834. if (LineNumber > 17) {
  1835. PutMore(&Stop);
  1836. if (Stop) {
  1837. return;
  1838. }
  1839. LineNumber = 0;
  1840. }
  1841. swprintf(OutputBuffer,
  1842. GetMessage(SAC_TLIST_MEMORY1_DATA),
  1843. Buffer->BasicInfo.NumberOfPhysicalPages * (Buffer->BasicInfo.PageSize/1024),
  1844. Buffer->PerfInfo.AvailablePages * (Buffer->BasicInfo.PageSize/1024),
  1845. SumWorkingSet,
  1846. (Buffer->PerfInfo.ResidentSystemCodePage + Buffer->PerfInfo.ResidentSystemDriverPage) *
  1847. (Buffer->BasicInfo.PageSize/1024),
  1848. (Buffer->PerfInfo.ResidentPagedPoolPage) * (Buffer->BasicInfo.PageSize/1024)
  1849. );
  1850. SacPutUnicodeString(OutputBuffer);
  1851. LineNumber += 2;
  1852. if (LineNumber > 18) {
  1853. PutMore(&Stop);
  1854. if (Stop) {
  1855. return;
  1856. }
  1857. LineNumber = 0;
  1858. }
  1859. swprintf(OutputBuffer,
  1860. GetMessage(SAC_TLIST_MEMORY2_DATA),
  1861. Buffer->PerfInfo.CommittedPages * (Buffer->BasicInfo.PageSize/1024),
  1862. SumCommit,
  1863. Buffer->PerfInfo.CommitLimit * (Buffer->BasicInfo.PageSize/1024),
  1864. Buffer->PerfInfo.PeakCommitment * (Buffer->BasicInfo.PageSize/1024),
  1865. Buffer->PerfInfo.NonPagedPoolPages * (Buffer->BasicInfo.PageSize/1024),
  1866. Buffer->PerfInfo.PagedPoolPages * (Buffer->BasicInfo.PageSize/1024)
  1867. );
  1868. SacPutUnicodeString(OutputBuffer);
  1869. LineNumber++;
  1870. if (LineNumber > 18) {
  1871. PutMore(&Stop);
  1872. if (Stop) {
  1873. return;
  1874. }
  1875. LineNumber = 0;
  1876. }
  1877. SacPutSimpleMessage(SAC_ENTER);
  1878. PutMore(&Stop);
  1879. if (Stop) {
  1880. return;
  1881. }
  1882. LineNumber = 0;
  1883. SacPutSimpleMessage( SAC_TLIST_PROCESS1_HEADER );
  1884. LineNumber++;
  1885. swprintf(OutputBuffer,
  1886. GetMessage( SAC_TLIST_PROCESS2_HEADER ),
  1887. Buffer->FileCache.CurrentSize/1024,
  1888. Buffer->FileCache.PageFaultCount );
  1889. SacPutUnicodeString(OutputBuffer);
  1890. LineNumber++;
  1891. OffsetIncrement = 0;
  1892. TotalOffset = 0;
  1893. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  1894. do {
  1895. RtlTimeToElapsedTimeFields(&ProcessInfo->UserTime, &UserTime);
  1896. RtlTimeToElapsedTimeFields(&ProcessInfo->KernelTime, &KernelTime);
  1897. Process.Buffer = NULL;
  1898. if (ProcessInfo->UniqueProcessId == 0) {
  1899. RtlInitUnicodeString( &Process, L"Idle Process" );
  1900. } else if (!ProcessInfo->ImageName.Buffer) {
  1901. RtlInitUnicodeString( &Process, L"System" );
  1902. }
  1903. swprintf(OutputBuffer,
  1904. GetMessage( SAC_TLIST_PROCESS1_DATA ),
  1905. UserTime.Hour,
  1906. UserTime.Minute,
  1907. UserTime.Second,
  1908. UserTime.Milliseconds,
  1909. KernelTime.Hour,
  1910. KernelTime.Minute,
  1911. KernelTime.Second,
  1912. KernelTime.Milliseconds,
  1913. ProcessInfo->WorkingSetSize / 1024,
  1914. ProcessInfo->PageFaultCount,
  1915. ProcessInfo->PrivatePageCount / 1024,
  1916. ProcessInfo->BasePriority,
  1917. ProcessInfo->HandleCount,
  1918. ProcessInfo->NumberOfThreads,
  1919. HandleToUlong(ProcessInfo->UniqueProcessId),
  1920. Process.Buffer ? &Process : &ProcessInfo->ImageName
  1921. );
  1922. SacPutUnicodeString(OutputBuffer);
  1923. LineNumber++;
  1924. if( wcslen( OutputBuffer ) >= 80 ) {
  1925. //
  1926. // We line-wrapped, so include the additional line in our running-count.
  1927. //
  1928. LineNumber++;
  1929. }
  1930. //
  1931. // update the position in the process list before we check to see if we need
  1932. // to prompt for more. This way, if we are done, we don't prompt.
  1933. //
  1934. OffsetIncrement = ProcessInfo->NextEntryOffset;
  1935. TotalOffset += OffsetIncrement;
  1936. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart + TotalOffset);
  1937. //
  1938. // if there are more records and we have displayed a screen's worth of data
  1939. // Prompt for more and reset the line counter
  1940. //
  1941. if (( OffsetIncrement != 0 ) && (LineNumber > 18)) {
  1942. PutMore(&Stop);
  1943. if (Stop) {
  1944. return;
  1945. }
  1946. LineNumber = 0;
  1947. if (GlobalPagingNeeded) {
  1948. SacPutSimpleMessage( SAC_TLIST_PROCESS1_HEADER );
  1949. }
  1950. LineNumber++;
  1951. }
  1952. } while( OffsetIncrement != 0 );
  1953. if (!GlobalDoThreads) {
  1954. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Exiting (2).\n")));
  1955. return;
  1956. }
  1957. //
  1958. // Beginning of normal old style pstat output
  1959. //
  1960. TotalOffset = 0;
  1961. OffsetIncrement = 0;
  1962. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  1963. PutMore(&Stop);
  1964. if (Stop) {
  1965. return;
  1966. }
  1967. LineNumber = 0;
  1968. SacPutSimpleMessage(SAC_ENTER);
  1969. LineNumber++;
  1970. do {
  1971. Process.Buffer = NULL;
  1972. if (ProcessInfo->UniqueProcessId == 0) {
  1973. RtlInitUnicodeString( &Process, L"Idle Process" );
  1974. } else if (!ProcessInfo->ImageName.Buffer) {
  1975. RtlInitUnicodeString( &Process, L"System" );
  1976. }
  1977. swprintf(OutputBuffer,
  1978. GetMessage(SAC_TLIST_PSTAT_HEADER),
  1979. HandleToUlong(ProcessInfo->UniqueProcessId),
  1980. ProcessInfo->BasePriority,
  1981. ProcessInfo->HandleCount,
  1982. ProcessInfo->PageFaultCount,
  1983. ProcessInfo->WorkingSetSize / 1024,
  1984. Process.Buffer ? &Process : &ProcessInfo->ImageName
  1985. );
  1986. SacPutUnicodeString(OutputBuffer);
  1987. LineNumber++;
  1988. if( wcslen( OutputBuffer ) >= 80 ) {
  1989. //
  1990. // We line-wrapped, so include the additional line in our running-count.
  1991. //
  1992. LineNumber++;
  1993. }
  1994. if (LineNumber > 18) {
  1995. PutMore(&Stop);
  1996. if (Stop) {
  1997. return;
  1998. }
  1999. LineNumber = 0;
  2000. }
  2001. i = 0;
  2002. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  2003. if (ProcessInfo->NumberOfThreads) {
  2004. if ((LineNumber < 18) || !GlobalPagingNeeded) {
  2005. SacPutSimpleMessage( SAC_TLIST_PSTAT_THREAD_HEADER );
  2006. LineNumber++;
  2007. } else {
  2008. PutMore(&Stop);
  2009. if (Stop) {
  2010. return;
  2011. }
  2012. LineNumber = 0;
  2013. }
  2014. }
  2015. while (i < ProcessInfo->NumberOfThreads) {
  2016. RtlTimeToElapsedTimeFields ( &ThreadInfo->UserTime, &UserTime);
  2017. RtlTimeToElapsedTimeFields ( &ThreadInfo->KernelTime, &KernelTime);
  2018. swprintf(OutputBuffer,
  2019. GetMessage( SAC_TLIST_PSTAT_THREAD_DATA ),
  2020. ProcessInfo->UniqueProcessId == 0 ? 0 : HandleToUlong(ThreadInfo->ClientId.UniqueThread),
  2021. ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->Priority,
  2022. ThreadInfo->ContextSwitches,
  2023. ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->StartAddress,
  2024. UserTime.Hour,
  2025. UserTime.Minute,
  2026. UserTime.Second,
  2027. UserTime.Milliseconds,
  2028. KernelTime.Hour,
  2029. KernelTime.Minute,
  2030. KernelTime.Second,
  2031. KernelTime.Milliseconds,
  2032. StateTable[ThreadInfo->ThreadState],
  2033. (ThreadInfo->ThreadState == 5) ? WaitTable[ThreadInfo->WaitReason] : Empty
  2034. );
  2035. SacPutUnicodeString(OutputBuffer);
  2036. LineNumber++;
  2037. if( wcslen( OutputBuffer ) >= 80 ) {
  2038. //
  2039. // We line-wrapped, so include the additional line in our running-count.
  2040. //
  2041. LineNumber++;
  2042. }
  2043. if (LineNumber > 18) {
  2044. PutMore(&Stop);
  2045. if (Stop) {
  2046. return;
  2047. }
  2048. LineNumber = 0;
  2049. if (GlobalPagingNeeded) {
  2050. SacPutSimpleMessage( SAC_TLIST_PSTAT_THREAD_HEADER );
  2051. }
  2052. LineNumber++;
  2053. }
  2054. ThreadInfo += 1;
  2055. i += 1;
  2056. }
  2057. OffsetIncrement = ProcessInfo->NextEntryOffset;
  2058. TotalOffset += OffsetIncrement;
  2059. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart + TotalOffset);
  2060. SacPutSimpleMessage(SAC_ENTER);
  2061. LineNumber++;
  2062. if (LineNumber > 18) {
  2063. PutMore(&Stop);
  2064. if (Stop) {
  2065. return;
  2066. }
  2067. LineNumber = 0;
  2068. }
  2069. } while( OffsetIncrement != 0 );
  2070. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Exiting.\n")));
  2071. }
  2072. VOID
  2073. PutMore(
  2074. OUT PBOOLEAN Stop
  2075. )
  2076. {
  2077. PHEADLESS_RSP_GET_LINE Response;
  2078. UCHAR Buffer[20];
  2079. SIZE_T Length;
  2080. LARGE_INTEGER WaitTime;
  2081. NTSTATUS Status;
  2082. ASSERT(sizeof(HEADLESS_RSP_GET_LINE) <= (sizeof(UCHAR) * 20));
  2083. if (GlobalPagingNeeded) {
  2084. WaitTime.QuadPart = Int32x32To64((LONG)100, -1000); // 100ms from now.
  2085. SacPutSimpleMessage( SAC_MORE_MESSAGE );
  2086. Response = (PHEADLESS_RSP_GET_LINE)&(Buffer[0]);
  2087. Length = sizeof(UCHAR) * 20;
  2088. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2089. NULL,
  2090. 0,
  2091. Response,
  2092. &Length
  2093. );
  2094. while (NT_SUCCESS(Status) && !Response->LineComplete) {
  2095. KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
  2096. Length = sizeof(UCHAR) * 20;
  2097. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2098. NULL,
  2099. 0,
  2100. Response,
  2101. &Length
  2102. );
  2103. }
  2104. if (Response->Buffer[0] == 0x3) { // Control-C
  2105. *Stop = TRUE;
  2106. } else {
  2107. *Stop = FALSE;
  2108. }
  2109. //
  2110. // Drain any remaining buffered input
  2111. //
  2112. Length = sizeof(UCHAR) * 20;
  2113. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2114. NULL,
  2115. 0,
  2116. Response,
  2117. &Length
  2118. );
  2119. while (NT_SUCCESS(Status) && Response->LineComplete) {
  2120. Length = sizeof(UCHAR) * 20;
  2121. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2122. NULL,
  2123. 0,
  2124. Response,
  2125. &Length
  2126. );
  2127. }
  2128. } else {
  2129. *Stop = FALSE;
  2130. }
  2131. }
  2132. NTSTATUS
  2133. CallQueryIPIOCTL(
  2134. HANDLE IpDeviceHandle,
  2135. PKEVENT Event,
  2136. HANDLE EventHandle,
  2137. IO_STATUS_BLOCK *IoStatusBlock,
  2138. PVOID InputBuffer,
  2139. ULONG InputBufferSize,
  2140. PVOID OutputBuffer,
  2141. ULONG OutputBufferSize,
  2142. BOOLEAN PrintToTerminal,
  2143. BOOLEAN *putPrompt
  2144. )
  2145. {
  2146. NTSTATUS Status;
  2147. LARGE_INTEGER TimeOut;
  2148. //
  2149. // Submit the IOCTL
  2150. //
  2151. Status = NtDeviceIoControlFile(IpDeviceHandle,
  2152. EventHandle,
  2153. NULL,
  2154. NULL,
  2155. IoStatusBlock,
  2156. IOCTL_TCP_QUERY_INFORMATION_EX,
  2157. InputBuffer,
  2158. InputBufferSize,
  2159. OutputBuffer,
  2160. OutputBufferSize);
  2161. if (Status == STATUS_PENDING) {
  2162. //
  2163. // Wait up to 30 seconds for it to finish
  2164. //
  2165. if (PrintToTerminal != FALSE) {
  2166. SacPutSimpleMessage( SAC_ENTER );
  2167. SacPutSimpleMessage( SAC_RETRIEVING_IPADDR );
  2168. if (putPrompt) {
  2169. *putPrompt= TRUE;
  2170. }
  2171. }
  2172. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  2173. Status = KeWaitForSingleObject((PVOID)Event, Executive, KernelMode, FALSE, &TimeOut);
  2174. if (NT_SUCCESS(Status)) {
  2175. Status = IoStatusBlock->Status;
  2176. }
  2177. }
  2178. return(Status);
  2179. }
  2180. VOID
  2181. DoGetNetInfo(
  2182. BOOLEAN PrintToTerminal
  2183. )
  2184. /*++
  2185. Routine Description:
  2186. This routine attempts to get and print every IP net number and its IP
  2187. address.
  2188. Arguments:
  2189. PrintToTerminal - Determines if the IP information is printed ( == TRUE )
  2190. Or sent to the kernel ( == FALSE )
  2191. Return Value:
  2192. None.
  2193. --*/
  2194. {
  2195. NTSTATUS Status;
  2196. HANDLE Handle;
  2197. ULONG i;
  2198. IO_STATUS_BLOCK IoStatusBlock;
  2199. UNICODE_STRING UnicodeString;
  2200. OBJECT_ATTRIBUTES ObjectAttributes;
  2201. PTCP_REQUEST_QUERY_INFORMATION_EX TcpRequestQueryInformationEx;
  2202. IPAddrEntry *AddressEntry,*AddressArray;
  2203. IPSNMPInfo *IpsiInfo;
  2204. PHEADLESS_CMD_SET_BLUE_SCREEN_DATA LocalPropBuffer = NULL;
  2205. PVOID LocalBuffer;
  2206. PUCHAR pch = NULL;
  2207. ULONG len;
  2208. BOOLEAN putPrompt=FALSE;
  2209. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Entering.\n")));
  2210. //
  2211. // Alloc space for calling the IP driver
  2212. //
  2213. TcpRequestQueryInformationEx = ALLOCATE_POOL(
  2214. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2215. GENERAL_POOL_TAG );
  2216. if (TcpRequestQueryInformationEx == NULL) {
  2217. SacPutSimpleMessage(SAC_NO_MEMORY);
  2218. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (1).\n")));
  2219. return;
  2220. }
  2221. IpsiInfo = ALLOCATE_POOL( sizeof(IPSNMPInfo),
  2222. GENERAL_POOL_TAG );
  2223. if (IpsiInfo == NULL) {
  2224. SacPutSimpleMessage(SAC_NO_MEMORY);
  2225. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (1).\n")));
  2226. FREE_POOL(&TcpRequestQueryInformationEx);
  2227. return;
  2228. }
  2229. //
  2230. // zero out the context information and preload with the info we're gonna
  2231. // request (we want the count of interfaces)
  2232. //
  2233. RtlZeroMemory(TcpRequestQueryInformationEx, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  2234. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_STATS_ID;
  2235. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  2236. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  2237. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2238. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  2239. LocalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  2240. if (LocalBuffer == NULL) {
  2241. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (6).\n")));
  2242. FREE_POOL(&TcpRequestQueryInformationEx);
  2243. FREE_POOL(&IpsiInfo);
  2244. return;
  2245. }
  2246. //
  2247. // Start by opening the TCP driver
  2248. //
  2249. RtlInitUnicodeString(&UnicodeString, DD_TCP_DEVICE_NAME);
  2250. InitializeObjectAttributes(&ObjectAttributes,
  2251. &UnicodeString,
  2252. OBJ_CASE_INSENSITIVE,
  2253. NULL,
  2254. NULL
  2255. );
  2256. Status = ZwOpenFile(&Handle,
  2257. (ACCESS_MASK)FILE_GENERIC_READ,
  2258. &ObjectAttributes,
  2259. &IoStatusBlock,
  2260. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2261. 0
  2262. );
  2263. if (!NT_SUCCESS(Status)) {
  2264. if (PrintToTerminal ) {
  2265. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2266. SacPutSimpleMessage(SAC_ENTER);
  2267. }
  2268. FREE_POOL(&LocalBuffer);
  2269. FREE_POOL(&IpsiInfo);
  2270. FREE_POOL(&TcpRequestQueryInformationEx);
  2271. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (2).\n")));
  2272. return;
  2273. }
  2274. if (SACEvent == NULL) {
  2275. if (PrintToTerminal) {
  2276. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2277. }
  2278. ZwClose(Handle);
  2279. FREE_POOL(&LocalBuffer);
  2280. FREE_POOL(&IpsiInfo);
  2281. FREE_POOL(&TcpRequestQueryInformationEx);
  2282. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (14).\n")));
  2283. return;
  2284. }
  2285. //
  2286. // now call the ioctl
  2287. //
  2288. Status = CallQueryIPIOCTL(
  2289. Handle,
  2290. SACEvent,
  2291. SACEventHandle,
  2292. &IoStatusBlock,
  2293. TcpRequestQueryInformationEx,
  2294. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2295. IpsiInfo,
  2296. sizeof(IPSNMPInfo),
  2297. FALSE,
  2298. &putPrompt);
  2299. if (!NT_SUCCESS(Status)) {
  2300. if (PrintToTerminal){
  2301. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2302. }
  2303. ZwClose(Handle);
  2304. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2305. FREE_POOL(&LocalBuffer);
  2306. FREE_POOL(&IpsiInfo);
  2307. FREE_POOL(&TcpRequestQueryInformationEx);
  2308. return;
  2309. }
  2310. if (IpsiInfo->ipsi_numaddr == 0) {
  2311. if (PrintToTerminal) {
  2312. SacPutSimpleMessage( SAC_IPADDR_NONE );
  2313. }
  2314. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2315. ZwClose(Handle);
  2316. FREE_POOL(&LocalBuffer);
  2317. FREE_POOL(&IpsiInfo);
  2318. FREE_POOL(&TcpRequestQueryInformationEx);
  2319. return;
  2320. }
  2321. //
  2322. // if it succeeded, then allocate space for the array of IP addresses
  2323. //
  2324. AddressArray = ALLOCATE_POOL(IpsiInfo->ipsi_numaddr*sizeof(IPAddrEntry),
  2325. GENERAL_POOL_TAG);
  2326. if (AddressArray == NULL) {
  2327. SacPutSimpleMessage(SAC_NO_MEMORY);
  2328. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (16).\n")));
  2329. ZwClose(Handle);
  2330. FREE_POOL(&LocalBuffer);
  2331. FREE_POOL(&IpsiInfo);
  2332. FREE_POOL(&TcpRequestQueryInformationEx);
  2333. return;
  2334. }
  2335. //
  2336. // zero out the context information and preload with the info we're gonna
  2337. // request (we want the count of interfaces)
  2338. //
  2339. RtlZeroMemory(TcpRequestQueryInformationEx, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  2340. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  2341. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  2342. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  2343. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2344. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  2345. Status = CallQueryIPIOCTL(
  2346. Handle,
  2347. SACEvent,
  2348. SACEventHandle,
  2349. &IoStatusBlock,
  2350. TcpRequestQueryInformationEx,
  2351. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2352. AddressArray,
  2353. IpsiInfo->ipsi_numaddr*sizeof(IPAddrEntry),
  2354. PrintToTerminal,
  2355. &putPrompt);
  2356. //
  2357. // don't need this anymore
  2358. //
  2359. FREE_POOL(&TcpRequestQueryInformationEx);
  2360. ZwClose(Handle);
  2361. if (!NT_SUCCESS(Status)) {
  2362. if (PrintToTerminal){
  2363. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2364. swprintf((PWSTR)LocalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR), Status);
  2365. SacPutUnicodeString((PWSTR)LocalBuffer);
  2366. }
  2367. FREE_POOL(&LocalBuffer);
  2368. FREE_POOL(&AddressArray);
  2369. FREE_POOL(&IpsiInfo);
  2370. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2371. return;
  2372. }
  2373. //
  2374. // Need to allocate a buffer for the XML data.
  2375. //
  2376. if(PrintToTerminal==FALSE) {
  2377. LocalPropBuffer = (PHEADLESS_CMD_SET_BLUE_SCREEN_DATA) ALLOCATE_POOL(2*MEMORY_INCREMENT, GENERAL_POOL_TAG);
  2378. if (LocalPropBuffer == NULL) {
  2379. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (6).\n")));
  2380. FREE_POOL(&AddressArray);
  2381. FREE_POOL(&IpsiInfo);
  2382. return;
  2383. }
  2384. pch = &(LocalPropBuffer->Data[0]);
  2385. len = sprintf((LPSTR)pch,"IPADDRESS");
  2386. LocalPropBuffer->ValueIndex = len+1;
  2387. pch = pch+len+1;
  2388. len = sprintf((LPSTR)pch,"\r\n<PROPERTY.ARRAY NAME=\"IPADDRESS\" TYPE=\"string\">\r\n");
  2389. pch = pch + len;
  2390. len = sprintf((LPSTR)pch,"<VALUE.ARRAY>\r\n");
  2391. pch = pch + len;
  2392. }
  2393. //
  2394. // walk the list of IP addresses and spit out the data
  2395. //
  2396. for (i = 0; i < IpsiInfo->ipsi_numaddr; i++) {
  2397. AddressEntry = &AddressArray[i];
  2398. if (IP_LOOPBACK(AddressEntry->iae_addr)) {
  2399. continue;
  2400. }
  2401. if(PrintToTerminal){
  2402. swprintf(LocalBuffer,
  2403. GetMessage( SAC_IPADDR_DATA ),
  2404. AddressEntry->iae_context,
  2405. AddressEntry->iae_addr & 0xFF,
  2406. (AddressEntry->iae_addr >> 8) & 0xFF,
  2407. (AddressEntry->iae_addr >> 16) & 0xFF,
  2408. (AddressEntry->iae_addr >> 24) & 0xFF,
  2409. AddressEntry->iae_mask & 0xFF,
  2410. (AddressEntry->iae_mask >> 8) & 0xFF,
  2411. (AddressEntry->iae_mask >> 16) & 0xFF,
  2412. (AddressEntry->iae_mask >> 24) & 0xFF
  2413. );
  2414. SacPutUnicodeString(LocalBuffer);
  2415. } else {
  2416. len=sprintf((LPSTR)LocalBuffer,"<VALUE>\"%d.%d.%d.%d\"</VALUE>\r\n",
  2417. AddressEntry->iae_addr & 0xFF,
  2418. (AddressEntry->iae_addr >> 8) & 0xFF,
  2419. (AddressEntry->iae_addr >> 16) & 0xFF,
  2420. (AddressEntry->iae_addr >> 24) & 0xFF
  2421. );
  2422. if (pch + len < ((PUCHAR) LocalPropBuffer) + 2*MEMORY_INCREMENT - 80){
  2423. // the 80 characters ensures that we can end this XML data
  2424. // properly
  2425. strcat((LPSTR)pch,LocalBuffer);
  2426. pch = pch + len;
  2427. }
  2428. }
  2429. }
  2430. if(PrintToTerminal==FALSE) {
  2431. sprintf((LPSTR)pch, "</VALUE.ARRAY>\r\n</PROPERTY.ARRAY>");
  2432. }
  2433. FREE_POOL(&AddressArray);
  2434. FREE_POOL(&IpsiInfo);
  2435. if(!PrintToTerminal){
  2436. HeadlessDispatch(HeadlessCmdSetBlueScreenData,
  2437. LocalPropBuffer,
  2438. 2*MEMORY_INCREMENT,
  2439. NULL,
  2440. NULL
  2441. );
  2442. FREE_POOL(&LocalPropBuffer);
  2443. //
  2444. // open up the IP driver so we know if the addresses change
  2445. //
  2446. RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
  2447. InitializeObjectAttributes(&ObjectAttributes,
  2448. &UnicodeString,
  2449. OBJ_CASE_INSENSITIVE,
  2450. NULL,
  2451. NULL
  2452. );
  2453. Status = ZwOpenFile(&Handle,
  2454. (ACCESS_MASK)FILE_GENERIC_READ,
  2455. &ObjectAttributes,
  2456. &IoStatusBlock,
  2457. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2458. 0
  2459. );
  2460. if (!NT_SUCCESS(Status)) {
  2461. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (2).\n")));
  2462. return;
  2463. }
  2464. Status = ZwDeviceIoControlFile(Handle,
  2465. NULL,
  2466. NetAPCRoutine,
  2467. NULL,
  2468. &GlobalIoStatusBlock,
  2469. IOCTL_IP_ADDCHANGE_NOTIFY_REQUEST,
  2470. NULL,
  2471. 0,
  2472. NULL,
  2473. 0
  2474. );
  2475. if (Status == STATUS_PENDING) {
  2476. IoctlSubmitted = TRUE;
  2477. }
  2478. if (putPrompt) {
  2479. SacPutSimpleMessage(SAC_ENTER);
  2480. SacPutSimpleMessage(SAC_PROMPT);
  2481. }
  2482. }
  2483. ZwClose(Handle);
  2484. return;
  2485. }
  2486. VOID
  2487. NetAPCRoutine(IN PVOID ApcContext,
  2488. IN PIO_STATUS_BLOCK IoStatusBlock,
  2489. IN ULONG Reserved
  2490. )
  2491. /*++
  2492. Routine Description:
  2493. This is the APC routine called after IOCTL_IP_ADDCHANGE_NOTIFY_REQUEST
  2494. was completed
  2495. Arguments:
  2496. APCContext - UNUSED
  2497. IoStatusBlock - Status about the Fate of the IRP
  2498. Reserved - UNUSED
  2499. Return Value:
  2500. None.
  2501. --*/
  2502. {
  2503. UNREFERENCED_PARAMETER(Reserved);
  2504. UNREFERENCED_PARAMETER(ApcContext);
  2505. if (IoStatusBlock->Status == STATUS_CANCELLED) {
  2506. // The SAC driver might be unloading
  2507. // BUGBUG - If the IP driver is stopped and restarted
  2508. // then we are out of the loop. What to do ??
  2509. return;
  2510. }
  2511. // Refresh the kernel information and resend the IRP
  2512. DoGetNetInfo( FALSE );
  2513. return;
  2514. }
  2515. VOID
  2516. SubmitIPIoRequest(
  2517. )
  2518. /*++
  2519. Routine Description:
  2520. Called the first time by the Processing Thread to actually
  2521. submit the ADDR_CHANGE IOCTL to the IP Driver. Only the
  2522. processing thread can call this and calls it only once successfully.
  2523. Then on the APC is reentered only through the NetAPCRoutine
  2524. Arguments:
  2525. None.
  2526. Return Value:
  2527. None.
  2528. --*/
  2529. {
  2530. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  2531. KdPrint(("SAC Submit IP Ioctl: Entering.\n")));
  2532. DoGetNetInfo( FALSE );
  2533. return;
  2534. }
  2535. VOID
  2536. CancelIPIoRequest(
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. Called by the processing thread during unload of the driver
  2541. to cancel the IOCTL sent to the IP driver
  2542. Arguments:
  2543. None.
  2544. Return Value:
  2545. None.
  2546. --*/
  2547. {
  2548. IO_STATUS_BLOCK IoStatusBlock;
  2549. UNICODE_STRING UnicodeString;
  2550. OBJECT_ATTRIBUTES ObjectAttributes;
  2551. NTSTATUS Status;
  2552. HANDLE Handle;
  2553. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  2554. KdPrint(("SAC Cancel IP Ioctl: Entering.\n")));
  2555. RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
  2556. InitializeObjectAttributes(&ObjectAttributes,
  2557. &UnicodeString,
  2558. OBJ_CASE_INSENSITIVE,
  2559. NULL,
  2560. NULL
  2561. );
  2562. Status = ZwOpenFile(&Handle,
  2563. (ACCESS_MASK)FILE_GENERIC_READ,
  2564. &ObjectAttributes,
  2565. &IoStatusBlock,
  2566. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2567. 0
  2568. );
  2569. if (!NT_SUCCESS(Status)) {
  2570. // Well, well IP Driver was probably never loaded.
  2571. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC Cancel IP IOCTL: Exiting (2).\n")));
  2572. return;
  2573. }
  2574. ZwCancelIoFile(Handle,
  2575. &IoStatusBlock
  2576. );
  2577. ZwClose(Handle);
  2578. }
  2579. VOID
  2580. DoMachineInformationCommand(
  2581. VOID
  2582. )
  2583. /*++
  2584. Routine Description:
  2585. This function displays the contents of a buffer, which in turn contains
  2586. a bunch of machine-specific information that can be used to help identify
  2587. the machine.
  2588. Arguments:
  2589. None.
  2590. Return Value:
  2591. None.
  2592. --*/
  2593. {
  2594. LARGE_INTEGER TickCount;
  2595. LARGE_INTEGER ElapsedTime;
  2596. ULONG ElapsedHours = 0;
  2597. ULONG ElapsedMinutes = 0;
  2598. ULONG ElapsedSeconds = 0;
  2599. PWSTR TmpBuffer;
  2600. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  2601. KdPrint(("SAC Display Machine Information: Entering.\n")));
  2602. //
  2603. // If the information buffer hasn't been filled in yet, there's not much we can do.
  2604. //
  2605. if( MachineInformationBuffer == NULL ) {
  2606. //
  2607. // He's empty. This shouldn't have happened though because
  2608. // he gets filled as soon as we're initialized.
  2609. //
  2610. IF_SAC_DEBUG( SAC_DEBUG_FUNC_TRACE_LOUD,
  2611. KdPrint(("SAC Display Machine Information: MachineInformationBuffer hasn't been initialized yet.\n")));
  2612. SacPutSimpleMessage(SAC_IDENTIFICATION_UNAVAILABLE);
  2613. return;
  2614. }
  2615. //
  2616. // Static information about ourselves.
  2617. //
  2618. SacPutUnicodeString((PWSTR)MachineInformationBuffer);
  2619. //
  2620. // Elapsed machine uptime.
  2621. //
  2622. // Elapsed TickCount
  2623. KeQueryTickCount( &TickCount );
  2624. // ElapsedTime in seconds.
  2625. ElapsedTime.QuadPart = (TickCount.QuadPart)/(10000000/KeQueryTimeIncrement());
  2626. ElapsedHours = (ULONG)(ElapsedTime.QuadPart / 3600);
  2627. ElapsedMinutes = (ULONG)(ElapsedTime.QuadPart % 3600) / 60;
  2628. ElapsedSeconds = (ULONG)(ElapsedTime.QuadPart % 3600) % 60;
  2629. TmpBuffer = (PWSTR)ALLOCATE_POOL( 0x100, GENERAL_POOL_TAG );
  2630. if( TmpBuffer ) {
  2631. swprintf( (PWSTR)TmpBuffer,
  2632. GetMessage( SAC_HEARTBEAT_FORMAT ),
  2633. ElapsedHours,
  2634. ElapsedMinutes,
  2635. ElapsedSeconds );
  2636. SacPutUnicodeString( (PWSTR)TmpBuffer );
  2637. FREE_POOL( &TmpBuffer );
  2638. }
  2639. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  2640. KdPrint(("SAC Display Machine Information: Exiting.\n")));
  2641. return;
  2642. }