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.

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