1 /* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/concmd.c 5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "sacdrv.h" 12 13 #include <ndk/exfuncs.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 PVOID GlobalBuffer; 18 ULONG GlobalBufferSize; 19 20 /* FUNCTIONS ******************************************************************/ 21 22 NTSTATUS 23 DoChannelListCommand( 24 VOID 25 ) 26 { 27 return STATUS_NOT_IMPLEMENTED; 28 } 29 30 NTSTATUS 31 DoChannelCloseByNameCommand( 32 IN PCHAR Count 33 ) 34 { 35 return STATUS_NOT_IMPLEMENTED; 36 } 37 38 NTSTATUS 39 DoChannelCloseByIndexCommand( 40 IN ULONG ChannelIndex 41 ) 42 { 43 return STATUS_NOT_IMPLEMENTED; 44 } 45 46 NTSTATUS 47 DoChannelSwitchByNameCommand( 48 IN PCHAR Count 49 ) 50 { 51 return STATUS_NOT_IMPLEMENTED; 52 } 53 54 NTSTATUS 55 DoChannelSwitchByIndexCommand( 56 IN ULONG ChannelIndex 57 ) 58 { 59 return STATUS_NOT_IMPLEMENTED; 60 } 61 62 typedef struct _SAC_SYSTEM_INFORMATION 63 { 64 SYSTEM_BASIC_INFORMATION BasicInfo; 65 SYSTEM_TIMEOFDAY_INFORMATION TimeInfo; 66 SYSTEM_FILECACHE_INFORMATION CacheInfo; 67 SYSTEM_PERFORMANCE_INFORMATION PerfInfo; 68 ULONG RemainingSize; 69 ULONG ProcessDataOffset; 70 // SYSTEM_PAGEFILE_INFORMATION PageFileInfo; 71 // SYSTEM_PROCESS_INFORMATION ProcessInfo; 72 } SAC_SYSTEM_INFORMATION, *PSAC_SYSTEM_INFORMATION; 73 74 NTSTATUS 75 NTAPI 76 GetTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo, 77 IN ULONG InputSize, 78 OUT PULONG TotalSize) 79 { 80 NTSTATUS Status; 81 ULONG BufferLength, ReturnLength, RemainingSize; 82 PSYSTEM_PAGEFILE_INFORMATION PageFileInfo; 83 PSYSTEM_PROCESS_INFORMATION ProcessInfo; 84 ULONG_PTR P; 85 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); 86 87 /* Assume failure */ 88 *TotalSize = 0; 89 90 /* Bail out if the buffer is way too small */ 91 if (InputSize < 4) 92 { 93 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory.\n"); 94 return STATUS_NO_MEMORY; 95 } 96 97 /* Make sure it's at least big enough to hold the static structure */ 98 BufferLength = InputSize - sizeof(SAC_SYSTEM_INFORMATION); 99 if (InputSize < sizeof(SAC_SYSTEM_INFORMATION)) 100 { 101 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (2).\n"); 102 return STATUS_NO_MEMORY; 103 } 104 105 /* Query the time */ 106 Status = ZwQuerySystemInformation(SystemTimeOfDayInformation, 107 &SacInfo->TimeInfo, 108 sizeof(SacInfo->TimeInfo), 109 NULL); 110 if (!NT_SUCCESS(Status)) 111 { 112 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error.\n"); 113 return Status; 114 } 115 116 /* Query basic information */ 117 Status = ZwQuerySystemInformation(SystemBasicInformation, 118 &SacInfo->BasicInfo, 119 sizeof(SacInfo->BasicInfo), 120 NULL); 121 if (!NT_SUCCESS(Status)) 122 { 123 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (2).\n"); 124 return Status; 125 } 126 127 /* Now query the pagefile information, which comes right after */ 128 P = (ULONG_PTR)(SacInfo + 1); 129 PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)P; 130 Status = ZwQuerySystemInformation(SystemPageFileInformation, 131 PageFileInfo, 132 BufferLength, 133 &ReturnLength); 134 if (!NT_SUCCESS(Status) || !(ReturnLength)) 135 { 136 /* We failed -- is it because our buffer was too small? */ 137 if (BufferLength < ReturnLength) 138 { 139 /* Bail out */ 140 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(5).\n"); 141 return STATUS_NO_MEMORY; 142 } 143 144 /* Some other reason, assume the buffer is now full */ 145 SacInfo->RemainingSize = 0; 146 } 147 else 148 { 149 /* This is the leftover data */ 150 SacInfo->RemainingSize = InputSize - BufferLength; 151 152 /* This much has now been consumed, and where we are now */ 153 BufferLength -= ReturnLength; 154 P += ReturnLength; 155 156 /* Are we out of memory? */ 157 if ((LONG)BufferLength < 0) 158 { 159 /* Bail out */ 160 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(3).\n"); 161 return STATUS_NO_MEMORY; 162 } 163 164 /* All good, loop the pagefile data now */ 165 while (TRUE) 166 { 167 /* Is the pagefile name too big to fit? */ 168 if (PageFileInfo->PageFileName.Length > (LONG)BufferLength) 169 { 170 /* Bail out */ 171 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(3).\n"); 172 return STATUS_INFO_LENGTH_MISMATCH; 173 } 174 175 /* Copy the name into our own buffer */ 176 RtlCopyMemory((PVOID)P, 177 PageFileInfo->PageFileName.Buffer, 178 PageFileInfo->PageFileName.Length); 179 PageFileInfo->PageFileName.Buffer = (PWCHAR)P; 180 181 /* Update buffer lengths and offset */ 182 BufferLength -= PageFileInfo->PageFileName.Length; 183 P += PageFileInfo->PageFileName.Length; 184 185 /* Are we out of memory? */ 186 if ((LONG)BufferLength < 0) 187 { 188 /* Bail out */ 189 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(4).\n"); 190 return STATUS_NO_MEMORY; 191 } 192 193 /* If this was the only pagefile, break out */ 194 if (!PageFileInfo->NextEntryOffset) break; 195 196 /* Otherwise, move to the next one */ 197 PageFileInfo = (PVOID)((ULONG_PTR)PageFileInfo + 198 PageFileInfo->NextEntryOffset); 199 } 200 } 201 202 /* Next, query the file cache information */ 203 Status = ZwQuerySystemInformation(SystemFileCacheInformation, 204 &SacInfo->CacheInfo, 205 sizeof(SacInfo->CacheInfo), 206 NULL); 207 if (!NT_SUCCESS(Status)) 208 { 209 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (4).\n"); 210 return Status; 211 } 212 213 /* And then the performance information */ 214 Status = ZwQuerySystemInformation(SystemPerformanceInformation, 215 &SacInfo->PerfInfo, 216 sizeof(SacInfo->PerfInfo), 217 NULL); 218 if (!NT_SUCCESS(Status)) 219 { 220 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(5).\n"); 221 return Status; 222 } 223 224 /* Finally, align the buffer to query process and thread information */ 225 P = ALIGN_UP(P, SYSTEM_PROCESS_INFORMATION); 226 RemainingSize = (ULONG_PTR)SacInfo + InputSize - P; 227 228 /* Are we out of memory? */ 229 if ((LONG)RemainingSize < 0) 230 { 231 /* Bail out */ 232 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (6).\n"); 233 return STATUS_NO_MEMORY; 234 } 235 236 /* Now query the processes and threads */ 237 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)P; 238 Status = ZwQuerySystemInformation(SystemProcessInformation, 239 ProcessInfo, 240 RemainingSize, 241 &ReturnLength); 242 if (!NT_SUCCESS(Status)) 243 { 244 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(6).\n"); 245 return Status; 246 } 247 248 /* The first process name will be right after this buffer */ 249 P += ReturnLength; 250 251 /* The caller should look for process info over here */ 252 SacInfo->ProcessDataOffset = InputSize - RemainingSize; 253 254 /* This is how much buffer data we have left -- are we out? */ 255 BufferLength = RemainingSize - ReturnLength; 256 if ((LONG)BufferLength < 0) 257 { 258 /* Bail out */ 259 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(7).\n"); 260 return STATUS_NO_MEMORY; 261 } 262 263 /* All good and ready to parse the process and thread list */ 264 while (TRUE) 265 { 266 /* Does the process have a name? */ 267 if (ProcessInfo->ImageName.Buffer) 268 { 269 /* Is the process name too big to fit? */ 270 if ((LONG)BufferLength < ProcessInfo->ImageName.Length) 271 { 272 /* Bail out */ 273 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(7).\n"); 274 return STATUS_INFO_LENGTH_MISMATCH; 275 } 276 277 /* Copy the name into our own buffer */ 278 RtlCopyMemory((PVOID)P, 279 ProcessInfo->ImageName.Buffer, 280 ProcessInfo->ImageName.Length); 281 ProcessInfo->ImageName.Buffer = (PWCHAR)P; 282 283 /* Update buffer lengths and offset */ 284 BufferLength -= ProcessInfo->ImageName.Length; 285 P += ProcessInfo->ImageName.Length; 286 287 /* Are we out of memory? */ 288 if ((LONG)BufferLength < 0) 289 { 290 /* Bail out */ 291 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(8).\n"); 292 return STATUS_NO_MEMORY; 293 } 294 } 295 296 /* If this was the only process, break out */ 297 if (!ProcessInfo->NextEntryOffset) break; 298 299 /* Otherwise, move to the next one */ 300 ProcessInfo = (PVOID)((ULONG_PTR)ProcessInfo + 301 ProcessInfo->NextEntryOffset); 302 } 303 304 /* All done! */ 305 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting.\n"); 306 *TotalSize = InputSize - BufferLength; 307 return STATUS_SUCCESS; 308 } 309 310 VOID 311 NTAPI 312 PrintTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo) 313 { 314 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Testing: %d %d %I64d\n", 315 SacInfo->BasicInfo.NumberOfPhysicalPages, 316 SacInfo->PerfInfo.AvailablePages, 317 SacInfo->TimeInfo.BootTime); 318 } 319 320 VOID 321 NTAPI 322 PutMore(OUT PBOOLEAN ScreenFull) 323 { 324 *ScreenFull = FALSE; 325 } 326 327 BOOLEAN 328 RetrieveIpAddressFromString( 329 IN PWCHAR IpString, 330 OUT PULONG IpAddress 331 ) 332 { 333 return FALSE; 334 } 335 336 NTSTATUS 337 CallQueryIPIOCTL( 338 IN HANDLE DriverHandle, 339 IN PVOID DriverObject, 340 IN HANDLE WaitEvent, 341 IN PIO_STATUS_BLOCK IoStatusBlock, 342 IN PVOID InputBuffer, 343 IN ULONG InputBufferLength, 344 IN PVOID OutputBuffer, 345 IN ULONG OutputBufferLength, 346 IN BOOLEAN PrintMessage, 347 OUT PBOOLEAN MessagePrinted 348 ) 349 { 350 return STATUS_NOT_IMPLEMENTED; 351 } 352 353 VOID 354 NTAPI 355 DoRebootCommand(IN BOOLEAN Reboot) 356 { 357 LARGE_INTEGER Timeout, TickCount; 358 NTSTATUS Status; 359 KEVENT Event; 360 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Entering.\n"); 361 362 /* Get the current time now, and setup a timeout in 1 second */ 363 KeQueryTickCount(&TickCount); 364 Timeout.QuadPart = TickCount.QuadPart / (10000000 / KeQueryTimeIncrement()); 365 366 /* Check if the timeout is small enough */ 367 if (Timeout.QuadPart < 60 ) 368 { 369 /* Show the prompt */ 370 ConMgrSimpleEventMessage(Reboot ? 371 SAC_RESTART_PROMPT : SAC_SHUTDOWN_PROMPT, 372 TRUE); 373 374 /* Do the wait */ 375 KeInitializeEvent(&Event, SynchronizationEvent, 0); 376 Timeout.QuadPart = -10000000 * (60 - Timeout.LowPart); 377 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout); 378 } 379 380 /* Do a shutdown or a reboot, based on the request */ 381 Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff); 382 383 /* Check if anyone in the command channel already allocated this */ 384 if (!GlobalBuffer) 385 { 386 /* Allocate it */ 387 GlobalBuffer = SacAllocatePool(PAGE_SIZE, GLOBAL_BLOCK_TAG); 388 if (!GlobalBuffer) 389 { 390 /* We need the global buffer, bail out without it*/ 391 SacPutSimpleMessage(SAC_OUT_OF_MEMORY_PROMPT); 392 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting (1).\n"); 393 return; 394 } 395 396 /* Set the size of the buffer */ 397 GlobalBufferSize = PAGE_SIZE; 398 } 399 400 /* We came back from a reboot, this doesn't make sense, tell the user */ 401 SacPutSimpleMessage(Reboot ? SAC_RESTART_FAIL_PROMPT : SAC_SHUTDOWN_FAIL_PROMPT); 402 swprintf(GlobalBuffer, GetMessage(SAC_FAIL_PROMPT), Status); 403 SacPutString(GlobalBuffer); 404 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting.\n"); 405 } 406 407 VOID 408 NTAPI 409 DoFullInfoCommand(VOID) 410 { 411 /* Flip the flag */ 412 GlobalDoThreads = !GlobalDoThreads; 413 414 /* Print out the new state */ 415 SacPutSimpleMessage(GlobalDoThreads ? 8 : 7); 416 } 417 418 VOID 419 NTAPI 420 DoPagingCommand(VOID) 421 { 422 /* Flip the flag */ 423 GlobalPagingNeeded = !GlobalPagingNeeded; 424 425 /* Print out the new state */ 426 SacPutSimpleMessage(GlobalPagingNeeded ? 10 : 9); 427 } 428 429 VOID 430 NTAPI 431 DoSetTimeCommand(IN PCHAR InputTime) 432 { 433 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 434 } 435 436 VOID 437 NTAPI 438 DoKillCommand(IN PCHAR KillString) 439 { 440 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 441 } 442 443 VOID 444 NTAPI 445 DoLowerPriorityCommand(IN PCHAR PrioString) 446 { 447 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 448 } 449 450 VOID 451 NTAPI 452 DoRaisePriorityCommand(IN PCHAR PrioString) 453 { 454 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 455 } 456 457 VOID 458 NTAPI 459 DoLimitMemoryCommand(IN PCHAR LimitString) 460 { 461 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 462 } 463 464 VOID 465 NTAPI 466 DoCrashCommand(VOID) 467 { 468 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoCrashCommand: Entering.\n"); 469 470 /* Crash the machine */ 471 KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0); 472 __debugbreak(); 473 } 474 475 VOID 476 NTAPI 477 DoMachineInformationCommand(VOID) 478 { 479 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 480 } 481 482 VOID 483 NTAPI 484 DoChannelCommand(IN PCHAR ChannelString) 485 { 486 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 487 } 488 489 VOID 490 NTAPI 491 DoCmdCommand(IN PCHAR InputString) 492 { 493 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 494 } 495 496 VOID 497 NTAPI 498 DoLockCommand(VOID) 499 { 500 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 501 } 502 503 FORCEINLINE 504 BOOLEAN 505 PrintHelpMessage(IN ULONG MessageId, 506 IN OUT PULONG Count) 507 { 508 BOOLEAN ScreenFull; 509 ULONG NewCount; 510 511 /* Get the amount of lines this message will take */ 512 NewCount = GetMessageLineCount(MessageId); 513 if ((NewCount + *Count) > SAC_VTUTF8_ROW_HEIGHT) 514 { 515 /* We are going to overflow the screen, wait for input */ 516 PutMore(&ScreenFull); 517 if (ScreenFull) return FALSE; 518 *Count = 0; 519 } 520 521 /* Print out the message and update the amount of lines printed */ 522 SacPutSimpleMessage(MessageId); 523 *Count += NewCount; 524 return TRUE; 525 } 526 527 VOID 528 NTAPI 529 DoHelpCommand(VOID) 530 { 531 ULONG Count = 0; 532 533 /* Print out all the help messages */ 534 if (!PrintHelpMessage(112, &Count)) return; 535 if (!PrintHelpMessage(12, &Count)) return; 536 if (!PrintHelpMessage(13, &Count)) return; 537 if (!PrintHelpMessage(14, &Count)) return; 538 if (!PrintHelpMessage(15, &Count)) return; 539 if (!PrintHelpMessage(16, &Count)) return; 540 if (!PrintHelpMessage(31, &Count)) return; 541 if (!PrintHelpMessage(18, &Count)) return; 542 if (!PrintHelpMessage(19, &Count)) return; 543 if (!PrintHelpMessage(32, &Count)) return; 544 if (!PrintHelpMessage(20, &Count)) return; 545 if (!PrintHelpMessage(21, &Count)) return; 546 if (!PrintHelpMessage(22, &Count)) return; 547 if (!PrintHelpMessage(23, &Count)) return; 548 if (!PrintHelpMessage(24, &Count)) return; 549 if (!PrintHelpMessage(25, &Count)) return; 550 if (!PrintHelpMessage(27, &Count)) return; 551 if (!PrintHelpMessage(28, &Count)) return; 552 if (!PrintHelpMessage(29, &Count)) return; 553 } 554 555 VOID 556 NTAPI 557 DoGetNetInfo(IN BOOLEAN DoPrint) 558 { 559 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 560 } 561 562 VOID 563 NTAPI 564 DoSetIpAddressCommand(IN PCHAR IpString) 565 { 566 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 567 } 568 569 VOID 570 NTAPI 571 DoTlistCommand(VOID) 572 { 573 NTSTATUS Status; 574 PVOID NewGlobalBuffer; 575 ULONG Size; 576 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Entering.\n"); 577 578 /* Check if a global buffer already exists */ 579 if (!GlobalBuffer) 580 { 581 /* It doesn't, allocate one */ 582 GlobalBuffer = SacAllocatePool(4096, GLOBAL_BLOCK_TAG); 583 if (GlobalBuffer) 584 { 585 /* Remember its current size */ 586 GlobalBufferSize = 4096; 587 } 588 else 589 { 590 /* Out of memory, bail out */ 591 SacPutSimpleMessage(11); 592 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); 593 return; 594 } 595 } 596 597 /* Loop as long as the buffer is too small */ 598 while (TRUE) 599 { 600 /* Get the process list */ 601 Status = GetTListInfo(GlobalBuffer, GlobalBufferSize, &Size); 602 if ((Status != STATUS_NO_MEMORY) && 603 (Status != STATUS_INFO_LENGTH_MISMATCH)) 604 { 605 /* It fits! Bail out */ 606 break; 607 } 608 609 /* We need a new bigger buffer */ 610 NewGlobalBuffer = SacAllocatePool(GlobalBufferSize + 4096, 611 GLOBAL_BLOCK_TAG); 612 if (!NewGlobalBuffer) 613 { 614 /* Out of memory, bail out */ 615 SacPutSimpleMessage(11); 616 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); 617 return; 618 } 619 620 /* Free the old one, update state */ 621 SacFreePool(GlobalBuffer); 622 GlobalBufferSize += 4096; 623 GlobalBuffer = NewGlobalBuffer; 624 } 625 626 /* Did we get here because we have the whole list? */ 627 if (!NT_SUCCESS(Status)) 628 { 629 /* Nope, print out a failure message */ 630 SacPutSimpleMessage(68); 631 swprintf(GlobalBuffer, GetMessage(48), Status); 632 SacPutString(GlobalBuffer); 633 } 634 else 635 { 636 /* Yep, print out the list */ 637 PrintTListInfo(GlobalBuffer); 638 } 639 640 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); 641 } 642