1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Base API Server DLL 4 * FILE: subsystems/win/basesrv/vdm.c 5 * PURPOSE: Virtual DOS Machines (VDM) Support 6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) 7 * Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include "basesrv.h" 13 #include "vdm.h" 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* GLOBALS ********************************************************************/ 19 20 BOOLEAN FirstVDM = TRUE; 21 LIST_ENTRY VDMConsoleListHead; 22 RTL_CRITICAL_SECTION DosCriticalSection; 23 RTL_CRITICAL_SECTION WowCriticalSection; 24 25 /* HELPER FUNCTIONS ***********************************************************/ 26 27 PVDM_CONSOLE_RECORD BaseSrvCreateConsoleRecord(VOID) 28 { 29 PVDM_CONSOLE_RECORD ConsoleRecord; 30 31 ConsoleRecord = RtlAllocateHeap(BaseSrvHeap, HEAP_ZERO_MEMORY, 32 sizeof(VDM_CONSOLE_RECORD)); 33 if (ConsoleRecord == NULL) 34 return NULL; 35 36 /* Initialize the console record */ 37 ConsoleRecord->ConsoleHandle = NULL; 38 ConsoleRecord->ProcessHandle = NULL; 39 ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL; 40 ConsoleRecord->ReenterCount = 0; 41 ConsoleRecord->CurrentDirs = NULL; 42 ConsoleRecord->CurDirsLength = 0; 43 ConsoleRecord->SessionId = 0; 44 InitializeListHead(&ConsoleRecord->DosListHead); 45 46 return ConsoleRecord; 47 } 48 49 NTSTATUS BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record) 50 { 51 PLIST_ENTRY i; 52 PVDM_CONSOLE_RECORD CurrentRecord = NULL; 53 54 /* NULL is not a valid console handle */ 55 if (ConsoleHandle == NULL) return STATUS_INVALID_PARAMETER; 56 57 /* Search for a record that has the same console handle */ 58 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) 59 { 60 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); 61 if (CurrentRecord->ConsoleHandle == ConsoleHandle) break; 62 } 63 64 /* Check if nothing was found */ 65 if (i == &VDMConsoleListHead) CurrentRecord = NULL; 66 67 *Record = CurrentRecord; 68 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND; 69 } 70 71 VOID BaseSrvDestroyConsoleRecord(PVDM_CONSOLE_RECORD ConsoleRecord) 72 { 73 if (ConsoleRecord->CurrentDirs != NULL) 74 { 75 /* Free the current directories */ 76 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs); 77 ConsoleRecord->CurrentDirs = NULL; 78 ConsoleRecord->CurDirsLength = 0; 79 } 80 81 /* Close the process handle */ 82 if (ConsoleRecord->ProcessHandle) 83 NtClose(ConsoleRecord->ProcessHandle); 84 85 /* Close the event handle */ 86 if (ConsoleRecord->ServerEvent) 87 NtClose(ConsoleRecord->ServerEvent); 88 89 /* Remove the console record */ 90 // RemoveEntryList(&ConsoleRecord->Entry); 91 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); 92 93 } 94 95 NTSTATUS GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record) 96 { 97 PLIST_ENTRY i; 98 PVDM_CONSOLE_RECORD CurrentRecord = NULL; 99 100 /* Search for a record that has the same console handle */ 101 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) 102 { 103 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); 104 if (CurrentRecord->SessionId == TaskId) break; 105 } 106 107 /* Check if nothing was found */ 108 if (i == &VDMConsoleListHead) CurrentRecord = NULL; 109 110 *Record = CurrentRecord; 111 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND; 112 } 113 114 ULONG GetNextDosSesId(VOID) 115 { 116 ULONG SessionId; 117 PLIST_ENTRY i; 118 PVDM_CONSOLE_RECORD CurrentRecord = NULL; 119 BOOLEAN Found; 120 121 /* Search for an available session ID */ 122 for (SessionId = 1; SessionId != 0; SessionId++) 123 { 124 Found = FALSE; 125 126 /* Check if the ID is already in use */ 127 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) 128 { 129 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); 130 if (CurrentRecord->SessionId == SessionId) Found = TRUE; 131 } 132 133 /* If not, we found one */ 134 if (!Found) break; 135 } 136 137 ASSERT(SessionId != 0); 138 139 /* Return the session ID */ 140 return SessionId; 141 } 142 143 BOOLEAN BaseSrvIsVdmAllowed(VOID) 144 { 145 NTSTATUS Status; 146 BOOLEAN VdmAllowed = TRUE; 147 HANDLE RootKey, KeyHandle; 148 UNICODE_STRING KeyName, ValueName, MachineKeyName; 149 OBJECT_ATTRIBUTES Attributes; 150 UCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 151 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer; 152 ULONG ActualSize; 153 154 /* Initialize the unicode strings */ 155 RtlInitUnicodeString(&MachineKeyName, L"\\Registry\\Machine"); 156 RtlInitUnicodeString(&KeyName, VDM_POLICY_KEY_NAME); 157 RtlInitUnicodeString(&ValueName, VDM_DISALLOWED_VALUE_NAME); 158 159 InitializeObjectAttributes(&Attributes, 160 &MachineKeyName, 161 OBJ_CASE_INSENSITIVE, 162 NULL, 163 NULL); 164 165 /* Open the local machine key */ 166 Status = NtOpenKey(&RootKey, KEY_READ, &Attributes); 167 if (!NT_SUCCESS(Status)) return FALSE; 168 169 InitializeObjectAttributes(&Attributes, 170 &KeyName, 171 OBJ_CASE_INSENSITIVE, 172 RootKey, 173 NULL); 174 175 /* Open the policy key in the local machine hive, if it exists */ 176 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes))) 177 { 178 /* Read the value, if it's set */ 179 if (NT_SUCCESS(NtQueryValueKey(KeyHandle, 180 &ValueName, 181 KeyValuePartialInformation, 182 ValueInfo, 183 sizeof(ValueBuffer), 184 &ActualSize))) 185 { 186 if (*((PULONG)ValueInfo->Data)) 187 { 188 /* The VDM has been disabled in the registry */ 189 VdmAllowed = FALSE; 190 } 191 } 192 193 NtClose(KeyHandle); 194 } 195 196 /* Close the local machine key */ 197 NtClose(RootKey); 198 199 /* If it's disabled system-wide, there's no need to check the user key */ 200 if (!VdmAllowed) return FALSE; 201 202 /* Open the current user key of the client */ 203 if (!CsrImpersonateClient(NULL)) return VdmAllowed; 204 Status = RtlOpenCurrentUser(KEY_READ, &RootKey); 205 CsrRevertToSelf(); 206 207 /* If that fails, return the system-wide setting */ 208 if (!NT_SUCCESS(Status)) return VdmAllowed; 209 210 InitializeObjectAttributes(&Attributes, 211 &KeyName, 212 OBJ_CASE_INSENSITIVE, 213 RootKey, 214 NULL); 215 216 /* Open the policy key in the current user hive, if it exists */ 217 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes))) 218 { 219 /* Read the value, if it's set */ 220 if (NT_SUCCESS(NtQueryValueKey(KeyHandle, 221 &ValueName, 222 KeyValuePartialInformation, 223 ValueInfo, 224 sizeof(ValueBuffer), 225 &ActualSize))) 226 { 227 if (*((PULONG)ValueInfo->Data)) 228 { 229 /* The VDM has been disabled in the registry */ 230 VdmAllowed = FALSE; 231 } 232 } 233 234 NtClose(KeyHandle); 235 } 236 237 return VdmAllowed; 238 } 239 240 NTSTATUS BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent) 241 { 242 NTSTATUS Status; 243 244 /* Create the event */ 245 Status = NtCreateEvent(ServerEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 246 if (!NT_SUCCESS(Status)) return Status; 247 248 /* Duplicate the event into the client process */ 249 Status = NtDuplicateObject(NtCurrentProcess(), 250 *ServerEvent, 251 CsrGetClientThread()->Process->ProcessHandle, 252 ClientEvent, 253 0, 254 0, 255 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); 256 257 if (!NT_SUCCESS(Status)) NtClose(*ServerEvent); 258 return Status; 259 } 260 261 VOID BaseSrvDestroyPairWaitHandles(HANDLE ServerEvent, HANDLE ClientEvent) 262 { 263 if (ServerEvent) NtClose(ServerEvent); 264 if (ClientEvent) 265 { 266 /* Close the remote handle */ 267 NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle, 268 ClientEvent, 269 NULL, 270 NULL, 271 0, 272 0, 273 DUPLICATE_CLOSE_SOURCE); 274 } 275 } 276 277 /* WOW SUPPORT FUNCTIONS ******************************************************/ 278 279 /* DOS SUPPORT FUNCTIONS ******************************************************/ 280 281 VOID BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo) 282 { 283 /* Free the allocated structure members */ 284 if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine); 285 if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName); 286 if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile); 287 if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory); 288 if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env); 289 if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop); 290 if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title); 291 if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved); 292 293 /* Free the structure itself */ 294 RtlFreeHeap(BaseSrvHeap, 0, CommandInfo); 295 } 296 297 VOID BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess) 298 { 299 ULONG ProcessId = HandleToUlong(CsrProcess->ClientId.UniqueProcess); 300 PVDM_CONSOLE_RECORD ConsoleRecord = NULL; 301 PVDM_DOS_RECORD DosRecord; 302 PLIST_ENTRY i; 303 304 /* Enter the critical section */ 305 RtlEnterCriticalSection(&DosCriticalSection); 306 307 /* Search for a record that has the same process handle */ 308 i = VDMConsoleListHead.Flink; 309 while (i != &VDMConsoleListHead) 310 { 311 ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); 312 i = i->Flink; 313 314 if (ConsoleRecord->ProcessId == ProcessId) 315 { 316 if (ConsoleRecord->ServerEvent) 317 { 318 NtClose(ConsoleRecord->ServerEvent); 319 ConsoleRecord->ServerEvent = NULL; 320 } 321 322 /* Cleanup the DOS records */ 323 while (!IsListEmpty(&ConsoleRecord->DosListHead)) 324 { 325 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, 326 VDM_DOS_RECORD, Entry); 327 328 /* Set the event and close it */ 329 if (DosRecord->ServerEvent) 330 { 331 NtSetEvent(DosRecord->ServerEvent, NULL); 332 NtClose(DosRecord->ServerEvent); 333 DosRecord->ServerEvent = NULL; 334 } 335 336 /* Remove the DOS entry */ 337 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); 338 RemoveEntryList(&DosRecord->Entry); 339 RtlFreeHeap(BaseSrvHeap, 0, DosRecord); 340 } 341 342 /* Remove the console record */ 343 RemoveEntryList(&ConsoleRecord->Entry); 344 BaseSrvDestroyConsoleRecord(ConsoleRecord); 345 } 346 } 347 348 /* Leave the critical section */ 349 RtlLeaveCriticalSection(&DosCriticalSection); 350 } 351 352 BOOLEAN BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord) 353 { 354 BOOLEAN Success = FALSE; 355 PVDM_COMMAND_INFO CommandInfo = NULL; 356 357 /* Allocate the command information structure */ 358 CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap, 359 HEAP_ZERO_MEMORY, 360 sizeof(VDM_COMMAND_INFO)); 361 if (CommandInfo == NULL) return FALSE; 362 363 /* Fill the structure */ 364 CommandInfo->TaskId = CheckVdmRequest->iTask; 365 CommandInfo->ExitCode = DosRecord->ExitCode; 366 CommandInfo->CodePage = CheckVdmRequest->CodePage; 367 CommandInfo->StdIn = CheckVdmRequest->StdIn; 368 CommandInfo->StdOut = CheckVdmRequest->StdOut; 369 CommandInfo->StdErr = CheckVdmRequest->StdErr; 370 371 /* Allocate memory for the command line */ 372 CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap, 373 HEAP_ZERO_MEMORY, 374 CheckVdmRequest->CmdLen); 375 if (CommandInfo->CmdLine == NULL) goto Cleanup; 376 377 /* Copy the command line */ 378 RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen); 379 380 /* Allocate memory for the application name */ 381 CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap, 382 HEAP_ZERO_MEMORY, 383 CheckVdmRequest->AppLen); 384 if (CommandInfo->AppName == NULL) goto Cleanup; 385 386 /* Copy the application name */ 387 RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen); 388 389 /* Allocate memory for the PIF file name */ 390 if (CheckVdmRequest->PifLen != 0) 391 { 392 CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap, 393 HEAP_ZERO_MEMORY, 394 CheckVdmRequest->PifLen); 395 if (CommandInfo->PifFile == NULL) goto Cleanup; 396 397 /* Copy the PIF file name */ 398 RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen); 399 } 400 else CommandInfo->PifFile = NULL; 401 402 /* Allocate memory for the current directory */ 403 if (CheckVdmRequest->CurDirectoryLen != 0) 404 { 405 CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap, 406 HEAP_ZERO_MEMORY, 407 CheckVdmRequest->CurDirectoryLen); 408 if (CommandInfo->CurDirectory == NULL) goto Cleanup; 409 410 /* Copy the current directory */ 411 RtlMoveMemory(CommandInfo->CurDirectory, 412 CheckVdmRequest->CurDirectory, 413 CheckVdmRequest->CurDirectoryLen); 414 } 415 else CommandInfo->CurDirectory = NULL; 416 417 /* Allocate memory for the environment block */ 418 CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap, 419 HEAP_ZERO_MEMORY, 420 CheckVdmRequest->EnvLen); 421 if (CommandInfo->Env == NULL) goto Cleanup; 422 423 /* Copy the environment block */ 424 RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen); 425 426 CommandInfo->EnvLen = CheckVdmRequest->EnvLen; 427 RtlMoveMemory(&CommandInfo->StartupInfo, 428 CheckVdmRequest->StartupInfo, 429 sizeof(STARTUPINFOA)); 430 431 /* Allocate memory for the desktop */ 432 if (CheckVdmRequest->DesktopLen != 0) 433 { 434 CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap, 435 HEAP_ZERO_MEMORY, 436 CheckVdmRequest->DesktopLen); 437 if (CommandInfo->Desktop == NULL) goto Cleanup; 438 439 /* Copy the desktop name */ 440 RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen); 441 } 442 else CommandInfo->Desktop = NULL; 443 444 CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen; 445 446 /* Allocate memory for the title */ 447 if (CheckVdmRequest->TitleLen != 0) 448 { 449 CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap, 450 HEAP_ZERO_MEMORY, 451 CheckVdmRequest->TitleLen); 452 if (CommandInfo->Title == NULL) goto Cleanup; 453 454 /* Copy the title */ 455 RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen); 456 } 457 else CommandInfo->Title = NULL; 458 459 CommandInfo->TitleLen = CheckVdmRequest->TitleLen; 460 461 /* Allocate memory for the reserved field */ 462 if (CheckVdmRequest->ReservedLen != 0) 463 { 464 CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap, 465 HEAP_ZERO_MEMORY, 466 CheckVdmRequest->ReservedLen); 467 if (CommandInfo->Reserved == NULL) goto Cleanup; 468 469 /* Copy the reserved field */ 470 RtlMoveMemory(CommandInfo->Reserved, 471 CheckVdmRequest->Reserved, 472 CheckVdmRequest->ReservedLen); 473 } 474 else CommandInfo->Reserved = NULL; 475 476 CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen; 477 478 CommandInfo->CmdLen = CheckVdmRequest->CmdLen; 479 CommandInfo->AppLen = CheckVdmRequest->AppLen; 480 CommandInfo->PifLen = CheckVdmRequest->PifLen; 481 CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen; 482 CommandInfo->VDMState = DosRecord->State; 483 // TODO: Set CommandInfo->CurrentDrive 484 // TODO: Set CommandInfo->ComingFromBat 485 486 /* Set the DOS record's command structure */ 487 DosRecord->CommandInfo = CommandInfo; 488 489 /* The operation was successful */ 490 Success = TRUE; 491 492 Cleanup: 493 /* If it wasn't successful, free the memory */ 494 if (!Success) BaseSrvFreeVDMInfo(CommandInfo); 495 496 return Success; 497 } 498 499 NTSTATUS BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo, 500 PBASE_GET_NEXT_VDM_COMMAND Message) 501 { 502 NTSTATUS Status = STATUS_SUCCESS; 503 504 /* Copy the data */ 505 Message->iTask = CommandInfo->TaskId; 506 Message->StdIn = CommandInfo->StdIn; 507 Message->StdOut = CommandInfo->StdOut; 508 Message->StdErr = CommandInfo->StdErr; 509 Message->CodePage = CommandInfo->CodePage; 510 Message->dwCreationFlags = CommandInfo->CreationFlags; 511 Message->ExitCode = CommandInfo->ExitCode; 512 Message->CurrentDrive = CommandInfo->CurrentDrive; 513 Message->VDMState = CommandInfo->VDMState; 514 Message->fComingFromBat = CommandInfo->ComingFromBat; 515 516 if (Message->CmdLen >= CommandInfo->CmdLen) 517 { 518 /* Copy the command line */ 519 RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen); 520 } 521 else Status = STATUS_INVALID_PARAMETER; 522 Message->CmdLen = CommandInfo->CmdLen; 523 524 if (Message->AppLen >= CommandInfo->AppLen) 525 { 526 /* Copy the application name */ 527 RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen); 528 } 529 else Status = STATUS_INVALID_PARAMETER; 530 Message->AppLen = CommandInfo->AppLen; 531 532 if (Message->PifLen >= CommandInfo->PifLen) 533 { 534 /* Copy the PIF file name */ 535 RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen); 536 } 537 else Status = STATUS_INVALID_PARAMETER; 538 Message->PifLen = CommandInfo->PifLen; 539 540 if (Message->CurDirectoryLen >= CommandInfo->CurDirectoryLen) 541 { 542 /* Copy the current directory */ 543 RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen); 544 } 545 else Status = STATUS_INVALID_PARAMETER; 546 Message->CurDirectoryLen = CommandInfo->CurDirectoryLen; 547 548 if (Message->EnvLen >= CommandInfo->EnvLen) 549 { 550 /* Copy the environment */ 551 RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen); 552 } 553 else Status = STATUS_INVALID_PARAMETER; 554 Message->EnvLen = CommandInfo->EnvLen; 555 556 /* Copy the startup info */ 557 RtlMoveMemory(Message->StartupInfo, 558 &CommandInfo->StartupInfo, 559 sizeof(STARTUPINFOA)); 560 561 if (Message->DesktopLen >= CommandInfo->DesktopLen) 562 { 563 /* Copy the desktop name */ 564 RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen); 565 } 566 else Status = STATUS_INVALID_PARAMETER; 567 Message->DesktopLen = CommandInfo->DesktopLen; 568 569 if (Message->TitleLen >= CommandInfo->TitleLen) 570 { 571 /* Copy the title */ 572 RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen); 573 } 574 else Status = STATUS_INVALID_PARAMETER; 575 Message->TitleLen = CommandInfo->TitleLen; 576 577 if (Message->ReservedLen >= CommandInfo->ReservedLen) 578 { 579 /* Copy the reserved parameter */ 580 RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen); 581 } 582 else Status = STATUS_INVALID_PARAMETER; 583 Message->ReservedLen = CommandInfo->ReservedLen; 584 585 return Status; 586 } 587 588 VOID BaseInitializeVDM(VOID) 589 { 590 /* Initialize the list head */ 591 InitializeListHead(&VDMConsoleListHead); 592 593 /* Initialize the critical sections */ 594 RtlInitializeCriticalSection(&DosCriticalSection); 595 RtlInitializeCriticalSection(&WowCriticalSection); 596 } 597 598 /* PUBLIC SERVER APIS *********************************************************/ 599 600 CSR_API(BaseSrvCheckVDM) 601 { 602 NTSTATUS Status; 603 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest; 604 PRTL_CRITICAL_SECTION CriticalSection = NULL; 605 PVDM_CONSOLE_RECORD ConsoleRecord = NULL; 606 PVDM_DOS_RECORD DosRecord = NULL; 607 BOOLEAN NewConsoleRecord = FALSE; 608 BOOLEAN NewDosRecord = FALSE; 609 610 /* Don't do anything if the VDM has been disabled in the registry */ 611 if (!BaseSrvIsVdmAllowed()) return STATUS_VDM_DISALLOWED; 612 613 /* Validate the message buffers */ 614 if (!CsrValidateMessageBuffer(ApiMessage, 615 (PVOID*)&CheckVdmRequest->CmdLine, 616 CheckVdmRequest->CmdLen, 617 sizeof(*CheckVdmRequest->CmdLine)) 618 || !CsrValidateMessageBuffer(ApiMessage, 619 (PVOID*)&CheckVdmRequest->AppName, 620 CheckVdmRequest->AppLen, 621 sizeof(*CheckVdmRequest->AppName)) 622 || !CsrValidateMessageBuffer(ApiMessage, 623 (PVOID*)&CheckVdmRequest->PifFile, 624 CheckVdmRequest->PifLen, 625 sizeof(*CheckVdmRequest->PifFile)) 626 || !CsrValidateMessageBuffer(ApiMessage, 627 (PVOID*)&CheckVdmRequest->CurDirectory, 628 CheckVdmRequest->CurDirectoryLen, 629 sizeof(*CheckVdmRequest->CurDirectory)) 630 || !CsrValidateMessageBuffer(ApiMessage, 631 (PVOID*)&CheckVdmRequest->Desktop, 632 CheckVdmRequest->DesktopLen, 633 sizeof(*CheckVdmRequest->Desktop)) 634 || !CsrValidateMessageBuffer(ApiMessage, 635 (PVOID*)&CheckVdmRequest->Title, 636 CheckVdmRequest->TitleLen, 637 sizeof(*CheckVdmRequest->Title)) 638 || !CsrValidateMessageBuffer(ApiMessage, 639 (PVOID*)&CheckVdmRequest->Reserved, 640 CheckVdmRequest->ReservedLen, 641 sizeof(*CheckVdmRequest->Reserved))) 642 { 643 return STATUS_INVALID_PARAMETER; 644 } 645 646 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW) 647 ? &DosCriticalSection 648 : &WowCriticalSection; 649 650 /* Enter the critical section */ 651 RtlEnterCriticalSection(CriticalSection); 652 653 /* Check if this is a DOS or WOW VDM */ 654 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW) 655 { 656 /* Get the console record */ 657 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle, 658 &ConsoleRecord); 659 if (!NT_SUCCESS(Status)) 660 { 661 /* Allocate a new console record */ 662 ConsoleRecord = BaseSrvCreateConsoleRecord(); 663 if (ConsoleRecord == NULL) 664 { 665 Status = STATUS_NO_MEMORY; 666 goto Cleanup; 667 } 668 669 /* Initialize the console record */ 670 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle; 671 if (ConsoleRecord->ConsoleHandle == NULL) 672 { 673 /* The parent doesn't have a console, get a new session ID */ 674 ConsoleRecord->SessionId = GetNextDosSesId(); 675 } 676 else 677 { 678 /* No session ID is needed */ 679 ConsoleRecord->SessionId = 0; 680 } 681 682 /* Remember that the console record was allocated here */ 683 NewConsoleRecord = TRUE; 684 } 685 686 if (!NewConsoleRecord) 687 { 688 /* Get the primary DOS record */ 689 DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, 690 VDM_DOS_RECORD, Entry); 691 692 if (DosRecord->State != VDM_READY) // == VDM_NOT_READY 693 { 694 /* Allocate a new DOS record */ 695 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap, 696 HEAP_ZERO_MEMORY, 697 sizeof(VDM_DOS_RECORD)); 698 if (DosRecord == NULL) 699 { 700 Status = STATUS_NO_MEMORY; 701 goto Cleanup; 702 } 703 704 /* Remember that the DOS record was allocated here */ 705 NewDosRecord = TRUE; 706 } 707 } 708 else 709 { 710 /* Allocate a new DOS record */ 711 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap, 712 HEAP_ZERO_MEMORY, 713 sizeof(VDM_DOS_RECORD)); 714 if (DosRecord == NULL) 715 { 716 Status = STATUS_NO_MEMORY; 717 goto Cleanup; 718 } 719 720 /* Remember that the DOS record was allocated here */ 721 NewDosRecord = TRUE; 722 } 723 724 /* Initialize the DOS record */ 725 DosRecord->State = VDM_NOT_READY; 726 DosRecord->ExitCode = 0; 727 728 /* Translate the input structure into a VDM command structure and set it in the DOS record */ 729 if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord)) 730 { 731 /* The only possibility is that an allocation failure occurred */ 732 Status = STATUS_NO_MEMORY; 733 goto Cleanup; 734 } 735 736 if (NewDosRecord) 737 { 738 /* Add the DOS record */ 739 InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry); 740 } 741 742 if (!NewConsoleRecord) 743 { 744 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent); 745 if (!NT_SUCCESS(Status)) goto Cleanup; 746 747 /* Return the client event handle */ 748 CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent; 749 } 750 751 // FIXME: We may notify ONLY if ConsoleRecord->nReEntrancy is > 0 752 // in case NewConsoleRecord == FALSE AND NewDosRecord == TRUE. 753 if (ConsoleRecord->ServerEvent) 754 { 755 /* Signal the session event */ 756 NtSetEvent(ConsoleRecord->ServerEvent, NULL); 757 } 758 759 if (NewConsoleRecord) 760 { 761 /* Add the console record */ 762 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry); 763 } 764 765 CheckVdmRequest->iTask = ConsoleRecord->SessionId; 766 CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY; 767 Status = STATUS_SUCCESS; 768 } 769 else 770 { 771 // TODO: NOT IMPLEMENTED 772 UNIMPLEMENTED; 773 Status = STATUS_NOT_IMPLEMENTED; 774 } 775 776 Cleanup: 777 /* Check if it failed */ 778 if (!NT_SUCCESS(Status)) 779 { 780 /* Free the DOS record if it was allocated here */ 781 if (NewDosRecord) 782 { 783 ASSERT(DosRecord != NULL); 784 785 BaseSrvDestroyPairWaitHandles(DosRecord->ServerEvent, 786 DosRecord->ClientEvent); 787 788 RtlFreeHeap(BaseSrvHeap, 0, DosRecord); 789 DosRecord = NULL; 790 } 791 792 /* Free the console record if it was allocated here */ 793 if (NewConsoleRecord) 794 { 795 ASSERT(ConsoleRecord != NULL); 796 797 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); 798 ConsoleRecord = NULL; 799 } 800 } 801 802 /* Leave the critical section */ 803 RtlLeaveCriticalSection(CriticalSection); 804 805 return Status; 806 } 807 808 CSR_API(BaseSrvUpdateVDMEntry) 809 { 810 NTSTATUS Status; 811 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.UpdateVDMEntryRequest; 812 PRTL_CRITICAL_SECTION CriticalSection = NULL; 813 PVDM_CONSOLE_RECORD ConsoleRecord = NULL; 814 PVDM_DOS_RECORD DosRecord = NULL; 815 816 CriticalSection = (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW) 817 ? &DosCriticalSection 818 : &WowCriticalSection; 819 820 /* Enter the critical section */ 821 RtlEnterCriticalSection(CriticalSection); 822 823 /* Check if this is a DOS or WOW VDM */ 824 if (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW) 825 { 826 if (UpdateVdmEntryRequest->iTask != 0) 827 { 828 /* Get the console record using the task ID */ 829 Status = GetConsoleRecordBySessionId(UpdateVdmEntryRequest->iTask, 830 &ConsoleRecord); 831 } 832 else 833 { 834 /* Get the console record using the console handle */ 835 Status = BaseSrvGetConsoleRecord(UpdateVdmEntryRequest->ConsoleHandle, 836 &ConsoleRecord); 837 } 838 839 if (!NT_SUCCESS(Status)) goto Cleanup; 840 841 /* Get the primary DOS record */ 842 DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, 843 VDM_DOS_RECORD, Entry); 844 845 switch (UpdateVdmEntryRequest->EntryIndex) 846 { 847 case VdmEntryUndo: 848 { 849 /* Close the server event handle, the client will close the client handle */ 850 NtClose(DosRecord->ServerEvent); 851 DosRecord->ServerEvent = DosRecord->ClientEvent = NULL; 852 853 if (UpdateVdmEntryRequest->VDMCreationState & (VDM_UNDO_PARTIAL | VDM_UNDO_FULL)) 854 { 855 /* Remove the DOS record */ 856 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); 857 RemoveEntryList(&DosRecord->Entry); 858 RtlFreeHeap(BaseSrvHeap, 0, DosRecord); 859 860 /* 861 * Since this is an undo, if that was the only DOS record the VDM 862 * won't even start, so the console record should be removed too. 863 */ 864 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead) 865 { 866 RemoveEntryList(&ConsoleRecord->Entry); 867 BaseSrvDestroyConsoleRecord(ConsoleRecord); 868 } 869 } 870 871 /* It was successful */ 872 Status = STATUS_SUCCESS; 873 874 break; 875 } 876 877 case VdmEntryUpdateProcess: 878 { 879 /* Duplicate the VDM process handle */ 880 Status = NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle, 881 UpdateVdmEntryRequest->VDMProcessHandle, 882 NtCurrentProcess(), 883 &ConsoleRecord->ProcessHandle, 884 0, 885 0, 886 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); 887 if (!NT_SUCCESS(Status)) goto Cleanup; 888 889 // 890 // FIXME! Should we always do the following?? 891 // 892 893 /* Create a pair of handles to one event object */ 894 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, 895 &DosRecord->ClientEvent); 896 if (!NT_SUCCESS(Status)) goto Cleanup; 897 898 /* Return the client event handle */ 899 UpdateVdmEntryRequest->WaitObjectForParent = DosRecord->ClientEvent; 900 901 break; 902 } 903 904 case VdmEntryUpdateControlCHandler: 905 { 906 // TODO: NOT IMPLEMENTED 907 DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!"); 908 Status = STATUS_NOT_IMPLEMENTED; 909 910 break; 911 } 912 913 default: 914 { 915 /* Invalid */ 916 Status = STATUS_INVALID_PARAMETER; 917 } 918 } 919 } 920 else 921 { 922 // TODO: NOT IMPLEMENTED 923 UNIMPLEMENTED; 924 Status = STATUS_NOT_IMPLEMENTED; 925 } 926 927 Cleanup: 928 /* Leave the critical section */ 929 RtlLeaveCriticalSection(CriticalSection); 930 931 return Status; 932 } 933 934 CSR_API(BaseSrvGetNextVDMCommand) 935 { 936 NTSTATUS Status; 937 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest = 938 &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest; 939 PRTL_CRITICAL_SECTION CriticalSection; 940 PLIST_ENTRY i = NULL; 941 PVDM_CONSOLE_RECORD ConsoleRecord = NULL; 942 PVDM_DOS_RECORD DosRecord = NULL; 943 944 /* Validate the message buffers */ 945 if (!CsrValidateMessageBuffer(ApiMessage, 946 (PVOID*)&GetNextVdmCommandRequest->CmdLine, 947 GetNextVdmCommandRequest->CmdLen, 948 sizeof(*GetNextVdmCommandRequest->CmdLine)) 949 || !CsrValidateMessageBuffer(ApiMessage, 950 (PVOID*)&GetNextVdmCommandRequest->AppName, 951 GetNextVdmCommandRequest->AppLen, 952 sizeof(*GetNextVdmCommandRequest->AppName)) 953 || !CsrValidateMessageBuffer(ApiMessage, 954 (PVOID*)&GetNextVdmCommandRequest->PifFile, 955 GetNextVdmCommandRequest->PifLen, 956 sizeof(*GetNextVdmCommandRequest->PifFile)) 957 || !CsrValidateMessageBuffer(ApiMessage, 958 (PVOID*)&GetNextVdmCommandRequest->CurDirectory, 959 GetNextVdmCommandRequest->CurDirectoryLen, 960 sizeof(*GetNextVdmCommandRequest->CurDirectory)) 961 || !CsrValidateMessageBuffer(ApiMessage, 962 (PVOID*)&GetNextVdmCommandRequest->Env, 963 GetNextVdmCommandRequest->EnvLen, 964 sizeof(*GetNextVdmCommandRequest->Env)) 965 || !CsrValidateMessageBuffer(ApiMessage, 966 (PVOID*)&GetNextVdmCommandRequest->Desktop, 967 GetNextVdmCommandRequest->DesktopLen, 968 sizeof(*GetNextVdmCommandRequest->Desktop)) 969 || !CsrValidateMessageBuffer(ApiMessage, 970 (PVOID*)&GetNextVdmCommandRequest->Title, 971 GetNextVdmCommandRequest->TitleLen, 972 sizeof(*GetNextVdmCommandRequest->Title)) 973 || !CsrValidateMessageBuffer(ApiMessage, 974 (PVOID*)&GetNextVdmCommandRequest->Reserved, 975 GetNextVdmCommandRequest->ReservedLen, 976 sizeof(*GetNextVdmCommandRequest->Reserved)) 977 || !CsrValidateMessageBuffer(ApiMessage, 978 (PVOID*)&GetNextVdmCommandRequest->StartupInfo, 979 1, 980 sizeof(STARTUPINFOA))) 981 { 982 return STATUS_INVALID_PARAMETER; 983 } 984 985 CriticalSection = (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW) 986 ? &WowCriticalSection 987 : &DosCriticalSection; 988 989 /* Enter the critical section */ 990 RtlEnterCriticalSection(CriticalSection); 991 992 if (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW) 993 { 994 // TODO: WOW SUPPORT NOT IMPLEMENTED 995 UNIMPLEMENTED; 996 Status = STATUS_NOT_IMPLEMENTED; 997 goto Cleanup; 998 } 999 // else if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)) 1000 { 1001 if (GetNextVdmCommandRequest->iTask != 0) 1002 { 1003 /* Get the console record using the task ID */ 1004 Status = GetConsoleRecordBySessionId(GetNextVdmCommandRequest->iTask, 1005 &ConsoleRecord); 1006 } 1007 else 1008 { 1009 /* Get the console record using the console handle */ 1010 Status = BaseSrvGetConsoleRecord(GetNextVdmCommandRequest->ConsoleHandle, 1011 &ConsoleRecord); 1012 } 1013 1014 /* Make sure we found the console record */ 1015 if (!NT_SUCCESS(Status)) goto Cleanup; 1016 1017 /* Return the session ID */ 1018 GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId; 1019 GetNextVdmCommandRequest->WaitObjectForVDM = NULL; 1020 1021 if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND) 1022 { 1023 /* Check if the DOS record list is empty */ 1024 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead) 1025 { 1026 Status = STATUS_INVALID_PARAMETER; 1027 goto Cleanup; 1028 } 1029 1030 /* Get the first DOS record */ 1031 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, VDM_DOS_RECORD, Entry); 1032 1033 /* Make sure its command information is still there */ 1034 if (DosRecord->CommandInfo == NULL) 1035 { 1036 Status = STATUS_INVALID_PARAMETER; 1037 goto Cleanup; 1038 } 1039 1040 /* Check if the console handle hasn't been set yet */ 1041 if (ConsoleRecord->ConsoleHandle == NULL) 1042 { 1043 /* Set it now */ 1044 ConsoleRecord->ConsoleHandle = GetNextVdmCommandRequest->ConsoleHandle; 1045 } 1046 1047 /* Fill the command information */ 1048 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest); 1049 goto Cleanup; 1050 } 1051 1052 /* Check if we should set the state of a running DOS record to ready */ 1053 if (!(GetNextVdmCommandRequest->VDMState 1054 & (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK))) 1055 { 1056 /* Search for a DOS record that is currently running */ 1057 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink) 1058 { 1059 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry); 1060 if (DosRecord->State == VDM_NOT_READY) break; 1061 } 1062 1063 /* Check if we found any */ 1064 if (i == &ConsoleRecord->DosListHead) 1065 { 1066 Status = STATUS_INVALID_PARAMETER; 1067 goto Cleanup; 1068 } 1069 1070 /* Set the exit code */ 1071 DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode; 1072 1073 /* Update the VDM state */ 1074 DosRecord->State = VDM_READY; 1075 1076 /* Notify all waiting threads that the task is finished */ 1077 NtSetEvent(DosRecord->ServerEvent, NULL); 1078 NtClose(DosRecord->ServerEvent); 1079 DosRecord->ServerEvent = NULL; 1080 } 1081 1082 /* Search for a DOS record that is currently running and has command information */ 1083 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink) 1084 { 1085 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry); 1086 if ((DosRecord->State == VDM_NOT_READY) && (DosRecord->CommandInfo != NULL)) break; 1087 } 1088 1089 /* Check if we found any */ 1090 if (i != &ConsoleRecord->DosListHead) 1091 { 1092 ASSERT(DosRecord->CommandInfo != NULL); 1093 1094 /* Check if the caller only wants environment data */ 1095 if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT) 1096 { 1097 if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen) 1098 { 1099 /* Not enough space was reserved */ 1100 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen; 1101 Status = STATUS_BUFFER_OVERFLOW; 1102 goto Cleanup; 1103 } 1104 1105 /* Copy the environment data */ 1106 RtlMoveMemory(GetNextVdmCommandRequest->Env, 1107 DosRecord->CommandInfo->Env, 1108 DosRecord->CommandInfo->EnvLen); 1109 1110 /* Return the actual size to the caller */ 1111 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen; 1112 } 1113 else 1114 { 1115 /* Fill the command information */ 1116 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest); 1117 if (!NT_SUCCESS(Status)) goto Cleanup; 1118 1119 /* Free the command information, it's no longer needed */ 1120 BaseSrvFreeVDMInfo(DosRecord->CommandInfo); 1121 DosRecord->CommandInfo = NULL; 1122 1123 /* Update the VDM state */ 1124 DosRecord->State = VDM_NOT_READY; 1125 } 1126 1127 Status = STATUS_SUCCESS; 1128 goto Cleanup; 1129 } 1130 } 1131 1132 GetNextVdmCommandRequest->WaitObjectForVDM = NULL; 1133 1134 /* 1135 * There is no command yet. Prepare for waiting if we asked so, 1136 * and if we were not retrying a request. 1137 */ 1138 if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT) || 1139 !(GetNextVdmCommandRequest->VDMState & VDM_FLAG_RETRY)) 1140 { 1141 if (ConsoleRecord->ServerEvent) 1142 { 1143 /* Reset the event */ 1144 NtResetEvent(ConsoleRecord->ServerEvent, NULL); 1145 } 1146 else 1147 { 1148 /* Create a pair of wait handles */ 1149 Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent, 1150 &ConsoleRecord->ClientEvent); 1151 if (!NT_SUCCESS(Status)) goto Cleanup; 1152 } 1153 1154 /* Return the client event handle */ 1155 GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent; 1156 } 1157 1158 Cleanup: 1159 /* Leave the critical section */ 1160 RtlLeaveCriticalSection(CriticalSection); 1161 1162 return Status; 1163 } 1164 1165 CSR_API(BaseSrvExitVDM) 1166 { 1167 NTSTATUS Status; 1168 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest; 1169 PRTL_CRITICAL_SECTION CriticalSection = NULL; 1170 PVDM_CONSOLE_RECORD ConsoleRecord = NULL; 1171 PVDM_DOS_RECORD DosRecord; 1172 1173 CriticalSection = (ExitVdmRequest->iWowTask == 0) 1174 ? &DosCriticalSection 1175 : &WowCriticalSection; 1176 1177 /* Enter the critical section */ 1178 RtlEnterCriticalSection(CriticalSection); 1179 1180 if (ExitVdmRequest->iWowTask == 0) 1181 { 1182 /* Get the console record */ 1183 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord); 1184 if (!NT_SUCCESS(Status)) goto Cleanup; 1185 1186 if (ConsoleRecord->ServerEvent) 1187 ExitVdmRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent; 1188 1189 // NOTE: The following is the same as in BaseSrvCleanupVDMResources. 1190 1191 if (ConsoleRecord->ServerEvent) 1192 { 1193 NtClose(ConsoleRecord->ServerEvent); 1194 ConsoleRecord->ServerEvent = NULL; 1195 } 1196 1197 /* Cleanup the DOS records */ 1198 while (!IsListEmpty(&ConsoleRecord->DosListHead)) 1199 { 1200 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, 1201 VDM_DOS_RECORD, Entry); 1202 1203 /* Set the event and close it */ 1204 if (DosRecord->ServerEvent) 1205 { 1206 NtSetEvent(DosRecord->ServerEvent, NULL); 1207 NtClose(DosRecord->ServerEvent); 1208 DosRecord->ServerEvent = NULL; 1209 } 1210 1211 /* Remove the DOS entry */ 1212 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); 1213 RemoveEntryList(&DosRecord->Entry); 1214 RtlFreeHeap(BaseSrvHeap, 0, DosRecord); 1215 } 1216 1217 /* Remove the console record */ 1218 RemoveEntryList(&ConsoleRecord->Entry); 1219 BaseSrvDestroyConsoleRecord(ConsoleRecord); 1220 } 1221 else 1222 { 1223 // TODO: NOT IMPLEMENTED 1224 UNIMPLEMENTED; 1225 Status = STATUS_NOT_IMPLEMENTED; 1226 } 1227 1228 Cleanup: 1229 /* Leave the critical section */ 1230 RtlLeaveCriticalSection(CriticalSection); 1231 1232 return Status; 1233 } 1234 1235 CSR_API(BaseSrvIsFirstVDM) 1236 { 1237 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest; 1238 1239 /* Return the result */ 1240 IsFirstVDMRequest->FirstVDM = FirstVDM; 1241 1242 /* Clear the first VDM flag */ 1243 FirstVDM = FALSE; 1244 1245 return STATUS_SUCCESS; 1246 } 1247 1248 CSR_API(BaseSrvGetVDMExitCode) 1249 { 1250 NTSTATUS Status; 1251 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest; 1252 PLIST_ENTRY i = NULL; 1253 PVDM_CONSOLE_RECORD ConsoleRecord = NULL; 1254 PVDM_DOS_RECORD DosRecord = NULL; 1255 1256 /* Enter the critical section */ 1257 RtlEnterCriticalSection(&DosCriticalSection); 1258 1259 /* Get the console record */ 1260 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord); 1261 if (!NT_SUCCESS(Status)) goto Cleanup; 1262 1263 /* Search for a DOS record that has the same parent process handle */ 1264 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink) 1265 { 1266 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry); 1267 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break; 1268 } 1269 1270 /* Check if no DOS record was found */ 1271 if (i == &ConsoleRecord->DosListHead) 1272 { 1273 Status = STATUS_NOT_FOUND; 1274 goto Cleanup; 1275 } 1276 1277 /* Check if this task is still running */ 1278 if (DosRecord->State != VDM_READY) 1279 { 1280 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING; 1281 goto Cleanup; 1282 } 1283 1284 /* Return the exit code */ 1285 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode; 1286 1287 // FIXME: We may just change DosRecord->State to VDM_READY in some cases... 1288 1289 /* Since this is a zombie task record, remove it */ 1290 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); 1291 RemoveEntryList(&DosRecord->Entry); 1292 RtlFreeHeap(BaseSrvHeap, 0, DosRecord); 1293 1294 Cleanup: 1295 /* Leave the critical section */ 1296 RtlLeaveCriticalSection(&DosCriticalSection); 1297 1298 return Status; 1299 } 1300 1301 CSR_API(BaseSrvSetReenterCount) 1302 { 1303 NTSTATUS Status = STATUS_SUCCESS; 1304 PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest; 1305 PVDM_CONSOLE_RECORD ConsoleRecord; 1306 1307 /* Enter the critical section */ 1308 RtlEnterCriticalSection(&DosCriticalSection); 1309 1310 /* Get the console record */ 1311 Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord); 1312 if (!NT_SUCCESS(Status)) goto Cleanup; 1313 1314 if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) 1315 { 1316 ConsoleRecord->ReenterCount++; 1317 } 1318 else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT) 1319 { 1320 ConsoleRecord->ReenterCount--; 1321 if (ConsoleRecord->ServerEvent) 1322 NtSetEvent(ConsoleRecord->ServerEvent, NULL); 1323 } 1324 else 1325 { 1326 Status = STATUS_INVALID_PARAMETER; 1327 } 1328 1329 Cleanup: 1330 /* Leave the critical section */ 1331 RtlLeaveCriticalSection(&DosCriticalSection); 1332 1333 return Status; 1334 } 1335 1336 CSR_API(BaseSrvSetVDMCurDirs) 1337 { 1338 NTSTATUS Status; 1339 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest; 1340 PVDM_CONSOLE_RECORD ConsoleRecord; 1341 PCHAR Buffer = NULL; 1342 1343 /* Validate the input buffer */ 1344 if (!CsrValidateMessageBuffer(ApiMessage, 1345 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs, 1346 VDMCurrentDirsRequest->cchCurDirs, 1347 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs))) 1348 { 1349 return STATUS_INVALID_PARAMETER; 1350 } 1351 1352 /* Enter the critical section */ 1353 RtlEnterCriticalSection(&DosCriticalSection); 1354 1355 /* Find the console record */ 1356 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord); 1357 if (!NT_SUCCESS(Status)) goto Cleanup; 1358 1359 if (ConsoleRecord->CurrentDirs == NULL) 1360 { 1361 /* Allocate memory for the current directory information */ 1362 Buffer = RtlAllocateHeap(BaseSrvHeap, 1363 HEAP_ZERO_MEMORY, 1364 VDMCurrentDirsRequest->cchCurDirs); 1365 } 1366 else 1367 { 1368 /* Resize the amount of allocated memory */ 1369 Buffer = RtlReAllocateHeap(BaseSrvHeap, 1370 HEAP_ZERO_MEMORY, 1371 ConsoleRecord->CurrentDirs, 1372 VDMCurrentDirsRequest->cchCurDirs); 1373 } 1374 1375 if (Buffer == NULL) 1376 { 1377 /* Allocation failed */ 1378 Status = STATUS_NO_MEMORY; 1379 goto Cleanup; 1380 } 1381 1382 /* Update the console record */ 1383 ConsoleRecord->CurrentDirs = Buffer; 1384 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs; 1385 1386 /* Copy the data */ 1387 RtlMoveMemory(ConsoleRecord->CurrentDirs, 1388 VDMCurrentDirsRequest->lpszzCurDirs, 1389 VDMCurrentDirsRequest->cchCurDirs); 1390 1391 Cleanup: 1392 /* Leave the critical section */ 1393 RtlLeaveCriticalSection(&DosCriticalSection); 1394 1395 return Status; 1396 } 1397 1398 CSR_API(BaseSrvGetVDMCurDirs) 1399 { 1400 NTSTATUS Status; 1401 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest; 1402 PVDM_CONSOLE_RECORD ConsoleRecord; 1403 1404 /* Validate the output buffer */ 1405 if (!CsrValidateMessageBuffer(ApiMessage, 1406 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs, 1407 VDMCurrentDirsRequest->cchCurDirs, 1408 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs))) 1409 { 1410 return STATUS_INVALID_PARAMETER; 1411 } 1412 1413 /* Enter the critical section */ 1414 RtlEnterCriticalSection(&DosCriticalSection); 1415 1416 /* Find the console record */ 1417 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord); 1418 if (!NT_SUCCESS(Status)) goto Cleanup; 1419 1420 /* Return the actual size of the current directory information */ 1421 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength; 1422 1423 /* Check if the buffer is large enough */ 1424 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength) 1425 { 1426 Status = STATUS_BUFFER_TOO_SMALL; 1427 goto Cleanup; 1428 } 1429 1430 /* Copy the data */ 1431 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs, 1432 ConsoleRecord->CurrentDirs, 1433 ConsoleRecord->CurDirsLength); 1434 1435 Cleanup: 1436 /* Leave the critical section */ 1437 RtlLeaveCriticalSection(&DosCriticalSection); 1438 1439 return Status; 1440 } 1441 1442 CSR_API(BaseSrvBatNotification) 1443 { 1444 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1445 return STATUS_NOT_IMPLEMENTED; 1446 } 1447 1448 CSR_API(BaseSrvRegisterWowExec) 1449 { 1450 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1451 return STATUS_NOT_IMPLEMENTED; 1452 } 1453 1454 CSR_API(BaseSrvRefreshIniFileMapping) 1455 { 1456 DPRINT1("%s not yet implemented\n", __FUNCTION__); 1457 return STATUS_NOT_IMPLEMENTED; 1458 } 1459 1460 /* EOF */ 1461