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