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.

5002 lines
137 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. #define SAC_PUT_ERROR_STRING(_Status)\
  20. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_FAILURE_WITH_ERROR ) , _Status); \
  21. SacPutString((PWSTR)GlobalBuffer);
  22. //
  23. // Forward declarations.
  24. //
  25. NTSTATUS
  26. GetTListInfo(
  27. OUT PSAC_RSP_TLIST ResponseBuffer,
  28. IN LONG ResponseBufferSize,
  29. OUT PULONG ResponseDataSize
  30. );
  31. VOID
  32. PrintTListInfo(
  33. IN PSAC_RSP_TLIST Buffer
  34. );
  35. VOID
  36. PutMore(
  37. OUT PBOOLEAN Stop
  38. );
  39. VOID
  40. DoGetNetInfo(
  41. IN BOOLEAN PrintToTerminal
  42. );
  43. VOID
  44. NetAPCRoutine(IN PVOID ApcContext,
  45. IN PIO_STATUS_BLOCK IoStatusBlock,
  46. IN ULONG Reserved
  47. );
  48. NTSTATUS
  49. CallQueryIPIOCTL(
  50. HANDLE IpDeviceHandle,
  51. PKEVENT Event,
  52. HANDLE EventHandle,
  53. IO_STATUS_BLOCK *IoStatusBlock,
  54. PVOID InputBuffer,
  55. ULONG InputBufferSize,
  56. PVOID OutputBuffer,
  57. ULONG OutputBufferSize,
  58. BOOLEAN PrintToTerminal,
  59. BOOLEAN *putPrompt
  60. );
  61. //
  62. // The purpose of this macro is to provide implicit "more-ing"
  63. // when printing arbitrarily localized text.
  64. //
  65. #define SAC_PRINT_WITH_MORE(_m)\
  66. { \
  67. ULONG c; \
  68. BOOLEAN Stop; \
  69. c = GetMessageLineCount(_m); \
  70. if ((c + LineNumber) > SAC_VTUTF8_ROW_HEIGHT) { \
  71. PutMore(&Stop); \
  72. if (Stop) { \
  73. break; \
  74. } \
  75. LineNumber = 0; \
  76. } \
  77. SacPutSimpleMessage( _m ); \
  78. LineNumber += c; \
  79. }
  80. VOID
  81. DoHelpCommand(
  82. VOID
  83. )
  84. /*++
  85. Routine Description:
  86. This routine displays the help text on the terminal.
  87. Arguments:
  88. None.
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. ULONG LineNumber;
  94. LineNumber = 0;
  95. do {
  96. SAC_PRINT_WITH_MORE(SAC_HELP_CH_CMD);
  97. SAC_PRINT_WITH_MORE( SAC_HELP_CMD_CMD );
  98. SAC_PRINT_WITH_MORE( SAC_HELP_D_CMD );
  99. SAC_PRINT_WITH_MORE( SAC_HELP_F_CMD );
  100. SAC_PRINT_WITH_MORE( SAC_HELP_HELP_CMD );
  101. SAC_PRINT_WITH_MORE( SAC_HELP_I1_CMD );
  102. SAC_PRINT_WITH_MORE( SAC_HELP_I2_CMD );
  103. SAC_PRINT_WITH_MORE( SAC_HELP_IDENTIFICATION_CMD );
  104. SAC_PRINT_WITH_MORE( SAC_HELP_K_CMD );
  105. SAC_PRINT_WITH_MORE( SAC_HELP_L_CMD );
  106. #if ENABLE_CHANNEL_LOCKING
  107. SAC_PRINT_WITH_MORE( SAC_HELP_LOCK_CMD );
  108. #endif
  109. SAC_PRINT_WITH_MORE( SAC_HELP_M_CMD );
  110. SAC_PRINT_WITH_MORE( SAC_HELP_P_CMD );
  111. SAC_PRINT_WITH_MORE( SAC_HELP_R_CMD );
  112. SAC_PRINT_WITH_MORE( SAC_HELP_S1_CMD );
  113. SAC_PRINT_WITH_MORE( SAC_HELP_S2_CMD );
  114. SAC_PRINT_WITH_MORE( SAC_HELP_T_CMD );
  115. SAC_PRINT_WITH_MORE( SAC_HELP_RESTART_CMD );
  116. SAC_PRINT_WITH_MORE( SAC_HELP_SHUTDOWN_CMD );
  117. SAC_PRINT_WITH_MORE( SAC_HELP_CRASHDUMP1_CMD );
  118. } while ( FALSE );
  119. }
  120. VOID
  121. DoFullInfoCommand(
  122. VOID
  123. )
  124. /*++
  125. Routine Description:
  126. This routine toggles on and off full thread information on tlist.
  127. Arguments:
  128. None.
  129. Return Value:
  130. None.
  131. --*/
  132. {
  133. GlobalDoThreads = (BOOLEAN)!GlobalDoThreads;
  134. if (GlobalDoThreads) {
  135. SacPutSimpleMessage(SAC_THREAD_ON);
  136. } else {
  137. SacPutSimpleMessage(SAC_THREAD_OFF);
  138. }
  139. }
  140. VOID
  141. DoPagingCommand(
  142. VOID
  143. )
  144. /*++
  145. Routine Description:
  146. This routine toggles on and off paging information on tlist.
  147. Arguments:
  148. None.
  149. Return Value:
  150. None.
  151. --*/
  152. {
  153. GlobalPagingNeeded = (BOOLEAN)!GlobalPagingNeeded;
  154. if (GlobalPagingNeeded) {
  155. SacPutSimpleMessage(SAC_PAGING_ON);
  156. } else {
  157. SacPutSimpleMessage(SAC_PAGING_OFF);
  158. }
  159. }
  160. VOID
  161. DoSetTimeCommand(
  162. PUCHAR InputLine
  163. )
  164. /*++
  165. Routine Description:
  166. This routine sets the current system time.
  167. Arguments:
  168. InputLine - The users input line to parse.
  169. Return Value:
  170. None.
  171. --*/
  172. {
  173. NTSTATUS Status;
  174. PUCHAR pch = InputLine;
  175. PUCHAR pchTmp;
  176. TIME_FIELDS TimeFields;
  177. LARGE_INTEGER Time;
  178. SYSTEM_TIMEOFDAY_INFORMATION TimeOfDay;
  179. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Entering.\n")));
  180. //
  181. // Get the global buffer started so that we have room for error messages.
  182. //
  183. if (GlobalBuffer == NULL) {
  184. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  185. if (GlobalBuffer == NULL) {
  186. SacPutSimpleMessage(SAC_NO_MEMORY);
  187. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (1).\n")));
  188. return;
  189. }
  190. GlobalBufferSize = MEMORY_INCREMENT;
  191. }
  192. RtlZeroMemory(&TimeFields, sizeof(TIME_FIELDS));
  193. //
  194. // Skip the command.
  195. //
  196. pch += (sizeof(TIME_COMMAND_STRING) - sizeof(UCHAR));
  197. SKIP_WHITESPACE(pch);
  198. if (*pch == '\0') {
  199. //
  200. // This is a display time request.
  201. //
  202. Status = ZwQuerySystemInformation(SystemTimeOfDayInformation,
  203. &TimeOfDay,
  204. sizeof(TimeOfDay),
  205. NULL
  206. );
  207. if (!NT_SUCCESS(Status)) {
  208. SAC_PUT_ERROR_STRING(Status);
  209. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (2).\n")));
  210. return;
  211. }
  212. RtlTimeToTimeFields(&(TimeOfDay.CurrentTime), &TimeFields);
  213. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_DATETIME_FORMAT ),
  214. TimeFields.Month,
  215. TimeFields.Day,
  216. TimeFields.Year,
  217. TimeFields.Hour,
  218. TimeFields.Minute,
  219. TimeFields.Second,
  220. TimeFields.Milliseconds
  221. );
  222. SacPutString((PWSTR)GlobalBuffer);
  223. return;
  224. }
  225. pchTmp = pch;
  226. if (!IS_NUMBER(*pchTmp)) {
  227. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  228. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (3).\n")));
  229. return;
  230. }
  231. //
  232. // Skip all the numbers.
  233. //
  234. SKIP_NUMBERS(pchTmp);
  235. SKIP_WHITESPACE(pchTmp);
  236. //
  237. // If there is something other than the divider, it is a mal-formed line.
  238. //
  239. if (*pchTmp != '/') {
  240. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  241. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (4).\n")));
  242. return;
  243. }
  244. *pchTmp = '\0';
  245. pchTmp++;
  246. TimeFields.Month = (USHORT)(atoi((LPCSTR)pch));
  247. pch = pchTmp;
  248. SKIP_WHITESPACE(pchTmp);
  249. if (!IS_NUMBER(*pchTmp)) {
  250. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  251. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (4b).\n")));
  252. return;
  253. }
  254. //
  255. // Skip all the numbers.
  256. //
  257. SKIP_NUMBERS(pchTmp);
  258. SKIP_WHITESPACE(pchTmp);
  259. //
  260. // If there is something other than the divider, it is a mal-formed line.
  261. //
  262. if (*pchTmp != '/') {
  263. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  264. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (5).\n")));
  265. return;
  266. }
  267. *pchTmp = '\0';
  268. pchTmp++;
  269. TimeFields.Day = (USHORT)(atoi((LPCSTR)pch));
  270. pch = pchTmp;
  271. SKIP_WHITESPACE(pchTmp);
  272. if (!IS_NUMBER(*pchTmp)) {
  273. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  274. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (5b).\n")));
  275. return;
  276. }
  277. //
  278. // Skip all the numbers.
  279. //
  280. SKIP_NUMBERS(pchTmp);
  281. //
  282. // If there is something other than whitespace, it is a mal-formed line.
  283. //
  284. if (!IS_WHITESPACE(*pchTmp)) {
  285. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  286. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (6).\n")));
  287. return;
  288. }
  289. *pchTmp = '\0';
  290. pchTmp++;
  291. TimeFields.Year = (USHORT)(atoi((LPCSTR)pch));
  292. if ((TimeFields.Year < 1980) || (TimeFields.Year > 2099)) {
  293. SacPutSimpleMessage(SAC_DATETIME_LIMITS);
  294. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (6b).\n")));
  295. return;
  296. }
  297. pch = pchTmp;
  298. //
  299. // Skip to the hours
  300. //
  301. SKIP_WHITESPACE(pchTmp);
  302. if (!IS_NUMBER(*pchTmp)) {
  303. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  304. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (7).\n")));
  305. return;
  306. }
  307. pch = pchTmp;
  308. SKIP_NUMBERS(pchTmp);
  309. SKIP_WHITESPACE(pchTmp);
  310. if (*pchTmp != ':') {
  311. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  312. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (8).\n")));
  313. return;
  314. }
  315. *pchTmp = '\0';
  316. pchTmp++;
  317. TimeFields.Hour = (USHORT)(atoi((LPCSTR)pch));
  318. pch = pchTmp;
  319. //
  320. // Verify nothing else on the line but numbers
  321. //
  322. SKIP_WHITESPACE(pchTmp);
  323. if (!IS_NUMBER(*pchTmp)) {
  324. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  325. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (8a).\n")));
  326. return;
  327. }
  328. SKIP_NUMBERS(pchTmp);
  329. SKIP_WHITESPACE(pchTmp);
  330. if (*pchTmp != '\0') {
  331. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  332. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (8b).\n")));
  333. return;
  334. }
  335. //
  336. // Get the minutes.
  337. //
  338. TimeFields.Minute = (USHORT)(atoi((LPCSTR)pch));
  339. if (!RtlTimeFieldsToTime(&TimeFields, &Time)) {
  340. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  341. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (9).\n")));
  342. return;
  343. }
  344. Status = ZwSetSystemTime(&Time, NULL);
  345. if (!NT_SUCCESS(Status)) {
  346. sprintf((LPSTR)GlobalBuffer, "Failed with status 0x%X.\r\n", Status);
  347. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  348. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetTimeCommand: Exiting (10).\n")));
  349. return;
  350. }
  351. swprintf((PWSTR)GlobalBuffer, GetMessage( SAC_DATETIME_FORMAT2 ),
  352. TimeFields.Month,
  353. TimeFields.Day,
  354. TimeFields.Year,
  355. TimeFields.Hour,
  356. TimeFields.Minute
  357. );
  358. SacPutString((PWSTR)GlobalBuffer);
  359. return;
  360. }
  361. BOOLEAN
  362. RetrieveIpAddressFromString(
  363. IN PUCHAR InputString,
  364. OUT PULONG IPAddress
  365. )
  366. /*++
  367. Routine Description:
  368. This routine parses through a string and digs
  369. out the 32-bit IP address.
  370. Arguments:
  371. InputString - The users input line to parse.
  372. IPAddress - Holds the 32-bit IP address when we're done.
  373. Return Value:
  374. TRUE - We successfully retrieved an IP address.
  375. FALSE - We failed. Input was probably bad.
  376. --*/
  377. {
  378. ULONG TmpValue = 0;
  379. UCHAR TmpChar;
  380. PUCHAR pchTmp, pch;
  381. //
  382. // Init
  383. //
  384. if( (InputString == NULL) ||
  385. (IPAddress == NULL) ) {
  386. return FALSE;
  387. }
  388. *IPAddress = 0;
  389. //
  390. // Skip ahead to the divider and make it a \0.
  391. //
  392. pchTmp = InputString;
  393. pch = InputString;
  394. SKIP_WHITESPACE(pchTmp);
  395. if (!IS_NUMBER(*pchTmp)) {
  396. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (1).\n")));
  397. return FALSE;
  398. }
  399. SKIP_NUMBERS(pchTmp);
  400. SKIP_WHITESPACE(pchTmp);
  401. if (*pchTmp != '.') {
  402. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (1a).\n")));
  403. return FALSE;
  404. }
  405. TmpChar = *pchTmp;
  406. *pchTmp = '\0';
  407. //
  408. // Now get the digits this side of the divider.
  409. //
  410. TmpValue = atoi((LPCSTR)pch);
  411. *pchTmp = TmpChar;
  412. pchTmp++;
  413. if( TmpValue > 255 ) {
  414. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (1b).\n")));
  415. return FALSE;
  416. }
  417. *IPAddress = TmpValue;
  418. //
  419. // Get 2nd part
  420. //
  421. pch = pchTmp;
  422. SKIP_WHITESPACE(pchTmp);
  423. if (!IS_NUMBER(*pchTmp)) {
  424. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (1c).\n")));
  425. return FALSE;
  426. }
  427. SKIP_NUMBERS(pchTmp);
  428. SKIP_WHITESPACE(pchTmp);
  429. if (*pchTmp != '.') {
  430. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (1d).\n")));
  431. return FALSE;
  432. }
  433. TmpChar = *pchTmp;
  434. *pchTmp = '\0';
  435. TmpValue = atoi((LPCSTR)pch);
  436. *pchTmp = TmpChar;
  437. pchTmp++;
  438. if( TmpValue > 255 ) {
  439. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (1e).\n")));
  440. return FALSE;
  441. }
  442. *IPAddress |= (TmpValue << 8);
  443. //
  444. // Get 3rd part
  445. //
  446. pch = pchTmp;
  447. SKIP_WHITESPACE(pchTmp);
  448. if (!IS_NUMBER(*pchTmp)) {
  449. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (2a).\n")));
  450. return FALSE;
  451. }
  452. SKIP_NUMBERS(pchTmp);
  453. SKIP_WHITESPACE(pchTmp);
  454. if (*pchTmp != '.') {
  455. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (2b).\n")));
  456. return FALSE;
  457. }
  458. TmpChar = *pchTmp;
  459. *pchTmp = '\0';
  460. TmpValue = atoi((LPCSTR)pch);
  461. *pchTmp = TmpChar;
  462. pchTmp++;
  463. if( TmpValue > 255 ) {
  464. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (2c).\n")));
  465. return FALSE;
  466. }
  467. *IPAddress |= (TmpValue << 16);
  468. //
  469. // Get 4th part
  470. //
  471. pch = pchTmp;
  472. SKIP_WHITESPACE(pchTmp);
  473. if (!IS_NUMBER(*pchTmp)) {
  474. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (2d).\n")));
  475. return FALSE;
  476. }
  477. SKIP_NUMBERS(pchTmp);
  478. TmpChar = *pchTmp;
  479. *pchTmp = '\0';
  480. TmpValue = atoi((LPCSTR)pch);
  481. *pchTmp = TmpChar;
  482. pchTmp++;
  483. if( TmpValue > 255 ) {
  484. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC RetrieveIpAddressFromString: Exiting (2f).\n")));
  485. return FALSE;
  486. }
  487. *IPAddress |= (TmpValue << 24);
  488. return TRUE;
  489. }
  490. VOID
  491. DoSetIpAddressCommand(
  492. PUCHAR InputLine
  493. )
  494. /*++
  495. Routine Description:
  496. This routine sets the IP address and subnet mask.
  497. Arguments:
  498. InputLine - The users input line to parse.
  499. Return Value:
  500. None.
  501. --*/
  502. {
  503. NTSTATUS Status = STATUS_SUCCESS;
  504. PUCHAR pch = InputLine;
  505. PUCHAR pchTmp;
  506. HANDLE Handle = 0;
  507. HANDLE EventHandle = 0;
  508. ULONG IpAddress;
  509. ULONG SubnetMask;
  510. ULONG GatewayAddress;
  511. ULONG NetworkNumber;
  512. LARGE_INTEGER TimeOut;
  513. IO_STATUS_BLOCK IoStatusBlock;
  514. UNICODE_STRING UnicodeString;
  515. OBJECT_ATTRIBUTES ObjectAttributes;
  516. PIP_SET_ADDRESS_REQUEST IpRequest;
  517. IPRouteEntry *RouteEntry = NULL;
  518. ULONG i, j;
  519. PTCP_REQUEST_QUERY_INFORMATION_EX TcpRequestQueryInformationEx = NULL;
  520. PTCP_REQUEST_SET_INFORMATION_EX TcpRequestSetInformationEx = NULL;
  521. IPAddrEntry *AddressArray = NULL;
  522. IPSNMPInfo *IpsiInfo = NULL;
  523. BOOLEAN putPrompt = FALSE;
  524. ULONG InterfaceIndex;
  525. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Entering.\n")));
  526. //
  527. // Get the global buffer started so that we have room for error messages.
  528. //
  529. if (GlobalBuffer == NULL) {
  530. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  531. if (GlobalBuffer == NULL) {
  532. SacPutSimpleMessage(SAC_NO_MEMORY);
  533. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (1).\n")));
  534. return;
  535. }
  536. GlobalBufferSize = MEMORY_INCREMENT;
  537. }
  538. //
  539. // Skip the command.
  540. //
  541. pch += (sizeof(SETIP_COMMAND_STRING) - sizeof(UCHAR));
  542. SKIP_WHITESPACE(pch);
  543. if (*pch == '\0') {
  544. //
  545. // No other parameters, get the network numbers and their IP addresses.
  546. //
  547. DoGetNetInfo( TRUE );
  548. return;
  549. }
  550. //
  551. // Retrieve the network interface number they want to operate on.
  552. //
  553. pchTmp = pch;
  554. if (!IS_NUMBER(*pchTmp)) {
  555. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  556. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (1b).\n")));
  557. return;
  558. }
  559. SKIP_NUMBERS(pchTmp);
  560. if (!IS_WHITESPACE(*pchTmp)) {
  561. SacPutSimpleMessage(SAC_INVALID_NETWORK_INTERFACE_NUMBER);
  562. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (1c).\n")));
  563. return;
  564. }
  565. *pchTmp = '\0';
  566. pchTmp++;
  567. NetworkNumber = atoi((LPCSTR)pch);
  568. pch = pchTmp;
  569. //
  570. // Get the IP address.
  571. //
  572. if( !RetrieveIpAddressFromString( pchTmp, &IpAddress) ) {
  573. SacPutSimpleMessage(SAC_INVALID_IPADDRESS);
  574. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (2).\n")));
  575. return;
  576. }
  577. //
  578. // Jump over the IP address we just got and get
  579. // to the next bit of white space. Then get the
  580. // subnet mask.
  581. //
  582. while( (*pchTmp != ' ') &&
  583. (*pchTmp != '\0') ) {
  584. pchTmp++;
  585. }
  586. SKIP_WHITESPACE(pchTmp);
  587. if( !RetrieveIpAddressFromString( pchTmp, &SubnetMask) ) {
  588. SacPutSimpleMessage(SAC_INVALID_SUBNETMASK);
  589. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (3).\n")));
  590. return;
  591. }
  592. //
  593. // We should validate the subnet mask is valid. By that
  594. // we should check to make sure that there are no bits
  595. // set to the right of the first 0 bit we find. In other
  596. // words, all 1's in the address should be in the most
  597. // significant bits and all the 0 bits should be in the
  598. // least signficant bits.
  599. //
  600. // The bytes are in LE order. For example, an address
  601. // of 255.255.248.0 turns into 00f8ffff. Therefore, we
  602. // need to check each byte seperately.
  603. //
  604. putPrompt = FALSE;
  605. for (i = 0; i < 4; i++) {
  606. ULONG ByteValue;
  607. // isolate the next byte into the low-order 8 bits of ByteValue
  608. ByteValue = ((SubnetMask >> 8*i) & 0xFF);
  609. for (j = 0; j < 8; j++) {
  610. if( (ByteValue << j) & 0x80 ) {
  611. if( putPrompt == TRUE ) {
  612. // this bit is set and we've already come across a 0.
  613. SacPutSimpleMessage(SAC_INVALID_SUBNETMASK);
  614. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (3a).\n")));
  615. return;
  616. }
  617. } else {
  618. putPrompt = TRUE;
  619. }
  620. }
  621. }
  622. putPrompt = FALSE;
  623. //
  624. // Jump over the IP address we just got and get
  625. // to the next bit of white space. Then get the
  626. // gateway.
  627. //
  628. while( (*pchTmp != ' ') &&
  629. (*pchTmp != '\0') ) {
  630. pchTmp++;
  631. }
  632. SKIP_WHITESPACE(pchTmp);
  633. if( !RetrieveIpAddressFromString( pchTmp, &GatewayAddress) ) {
  634. SacPutSimpleMessage(SAC_INVALID_GATEWAY_IPADDRESS);
  635. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (4).\n")));
  636. return;
  637. }
  638. //
  639. // In order to set the gateway, we need to get the iae_index value
  640. // from the data structure that holds the IP address and subnet mask.
  641. // The iae_index in turn will give us an index into the data structure
  642. // which contains the gateways.
  643. //
  644. // To do this, we need to get the list if IP addresses/subnet masks
  645. // and go through them, looking for the one with the interface
  646. // number the user has specified on the command line. Once we
  647. // have the right structure, we need to remember the iae_index
  648. // from that structure so we know which gateway value to set later.
  649. //
  650. //
  651. // Opening the TCP driver
  652. //
  653. RtlInitUnicodeString(&UnicodeString, DD_TCP_DEVICE_NAME);
  654. InitializeObjectAttributes(&ObjectAttributes,
  655. &UnicodeString,
  656. OBJ_CASE_INSENSITIVE,
  657. NULL,
  658. NULL
  659. );
  660. Status = ZwOpenFile(&Handle,
  661. (ACCESS_MASK)FILE_GENERIC_READ,
  662. &ObjectAttributes,
  663. &IoStatusBlock,
  664. FILE_SHARE_READ | FILE_SHARE_WRITE,
  665. 0
  666. );
  667. if (!NT_SUCCESS(Status)) {
  668. SacPutSimpleMessage(SAC_IPADDRESS_SET_FAILURE);
  669. IF_SAC_DEBUG(
  670. SAC_DEBUG_FUNC_TRACE,
  671. KdPrint(("SAC DoSetIpAddressCommand: failed to open TCP device, ec = 0x%X\n",
  672. Status)));
  673. goto DoSetIpAddressCommand_Exit;
  674. }
  675. //
  676. // Build a command to ask for the number of interfaces, then call the ioctl
  677. //
  678. TcpRequestQueryInformationEx = ALLOCATE_POOL(
  679. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  680. GENERAL_POOL_TAG );
  681. if (TcpRequestQueryInformationEx == NULL) {
  682. SacPutSimpleMessage(SAC_NO_MEMORY);
  683. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (5).\n")));
  684. Status = STATUS_NO_MEMORY;
  685. goto DoSetIpAddressCommand_Exit;
  686. }
  687. IpsiInfo = ALLOCATE_POOL( sizeof(IPSNMPInfo),
  688. GENERAL_POOL_TAG );
  689. if (IpsiInfo == NULL) {
  690. SacPutSimpleMessage(SAC_NO_MEMORY);
  691. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (6).\n")));
  692. Status = STATUS_NO_MEMORY;
  693. goto DoSetIpAddressCommand_Exit;
  694. }
  695. RtlZeroMemory(TcpRequestQueryInformationEx, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  696. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_STATS_ID;
  697. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  698. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  699. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  700. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  701. Status = CallQueryIPIOCTL(
  702. Handle,
  703. SACEvent,
  704. SACEventHandle,
  705. &IoStatusBlock,
  706. TcpRequestQueryInformationEx,
  707. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  708. IpsiInfo,
  709. sizeof(IPSNMPInfo),
  710. FALSE,
  711. &putPrompt);
  712. if (!NT_SUCCESS(Status)) {
  713. SacPutSimpleMessage(SAC_IPADDRESS_SET_FAILURE);
  714. IF_SAC_DEBUG(
  715. SAC_DEBUG_FUNC_TRACE,
  716. KdPrint(("SAC DoSetIpAddressCommand: failed to query TCP device, ec = 0x%X\n",
  717. Status)));
  718. goto DoSetIpAddressCommand_Exit;
  719. }
  720. if (IpsiInfo->ipsi_numaddr == 0) {
  721. SacPutSimpleMessage( SAC_IPADDR_NONE );
  722. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (10).\n")));
  723. Status = STATUS_NO_MEMORY;
  724. goto DoSetIpAddressCommand_Exit;
  725. }
  726. //
  727. // Allocate space for the array of IP addresses
  728. //
  729. AddressArray = ALLOCATE_POOL(IpsiInfo->ipsi_numaddr*sizeof(IPAddrEntry),
  730. GENERAL_POOL_TAG);
  731. if (AddressArray == NULL) {
  732. SacPutSimpleMessage(SAC_NO_MEMORY);
  733. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  734. Status = STATUS_NO_MEMORY;
  735. goto DoSetIpAddressCommand_Exit;
  736. }
  737. //
  738. // zero out the context information and preload with the info we're gonna
  739. // request (we want information on each of the interfaces on this machine)
  740. //
  741. RtlZeroMemory(TcpRequestQueryInformationEx, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  742. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  743. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  744. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  745. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  746. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  747. Status = CallQueryIPIOCTL(
  748. Handle,
  749. SACEvent,
  750. SACEventHandle,
  751. &IoStatusBlock,
  752. TcpRequestQueryInformationEx,
  753. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  754. AddressArray,
  755. IpsiInfo->ipsi_numaddr*sizeof(IPAddrEntry),
  756. FALSE,
  757. &putPrompt);
  758. if (!NT_SUCCESS(Status)) {
  759. SacPutSimpleMessage(SAC_IPADDRESS_SET_FAILURE);
  760. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (20).\n")));
  761. goto DoSetIpAddressCommand_Exit;
  762. }
  763. //
  764. // Now cycle through the list and figure out the context number of
  765. // the interface the user wants to set. We need this so we can later
  766. // tell which context to apply the new gateway to.
  767. //
  768. InterfaceIndex = 0xFFFFFFFF;
  769. for (i = 0; i < IpsiInfo->ipsi_numaddr; i++) {
  770. if( (ULONG)(AddressArray[i].iae_context) == NetworkNumber ) {
  771. //
  772. // remember the index of this interface.
  773. //
  774. InterfaceIndex = AddressArray[i].iae_index;
  775. break;
  776. }
  777. }
  778. //
  779. // Get rid of the memory and handles that we don't need any longer.
  780. //
  781. FREE_POOL(&TcpRequestQueryInformationEx);
  782. FREE_POOL(&AddressArray);
  783. FREE_POOL(&IpsiInfo);
  784. ZwClose(Handle);
  785. Handle = 0;
  786. if( InterfaceIndex == 0xFFFFFFFF ) {
  787. //
  788. // We couldn't find the NIC they're trying to talk to.
  789. //
  790. SacPutSimpleMessage(SAC_IPADDRESS_RETRIEVE_FAILURE);
  791. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (20).\n")));
  792. return;
  793. }
  794. //
  795. // We now know which gateway entry they want to change.
  796. // We can now go update the ip address, subnet mask, and
  797. // gateway.
  798. //
  799. //
  800. // Setup notification event. We'll use this in case the IOCTLs
  801. // tell us to wait while the address updates take place.
  802. //
  803. Status = NtCreateEvent(
  804. &EventHandle, // EventHandle
  805. EVENT_ALL_ACCESS, // DesiredAccess
  806. NULL, // ObjectAttributes
  807. SynchronizationEvent, // EventType
  808. FALSE // InitialState
  809. );
  810. if (! NT_SUCCESS(Status)) {
  811. SacPutSimpleMessage(SAC_IPADDRESS_RETRIEVE_FAILURE);
  812. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Event is NULL.\n")));
  813. return;
  814. }
  815. //
  816. // Set IP address and subnet mask.
  817. //
  818. //
  819. // Start by opening the driver
  820. //
  821. RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
  822. InitializeObjectAttributes(&ObjectAttributes,
  823. &UnicodeString,
  824. OBJ_CASE_INSENSITIVE,
  825. NULL,
  826. NULL
  827. );
  828. Status = ZwOpenFile(&Handle,
  829. (ACCESS_MASK)FILE_GENERIC_READ,
  830. &ObjectAttributes,
  831. &IoStatusBlock,
  832. FILE_SHARE_READ | FILE_SHARE_WRITE,
  833. 0
  834. );
  835. if (!NT_SUCCESS(Status)) {
  836. SacPutSimpleMessage(SAC_IPADDRESS_SET_FAILURE);
  837. IF_SAC_DEBUG(
  838. SAC_DEBUG_FUNC_TRACE,
  839. KdPrint(("SAC DoSetIpAddressCommand: failed to open IP device, ec = 0x%X\n",
  840. Status)));
  841. goto DoSetIpAddressCommand_Exit;
  842. }
  843. //
  844. // Setup the IOCTL buffer to delete the old address.
  845. //
  846. IpRequest = (PIP_SET_ADDRESS_REQUEST)GlobalBuffer;
  847. RtlZeroMemory(IpRequest, sizeof(IP_SET_ADDRESS_REQUEST));
  848. IpRequest->Address = 0;
  849. IpRequest->SubnetMask = 0;
  850. IpRequest->Context = (USHORT)NetworkNumber;
  851. //
  852. // Submit the IOCTL
  853. //
  854. Status = NtDeviceIoControlFile(Handle,
  855. EventHandle,
  856. NULL,
  857. NULL,
  858. &IoStatusBlock,
  859. IOCTL_IP_SET_ADDRESS,
  860. IpRequest,
  861. sizeof(IP_SET_ADDRESS_REQUEST),
  862. NULL,
  863. 0
  864. );
  865. if (Status == STATUS_PENDING) {
  866. //
  867. // Wait up to 30 seconds for it to finish
  868. //
  869. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  870. Status = NtWaitForSingleObject((PVOID)EventHandle, FALSE, &TimeOut);
  871. if (Status == STATUS_SUCCESS) {
  872. Status = IoStatusBlock.Status;
  873. }
  874. }
  875. if (Status != STATUS_SUCCESS) {
  876. SacPutSimpleMessage( SAC_IPADDRESS_CLEAR_FAILURE );
  877. IF_SAC_DEBUG(
  878. SAC_DEBUG_FUNC_TRACE,
  879. KdPrint(("SAC DoSetIpAddressCommand: Exiting because it couldn't clear existing IP Address (0x%X).\n",
  880. Status)));
  881. goto DoSetIpAddressCommand_Exit;
  882. }
  883. //
  884. // Now add our address.
  885. //
  886. IpRequest = (PIP_SET_ADDRESS_REQUEST)GlobalBuffer;
  887. RtlZeroMemory(IpRequest, sizeof(IP_SET_ADDRESS_REQUEST));
  888. IpRequest->Address = IpAddress;
  889. IpRequest->SubnetMask = SubnetMask;
  890. IpRequest->Context = (USHORT)NetworkNumber;
  891. //
  892. // Submit the IOCTL
  893. //
  894. Status = NtDeviceIoControlFile(Handle,
  895. EventHandle,
  896. NULL,
  897. NULL,
  898. &IoStatusBlock,
  899. IOCTL_IP_SET_ADDRESS,
  900. IpRequest,
  901. sizeof(IP_SET_ADDRESS_REQUEST),
  902. NULL,
  903. 0
  904. );
  905. if (Status == STATUS_PENDING) {
  906. //
  907. // Wait up to 30 seconds for it to finish
  908. //
  909. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  910. Status = NtWaitForSingleObject((PVOID)EventHandle, FALSE, &TimeOut);
  911. if (NT_SUCCESS(Status)) {
  912. Status = IoStatusBlock.Status;
  913. }
  914. }
  915. //
  916. // Don't need this anymore.
  917. //
  918. ZwClose(Handle);
  919. Handle = 0;
  920. if (!NT_SUCCESS(Status)) {
  921. SacPutSimpleMessage( SAC_IPADDRESS_SET_FAILURE );
  922. IF_SAC_DEBUG(
  923. SAC_DEBUG_FUNC_TRACE,
  924. KdPrint(("SAC DoSetIpAddressCommand: Exiting because it couldn't set existing IP Address (0x%X).\n",
  925. Status)));
  926. goto DoSetIpAddressCommand_Exit;
  927. }
  928. //
  929. // Now set the default gateway address based on the information we dug up
  930. // at the top of the function.
  931. //
  932. //
  933. // Start by opening the TCP driver
  934. //
  935. RtlInitUnicodeString(&UnicodeString, DD_TCP_DEVICE_NAME);
  936. InitializeObjectAttributes(&ObjectAttributes,
  937. &UnicodeString,
  938. OBJ_CASE_INSENSITIVE,
  939. NULL,
  940. NULL
  941. );
  942. Status = ZwOpenFile(&Handle,
  943. (ACCESS_MASK)FILE_GENERIC_READ,
  944. &ObjectAttributes,
  945. &IoStatusBlock,
  946. FILE_SHARE_READ | FILE_SHARE_WRITE,
  947. 0
  948. );
  949. if (!NT_SUCCESS(Status)) {
  950. SacPutSimpleMessage(SAC_IPADDRESS_SET_FAILURE);
  951. IF_SAC_DEBUG(
  952. SAC_DEBUG_FUNC_TRACE,
  953. KdPrint(("SAC DoSetIpAddressCommand: failed to open TCP device, ec = 0x%X\n",
  954. Status)));
  955. goto DoSetIpAddressCommand_Exit;
  956. }
  957. //
  958. // Fill in the route entry and submit the IOCTL
  959. //
  960. RouteEntry = ALLOCATE_POOL( sizeof(IPRouteEntry), GENERAL_POOL_TAG );
  961. if (RouteEntry == NULL) {
  962. SacPutSimpleMessage(SAC_NO_MEMORY);
  963. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (21).\n")));
  964. Status = STATUS_NO_MEMORY;
  965. goto DoSetIpAddressCommand_Exit;
  966. }
  967. RouteEntry->ire_dest = 0;
  968. RouteEntry->ire_index = InterfaceIndex;
  969. RouteEntry->ire_metric1 = 1;
  970. RouteEntry->ire_metric2 = (ULONG)(-1);
  971. RouteEntry->ire_metric3 = (ULONG)(-1);
  972. RouteEntry->ire_metric4 = (ULONG)(-1);
  973. RouteEntry->ire_metric5 = (ULONG)(-1);
  974. RouteEntry->ire_nexthop = GatewayAddress;
  975. RouteEntry->ire_type =
  976. ((IpAddress == GatewayAddress) ? IRE_TYPE_DIRECT : IRE_TYPE_INDIRECT);
  977. RouteEntry->ire_proto = IRE_PROTO_NETMGMT;
  978. RouteEntry->ire_age = 0;
  979. RouteEntry->ire_mask = 0;
  980. RouteEntry->ire_context = 0;
  981. i = FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) + sizeof(IPRouteEntry);
  982. TcpRequestSetInformationEx = ALLOCATE_POOL( i, GENERAL_POOL_TAG );
  983. if (TcpRequestSetInformationEx == NULL) {
  984. SacPutSimpleMessage(SAC_NO_MEMORY);
  985. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (22).\n")));
  986. Status = STATUS_NO_MEMORY;
  987. goto DoSetIpAddressCommand_Exit;
  988. }
  989. RtlZeroMemory(TcpRequestSetInformationEx, i);
  990. TcpRequestSetInformationEx->ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  991. TcpRequestSetInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  992. TcpRequestSetInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  993. TcpRequestSetInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  994. TcpRequestSetInformationEx->ID.toi_entity.tei_instance = 0;
  995. TcpRequestSetInformationEx->BufferSize = sizeof(IPRouteEntry);
  996. memcpy(&TcpRequestSetInformationEx->Buffer[0], RouteEntry, sizeof(IPRouteEntry));
  997. //
  998. // set the default gateway address.
  999. //
  1000. Status = NtDeviceIoControlFile(Handle, // driver handle
  1001. EventHandle, // sync event
  1002. NULL, // APC routine
  1003. NULL, // APC context
  1004. &IoStatusBlock,
  1005. IOCTL_TCP_SET_INFORMATION_EX,
  1006. TcpRequestSetInformationEx,
  1007. i,
  1008. NULL,
  1009. 0
  1010. );
  1011. if (Status == STATUS_PENDING) {
  1012. //
  1013. // Wait up to 30 seconds for it to finish
  1014. //
  1015. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  1016. Status = NtWaitForSingleObject((PVOID)EventHandle, FALSE, &TimeOut);
  1017. if (Status == STATUS_SUCCESS) {
  1018. Status = IoStatusBlock.Status;
  1019. }
  1020. }
  1021. if (Status != STATUS_SUCCESS) {
  1022. SacPutSimpleMessage( SAC_IPADDRESS_SET_FAILURE );
  1023. IF_SAC_DEBUG(
  1024. SAC_DEBUG_FUNC_TRACE,
  1025. KdPrint(("SAC DoSetIpAddressCommand: Exiting because it couldn't set gateway Address (0x%X).\n",
  1026. Status)));
  1027. goto DoSetIpAddressCommand_Exit;
  1028. }
  1029. DoSetIpAddressCommand_Exit:
  1030. if( EventHandle != 0 ) {
  1031. ZwClose(EventHandle);
  1032. }
  1033. if( Handle != 0 ) {
  1034. ZwClose(Handle);
  1035. }
  1036. if( TcpRequestQueryInformationEx != NULL ) {
  1037. FREE_POOL( &TcpRequestQueryInformationEx );
  1038. }
  1039. if( TcpRequestSetInformationEx != NULL ) {
  1040. FREE_POOL( &TcpRequestSetInformationEx );
  1041. }
  1042. if( IpsiInfo != NULL ) {
  1043. FREE_POOL( &IpsiInfo );
  1044. }
  1045. if( RouteEntry != NULL ) {
  1046. FREE_POOL( &RouteEntry );
  1047. }
  1048. if( Status == STATUS_SUCCESS ) {
  1049. SacPutSimpleMessage( SAC_IPADDRESS_SET_SUCCESS );
  1050. }
  1051. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting.\n")));
  1052. return;
  1053. }
  1054. VOID
  1055. DoKillCommand(
  1056. PUCHAR InputLine
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine kill a process.
  1061. Arguments:
  1062. InputLine - The users input line to parse.
  1063. Return Value:
  1064. None.
  1065. --*/
  1066. {
  1067. NTSTATUS Status;
  1068. NTSTATUS StatusOfJobObject;
  1069. HANDLE Handle = NULL;
  1070. HANDLE JobHandle = NULL;
  1071. PUCHAR pch = InputLine;
  1072. PUCHAR pchTmp;
  1073. ULONG ProcessId;
  1074. OBJECT_ATTRIBUTES ObjectAttributes;
  1075. UNICODE_STRING UnicodeString;
  1076. CLIENT_ID ClientId;
  1077. BOOLEAN TerminateJobObject;
  1078. BOOLEAN TerminateProcessObject;
  1079. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Entering.\n")));
  1080. //
  1081. // Get the global buffer started so that we have room for error messages.
  1082. //
  1083. if (GlobalBuffer == NULL) {
  1084. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1085. if (GlobalBuffer == NULL) {
  1086. SacPutSimpleMessage(SAC_NO_MEMORY);
  1087. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (1).\n")));
  1088. return;
  1089. }
  1090. GlobalBufferSize = MEMORY_INCREMENT;
  1091. }
  1092. //
  1093. // Skip to next argument (process id)
  1094. //
  1095. pch += (sizeof(KILL_COMMAND_STRING) - sizeof(UCHAR));
  1096. SKIP_WHITESPACE(pch);
  1097. if (*pch == '\0') {
  1098. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1099. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (2).\n")));
  1100. return;
  1101. }
  1102. pchTmp = pch;
  1103. if (!IS_NUMBER(*pchTmp)) {
  1104. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1105. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (2b).\n")));
  1106. return;
  1107. }
  1108. SKIP_NUMBERS(pchTmp);
  1109. SKIP_WHITESPACE(pchTmp);
  1110. if (*pchTmp != '\0') {
  1111. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1112. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (3).\n")));
  1113. return;
  1114. }
  1115. ProcessId = atoi((LPCSTR)pch);
  1116. //
  1117. // Try and open an existing job object
  1118. //
  1119. swprintf((PWCHAR)GlobalBuffer, L"\\BaseNamedObjects\\SAC%d", ProcessId);
  1120. RtlInitUnicodeString(&UnicodeString, (PWCHAR)GlobalBuffer);
  1121. InitializeObjectAttributes(&ObjectAttributes,
  1122. &UnicodeString,
  1123. OBJ_CASE_INSENSITIVE,
  1124. NULL,
  1125. NULL
  1126. );
  1127. StatusOfJobObject = ZwOpenJobObject(&JobHandle, MAXIMUM_ALLOWED, &ObjectAttributes);
  1128. //
  1129. // Also open a handle to the process itself.
  1130. //
  1131. InitializeObjectAttributes(&ObjectAttributes,
  1132. NULL,
  1133. OBJ_CASE_INSENSITIVE,
  1134. NULL,
  1135. NULL
  1136. );
  1137. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1138. ClientId.UniqueThread = NULL;
  1139. Status = ZwOpenProcess(&Handle,
  1140. MAXIMUM_ALLOWED,
  1141. &ObjectAttributes,
  1142. &ClientId
  1143. );
  1144. if (!NT_SUCCESS(Status) && !NT_SUCCESS(StatusOfJobObject)) {
  1145. SacPutSimpleMessage(SAC_KILL_FAILURE);
  1146. SAC_PUT_ERROR_STRING(Status);
  1147. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (4).\n")));
  1148. return;
  1149. }
  1150. //
  1151. // To make the logic here more understandable, I use two booleans. We have to use
  1152. // ZwIsProcessInJob because there may be a previous JobObject for a process that we
  1153. // have killed, but has not yet been fully cleaned up by the system to determine if
  1154. // the process we are trying to kill is, in fact, in the JobObject we have opened.
  1155. //
  1156. TerminateJobObject = (BOOLEAN)(NT_SUCCESS(StatusOfJobObject) &&
  1157. (BOOLEAN)NT_SUCCESS(Status) &&
  1158. (BOOLEAN)(ZwIsProcessInJob(Handle, JobHandle) == STATUS_PROCESS_IN_JOB)
  1159. );
  1160. TerminateProcessObject = !TerminateJobObject && (BOOLEAN)NT_SUCCESS(Status);
  1161. if (TerminateJobObject) {
  1162. Status = ZwTerminateJobObject(JobHandle, 1);
  1163. //
  1164. // Make the job object temporary so that when we do our close it
  1165. // will remove it.
  1166. //
  1167. ZwMakeTemporaryObject(JobHandle);
  1168. } else if (TerminateProcessObject) {
  1169. Status = ZwTerminateProcess(Handle, 1);
  1170. }
  1171. if (JobHandle != NULL) {
  1172. ZwClose(JobHandle);
  1173. }
  1174. if (Handle != NULL) {
  1175. ZwClose(Handle);
  1176. }
  1177. if (!TerminateProcessObject && !TerminateJobObject) {
  1178. SacPutSimpleMessage(SAC_PROCESS_STALE);
  1179. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (5).\n")));
  1180. return;
  1181. } else if (!NT_SUCCESS(Status)) {
  1182. SacPutSimpleMessage(SAC_KILL_FAILURE);
  1183. SAC_PUT_ERROR_STRING(Status);
  1184. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting (6).\n")));
  1185. return;
  1186. }
  1187. //
  1188. // All done
  1189. //
  1190. SacPutSimpleMessage(SAC_KILL_SUCCESS);
  1191. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoKillCommand: Exiting.\n")));
  1192. return;
  1193. }
  1194. VOID
  1195. DoLowerPriorityCommand(
  1196. PUCHAR InputLine
  1197. )
  1198. /*++
  1199. Routine Description:
  1200. This routine slams the priority of a process down to the lowest possible, IDLE.
  1201. Arguments:
  1202. InputLine - The users input line to parse.
  1203. Return Value:
  1204. None.
  1205. --*/
  1206. {
  1207. NTSTATUS Status;
  1208. PUCHAR pch = InputLine;
  1209. PUCHAR pchTmp;
  1210. ULONG ProcessId;
  1211. CLIENT_ID ClientId;
  1212. OBJECT_ATTRIBUTES ObjectAttributes;
  1213. HANDLE ProcessHandle = NULL;
  1214. PROCESS_BASIC_INFORMATION BasicInfo;
  1215. ULONG LoopCounter;
  1216. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Entering.\n")));
  1217. //
  1218. // Get the global buffer started so that we have room for error messages.
  1219. //
  1220. if (GlobalBuffer == NULL) {
  1221. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1222. if (GlobalBuffer == NULL) {
  1223. SacPutSimpleMessage(SAC_NO_MEMORY);
  1224. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (1).\n")));
  1225. goto Exit;
  1226. }
  1227. GlobalBufferSize = MEMORY_INCREMENT;
  1228. }
  1229. //
  1230. // Skip to next argument (process id)
  1231. //
  1232. pch += (sizeof(LOWER_COMMAND_STRING) - sizeof(UCHAR));
  1233. SKIP_WHITESPACE(pch);
  1234. if (!IS_NUMBER(*pch)) {
  1235. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1236. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (2).\n")));
  1237. goto Exit;
  1238. }
  1239. pchTmp = pch;
  1240. SKIP_NUMBERS(pchTmp);
  1241. SKIP_WHITESPACE(pchTmp);
  1242. if (*pchTmp != '\0') {
  1243. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1244. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (3).\n")));
  1245. return;
  1246. }
  1247. ProcessId = atoi((LPCSTR)pch);
  1248. //
  1249. // Try to open the process
  1250. //
  1251. InitializeObjectAttributes(&ObjectAttributes,
  1252. NULL,
  1253. OBJ_CASE_INSENSITIVE,
  1254. NULL,
  1255. NULL
  1256. );
  1257. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1258. ClientId.UniqueThread = NULL;
  1259. Status = ZwOpenProcess(&ProcessHandle,
  1260. MAXIMUM_ALLOWED,
  1261. &ObjectAttributes,
  1262. &ClientId
  1263. );
  1264. if (!NT_SUCCESS(Status)) {
  1265. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1266. SAC_PUT_ERROR_STRING(Status);
  1267. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (4).\n")));
  1268. goto Exit;
  1269. }
  1270. //
  1271. // Query information on the process.
  1272. //
  1273. Status = ZwQueryInformationProcess( ProcessHandle,
  1274. ProcessBasicInformation,
  1275. &BasicInfo,
  1276. sizeof(PROCESS_BASIC_INFORMATION),
  1277. NULL );
  1278. if (!NT_SUCCESS(Status)) {
  1279. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1280. SAC_PUT_ERROR_STRING(Status);
  1281. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (5).\n")));
  1282. goto Exit;
  1283. }
  1284. //
  1285. // Lower the priority and set. Keep lowering it until we fail. Remember
  1286. // that we're supposed to lower it as far as it will go.
  1287. //
  1288. Status = STATUS_SUCCESS;
  1289. LoopCounter = 0;
  1290. while( (Status == STATUS_SUCCESS) &&
  1291. (BasicInfo.BasePriority > 0) ) {
  1292. BasicInfo.BasePriority--;
  1293. Status = ZwSetInformationProcess( ProcessHandle,
  1294. ProcessBasePriority,
  1295. &BasicInfo.BasePriority,
  1296. sizeof(BasicInfo.BasePriority) );
  1297. //
  1298. // Only treat a failure on the first time through.
  1299. //
  1300. if( (!NT_SUCCESS(Status)) && (LoopCounter == 0) ) {
  1301. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1302. SAC_PUT_ERROR_STRING(Status);
  1303. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting (6).\n")));
  1304. goto Exit;
  1305. }
  1306. LoopCounter++;
  1307. }
  1308. //
  1309. // All done.
  1310. //
  1311. SacPutSimpleMessage(SAC_LOWERPRI_SUCCESS);
  1312. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLowerPriorityCommand: Exiting.\n")));
  1313. Exit:
  1314. if (ProcessHandle != NULL) {
  1315. ZwClose(ProcessHandle);
  1316. }
  1317. return;
  1318. }
  1319. VOID
  1320. DoRaisePriorityCommand(
  1321. PUCHAR InputLine
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. This routine raises the priority of a process up one increment.
  1326. Arguments:
  1327. InputLine - The users input line to parse.
  1328. Return Value:
  1329. None.
  1330. --*/
  1331. {
  1332. NTSTATUS Status;
  1333. PUCHAR pch = InputLine;
  1334. PUCHAR pchTmp;
  1335. ULONG ProcessId;
  1336. CLIENT_ID ClientId;
  1337. OBJECT_ATTRIBUTES ObjectAttributes;
  1338. HANDLE ProcessHandle = NULL;
  1339. PROCESS_BASIC_INFORMATION BasicInfo;
  1340. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Entering.\n")));
  1341. //
  1342. // Get the global buffer started so that we have room for error messages.
  1343. //
  1344. if (GlobalBuffer == NULL) {
  1345. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1346. if (GlobalBuffer == NULL) {
  1347. SacPutSimpleMessage(SAC_NO_MEMORY);
  1348. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (1).\n")));
  1349. goto Exit;
  1350. }
  1351. GlobalBufferSize = MEMORY_INCREMENT;
  1352. }
  1353. //
  1354. // Skip to next argument (process id)
  1355. //
  1356. pch += (sizeof(RAISE_COMMAND_STRING) - sizeof(UCHAR));
  1357. SKIP_WHITESPACE(pch);
  1358. if (!IS_NUMBER(*pch)) {
  1359. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1360. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (2).\n")));
  1361. goto Exit;
  1362. }
  1363. pchTmp = pch;
  1364. SKIP_NUMBERS(pchTmp);
  1365. SKIP_WHITESPACE(pchTmp);
  1366. if (*pchTmp != '\0') {
  1367. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1368. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (3).\n")));
  1369. return;
  1370. }
  1371. ProcessId = atoi((LPCSTR)pch);
  1372. //
  1373. // See if the process even exists.
  1374. //
  1375. InitializeObjectAttributes(&ObjectAttributes,
  1376. NULL,
  1377. OBJ_CASE_INSENSITIVE,
  1378. NULL,
  1379. NULL
  1380. );
  1381. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1382. ClientId.UniqueThread = NULL;
  1383. Status = ZwOpenProcess(&ProcessHandle,
  1384. MAXIMUM_ALLOWED,
  1385. &ObjectAttributes,
  1386. &ClientId
  1387. );
  1388. if (!NT_SUCCESS(Status)) {
  1389. SacPutSimpleMessage(SAC_RAISEPRI_FAILURE);
  1390. SAC_PUT_ERROR_STRING(Status);
  1391. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (4).\n")));
  1392. goto Exit;
  1393. }
  1394. //
  1395. // Query information on the process.
  1396. //
  1397. Status = ZwQueryInformationProcess( ProcessHandle,
  1398. ProcessBasicInformation,
  1399. &BasicInfo,
  1400. sizeof(PROCESS_BASIC_INFORMATION),
  1401. NULL );
  1402. if (!NT_SUCCESS(Status)) {
  1403. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1404. SAC_PUT_ERROR_STRING(Status);
  1405. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (5).\n")));
  1406. goto Exit;
  1407. }
  1408. //
  1409. // Lower the priority and set. Keep lowering it until we fail. Remember
  1410. // that we're supposed to lower it as far as it will go.
  1411. //
  1412. BasicInfo.BasePriority++;
  1413. Status = ZwSetInformationProcess( ProcessHandle,
  1414. ProcessBasePriority,
  1415. &BasicInfo.BasePriority,
  1416. sizeof(BasicInfo.BasePriority) );
  1417. //
  1418. // Only treat a failure on the first time through.
  1419. //
  1420. if( !NT_SUCCESS(Status) ) {
  1421. SacPutSimpleMessage(SAC_LOWERPRI_FAILURE);
  1422. SAC_PUT_ERROR_STRING(Status);
  1423. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (6).\n")));
  1424. goto Exit;
  1425. }
  1426. //
  1427. // All done.
  1428. //
  1429. SacPutSimpleMessage(SAC_RAISEPRI_SUCCESS);
  1430. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting.\n")));
  1431. Exit:
  1432. if (ProcessHandle != NULL) {
  1433. ZwClose(ProcessHandle);
  1434. }
  1435. return;
  1436. }
  1437. VOID
  1438. DoLimitMemoryCommand(
  1439. PUCHAR InputLine
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This routine reduces the memory working set of a process to the values in
  1444. the input line given.
  1445. Arguments:
  1446. InputLine - The users input line to parse.
  1447. Return Value:
  1448. None.
  1449. --*/
  1450. {
  1451. NTSTATUS Status;
  1452. NTSTATUS StatusOfJobObject;
  1453. PUCHAR pch = InputLine;
  1454. PUCHAR pchTmp;
  1455. ULONG ProcessId;
  1456. ULONG MemoryLimit;
  1457. CLIENT_ID ClientId;
  1458. OBJECT_ATTRIBUTES ObjectAttributes;
  1459. UNICODE_STRING UnicodeString;
  1460. HANDLE JobHandle = NULL;
  1461. HANDLE ProcessHandle = NULL;
  1462. JOBOBJECT_EXTENDED_LIMIT_INFORMATION ProposedLimits;
  1463. ULONG ReturnedLength;
  1464. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Entering.\n")));
  1465. //
  1466. // Get the global buffer started so that we have room for error messages.
  1467. //
  1468. if (GlobalBuffer == NULL) {
  1469. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1470. if (GlobalBuffer == NULL) {
  1471. SacPutSimpleMessage(SAC_NO_MEMORY);
  1472. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (1).\n")));
  1473. goto Exit;
  1474. }
  1475. GlobalBufferSize = MEMORY_INCREMENT;
  1476. }
  1477. //
  1478. // Get process id
  1479. //
  1480. pch += (sizeof(LIMIT_COMMAND_STRING) - sizeof(UCHAR));
  1481. SKIP_WHITESPACE(pch);
  1482. if (!IS_NUMBER(*pch)) {
  1483. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1484. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (2).\n")));
  1485. goto Exit;
  1486. }
  1487. pchTmp = pch;
  1488. SKIP_NUMBERS(pchTmp);
  1489. if (!IS_WHITESPACE(*pchTmp)) {
  1490. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1491. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (3).\n")));
  1492. return;
  1493. }
  1494. *pchTmp = '\0';
  1495. pchTmp++;
  1496. ProcessId = atoi((LPCSTR)pch);
  1497. //
  1498. // Now get memory limit
  1499. //
  1500. SKIP_WHITESPACE(pchTmp);
  1501. if (!IS_NUMBER(*pchTmp)) {
  1502. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1503. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (4).\n")));
  1504. return;
  1505. }
  1506. pch = pchTmp;
  1507. SKIP_NUMBERS(pchTmp);
  1508. SKIP_WHITESPACE(pchTmp);
  1509. if (*pchTmp != '\0') {
  1510. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1511. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (5).\n")));
  1512. return;
  1513. }
  1514. MemoryLimit = atoi((LPCSTR)pch);
  1515. if (MemoryLimit == 0) {
  1516. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  1517. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (6).\n")));
  1518. goto Exit;
  1519. }
  1520. //
  1521. // Create the name for the job object
  1522. //
  1523. swprintf((PWCHAR)GlobalBuffer, L"\\BaseNamedObjects\\SAC%d", ProcessId);
  1524. //
  1525. // Try and open the existing job object
  1526. //
  1527. RtlInitUnicodeString(&UnicodeString, (PWCHAR)GlobalBuffer);
  1528. InitializeObjectAttributes(&ObjectAttributes,
  1529. &UnicodeString,
  1530. OBJ_CASE_INSENSITIVE,
  1531. NULL,
  1532. NULL
  1533. );
  1534. StatusOfJobObject = ZwOpenJobObject(&JobHandle, MAXIMUM_ALLOWED, &ObjectAttributes);
  1535. //
  1536. // Try to open the process
  1537. //
  1538. InitializeObjectAttributes(&ObjectAttributes,
  1539. NULL,
  1540. OBJ_CASE_INSENSITIVE,
  1541. NULL,
  1542. NULL
  1543. );
  1544. ClientId.UniqueProcess = (HANDLE)UlongToPtr(ProcessId);
  1545. ClientId.UniqueThread = NULL;
  1546. Status = ZwOpenProcess(&ProcessHandle,
  1547. MAXIMUM_ALLOWED,
  1548. &ObjectAttributes,
  1549. &ClientId
  1550. );
  1551. if (!NT_SUCCESS(Status) && !NT_SUCCESS(StatusOfJobObject)) {
  1552. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1553. SAC_PUT_ERROR_STRING(Status);
  1554. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (7).\n")));
  1555. goto Exit;
  1556. }
  1557. if (NT_SUCCESS(Status) &&
  1558. NT_SUCCESS(StatusOfJobObject) &&
  1559. (ZwIsProcessInJob(ProcessHandle, JobHandle) != STATUS_PROCESS_IN_JOB)) {
  1560. SacPutSimpleMessage(SAC_DUPLICATE_PROCESS);
  1561. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (8).\n")));
  1562. goto Exit;
  1563. }
  1564. if (!NT_SUCCESS(StatusOfJobObject)) {
  1565. //
  1566. // Now try and create a job object to wrap around this process.
  1567. //
  1568. InitializeObjectAttributes(&ObjectAttributes,
  1569. &UnicodeString,
  1570. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  1571. NULL,
  1572. NULL
  1573. );
  1574. Status = ZwCreateJobObject(&JobHandle, MAXIMUM_ALLOWED, &ObjectAttributes);
  1575. if (!NT_SUCCESS(Status)) {
  1576. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1577. SAC_PUT_ERROR_STRING(Status);
  1578. ZwClose(ProcessHandle);
  1579. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (8b).\n")));
  1580. goto Exit;
  1581. }
  1582. //
  1583. // Assign the process to this new job object.
  1584. //
  1585. Status = ZwAssignProcessToJobObject(JobHandle, ProcessHandle);
  1586. ZwClose(ProcessHandle);
  1587. if (!NT_SUCCESS(Status)) {
  1588. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1589. SAC_PUT_ERROR_STRING(Status);
  1590. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (9).\n")));
  1591. goto Exit;
  1592. }
  1593. }
  1594. //
  1595. // Get the current set of limits
  1596. //
  1597. Status = ZwQueryInformationJobObject(JobHandle,
  1598. JobObjectExtendedLimitInformation,
  1599. &ProposedLimits,
  1600. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
  1601. &ReturnedLength
  1602. );
  1603. if (!NT_SUCCESS(Status)) {
  1604. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1605. SAC_PUT_ERROR_STRING(Status);
  1606. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (10).\n")));
  1607. goto Exit;
  1608. }
  1609. //
  1610. // Change the memory limits
  1611. //
  1612. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  1613. ProposedLimits.ProcessMemoryLimit = MemoryLimit * 1024 * 1024;
  1614. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
  1615. ProposedLimits.JobMemoryLimit = MemoryLimit * 1024 * 1024;
  1616. Status = ZwSetInformationJobObject(JobHandle,
  1617. JobObjectExtendedLimitInformation,
  1618. &ProposedLimits,
  1619. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)
  1620. );
  1621. if (!NT_SUCCESS(Status)) {
  1622. SacPutSimpleMessage(SAC_LOWERMEM_FAILURE);
  1623. SAC_PUT_ERROR_STRING(Status);
  1624. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting (11).\n")));\
  1625. goto Exit;
  1626. }
  1627. //
  1628. // All done.
  1629. //
  1630. SacPutSimpleMessage(SAC_LOWERMEM_SUCCESS);
  1631. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoLimitMemoryCommand: Exiting.\n")));
  1632. Exit:
  1633. if (JobHandle != NULL) {
  1634. ZwClose(JobHandle);
  1635. }
  1636. if (ProcessHandle != NULL) {
  1637. ZwClose(ProcessHandle);
  1638. }
  1639. return;
  1640. }
  1641. VOID
  1642. DoRebootCommand(
  1643. BOOLEAN Reboot
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. This routine does a shutdown and an optional reboot.
  1648. Arguments:
  1649. Reboot - To Reboot or not to reboot, that is the question answered here.
  1650. Return Value:
  1651. None.
  1652. --*/
  1653. {
  1654. #define RESTART_DELAY_TIME (60)
  1655. NTSTATUS Status;
  1656. LARGE_INTEGER TickCount;
  1657. LARGE_INTEGER ElapsedTime;
  1658. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRebootCommand: Entering.\n")));
  1659. //
  1660. // If we attempt to shutdown the system before smss.exe has initialized
  1661. // properly, and if there's no debugger, the machine may bugcheck. Figuring
  1662. // out exactly what's going on is difficult because if we put a debugger on
  1663. // the machine, he won't repro the problem. To work around this, we're going
  1664. // to make sure the machine has had time to initialize before we tell it to
  1665. // restart/shutdown.
  1666. //
  1667. // Elapsed TickCount
  1668. KeQueryTickCount( &TickCount );
  1669. // ElapsedTime in seconds.
  1670. ElapsedTime.QuadPart = (TickCount.QuadPart)/(10000000/KeQueryTimeIncrement());
  1671. if( ElapsedTime.QuadPart < RESTART_DELAY_TIME ) {
  1672. KEVENT Event;
  1673. ConMgrSimpleEventMessage(
  1674. Reboot ? SAC_PREPARE_RESTART : SAC_PREPARE_SHUTDOWN,
  1675. TRUE
  1676. );
  1677. // wait until the machine has been up for at least RESTART_DELAY_TIME seconds.
  1678. KeInitializeEvent( &Event,
  1679. SynchronizationEvent,
  1680. FALSE );
  1681. ElapsedTime.QuadPart = Int32x32To64((LONG)((RESTART_DELAY_TIME-ElapsedTime.LowPart)*10000), // milliseconds until we reach RESTART_DELAY_TIME
  1682. -1000);
  1683. KeWaitForSingleObject((PVOID)&Event, Executive, KernelMode, FALSE, &ElapsedTime);
  1684. }
  1685. Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff);
  1686. //
  1687. // Get the global buffer started so that we have room for error messages.
  1688. //
  1689. if (GlobalBuffer == NULL) {
  1690. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1691. if (GlobalBuffer == NULL) {
  1692. SacPutSimpleMessage(SAC_NO_MEMORY);
  1693. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRebootCommand: Exiting (1).\n")));
  1694. return;
  1695. }
  1696. GlobalBufferSize = MEMORY_INCREMENT;
  1697. }
  1698. SacPutSimpleMessage(Reboot ? SAC_RESTART_FAILURE : SAC_SHUTDOWN_FAILURE);
  1699. SAC_PUT_ERROR_STRING(Status);
  1700. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRebootCommand: Exiting.\n")));
  1701. }
  1702. VOID
  1703. DoCrashCommand(
  1704. VOID
  1705. )
  1706. /*++
  1707. Routine Description:
  1708. This routine does a shutdown and bugcheck.
  1709. Arguments:
  1710. None.
  1711. Return Value:
  1712. None.
  1713. --*/
  1714. {
  1715. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCrashCommand: Entering.\n")));
  1716. //
  1717. // this call does not return
  1718. //
  1719. KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0);
  1720. // SacPutSimpleMessage( SAC_CRASHDUMP_FAILURE );
  1721. // IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCrashCommand: Exiting.\n")));
  1722. }
  1723. VOID
  1724. DoTlistCommand(
  1725. VOID
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This routine gets a Tlist and displays it.
  1730. Arguments:
  1731. None.
  1732. Return Value:
  1733. None.
  1734. --*/
  1735. {
  1736. NTSTATUS Status;
  1737. ULONG DataLength;
  1738. PVOID NewBuffer;
  1739. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Entering.\n")));
  1740. if (GlobalBuffer == NULL) {
  1741. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1742. if (GlobalBuffer == NULL) {
  1743. SacPutSimpleMessage(SAC_NO_MEMORY);
  1744. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Exiting.\n")));
  1745. return;
  1746. }
  1747. GlobalBufferSize = MEMORY_INCREMENT;
  1748. }
  1749. RetryTList:
  1750. Status = GetTListInfo((PSAC_RSP_TLIST)GlobalBuffer,
  1751. (LONG)GlobalBufferSize,
  1752. &DataLength
  1753. );
  1754. if ((Status == STATUS_NO_MEMORY) ||
  1755. (Status == STATUS_INFO_LENGTH_MISMATCH)) {
  1756. //
  1757. // Try to get more memory, if not available, then just fail without out of memory error.
  1758. //
  1759. NewBuffer = ALLOCATE_POOL(GlobalBufferSize + MEMORY_INCREMENT, GENERAL_POOL_TAG);
  1760. if (NewBuffer != NULL) {
  1761. FREE_POOL(&GlobalBuffer);
  1762. GlobalBuffer = NewBuffer;
  1763. GlobalBufferSize += MEMORY_INCREMENT;
  1764. goto RetryTList;
  1765. }
  1766. SacPutSimpleMessage(SAC_NO_MEMORY);
  1767. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Exiting.\n")));
  1768. return;
  1769. }
  1770. if (NT_SUCCESS(Status)) {
  1771. PrintTListInfo((PSAC_RSP_TLIST)GlobalBuffer);
  1772. } else {
  1773. SacPutSimpleMessage( SAC_TLIST_FAILURE );
  1774. SAC_PUT_ERROR_STRING(Status);
  1775. }
  1776. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoTlistCommand: Exiting.\n")));
  1777. }
  1778. NTSTATUS
  1779. GetTListInfo(
  1780. OUT PSAC_RSP_TLIST ResponseBuffer,
  1781. IN LONG ResponseBufferSize,
  1782. OUT PULONG ResponseDataSize
  1783. )
  1784. /*++
  1785. Routine Description:
  1786. This routine gets all the information necessary for the TList command.
  1787. Arguments:
  1788. ResponseBuffer - The buffer to put the results into.
  1789. ResponseBufferSize - The length of the above buffer.
  1790. ResponseDataSize - The length of the resulting buffer.
  1791. Return Value:
  1792. None.
  1793. --*/
  1794. {
  1795. NTSTATUS Status;
  1796. PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
  1797. PUCHAR DataBuffer;
  1798. PUCHAR StartProcessInfo;
  1799. LONG CurrentBufferSize;
  1800. ULONG ReturnLength;
  1801. ULONG TotalOffset;
  1802. ULONG OffsetIncrement = 0;
  1803. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  1804. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Entering.\n")));
  1805. *ResponseDataSize = 0;
  1806. if (ResponseBufferSize < sizeof(ResponseBuffer)) {
  1807. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory.\n")));
  1808. return(STATUS_NO_MEMORY);
  1809. }
  1810. DataBuffer = (PUCHAR)(ResponseBuffer + 1);
  1811. CurrentBufferSize = ResponseBufferSize - sizeof(SAC_RSP_TLIST);
  1812. if (CurrentBufferSize < 0) {
  1813. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory (2).\n")));
  1814. return STATUS_NO_MEMORY;
  1815. }
  1816. //
  1817. // Get system-wide information
  1818. //
  1819. Status = ZwQuerySystemInformation(SystemTimeOfDayInformation,
  1820. &(ResponseBuffer->TimeOfDayInfo),
  1821. sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
  1822. NULL
  1823. );
  1824. if (!NT_SUCCESS(Status)) {
  1825. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error.\n")));
  1826. return(Status);
  1827. }
  1828. Status = ZwQuerySystemInformation(SystemBasicInformation,
  1829. &(ResponseBuffer->BasicInfo),
  1830. sizeof(SYSTEM_BASIC_INFORMATION),
  1831. NULL
  1832. );
  1833. if (!NT_SUCCESS(Status)) {
  1834. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(2).\n")));
  1835. return(Status);
  1836. }
  1837. //
  1838. // Get pagefile information
  1839. //
  1840. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)DataBuffer;
  1841. Status = ZwQuerySystemInformation(SystemPageFileInformation,
  1842. PageFileInfo,
  1843. CurrentBufferSize,
  1844. &ReturnLength
  1845. );
  1846. if (NT_SUCCESS(Status) && (ReturnLength != 0)) {
  1847. ResponseBuffer->PagefileInfoOffset = ResponseBufferSize - CurrentBufferSize;
  1848. CurrentBufferSize -= ReturnLength;
  1849. DataBuffer += ReturnLength;
  1850. if (CurrentBufferSize < 0) {
  1851. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(3).\n")));
  1852. return STATUS_NO_MEMORY;
  1853. }
  1854. //
  1855. // Go thru each pagefile and fixup the names...
  1856. //
  1857. for (; ; ) {
  1858. if (PageFileInfo->PageFileName.Length > CurrentBufferSize) {
  1859. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(3).\n")));
  1860. return(STATUS_INFO_LENGTH_MISMATCH);
  1861. }
  1862. RtlCopyMemory(DataBuffer,
  1863. (PUCHAR)(PageFileInfo->PageFileName.Buffer),
  1864. PageFileInfo->PageFileName.Length
  1865. );
  1866. PageFileInfo->PageFileName.Buffer = (PWSTR)DataBuffer;
  1867. DataBuffer += PageFileInfo->PageFileName.Length;
  1868. CurrentBufferSize -= PageFileInfo->PageFileName.Length;
  1869. if (CurrentBufferSize < 0) {
  1870. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory (4).\n")));
  1871. return STATUS_NO_MEMORY;
  1872. }
  1873. if (PageFileInfo->NextEntryOffset == 0) {
  1874. break;
  1875. }
  1876. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
  1877. }
  1878. } else if (((ULONG)CurrentBufferSize) < ReturnLength) {
  1879. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(5).\n")));
  1880. return(STATUS_NO_MEMORY);
  1881. } else {
  1882. //
  1883. // Either failure or no paging file present.
  1884. //
  1885. ResponseBuffer->PagefileInfoOffset = 0;
  1886. }
  1887. //
  1888. // Get process information
  1889. //
  1890. Status = ZwQuerySystemInformation(SystemFileCacheInformation,
  1891. &(ResponseBuffer->FileCache),
  1892. sizeof(ResponseBuffer->FileCache),
  1893. NULL
  1894. );
  1895. if (!NT_SUCCESS(Status)) {
  1896. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(4).\n")));
  1897. return(Status);
  1898. }
  1899. Status = ZwQuerySystemInformation(SystemPerformanceInformation,
  1900. &(ResponseBuffer->PerfInfo),
  1901. sizeof(ResponseBuffer->PerfInfo),
  1902. NULL
  1903. );
  1904. if (!NT_SUCCESS(Status)) {
  1905. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(5).\n")));
  1906. return(Status);
  1907. }
  1908. //
  1909. // Realign DataBuffer for the next query
  1910. //
  1911. DataBuffer = ALIGN_UP_POINTER(DataBuffer, SYSTEM_PROCESS_INFORMATION);
  1912. CurrentBufferSize = (ULONG)(ResponseBufferSize - (((ULONG_PTR)DataBuffer) - ((ULONG_PTR)ResponseBuffer)));
  1913. if (CurrentBufferSize < 0) {
  1914. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory (6).\n")));
  1915. return STATUS_NO_MEMORY;
  1916. }
  1917. Status = ZwQuerySystemInformation(SystemProcessInformation,
  1918. DataBuffer,
  1919. CurrentBufferSize,
  1920. &ReturnLength
  1921. );
  1922. if (!NT_SUCCESS(Status)) {
  1923. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(6).\n")));
  1924. return(Status);
  1925. }
  1926. StartProcessInfo = DataBuffer;
  1927. ResponseBuffer->ProcessInfoOffset = ResponseBufferSize - CurrentBufferSize;
  1928. DataBuffer += ReturnLength;
  1929. CurrentBufferSize -= ReturnLength;
  1930. if (CurrentBufferSize < 0) {
  1931. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(7).\n")));
  1932. return STATUS_NO_MEMORY;
  1933. }
  1934. OffsetIncrement = 0;
  1935. TotalOffset = 0;
  1936. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)StartProcessInfo;
  1937. do {
  1938. //
  1939. // We have to take the name of each process and pack the UNICODE_STRING
  1940. // buffer in our buffer so it doesn't collide with the subsequent data
  1941. //
  1942. if (ProcessInfo->ImageName.Buffer) {
  1943. if (CurrentBufferSize < ProcessInfo->ImageName.Length ) {
  1944. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, error(7).\n")));
  1945. return(STATUS_INFO_LENGTH_MISMATCH);
  1946. }
  1947. RtlCopyMemory(DataBuffer, (PUCHAR)(ProcessInfo->ImageName.Buffer), ProcessInfo->ImageName.Length);
  1948. ProcessInfo->ImageName.Buffer = (PWSTR)DataBuffer;
  1949. DataBuffer += ProcessInfo->ImageName.Length;
  1950. CurrentBufferSize -= ProcessInfo->ImageName.Length;
  1951. if (CurrentBufferSize < 0) {
  1952. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting, no memory(8).\n")));
  1953. return STATUS_NO_MEMORY;
  1954. }
  1955. }
  1956. if (ProcessInfo->NextEntryOffset == 0) {
  1957. break;
  1958. }
  1959. OffsetIncrement = ProcessInfo->NextEntryOffset;
  1960. TotalOffset += OffsetIncrement;
  1961. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&(StartProcessInfo[TotalOffset]);
  1962. } while( OffsetIncrement != 0 );
  1963. *ResponseDataSize = (ULONG)(ResponseBufferSize - CurrentBufferSize);
  1964. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC GetTlistInfo: Exiting.\n")));
  1965. return STATUS_SUCCESS;
  1966. }
  1967. VOID
  1968. PrintTListInfo(
  1969. IN PSAC_RSP_TLIST Buffer
  1970. )
  1971. /*++
  1972. Routine Description:
  1973. This routine prints TList info to the headless terminal.
  1974. Arguments:
  1975. Buffer - The buffer with the results.
  1976. Return Value:
  1977. None.
  1978. --*/
  1979. {
  1980. LARGE_INTEGER Time;
  1981. TIME_FIELDS UserTime;
  1982. TIME_FIELDS KernelTime;
  1983. TIME_FIELDS UpTime;
  1984. ULONG TotalOffset;
  1985. ULONG OffsetIncrement = 0;
  1986. SIZE_T SumCommit;
  1987. SIZE_T SumWorkingSet;
  1988. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  1989. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  1990. PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
  1991. ULONG i;
  1992. PUCHAR ProcessInfoStart;
  1993. PUCHAR BufferStart = (PUCHAR)Buffer;
  1994. ULONG LineNumber = 0;
  1995. ULONG OutputBufferSize;
  1996. PWCHAR OutputBuffer;
  1997. UNICODE_STRING Process;
  1998. BOOLEAN Stop;
  1999. PCWSTR Message;
  2000. //
  2001. // Allocate work buffer
  2002. // should never be more than 80, but just to be safe....
  2003. //
  2004. OutputBufferSize = 200*sizeof(WCHAR);
  2005. OutputBuffer = ALLOCATE_POOL(OutputBufferSize, GENERAL_POOL_TAG);
  2006. ASSERT(OutputBuffer);
  2007. if (OutputBuffer == NULL) {
  2008. IF_SAC_DEBUG(
  2009. SAC_DEBUG_FAILS,
  2010. KdPrint(("SAC PrintTlistInfo: Failed to allocate OuputBuffer\n"))
  2011. );
  2012. return;
  2013. }
  2014. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Entering.\n")));
  2015. Time.QuadPart = Buffer->TimeOfDayInfo.CurrentTime.QuadPart - Buffer->TimeOfDayInfo.BootTime.QuadPart;
  2016. RtlTimeToElapsedTimeFields(&Time, &UpTime);
  2017. SAFE_SWPRINTF(
  2018. OutputBufferSize,
  2019. (OutputBuffer,
  2020. GetMessage( SAC_TLIST_HEADER1_FORMAT ),
  2021. Buffer->BasicInfo.NumberOfPhysicalPages * (Buffer->BasicInfo.PageSize / 1024),
  2022. UpTime.Day,
  2023. UpTime.Hour,
  2024. UpTime.Minute,
  2025. UpTime.Second,
  2026. UpTime.Milliseconds
  2027. ));
  2028. SacPutString(OutputBuffer);
  2029. LineNumber += 2;
  2030. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)(BufferStart + Buffer->PagefileInfoOffset);
  2031. //
  2032. // Print out the page file information.
  2033. //
  2034. if (Buffer->PagefileInfoOffset == 0) {
  2035. SacPutSimpleMessage(SAC_TLIST_NOPAGEFILE);
  2036. LineNumber++;
  2037. } else {
  2038. for (; ; ) {
  2039. //
  2040. // ensure that the OutputBuffer is big enough to hold the string
  2041. //
  2042. Message = GetMessage(SAC_TLIST_PAGEFILE_NAME);
  2043. if (Message == NULL) {
  2044. //
  2045. // we must have this resource
  2046. //
  2047. ASSERT(0);
  2048. //
  2049. // give up trying to print page file info
  2050. //
  2051. break;
  2052. }
  2053. if (((wcslen(Message) +
  2054. wcslen((PWSTR)&(PageFileInfo->PageFileName))) * sizeof(WCHAR)) > (OutputBufferSize-2)) {
  2055. //
  2056. // Since we don't expect the pagefilename to be > 80 chars, we should stop and
  2057. // take a look at the name if this does happen
  2058. //
  2059. ASSERT(0);
  2060. //
  2061. // give up trying to print page file info
  2062. //
  2063. break;
  2064. }
  2065. SAFE_SWPRINTF(
  2066. OutputBufferSize,
  2067. (OutputBuffer,
  2068. Message,
  2069. &PageFileInfo->PageFileName
  2070. ));
  2071. SacPutString(OutputBuffer);
  2072. LineNumber++;
  2073. SAFE_SWPRINTF(
  2074. OutputBufferSize,
  2075. (OutputBuffer,
  2076. GetMessage(SAC_TLIST_PAGEFILE_DATA),
  2077. PageFileInfo->TotalSize * (Buffer->BasicInfo.PageSize/1024),
  2078. PageFileInfo->TotalInUse * (Buffer->BasicInfo.PageSize/1024),
  2079. PageFileInfo->PeakUsage * (Buffer->BasicInfo.PageSize/1024)
  2080. ));
  2081. SacPutString(OutputBuffer);
  2082. LineNumber++;
  2083. if (PageFileInfo->NextEntryOffset == 0) {
  2084. break;
  2085. }
  2086. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
  2087. }
  2088. }
  2089. //
  2090. // display pmon style process output, then detailed output that includes
  2091. // per thread stuff
  2092. //
  2093. if (Buffer->ProcessInfoOffset == 0) {
  2094. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Exiting (1).\n")));
  2095. goto PrintTListInfoCleanup;
  2096. }
  2097. OffsetIncrement = 0;
  2098. TotalOffset = 0;
  2099. SumCommit = 0;
  2100. SumWorkingSet = 0;
  2101. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  2102. ProcessInfoStart = (PUCHAR)ProcessInfo;
  2103. do {
  2104. SumCommit += ProcessInfo->PrivatePageCount / 1024;
  2105. SumWorkingSet += ProcessInfo->WorkingSetSize / 1024;
  2106. OffsetIncrement = ProcessInfo->NextEntryOffset;
  2107. TotalOffset += OffsetIncrement;
  2108. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart +TotalOffset);
  2109. } while( OffsetIncrement != 0 );
  2110. SumWorkingSet += Buffer->FileCache.CurrentSize/1024;
  2111. if (LineNumber > 17) {
  2112. PutMore(&Stop);
  2113. if (Stop) {
  2114. goto PrintTListInfoCleanup;
  2115. }
  2116. LineNumber = 0;
  2117. }
  2118. SAFE_SWPRINTF(
  2119. OutputBufferSize,
  2120. (OutputBuffer,
  2121. GetMessage(SAC_TLIST_MEMORY1_DATA),
  2122. Buffer->BasicInfo.NumberOfPhysicalPages * (Buffer->BasicInfo.PageSize/1024),
  2123. Buffer->PerfInfo.AvailablePages * (Buffer->BasicInfo.PageSize/1024),
  2124. SumWorkingSet,
  2125. (Buffer->PerfInfo.ResidentSystemCodePage + Buffer->PerfInfo.ResidentSystemDriverPage) *
  2126. (Buffer->BasicInfo.PageSize/1024),
  2127. (Buffer->PerfInfo.ResidentPagedPoolPage) * (Buffer->BasicInfo.PageSize/1024)
  2128. ));
  2129. SacPutString(OutputBuffer);
  2130. LineNumber += 2;
  2131. if (LineNumber > 18) {
  2132. PutMore(&Stop);
  2133. if (Stop) {
  2134. goto PrintTListInfoCleanup;
  2135. }
  2136. LineNumber = 0;
  2137. }
  2138. SAFE_SWPRINTF(
  2139. OutputBufferSize,
  2140. (OutputBuffer,
  2141. GetMessage(SAC_TLIST_MEMORY2_DATA),
  2142. Buffer->PerfInfo.CommittedPages * (Buffer->BasicInfo.PageSize/1024),
  2143. SumCommit,
  2144. Buffer->PerfInfo.CommitLimit * (Buffer->BasicInfo.PageSize/1024),
  2145. Buffer->PerfInfo.PeakCommitment * (Buffer->BasicInfo.PageSize/1024),
  2146. Buffer->PerfInfo.NonPagedPoolPages * (Buffer->BasicInfo.PageSize/1024),
  2147. Buffer->PerfInfo.PagedPoolPages * (Buffer->BasicInfo.PageSize/1024)
  2148. ));
  2149. SacPutString(OutputBuffer);
  2150. LineNumber++;
  2151. if (LineNumber > 18) {
  2152. PutMore(&Stop);
  2153. if (Stop) {
  2154. goto PrintTListInfoCleanup;
  2155. }
  2156. LineNumber = 0;
  2157. }
  2158. SacPutSimpleMessage(SAC_ENTER);
  2159. PutMore(&Stop);
  2160. if (Stop) {
  2161. goto PrintTListInfoCleanup;
  2162. }
  2163. LineNumber = 0;
  2164. SacPutSimpleMessage( SAC_TLIST_PROCESS1_HEADER );
  2165. LineNumber++;
  2166. SAFE_SWPRINTF(
  2167. OutputBufferSize,
  2168. (OutputBuffer,
  2169. GetMessage( SAC_TLIST_PROCESS2_HEADER ),
  2170. Buffer->FileCache.CurrentSize/1024,
  2171. Buffer->FileCache.PageFaultCount
  2172. ));
  2173. SacPutString(OutputBuffer);
  2174. LineNumber++;
  2175. OffsetIncrement = 0;
  2176. TotalOffset = 0;
  2177. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  2178. do {
  2179. RtlTimeToElapsedTimeFields(&ProcessInfo->UserTime, &UserTime);
  2180. RtlTimeToElapsedTimeFields(&ProcessInfo->KernelTime, &KernelTime);
  2181. Process.Buffer = NULL;
  2182. if (ProcessInfo->UniqueProcessId == 0) {
  2183. RtlInitUnicodeString( &Process, L"Idle Process" );
  2184. } else if (!ProcessInfo->ImageName.Buffer) {
  2185. RtlInitUnicodeString( &Process, L"System" );
  2186. }
  2187. SAFE_SWPRINTF(
  2188. OutputBufferSize,
  2189. (OutputBuffer,
  2190. GetMessage( SAC_TLIST_PROCESS1_DATA ),
  2191. UserTime.Hour,
  2192. UserTime.Minute,
  2193. UserTime.Second,
  2194. UserTime.Milliseconds,
  2195. KernelTime.Hour,
  2196. KernelTime.Minute,
  2197. KernelTime.Second,
  2198. KernelTime.Milliseconds,
  2199. ProcessInfo->WorkingSetSize / 1024,
  2200. ProcessInfo->PageFaultCount,
  2201. ProcessInfo->PrivatePageCount / 1024,
  2202. ProcessInfo->BasePriority,
  2203. ProcessInfo->HandleCount,
  2204. ProcessInfo->NumberOfThreads,
  2205. HandleToUlong(ProcessInfo->UniqueProcessId),
  2206. Process.Buffer ? &Process : &ProcessInfo->ImageName
  2207. ));
  2208. SacPutString(OutputBuffer);
  2209. LineNumber++;
  2210. if( wcslen( OutputBuffer ) >= 80 ) {
  2211. //
  2212. // We line-wrapped, so include the additional line in our running-count.
  2213. //
  2214. LineNumber++;
  2215. }
  2216. //
  2217. // update the position in the process list before we check to see if we need
  2218. // to prompt for more. This way, if we are done, we don't prompt.
  2219. //
  2220. OffsetIncrement = ProcessInfo->NextEntryOffset;
  2221. TotalOffset += OffsetIncrement;
  2222. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart + TotalOffset);
  2223. //
  2224. // if there are more records and we have displayed a screen's worth of data
  2225. // Prompt for more and reset the line counter
  2226. //
  2227. if (( OffsetIncrement != 0 ) && (LineNumber > 18)) {
  2228. PutMore(&Stop);
  2229. if (Stop) {
  2230. goto PrintTListInfoCleanup;
  2231. }
  2232. LineNumber = 0;
  2233. if (GlobalPagingNeeded) {
  2234. SacPutSimpleMessage( SAC_TLIST_PROCESS1_HEADER );
  2235. }
  2236. LineNumber++;
  2237. }
  2238. } while( OffsetIncrement != 0 );
  2239. if (!GlobalDoThreads) {
  2240. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Exiting (2).\n")));
  2241. goto PrintTListInfoCleanup;
  2242. }
  2243. //
  2244. // Beginning of normal old style pstat output
  2245. //
  2246. TotalOffset = 0;
  2247. OffsetIncrement = 0;
  2248. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  2249. PutMore(&Stop);
  2250. if (Stop) {
  2251. goto PrintTListInfoCleanup;
  2252. }
  2253. LineNumber = 0;
  2254. SacPutSimpleMessage(SAC_ENTER);
  2255. LineNumber++;
  2256. do {
  2257. Process.Buffer = NULL;
  2258. if (ProcessInfo->UniqueProcessId == 0) {
  2259. RtlInitUnicodeString( &Process, L"Idle Process" );
  2260. } else if (!ProcessInfo->ImageName.Buffer) {
  2261. RtlInitUnicodeString( &Process, L"System" );
  2262. }
  2263. SAFE_SWPRINTF(
  2264. OutputBufferSize,
  2265. (OutputBuffer,
  2266. GetMessage(SAC_TLIST_PSTAT_HEADER),
  2267. HandleToUlong(ProcessInfo->UniqueProcessId),
  2268. ProcessInfo->BasePriority,
  2269. ProcessInfo->HandleCount,
  2270. ProcessInfo->PageFaultCount,
  2271. ProcessInfo->WorkingSetSize / 1024,
  2272. Process.Buffer ? &Process : &ProcessInfo->ImageName
  2273. ));
  2274. SacPutString(OutputBuffer);
  2275. LineNumber++;
  2276. if( wcslen( OutputBuffer ) >= 80 ) {
  2277. //
  2278. // We line-wrapped, so include the additional line in our running-count.
  2279. //
  2280. LineNumber++;
  2281. }
  2282. if (LineNumber > 18) {
  2283. PutMore(&Stop);
  2284. if (Stop) {
  2285. goto PrintTListInfoCleanup;
  2286. }
  2287. LineNumber = 0;
  2288. }
  2289. i = 0;
  2290. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  2291. if (ProcessInfo->NumberOfThreads) {
  2292. if ((LineNumber < 18) || !GlobalPagingNeeded) {
  2293. SacPutSimpleMessage( SAC_TLIST_PSTAT_THREAD_HEADER );
  2294. LineNumber++;
  2295. } else {
  2296. PutMore(&Stop);
  2297. if (Stop) {
  2298. goto PrintTListInfoCleanup;
  2299. }
  2300. LineNumber = 0;
  2301. }
  2302. }
  2303. while (i < ProcessInfo->NumberOfThreads) {
  2304. RtlTimeToElapsedTimeFields ( &ThreadInfo->UserTime, &UserTime);
  2305. RtlTimeToElapsedTimeFields ( &ThreadInfo->KernelTime, &KernelTime);
  2306. SAFE_SWPRINTF(
  2307. OutputBufferSize,
  2308. (OutputBuffer,
  2309. GetMessage( SAC_TLIST_PSTAT_THREAD_DATA ),
  2310. ProcessInfo->UniqueProcessId == 0 ? 0 : HandleToUlong(ThreadInfo->ClientId.UniqueThread),
  2311. ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->Priority,
  2312. ThreadInfo->ContextSwitches,
  2313. ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->StartAddress,
  2314. UserTime.Hour,
  2315. UserTime.Minute,
  2316. UserTime.Second,
  2317. UserTime.Milliseconds,
  2318. KernelTime.Hour,
  2319. KernelTime.Minute,
  2320. KernelTime.Second,
  2321. KernelTime.Milliseconds,
  2322. StateTable[ThreadInfo->ThreadState],
  2323. (ThreadInfo->ThreadState == 5) ? WaitTable[ThreadInfo->WaitReason] : Empty
  2324. ));
  2325. SacPutString(OutputBuffer);
  2326. LineNumber++;
  2327. if( wcslen( OutputBuffer ) >= 80 ) {
  2328. //
  2329. // We line-wrapped, so include the additional line in our running-count.
  2330. //
  2331. LineNumber++;
  2332. }
  2333. if (LineNumber > 18) {
  2334. PutMore(&Stop);
  2335. if (Stop) {
  2336. goto PrintTListInfoCleanup;
  2337. }
  2338. LineNumber = 0;
  2339. if (GlobalPagingNeeded) {
  2340. SacPutSimpleMessage( SAC_TLIST_PSTAT_THREAD_HEADER );
  2341. }
  2342. LineNumber++;
  2343. }
  2344. ThreadInfo += 1;
  2345. i += 1;
  2346. }
  2347. OffsetIncrement = ProcessInfo->NextEntryOffset;
  2348. TotalOffset += OffsetIncrement;
  2349. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart + TotalOffset);
  2350. SacPutSimpleMessage(SAC_ENTER);
  2351. LineNumber++;
  2352. if (LineNumber > 18) {
  2353. PutMore(&Stop);
  2354. if (Stop) {
  2355. goto PrintTListInfoCleanup;
  2356. }
  2357. LineNumber = 0;
  2358. }
  2359. } while( OffsetIncrement != 0 );
  2360. PrintTListInfoCleanup:
  2361. SAFE_FREE_POOL(&OutputBuffer);
  2362. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PrintTlistInfo: Exiting.\n")));
  2363. }
  2364. VOID
  2365. PutMore(
  2366. OUT PBOOLEAN Stop
  2367. )
  2368. {
  2369. #if 0
  2370. PHEADLESS_RSP_GET_LINE Response;
  2371. UCHAR Buffer[20];
  2372. SIZE_T Length;
  2373. #endif
  2374. LARGE_INTEGER WaitTime;
  2375. NTSTATUS Status;
  2376. UCHAR ch;
  2377. #if 0
  2378. ASSERT(sizeof(HEADLESS_RSP_GET_LINE) <= (sizeof(UCHAR) * 20));
  2379. #endif
  2380. //
  2381. // Default: we will not stop paging
  2382. //
  2383. *Stop = FALSE;
  2384. //
  2385. // If paging is enabled,
  2386. // then wait for user input
  2387. //
  2388. if (GlobalPagingNeeded) {
  2389. WaitTime.QuadPart = Int32x32To64((LONG)100, -1000); // 100ms from now.
  2390. //
  2391. // Prompt for user input
  2392. //
  2393. SacPutSimpleMessage( SAC_MORE_MESSAGE );
  2394. while (! *Stop) {
  2395. //
  2396. // Query the serial port buffer
  2397. //
  2398. Status = SerialBufferGetChar(&ch);
  2399. //
  2400. // wait if there are no characters
  2401. //
  2402. if (Status == STATUS_NO_DATA_DETECTED) {
  2403. KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
  2404. continue;
  2405. }
  2406. //
  2407. // if the user input a ctrl-c,
  2408. // then stop paging
  2409. //
  2410. if (ch == 0x3) { // Control-C
  2411. *Stop = TRUE;
  2412. }
  2413. //
  2414. // if we get a CR || LF,
  2415. // then continue to the next page
  2416. //
  2417. if (ch == 0x0D || ch == 0x0A) {
  2418. break;
  2419. }
  2420. }
  2421. #if 0
  2422. Response = (PHEADLESS_RSP_GET_LINE)&(Buffer[0]);
  2423. Length = sizeof(UCHAR) * 20;
  2424. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2425. NULL,
  2426. 0,
  2427. Response,
  2428. &Length
  2429. );
  2430. while (NT_SUCCESS(Status) && !Response->LineComplete) {
  2431. KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
  2432. Length = sizeof(UCHAR) * 20;
  2433. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2434. NULL,
  2435. 0,
  2436. Response,
  2437. &Length
  2438. );
  2439. }
  2440. if (Response->Buffer[0] == 0x3) { // Control-C
  2441. *Stop = TRUE;
  2442. } else {
  2443. *Stop = FALSE;
  2444. }
  2445. //
  2446. // Drain any remaining buffered input
  2447. //
  2448. Length = sizeof(UCHAR) * 20;
  2449. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2450. NULL,
  2451. 0,
  2452. Response,
  2453. &Length
  2454. );
  2455. while (NT_SUCCESS(Status) && Response->LineComplete) {
  2456. Length = sizeof(UCHAR) * 20;
  2457. Status = HeadlessDispatch(HeadlessCmdGetLine,
  2458. NULL,
  2459. 0,
  2460. Response,
  2461. &Length
  2462. );
  2463. }
  2464. #endif
  2465. } else {
  2466. *Stop = FALSE;
  2467. }
  2468. }
  2469. NTSTATUS
  2470. CallQueryIPIOCTL(
  2471. HANDLE IpDeviceHandle,
  2472. PKEVENT Event,
  2473. HANDLE EventHandle,
  2474. IO_STATUS_BLOCK *IoStatusBlock,
  2475. PVOID InputBuffer,
  2476. ULONG InputBufferSize,
  2477. PVOID OutputBuffer,
  2478. ULONG OutputBufferSize,
  2479. BOOLEAN PrintToTerminal,
  2480. BOOLEAN *putPrompt
  2481. )
  2482. {
  2483. NTSTATUS Status;
  2484. LARGE_INTEGER TimeOut;
  2485. //
  2486. // Submit the IOCTL
  2487. //
  2488. Status = NtDeviceIoControlFile(IpDeviceHandle,
  2489. EventHandle,
  2490. NULL,
  2491. NULL,
  2492. IoStatusBlock,
  2493. IOCTL_TCP_QUERY_INFORMATION_EX,
  2494. InputBuffer,
  2495. InputBufferSize,
  2496. OutputBuffer,
  2497. OutputBufferSize);
  2498. if (Status == STATUS_PENDING) {
  2499. //
  2500. // Wait up to 30 seconds for it to finish
  2501. //
  2502. if (PrintToTerminal != FALSE) {
  2503. SacPutSimpleMessage( SAC_ENTER );
  2504. SacPutSimpleMessage( SAC_RETRIEVING_IPADDR );
  2505. if (putPrompt) {
  2506. *putPrompt= TRUE;
  2507. }
  2508. }
  2509. TimeOut.QuadPart = Int32x32To64((LONG)30000, -1000);
  2510. Status = KeWaitForSingleObject((PVOID)Event, Executive, KernelMode, FALSE, &TimeOut);
  2511. if (NT_SUCCESS(Status)) {
  2512. Status = IoStatusBlock->Status;
  2513. }
  2514. }
  2515. return(Status);
  2516. }
  2517. VOID
  2518. DoGetNetInfo(
  2519. BOOLEAN PrintToTerminal
  2520. )
  2521. /*++
  2522. Routine Description:
  2523. This routine attempts to get and print every IP net number and its IP
  2524. address.
  2525. Arguments:
  2526. PrintToTerminal - Determines if the IP information is printed ( == TRUE )
  2527. Or sent to the kernel ( == FALSE )
  2528. Return Value:
  2529. None.
  2530. --*/
  2531. {
  2532. NTSTATUS Status;
  2533. HANDLE Handle;
  2534. ULONG i, j;
  2535. IO_STATUS_BLOCK IoStatusBlock;
  2536. UNICODE_STRING UnicodeString;
  2537. OBJECT_ATTRIBUTES ObjectAttributes;
  2538. PTCP_REQUEST_QUERY_INFORMATION_EX TcpRequestQueryInformationEx;
  2539. IPAddrEntry *AddressEntry,*AddressArray;
  2540. IPSNMPInfo *IpsiInfo;
  2541. IPRouteEntry *RouteTable;
  2542. ULONG Gateway;
  2543. PHEADLESS_CMD_SET_BLUE_SCREEN_DATA LocalPropBuffer = NULL;
  2544. PVOID LocalBuffer;
  2545. PUCHAR pch = NULL;
  2546. ULONG len;
  2547. BOOLEAN putPrompt=FALSE;
  2548. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Entering.\n")));
  2549. //
  2550. // Alloc space for calling the IP driver
  2551. //
  2552. TcpRequestQueryInformationEx = ALLOCATE_POOL(
  2553. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2554. GENERAL_POOL_TAG );
  2555. if (TcpRequestQueryInformationEx == NULL) {
  2556. SacPutSimpleMessage(SAC_NO_MEMORY);
  2557. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (1).\n")));
  2558. return;
  2559. }
  2560. IpsiInfo = ALLOCATE_POOL( sizeof(IPSNMPInfo),
  2561. GENERAL_POOL_TAG );
  2562. if (IpsiInfo == NULL) {
  2563. SacPutSimpleMessage(SAC_NO_MEMORY);
  2564. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (1).\n")));
  2565. FREE_POOL(&TcpRequestQueryInformationEx);
  2566. return;
  2567. }
  2568. //
  2569. // zero out the context information and preload with the info we're gonna
  2570. // request (we want the count of interfaces)
  2571. //
  2572. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_STATS_ID;
  2573. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  2574. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  2575. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2576. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  2577. LocalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  2578. if (LocalBuffer == NULL) {
  2579. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (6).\n")));
  2580. FREE_POOL(&TcpRequestQueryInformationEx);
  2581. FREE_POOL(&IpsiInfo);
  2582. return;
  2583. }
  2584. //
  2585. // Start by opening the TCP driver
  2586. //
  2587. RtlInitUnicodeString(&UnicodeString, DD_TCP_DEVICE_NAME);
  2588. InitializeObjectAttributes(&ObjectAttributes,
  2589. &UnicodeString,
  2590. OBJ_CASE_INSENSITIVE,
  2591. NULL,
  2592. NULL
  2593. );
  2594. Status = ZwOpenFile(&Handle,
  2595. (ACCESS_MASK)FILE_GENERIC_READ,
  2596. &ObjectAttributes,
  2597. &IoStatusBlock,
  2598. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2599. 0
  2600. );
  2601. if (!NT_SUCCESS(Status)) {
  2602. if (PrintToTerminal ) {
  2603. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2604. SacPutSimpleMessage(SAC_ENTER);
  2605. }
  2606. FREE_POOL(&LocalBuffer);
  2607. FREE_POOL(&IpsiInfo);
  2608. FREE_POOL(&TcpRequestQueryInformationEx);
  2609. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (2).\n")));
  2610. return;
  2611. }
  2612. if (SACEvent == NULL) {
  2613. if (PrintToTerminal) {
  2614. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2615. }
  2616. ZwClose(Handle);
  2617. FREE_POOL(&LocalBuffer);
  2618. FREE_POOL(&IpsiInfo);
  2619. FREE_POOL(&TcpRequestQueryInformationEx);
  2620. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (14).\n")));
  2621. return;
  2622. }
  2623. //
  2624. // now call the ioctl
  2625. //
  2626. Status = CallQueryIPIOCTL(
  2627. Handle,
  2628. SACEvent,
  2629. SACEventHandle,
  2630. &IoStatusBlock,
  2631. TcpRequestQueryInformationEx,
  2632. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2633. IpsiInfo,
  2634. sizeof(IPSNMPInfo),
  2635. FALSE,
  2636. &putPrompt);
  2637. if (!NT_SUCCESS(Status)) {
  2638. if (PrintToTerminal){
  2639. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2640. }
  2641. ZwClose(Handle);
  2642. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2643. FREE_POOL(&LocalBuffer);
  2644. FREE_POOL(&IpsiInfo);
  2645. FREE_POOL(&TcpRequestQueryInformationEx);
  2646. return;
  2647. }
  2648. if (IpsiInfo->ipsi_numaddr == 0) {
  2649. if (PrintToTerminal) {
  2650. SacPutSimpleMessage( SAC_IPADDR_NONE );
  2651. }
  2652. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2653. ZwClose(Handle);
  2654. FREE_POOL(&LocalBuffer);
  2655. FREE_POOL(&IpsiInfo);
  2656. FREE_POOL(&TcpRequestQueryInformationEx);
  2657. return;
  2658. }
  2659. //
  2660. // if it succeeded, then allocate space for the array of IP addresses
  2661. //
  2662. AddressArray = ALLOCATE_POOL(IpsiInfo->ipsi_numaddr*sizeof(IPAddrEntry),
  2663. GENERAL_POOL_TAG);
  2664. if (AddressArray == NULL) {
  2665. SacPutSimpleMessage(SAC_NO_MEMORY);
  2666. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (16).\n")));
  2667. ZwClose(Handle);
  2668. FREE_POOL(&LocalBuffer);
  2669. FREE_POOL(&IpsiInfo);
  2670. FREE_POOL(&TcpRequestQueryInformationEx);
  2671. return;
  2672. }
  2673. //
  2674. // zero out the context information and preload with the info we're gonna
  2675. // request (we want information on each of the interfaces on this machine)
  2676. //
  2677. RtlZeroMemory(TcpRequestQueryInformationEx, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  2678. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  2679. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  2680. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  2681. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2682. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  2683. Status = CallQueryIPIOCTL(
  2684. Handle,
  2685. SACEvent,
  2686. SACEventHandle,
  2687. &IoStatusBlock,
  2688. TcpRequestQueryInformationEx,
  2689. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2690. AddressArray,
  2691. IpsiInfo->ipsi_numaddr*sizeof(IPAddrEntry),
  2692. PrintToTerminal,
  2693. &putPrompt);
  2694. if (!NT_SUCCESS(Status)) {
  2695. if (PrintToTerminal){
  2696. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2697. SAC_PUT_ERROR_STRING(Status);
  2698. }
  2699. FREE_POOL(&TcpRequestQueryInformationEx);
  2700. ZwClose(Handle);
  2701. FREE_POOL(&LocalBuffer);
  2702. FREE_POOL(&AddressArray);
  2703. FREE_POOL(&IpsiInfo);
  2704. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2705. return;
  2706. }
  2707. //
  2708. // Load the route table information too so we can display the gateway for
  2709. // each NIC.
  2710. //
  2711. RouteTable = ALLOCATE_POOL(IpsiInfo->ipsi_numroutes*sizeof(IPRouteEntry),
  2712. GENERAL_POOL_TAG);
  2713. if (RouteTable == NULL) {
  2714. SacPutSimpleMessage(SAC_NO_MEMORY);
  2715. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (14).\n")));
  2716. ZwClose(Handle);
  2717. FREE_POOL(&LocalBuffer);
  2718. FREE_POOL(&IpsiInfo);
  2719. FREE_POOL(&TcpRequestQueryInformationEx);
  2720. FREE_POOL(&AddressArray);
  2721. return;
  2722. }
  2723. //
  2724. // zero out the context information and preload with the info we're gonna
  2725. // request (we want routing information on each of the interfaces)
  2726. //
  2727. RtlZeroMemory(TcpRequestQueryInformationEx, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  2728. TcpRequestQueryInformationEx->ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  2729. TcpRequestQueryInformationEx->ID.toi_type = INFO_TYPE_PROVIDER;
  2730. TcpRequestQueryInformationEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  2731. TcpRequestQueryInformationEx->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2732. TcpRequestQueryInformationEx->ID.toi_entity.tei_instance = 0;
  2733. Status = CallQueryIPIOCTL(
  2734. Handle,
  2735. SACEvent,
  2736. SACEventHandle,
  2737. &IoStatusBlock,
  2738. TcpRequestQueryInformationEx,
  2739. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  2740. RouteTable,
  2741. IpsiInfo->ipsi_numroutes*sizeof(IPRouteEntry),
  2742. PrintToTerminal,
  2743. &putPrompt);
  2744. if (!NT_SUCCESS(Status)) {
  2745. if (PrintToTerminal){
  2746. SacPutSimpleMessage(SAC_IPADDR_FAILED);
  2747. SAC_PUT_ERROR_STRING(Status);
  2748. }
  2749. FREE_POOL(&TcpRequestQueryInformationEx);
  2750. ZwClose(Handle);
  2751. FREE_POOL(&LocalBuffer);
  2752. FREE_POOL(&AddressArray);
  2753. FREE_POOL(&RouteTable);
  2754. FREE_POOL(&IpsiInfo);
  2755. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoSetIpAddressCommand: Exiting (15).\n")));
  2756. return;
  2757. }
  2758. //
  2759. // Need to allocate a buffer for the XML data.
  2760. //
  2761. if(PrintToTerminal==FALSE) {
  2762. LocalPropBuffer = (PHEADLESS_CMD_SET_BLUE_SCREEN_DATA) ALLOCATE_POOL(2*MEMORY_INCREMENT, GENERAL_POOL_TAG);
  2763. if (LocalPropBuffer == NULL) {
  2764. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (6).\n")));
  2765. FREE_POOL(&AddressArray);
  2766. FREE_POOL(&RouteTable);
  2767. FREE_POOL(&LocalBuffer);
  2768. FREE_POOL(&IpsiInfo);
  2769. FREE_POOL(&TcpRequestQueryInformationEx);
  2770. ZwClose(Handle);
  2771. return;
  2772. }
  2773. pch = &(LocalPropBuffer->Data[0]);
  2774. len = sprintf((LPSTR)pch,"IPADDRESS");
  2775. LocalPropBuffer->ValueIndex = len+1;
  2776. pch = pch+len+1;
  2777. len = sprintf((LPSTR)pch,"\r\n<PROPERTY.ARRAY NAME=\"IPADDRESS\" TYPE=\"string\">\r\n");
  2778. pch = pch + len;
  2779. len = sprintf((LPSTR)pch,"<VALUE.ARRAY>\r\n");
  2780. pch = pch + len;
  2781. }
  2782. //
  2783. // walk the list of IP addresses and spit out the data
  2784. //
  2785. for (i = 0; i < IpsiInfo->ipsi_numaddr; i++) {
  2786. AddressEntry = &AddressArray[i];
  2787. if (IP_LOOPBACK(AddressEntry->iae_addr)) {
  2788. continue;
  2789. }
  2790. //
  2791. // We need to find which gateway pertains to this
  2792. // interface. The only way to do that is go dig
  2793. // through the list of gateway addresses and see
  2794. // if we can find one for this IP address and mask.
  2795. //
  2796. Gateway = 0;
  2797. for( j = 0; j < IpsiInfo->ipsi_numroutes; j++ ) {
  2798. //
  2799. // See if we can match masks on the IP address
  2800. // and the gateway.
  2801. //
  2802. if( (AddressEntry->iae_addr != 0) &&
  2803. (AddressEntry->iae_mask != 0) &&
  2804. ((AddressEntry->iae_addr & AddressEntry->iae_mask) ==
  2805. (RouteTable[j].ire_nexthop & AddressEntry->iae_mask)) ) {
  2806. // We found a match. Remember it and exit.
  2807. Gateway = RouteTable[j].ire_nexthop;
  2808. break;
  2809. }
  2810. }
  2811. if( Gateway == 0 ) {
  2812. //
  2813. // We failed to find a gateway. Look again, this time
  2814. // see if we can get an exact match between the IP address
  2815. // and the gateway.
  2816. //
  2817. for( j = 0; j < IpsiInfo->ipsi_numroutes; j++ ) {
  2818. if( RouteTable[j].ire_nexthop == AddressEntry->iae_addr ) {
  2819. // We found a match. Remember it and exit.
  2820. Gateway = RouteTable[j].ire_nexthop;
  2821. break;
  2822. }
  2823. }
  2824. }
  2825. if(PrintToTerminal){
  2826. swprintf(LocalBuffer,
  2827. GetMessage( SAC_IPADDR_DATA ),
  2828. //
  2829. // Interface number.
  2830. //
  2831. AddressEntry->iae_context,
  2832. //
  2833. // IP address.
  2834. //
  2835. AddressEntry->iae_addr & 0xFF,
  2836. (AddressEntry->iae_addr >> 8) & 0xFF,
  2837. (AddressEntry->iae_addr >> 16) & 0xFF,
  2838. (AddressEntry->iae_addr >> 24) & 0xFF,
  2839. //
  2840. // Subnet mask.
  2841. //
  2842. AddressEntry->iae_mask & 0xFF,
  2843. (AddressEntry->iae_mask >> 8) & 0xFF,
  2844. (AddressEntry->iae_mask >> 16) & 0xFF,
  2845. (AddressEntry->iae_mask >> 24) & 0xFF,
  2846. //
  2847. // Gateway address.
  2848. //
  2849. Gateway & 0xFF,
  2850. (Gateway >> 8) & 0xFF,
  2851. (Gateway >> 16) & 0xFF,
  2852. (Gateway >> 24) & 0xFF
  2853. );
  2854. SacPutString(LocalBuffer);
  2855. } else {
  2856. len=sprintf((LPSTR)LocalBuffer,"<VALUE>\"%d.%d.%d.%d\"</VALUE>\r\n",
  2857. AddressEntry->iae_addr & 0xFF,
  2858. (AddressEntry->iae_addr >> 8) & 0xFF,
  2859. (AddressEntry->iae_addr >> 16) & 0xFF,
  2860. (AddressEntry->iae_addr >> 24) & 0xFF
  2861. );
  2862. if (pch + len < ((PUCHAR) LocalPropBuffer) + 2*MEMORY_INCREMENT - 80){
  2863. // the 80 characters ensures that we can end this XML data
  2864. // properly
  2865. strcat((LPSTR)pch,LocalBuffer);
  2866. pch = pch + len;
  2867. }
  2868. }
  2869. }
  2870. if(PrintToTerminal==FALSE) {
  2871. sprintf((LPSTR)pch, "</VALUE.ARRAY>\r\n</PROPERTY.ARRAY>");
  2872. }
  2873. FREE_POOL(&TcpRequestQueryInformationEx);
  2874. ZwClose(Handle); // handle to the TCP driver.
  2875. FREE_POOL(&LocalBuffer);
  2876. FREE_POOL(&AddressArray);
  2877. FREE_POOL(&RouteTable);
  2878. FREE_POOL(&IpsiInfo);
  2879. if(!PrintToTerminal){
  2880. HeadlessDispatch(HeadlessCmdSetBlueScreenData,
  2881. LocalPropBuffer,
  2882. 2*MEMORY_INCREMENT,
  2883. NULL,
  2884. NULL
  2885. );
  2886. FREE_POOL(&LocalPropBuffer);
  2887. //
  2888. // open up the IP driver so we know if the addresses change
  2889. //
  2890. RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
  2891. InitializeObjectAttributes(&ObjectAttributes,
  2892. &UnicodeString,
  2893. OBJ_CASE_INSENSITIVE,
  2894. NULL,
  2895. NULL
  2896. );
  2897. Status = ZwOpenFile(&Handle,
  2898. (ACCESS_MASK)FILE_GENERIC_READ,
  2899. &ObjectAttributes,
  2900. &IoStatusBlock,
  2901. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2902. 0
  2903. );
  2904. if (!NT_SUCCESS(Status)) {
  2905. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoGetNetInfo: Exiting (2).\n")));
  2906. return;
  2907. }
  2908. Status = ZwDeviceIoControlFile(Handle,
  2909. NULL,
  2910. NetAPCRoutine,
  2911. NULL,
  2912. &GlobalIoStatusBlock,
  2913. IOCTL_IP_ADDCHANGE_NOTIFY_REQUEST,
  2914. NULL,
  2915. 0,
  2916. NULL,
  2917. 0
  2918. );
  2919. if (Status == STATUS_PENDING) {
  2920. IoctlSubmitted = TRUE;
  2921. }
  2922. if (putPrompt) {
  2923. SacPutSimpleMessage(SAC_ENTER);
  2924. SacPutSimpleMessage(SAC_PROMPT);
  2925. }
  2926. ZwClose(Handle);
  2927. }
  2928. return;
  2929. }
  2930. VOID
  2931. NetAPCRoutine(IN PVOID ApcContext,
  2932. IN PIO_STATUS_BLOCK IoStatusBlock,
  2933. IN ULONG Reserved
  2934. )
  2935. /*++
  2936. Routine Description:
  2937. This is the APC routine called after IOCTL_IP_ADDCHANGE_NOTIFY_REQUEST
  2938. was completed
  2939. Arguments:
  2940. APCContext - UNUSED
  2941. IoStatusBlock - Status about the Fate of the IRP
  2942. Reserved - UNUSED
  2943. Return Value:
  2944. None.
  2945. --*/
  2946. {
  2947. UNREFERENCED_PARAMETER(Reserved);
  2948. UNREFERENCED_PARAMETER(ApcContext);
  2949. if (IoStatusBlock->Status == STATUS_CANCELLED) {
  2950. // The SAC driver might be unloading
  2951. // BUGBUG - If the IP driver is stopped and restarted
  2952. // then we are out of the loop. What to do ??
  2953. return;
  2954. }
  2955. // Refresh the kernel information and resend the IRP
  2956. DoGetNetInfo( FALSE );
  2957. return;
  2958. }
  2959. VOID
  2960. SubmitIPIoRequest(
  2961. )
  2962. /*++
  2963. Routine Description:
  2964. Called the first time by the Processing Thread to actually
  2965. submit the ADDR_CHANGE IOCTL to the IP Driver. Only the
  2966. processing thread can call this and calls it only once successfully.
  2967. Then on the APC is reentered only through the NetAPCRoutine
  2968. Arguments:
  2969. None.
  2970. Return Value:
  2971. None.
  2972. --*/
  2973. {
  2974. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  2975. KdPrint(("SAC Submit IP Ioctl: Entering.\n")));
  2976. DoGetNetInfo( FALSE );
  2977. return;
  2978. }
  2979. VOID
  2980. CancelIPIoRequest(
  2981. )
  2982. /*++
  2983. Routine Description:
  2984. Called by the processing thread during unload of the driver
  2985. to cancel the IOCTL sent to the IP driver
  2986. Arguments:
  2987. None.
  2988. Return Value:
  2989. None.
  2990. --*/
  2991. {
  2992. IO_STATUS_BLOCK IoStatusBlock;
  2993. UNICODE_STRING UnicodeString;
  2994. OBJECT_ATTRIBUTES ObjectAttributes;
  2995. NTSTATUS Status;
  2996. HANDLE Handle;
  2997. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  2998. KdPrint(("SAC Cancel IP Ioctl: Entering.\n")));
  2999. RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
  3000. InitializeObjectAttributes(&ObjectAttributes,
  3001. &UnicodeString,
  3002. OBJ_CASE_INSENSITIVE,
  3003. NULL,
  3004. NULL
  3005. );
  3006. Status = ZwOpenFile(&Handle,
  3007. (ACCESS_MASK)FILE_GENERIC_READ,
  3008. &ObjectAttributes,
  3009. &IoStatusBlock,
  3010. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3011. 0
  3012. );
  3013. if (!NT_SUCCESS(Status)) {
  3014. // Well, well IP Driver was probably never loaded.
  3015. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC Cancel IP IOCTL: Exiting (2).\n")));
  3016. return;
  3017. }
  3018. ZwCancelIoFile(Handle,
  3019. &IoStatusBlock
  3020. );
  3021. ZwClose(Handle);
  3022. }
  3023. VOID
  3024. DoMachineInformationCommand(
  3025. VOID
  3026. )
  3027. /*++
  3028. Routine Description:
  3029. This function displays the contents of a buffer, which in turn contains
  3030. a bunch of machine-specific information that can be used to help identify
  3031. the machine.
  3032. Arguments:
  3033. None.
  3034. Return Value:
  3035. None.
  3036. --*/
  3037. {
  3038. LARGE_INTEGER TickCount;
  3039. LARGE_INTEGER ElapsedTime;
  3040. ULONG ElapsedHours = 0;
  3041. ULONG ElapsedMinutes = 0;
  3042. ULONG ElapsedSeconds = 0;
  3043. ULONG TmpBufferSize;
  3044. PWSTR TmpBuffer;
  3045. PWSTR MIBuffer;
  3046. NTSTATUS Status;
  3047. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  3048. KdPrint(("SAC Display Machine Information: Entering.\n")));
  3049. //
  3050. // If the information buffer hasn't been filled in yet, there's not much we can do.
  3051. //
  3052. if( MachineInformation == NULL ) {
  3053. //
  3054. // He's empty. This shouldn't have happened though because
  3055. // he gets filled as soon as we're initialized.
  3056. //
  3057. IF_SAC_DEBUG( SAC_DEBUG_FUNC_TRACE_LOUD,
  3058. KdPrint(("SAC Display Machine Information: MachineInformationBuffer hasn't been initialized yet.\n")));
  3059. SacPutSimpleMessage(SAC_IDENTIFICATION_UNAVAILABLE);
  3060. return;
  3061. }
  3062. //
  3063. // Get machine information
  3064. //
  3065. Status = TranslateMachineInformationText(&MIBuffer);
  3066. if (! NT_SUCCESS(Status)) {
  3067. SacPutSimpleMessage(SAC_IDENTIFICATION_UNAVAILABLE);
  3068. return;
  3069. }
  3070. //
  3071. // Display the machine info portion
  3072. //
  3073. SacPutString(MIBuffer);
  3074. FREE_POOL(&MIBuffer);
  3075. //
  3076. // Build and display Elapsed machine uptime.
  3077. //
  3078. // Elapsed TickCount
  3079. KeQueryTickCount( &TickCount );
  3080. // ElapsedTime in seconds.
  3081. // ElapsedTime.QuadPart = (TickCount.QuadPart)/(10000000/KeQueryTimeIncrement());
  3082. ElapsedTime.QuadPart = (TickCount.QuadPart * KeQueryTimeIncrement()) / 10000000;
  3083. ElapsedHours = (ULONG)(ElapsedTime.QuadPart / 3600);
  3084. ElapsedMinutes = (ULONG)(ElapsedTime.QuadPart % 3600) / 60;
  3085. ElapsedSeconds = (ULONG)(ElapsedTime.QuadPart % 3600) % 60;
  3086. TmpBufferSize = 0x100;
  3087. TmpBuffer = (PWSTR)ALLOCATE_POOL( TmpBufferSize, GENERAL_POOL_TAG );
  3088. if( TmpBuffer ) {
  3089. SAFE_SWPRINTF(
  3090. TmpBufferSize,
  3091. ((PWSTR)TmpBuffer,
  3092. GetMessage( SAC_HEARTBEAT_FORMAT ),
  3093. ElapsedHours,
  3094. ElapsedMinutes,
  3095. ElapsedSeconds
  3096. ));
  3097. //
  3098. // Display machine uptime
  3099. //
  3100. SacPutString((PWSTR)TmpBuffer);
  3101. FREE_POOL(&TmpBuffer);
  3102. }
  3103. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  3104. KdPrint(("SAC Display Machine Information: Exiting.\n")));
  3105. return;
  3106. }
  3107. NTSTATUS
  3108. DoChannelListCommand(
  3109. VOID
  3110. )
  3111. /*++
  3112. Routine Description:
  3113. This routine lists the channels.
  3114. Arguments:
  3115. None.
  3116. Return Value:
  3117. Status
  3118. --*/
  3119. {
  3120. NTSTATUS Status;
  3121. PSAC_CHANNEL Channel;
  3122. ULONG i;
  3123. PWCHAR Buffer;
  3124. ULONG BufferSize;
  3125. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelListCommand: Entering.\n")));
  3126. //
  3127. // Allocate local memory
  3128. //
  3129. BufferSize = 8 * sizeof(WCHAR);
  3130. Buffer = ALLOCATE_POOL(BufferSize, GENERAL_POOL_TAG);
  3131. ASSERT_STATUS(Buffer, STATUS_NO_MEMORY);
  3132. //
  3133. // default: we listed the channels
  3134. //
  3135. Status = STATUS_SUCCESS;
  3136. //
  3137. // List all the channels
  3138. //
  3139. SacPutSimpleMessage(SAC_CHANNEL_PROMPT);
  3140. //
  3141. // Iterate through the channels and display the attributes
  3142. // of the active channels
  3143. //
  3144. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  3145. PWSTR Name;
  3146. SAC_CHANNEL_STATUS ChannelStatus;
  3147. //
  3148. // Query the channel manager for a list of all currently active channels
  3149. //
  3150. Status = ChanMgrGetByIndex(
  3151. i,
  3152. &Channel
  3153. );
  3154. //
  3155. // skip empty slots
  3156. //
  3157. if (Status == STATUS_NOT_FOUND) {
  3158. continue;
  3159. }
  3160. if (! NT_SUCCESS(Status)) {
  3161. break;
  3162. }
  3163. ASSERT(Channel != NULL);
  3164. //
  3165. // Get the channel's status
  3166. //
  3167. ChannelGetStatus(
  3168. Channel,
  3169. &ChannelStatus
  3170. );
  3171. //
  3172. // construct channel attribute information
  3173. //
  3174. SAFE_SWPRINTF(
  3175. BufferSize,
  3176. (Buffer, L"%1d (%s%s)",
  3177. ChannelGetIndex(Channel),
  3178. (ChannelStatus == ChannelStatusInactive) ? L"I" : L"A",
  3179. ((ChannelGetType(Channel) == ChannelTypeVTUTF8) ||
  3180. (ChannelGetType(Channel) == ChannelTypeCmd)
  3181. ) ? L"V" : L"R"
  3182. ));
  3183. SacPutString(Buffer);
  3184. SacPutString(L" ");
  3185. ChannelGetName(
  3186. Channel,
  3187. &Name
  3188. );
  3189. SacPutString(Name);
  3190. FREE_POOL(&Name);
  3191. SacPutString(L"\r\n");
  3192. //
  3193. // We are done with the channel
  3194. //
  3195. Status = ChanMgrReleaseChannel(Channel);
  3196. if (! NT_SUCCESS(Status)) {
  3197. break;
  3198. }
  3199. }
  3200. ASSERT(Buffer);
  3201. FREE_POOL(&Buffer);
  3202. return Status;
  3203. }
  3204. NTSTATUS
  3205. DoChannelCloseByNameCommand(
  3206. PCSTR ChannelName
  3207. )
  3208. /*++
  3209. Routine Description:
  3210. This routine closes the channel of the given name.
  3211. Arguments:
  3212. ChannelName - the name of the channel to close
  3213. Return Value:
  3214. Status
  3215. --*/
  3216. {
  3217. NTSTATUS Status;
  3218. PSAC_CHANNEL Channel;
  3219. ULONG Count;
  3220. PWSTR Name;
  3221. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCloseCommand: Entering.\n")));
  3222. //
  3223. // Allocate local memory
  3224. //
  3225. Name = ALLOCATE_POOL(SAC_MAX_CHANNEL_NAME_SIZE, GENERAL_POOL_TAG);
  3226. ASSERT_STATUS(Name, STATUS_NO_MEMORY);
  3227. //
  3228. // Copy the ASCII to Unicode
  3229. //
  3230. Count = ConvertAnsiToUnicode(Name, (PSTR)ChannelName, SAC_MAX_CHANNEL_NAME_LENGTH+1);
  3231. ASSERT_STATUS(Count > 0, STATUS_INVALID_PARAMETER);
  3232. //
  3233. // Attempt to find the specified channel
  3234. //
  3235. Status = ChanMgrGetChannelByName(
  3236. Name,
  3237. &Channel
  3238. );
  3239. if (NT_SUCCESS(Status)) {
  3240. do {
  3241. //
  3242. // If the user is trying to close the SAC channel,
  3243. // then report an error message to the user and fail
  3244. //
  3245. if (ConMgrIsSacChannel(Channel)) {
  3246. //
  3247. // tell the user they can't delete the SAC channel
  3248. //
  3249. SacPutSimpleMessage(SAC_CANNOT_REMOVE_SAC_CHANNEL);
  3250. Status = STATUS_UNSUCCESSFUL;
  3251. break;
  3252. }
  3253. //
  3254. // we currently own the current channel lock.
  3255. // hence, since closing a channel results in a call to the
  3256. // channel IO Manager, we will get into a deadlock
  3257. // over the current channel lock.
  3258. // so we can do this after we get out of the consumer loop
  3259. //
  3260. ExecutePostConsumerCommand = CloseChannel;
  3261. ExecutePostConsumerCommandData = (PVOID)Channel;
  3262. } while ( FALSE );
  3263. } else {
  3264. //
  3265. // We couldn't find the channel to close
  3266. //
  3267. SacPutSimpleMessage(SAC_CHANNEL_NOT_FOUND);
  3268. }
  3269. SAFE_FREE_POOL(&Name);
  3270. return Status;
  3271. }
  3272. NTSTATUS
  3273. DoChannelCloseByIndexCommand(
  3274. ULONG ChannelIndex
  3275. )
  3276. /*++
  3277. Routine Description:
  3278. This routine closes the channel with the specified index
  3279. Arguments:
  3280. ChannelName - the name of the channel
  3281. Return Value:
  3282. Status
  3283. --*/
  3284. {
  3285. NTSTATUS Status;
  3286. PSAC_CHANNEL Channel;
  3287. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelSwitchByIndexCommand: Entering.\n")));
  3288. ASSERT_STATUS(ChannelIndex < MAX_CHANNEL_COUNT, STATUS_INVALID_PARAMETER);
  3289. do {
  3290. //
  3291. // Attempt to get the new current channel by index.
  3292. // If we are successful, we need to keep a reference
  3293. // count on the new current channel since we hold
  3294. // it until we switch away.
  3295. //
  3296. Status = ChanMgrGetByIndex(
  3297. ChannelIndex,
  3298. &Channel
  3299. );
  3300. if (! NT_SUCCESS(Status)) {
  3301. //
  3302. // We couldn't find the channel
  3303. //
  3304. SacPutSimpleMessage(SAC_CHANNEL_NOT_FOUND_AT_INDEX);
  3305. break;
  3306. }
  3307. //
  3308. // If the user is trying to close the SAC channel,
  3309. // then report an error message to the user and fail
  3310. //
  3311. if (ConMgrIsSacChannel(Channel)) {
  3312. //
  3313. // tell the user they can't delete the SAC channel
  3314. //
  3315. SacPutSimpleMessage(SAC_CANNOT_REMOVE_SAC_CHANNEL);
  3316. Status = STATUS_UNSUCCESSFUL;
  3317. break;
  3318. }
  3319. //
  3320. // we currently own the current channel lock.
  3321. // hence, since closing a channel results in a call to the
  3322. // channel IO Manager, we will get into a deadlock
  3323. // over the current channel lock.
  3324. // so we can do this after we get out of the consumer loop
  3325. //
  3326. ExecutePostConsumerCommand = CloseChannel;
  3327. ExecutePostConsumerCommandData = (PVOID)Channel;
  3328. } while ( FALSE );
  3329. return Status;
  3330. }
  3331. NTSTATUS
  3332. DoChannelSwitchByNameCommand(
  3333. PCSTR ChannelName
  3334. )
  3335. /*++
  3336. Routine Description:
  3337. This routine switchs to the channel with the specified name.
  3338. Arguments:
  3339. ChannelName - the name of the channel
  3340. Return Value:
  3341. Status
  3342. --*/
  3343. {
  3344. NTSTATUS Status;
  3345. PSAC_CHANNEL Channel;
  3346. ULONG Count;
  3347. PWSTR Name;
  3348. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelSwitchByNameCommand: Entering.\n")));
  3349. //
  3350. // Allocate local memory
  3351. //
  3352. Name = ALLOCATE_POOL(SAC_MAX_CHANNEL_NAME_SIZE, GENERAL_POOL_TAG);
  3353. ASSERT_STATUS(Name, STATUS_NO_MEMORY);
  3354. //
  3355. // Copy the ASCII to Unicode
  3356. //
  3357. Count = ConvertAnsiToUnicode(Name, (PSTR)ChannelName, SAC_MAX_CHANNEL_NAME_LENGTH+1);
  3358. ASSERT_STATUS(Count > 0, STATUS_INVALID_PARAMETER);
  3359. do {
  3360. //
  3361. // Attempt to get the specified channel
  3362. //
  3363. Status = ChanMgrGetChannelByName(
  3364. Name,
  3365. &Channel
  3366. );
  3367. if (! NT_SUCCESS(Status)) {
  3368. //
  3369. // We couldn't find the channel
  3370. //
  3371. SacPutSimpleMessage(SAC_CHANNEL_NOT_FOUND);
  3372. break;
  3373. }
  3374. //
  3375. // Change the current channel to the specified channel
  3376. //
  3377. // Go from the SAC --> specified channel
  3378. //
  3379. Status = ConMgrSetCurrentChannel(Channel);
  3380. if (! NT_SUCCESS(Status)) {
  3381. break;
  3382. }
  3383. #if 0
  3384. //
  3385. // Flush the channel data to the screen
  3386. //
  3387. Status = ConMgrDisplayCurrentChannel();
  3388. #else
  3389. //
  3390. // Let the user know we switched via the Channel switching interface
  3391. //
  3392. Status = ConMgrDisplayFastChannelSwitchingInterface(Channel);
  3393. #endif
  3394. if (! NT_SUCCESS(Status)) {
  3395. break;
  3396. }
  3397. //
  3398. // Note: we DO NOT release the channel here because
  3399. // it is now the current channel
  3400. //
  3401. } while ( FALSE );
  3402. SAFE_FREE_POOL(&Name);
  3403. return Status;
  3404. }
  3405. NTSTATUS
  3406. DoChannelSwitchByIndexCommand(
  3407. ULONG ChannelIndex
  3408. )
  3409. /*++
  3410. Routine Description:
  3411. This routine switchs to the channel with the specified index
  3412. Arguments:
  3413. ChannelName - the name of the channel
  3414. Return Value:
  3415. Status
  3416. --*/
  3417. {
  3418. NTSTATUS Status;
  3419. PSAC_CHANNEL Channel;
  3420. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelSwitchByIndexCommand: Entering.\n")));
  3421. ASSERT_STATUS(ChannelIndex < MAX_CHANNEL_COUNT, STATUS_INVALID_PARAMETER);
  3422. do {
  3423. //
  3424. // Attempt to get the new current channel by index.
  3425. // If we are successful, we need to keep a reference
  3426. // count on the new current channel since we hold
  3427. // it until we switch away.
  3428. //
  3429. Status = ChanMgrGetByIndex(
  3430. ChannelIndex,
  3431. &Channel
  3432. );
  3433. if (! NT_SUCCESS(Status)) {
  3434. //
  3435. // We couldn't find the channel
  3436. //
  3437. SacPutSimpleMessage(SAC_CHANNEL_NOT_FOUND_AT_INDEX);
  3438. break;
  3439. }
  3440. //
  3441. // Change the current channel to the specified channel
  3442. //
  3443. // Go from the SAC --> specified channel
  3444. //
  3445. Status = ConMgrSetCurrentChannel(Channel);
  3446. if (! NT_SUCCESS(Status)) {
  3447. break;
  3448. }
  3449. #if 0
  3450. //
  3451. // Flush the channel data to the screen
  3452. //
  3453. Status = ConMgrDisplayCurrentChannel();
  3454. #else
  3455. //
  3456. // Let the user know we switched via the Channel switching interface
  3457. //
  3458. Status = ConMgrDisplayFastChannelSwitchingInterface(Channel);
  3459. #endif
  3460. if (! NT_SUCCESS(Status)) {
  3461. break;
  3462. }
  3463. //
  3464. // Note: we DO NOT release the channel here because
  3465. // it is now the current channel
  3466. //
  3467. } while ( FALSE );
  3468. return Status;
  3469. }
  3470. VOID
  3471. DoChannelCommand(
  3472. PUCHAR InputLine
  3473. )
  3474. /*++
  3475. Routine Description:
  3476. This routine lists the channels if a NULL name is given, otw it closes the channel
  3477. of the given name.
  3478. Arguments:
  3479. InputLine - The user's input line.
  3480. Return Value:
  3481. None.
  3482. --*/
  3483. {
  3484. NTSTATUS Status;
  3485. PUCHAR pch;
  3486. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Entering.\n")));
  3487. //
  3488. // Get the global buffer started so that we have room for error messages.
  3489. //
  3490. if (GlobalBuffer == NULL) {
  3491. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  3492. if (GlobalBuffer == NULL) {
  3493. SacPutSimpleMessage(SAC_NO_MEMORY);
  3494. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (1).\n")));
  3495. return;
  3496. }
  3497. GlobalBufferSize = MEMORY_INCREMENT;
  3498. }
  3499. //
  3500. // goto the sub-commmand
  3501. //
  3502. pch = InputLine;
  3503. pch += (sizeof(CHANNEL_COMMAND_STRING) - sizeof(UCHAR));
  3504. SKIP_WHITESPACE(pch);
  3505. //
  3506. // if we are at the end of the command, do a list
  3507. // else, try to find a sub-command
  3508. //
  3509. if (*pch == '\0') {
  3510. DoChannelListCommand();
  3511. } else {
  3512. //
  3513. // determine which sub-command we have
  3514. //
  3515. if (!strncmp((LPSTR)pch,
  3516. EXTENDED_HELP_SUBCOMMAND,
  3517. strlen(EXTENDED_HELP_SUBCOMMAND))) {
  3518. SacPutSimpleMessage(SAC_HELP_CH_CMD_EXT);
  3519. } else if (!strncmp((LPSTR)pch,
  3520. CHANNEL_CLOSE_NAME_COMMAND_STRING,
  3521. strlen(CHANNEL_CLOSE_NAME_COMMAND_STRING))) {
  3522. //
  3523. // skip the sub-command and determine which channel to close
  3524. //
  3525. pch += (sizeof(CHANNEL_CLOSE_NAME_COMMAND_STRING) - sizeof(UCHAR));
  3526. SKIP_WHITESPACE(pch);
  3527. if (*pch == '\0') {
  3528. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3529. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (2).\n")));
  3530. return;
  3531. }
  3532. Status = DoChannelCloseByNameCommand((PCSTR)pch);
  3533. } else if (!strncmp((LPSTR)pch,
  3534. CHANNEL_CLOSE_INDEX_COMMAND_STRING,
  3535. strlen(CHANNEL_CLOSE_INDEX_COMMAND_STRING))) {
  3536. ULONG ChannelIndex;
  3537. //
  3538. // Determine which channel to close
  3539. //
  3540. pch += (sizeof(CHANNEL_CLOSE_INDEX_COMMAND_STRING) - sizeof(UCHAR));
  3541. SKIP_WHITESPACE(pch);
  3542. if (*pch == '\0') {
  3543. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3544. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (2).\n")));
  3545. return;
  3546. }
  3547. if (!IS_NUMBER(*pch)) {
  3548. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3549. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (3).\n")));
  3550. return;
  3551. }
  3552. ChannelIndex = atoi((LPCSTR)pch);
  3553. if (ChannelIndex < MAX_CHANNEL_COUNT) {
  3554. Status = DoChannelCloseByIndexCommand(ChannelIndex);
  3555. } else {
  3556. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3557. }
  3558. } else if (!strncmp((LPSTR)pch,
  3559. CHANNEL_SWITCH_NAME_COMMAND_STRING,
  3560. strlen(CHANNEL_SWITCH_NAME_COMMAND_STRING))) {
  3561. //
  3562. // Determine which channel to switch to
  3563. //
  3564. pch += (sizeof(CHANNEL_SWITCH_NAME_COMMAND_STRING) - sizeof(UCHAR));
  3565. SKIP_WHITESPACE(pch);
  3566. if (*pch == '\0') {
  3567. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3568. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (2).\n")));
  3569. return;
  3570. }
  3571. DoChannelSwitchByNameCommand((PCSTR)pch);
  3572. } else if (!strncmp((LPSTR)pch,
  3573. CHANNEL_SWITCH_INDEX_COMMAND_STRING,
  3574. strlen(CHANNEL_SWITCH_INDEX_COMMAND_STRING))) {
  3575. ULONG ChannelIndex;
  3576. //
  3577. // Determine which channel to switch to
  3578. //
  3579. pch += (sizeof(CHANNEL_SWITCH_INDEX_COMMAND_STRING) - sizeof(UCHAR));
  3580. SKIP_WHITESPACE(pch);
  3581. if (*pch == '\0') {
  3582. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3583. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (2).\n")));
  3584. return;
  3585. }
  3586. if (!IS_NUMBER(*pch)) {
  3587. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3588. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelCommand: Exiting (3).\n")));
  3589. return;
  3590. }
  3591. ChannelIndex = atoi((LPCSTR)pch);
  3592. if (ChannelIndex < MAX_CHANNEL_COUNT) {
  3593. DoChannelSwitchByIndexCommand(ChannelIndex);
  3594. } else {
  3595. SacPutSimpleMessage(SAC_INVALID_PARAMETER);
  3596. }
  3597. } else if (!strncmp((LPSTR)pch,
  3598. CHANNEL_LIST_COMMAND_STRING,
  3599. strlen(CHANNEL_LIST_COMMAND_STRING))) {
  3600. DoChannelListCommand();
  3601. } else {
  3602. SacPutSimpleMessage(SAC_UNKNOWN_COMMAND);
  3603. }
  3604. }
  3605. return;
  3606. }
  3607. VOID
  3608. DoCmdCommand(
  3609. PUCHAR InputLine
  3610. )
  3611. /*++
  3612. Routine Description:
  3613. This routine launches a Command Console Channel
  3614. Arguments:
  3615. InputLine - The user's input line.
  3616. Return Value:
  3617. None.
  3618. --*/
  3619. {
  3620. NTSTATUS Status;
  3621. BOOLEAN IsFull;
  3622. UNREFERENCED_PARAMETER(InputLine);
  3623. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCmdCommand: Entering.\n")));
  3624. //
  3625. // Get the global buffer started so that we have room for error messages.
  3626. //
  3627. if (GlobalBuffer == NULL) {
  3628. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  3629. if (GlobalBuffer == NULL) {
  3630. SacPutSimpleMessage(SAC_NO_MEMORY);
  3631. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCmdCommand: Exiting (1).\n")));
  3632. return;
  3633. }
  3634. GlobalBufferSize = MEMORY_INCREMENT;
  3635. }
  3636. //
  3637. // Ensure that it is possible to add another channel before
  3638. // launching a cmd session.
  3639. //
  3640. Status = ChanMgrIsFull(&IsFull);
  3641. if (!NT_SUCCESS(Status)) {
  3642. SacPutSimpleMessage(SAC_CMD_SERVICE_FAILURE);
  3643. SAC_PUT_ERROR_STRING(Status);
  3644. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCmdCommand: Exiting (2).\n")));
  3645. return;
  3646. }
  3647. if (IsFull) {
  3648. //
  3649. // Notify the user
  3650. //
  3651. SacPutSimpleMessage(SAC_CMD_CHAN_MGR_IS_FULL);
  3652. return;
  3653. }
  3654. KeWaitForMutexObject(
  3655. &SACCmdEventInfoMutex,
  3656. Executive,
  3657. KernelMode,
  3658. FALSE,
  3659. NULL
  3660. );
  3661. //
  3662. // Before we do anything with the cmd operation, make sure
  3663. // the user-mode service has registered itself with us. If not,
  3664. // then there is no point in going further.
  3665. //
  3666. if (!UserModeServiceHasRegisteredCmdEvent()) {
  3667. //
  3668. // inform the user
  3669. //
  3670. SacPutSimpleMessage(SAC_CMD_SERVICE_NOT_REGISTERED);
  3671. goto DoCmdCommandCleanup;
  3672. }
  3673. //
  3674. // Fire the event in the user-mode app that is responsible for launching
  3675. // the cmd console channel
  3676. //
  3677. Status = InvokeUserModeService();
  3678. if (Status == STATUS_TIMEOUT) {
  3679. //
  3680. // Service didn't respond in Timeout period.
  3681. // Service may not be working properly or usermode is unresponsive
  3682. //
  3683. SacPutSimpleMessage(SAC_CMD_SERVICE_TIMED_OUT);
  3684. } else if (NT_SUCCESS(Status)) {
  3685. SacPutSimpleMessage(SAC_CMD_SERVICE_SUCCESS);
  3686. } else {
  3687. //
  3688. // Error condition
  3689. //
  3690. SacPutSimpleMessage(SAC_CMD_SERVICE_FAILURE);
  3691. SAC_PUT_ERROR_STRING(Status);
  3692. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoCmdCommand: Error %X.\n", Status)));
  3693. }
  3694. DoCmdCommandCleanup:
  3695. KeReleaseMutex(&SACCmdEventInfoMutex, FALSE);
  3696. }
  3697. #if ENABLE_CHANNEL_LOCKING
  3698. VOID
  3699. DoLockCommand(
  3700. VOID
  3701. )
  3702. /*++
  3703. Routine Description:
  3704. Arguments:
  3705. None.
  3706. Return Value:
  3707. None.
  3708. --*/
  3709. {
  3710. NTSTATUS Status;
  3711. PSAC_CHANNEL Channel;
  3712. ULONG i;
  3713. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoChannelLockCommand: Entering.\n")));
  3714. //
  3715. // Iterate through the channels via the channel manager
  3716. // and fire the lock events
  3717. //
  3718. //
  3719. // default: we listed the channels
  3720. //
  3721. Status = STATUS_SUCCESS;
  3722. //
  3723. // Iterate through the channels and display the attributes
  3724. // of the active channels
  3725. //
  3726. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  3727. //
  3728. // Query the channel manager for a list of all currently active channels
  3729. //
  3730. Status = ChanMgrGetByIndex(
  3731. i,
  3732. &Channel
  3733. );
  3734. //
  3735. // skip empty slots
  3736. //
  3737. if (Status == STATUS_NOT_FOUND) {
  3738. continue;
  3739. }
  3740. if (! NT_SUCCESS(Status)) {
  3741. break;
  3742. }
  3743. ASSERT(Channel != NULL);
  3744. //
  3745. // If the channel has a lock event,
  3746. // then fire it
  3747. //
  3748. if (ChannelHasLockEvent(Channel)) {
  3749. Status = ChannelSetLockEvent(Channel);
  3750. if (! NT_SUCCESS(Status)) {
  3751. break;
  3752. }
  3753. }
  3754. //
  3755. // We are done with the channel
  3756. //
  3757. Status = ChanMgrReleaseChannel(Channel);
  3758. if (! NT_SUCCESS(Status)) {
  3759. break;
  3760. }
  3761. }
  3762. //
  3763. // notify the SAC user that the lock
  3764. //
  3765. SacPutSimpleMessage(SAC_CMD_CHANNELS_LOCKED);
  3766. }
  3767. #endif