1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: dll/win32/kernel32/client/proc.c 5 * PURPOSE: Process functions 6 * PROGRAMMERS: Ariadne (ariadne@xs4all.nl) 7 * UPDATE HISTORY: 8 * Created 01/11/98 9 */ 10 11 /* INCLUDES ****************************************************************/ 12 13 #include <k32.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* GLOBALS *******************************************************************/ 19 20 WaitForInputIdleType UserWaitForInputIdleRoutine; 21 UNICODE_STRING BaseUnicodeCommandLine; 22 ANSI_STRING BaseAnsiCommandLine; 23 UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH"); 24 LPSTARTUPINFOA BaseAnsiStartupInfo = NULL; 25 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry; 26 BOOLEAN g_AppCertInitialized; 27 BOOLEAN g_HaveAppCerts; 28 LIST_ENTRY BasepAppCertDllsList; 29 RTL_CRITICAL_SECTION gcsAppCert; 30 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc; 31 NTSTATUS g_AppCertStatus; 32 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable[2] = 33 { 34 { 35 BasepConfigureAppCertDlls, 36 1, 37 L"AppCertDlls", 38 &BasepAppCertDllsList, 39 0, 40 NULL, 41 0 42 } 43 }; 44 45 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens; 46 HMODULE gSaferHandle = (HMODULE)-1; 47 48 VOID WINAPI 49 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle); 50 51 #define CMD_STRING L"cmd /c " 52 53 /* FUNCTIONS ****************************************************************/ 54 55 VOID 56 WINAPI 57 StuffStdHandle(IN HANDLE ProcessHandle, 58 IN HANDLE StandardHandle, 59 IN PHANDLE Address) 60 { 61 NTSTATUS Status; 62 HANDLE DuplicatedHandle; 63 SIZE_T NumberOfBytesWritten; 64 65 /* If there is no handle to duplicate, return immediately */ 66 if (!StandardHandle) return; 67 68 /* Duplicate the handle */ 69 Status = NtDuplicateObject(NtCurrentProcess(), 70 StandardHandle, 71 ProcessHandle, 72 &DuplicatedHandle, 73 0, 74 0, 75 DUPLICATE_SAME_ACCESS | 76 DUPLICATE_SAME_ATTRIBUTES); 77 if (!NT_SUCCESS(Status)) return; 78 79 /* Write it */ 80 NtWriteVirtualMemory(ProcessHandle, 81 Address, 82 &DuplicatedHandle, 83 sizeof(HANDLE), 84 &NumberOfBytesWritten); 85 } 86 87 BOOLEAN 88 WINAPI 89 BuildSubSysCommandLine(IN LPCWSTR SubsystemName, 90 IN LPCWSTR ApplicationName, 91 IN LPCWSTR CommandLine, 92 OUT PUNICODE_STRING SubsysCommandLine) 93 { 94 UNICODE_STRING CommandLineString, ApplicationNameString; 95 PWCHAR Buffer; 96 ULONG Length; 97 98 /* Convert to unicode strings */ 99 RtlInitUnicodeString(&CommandLineString, ApplicationName); 100 RtlInitUnicodeString(&ApplicationNameString, CommandLine); 101 102 /* Allocate buffer for the output string */ 103 Length = CommandLineString.MaximumLength + ApplicationNameString.MaximumLength + 32; 104 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); 105 RtlInitEmptyUnicodeString(SubsysCommandLine, Buffer, (USHORT)Length); 106 if (!Buffer) 107 { 108 /* Fail, no memory */ 109 BaseSetLastNTError(STATUS_NO_MEMORY); 110 return FALSE; 111 } 112 113 /* Build the final subsystem command line */ 114 RtlAppendUnicodeToString(SubsysCommandLine, SubsystemName); 115 RtlAppendUnicodeStringToString(SubsysCommandLine, &CommandLineString); 116 RtlAppendUnicodeToString(SubsysCommandLine, L" /C "); 117 RtlAppendUnicodeStringToString(SubsysCommandLine, &ApplicationNameString); 118 return TRUE; 119 } 120 121 BOOLEAN 122 WINAPI 123 BasepIsImageVersionOk(IN ULONG ImageMajorVersion, 124 IN ULONG ImageMinorVersion) 125 { 126 /* Accept images for NT 3.1 or higher */ 127 if (ImageMajorVersion > 3 || 128 (ImageMajorVersion == 3 && ImageMinorVersion >= 10)) 129 { 130 /* ReactOS-specific: Accept images even if they are newer than our internal NT version. */ 131 if (ImageMajorVersion > SharedUserData->NtMajorVersion || 132 (ImageMajorVersion == SharedUserData->NtMajorVersion && ImageMinorVersion > SharedUserData->NtMinorVersion)) 133 { 134 DPRINT1("Accepting image version %lu.%lu, although ReactOS is an NT %hu.%hu OS!\n", 135 ImageMajorVersion, 136 ImageMinorVersion, 137 SharedUserData->NtMajorVersion, 138 SharedUserData->NtMinorVersion); 139 } 140 141 return TRUE; 142 } 143 144 return FALSE; 145 } 146 147 NTSTATUS 148 WINAPI 149 BasepCheckWebBladeHashes(IN HANDLE FileHandle) 150 { 151 NTSTATUS Status; 152 CHAR Hash[16]; 153 154 /* Get all the MD5 hashes */ 155 Status = RtlComputeImportTableHash(FileHandle, Hash, 1); 156 if (!NT_SUCCESS(Status)) return Status; 157 158 /* Depending on which suite this is, run a bsearch and block the appropriate ones */ 159 if (SharedUserData->SuiteMask & VER_SUITE_COMPUTE_SERVER) 160 { 161 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't."); 162 } 163 else if (SharedUserData->SuiteMask & VER_SUITE_STORAGE_SERVER) 164 { 165 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't."); 166 } 167 else if (SharedUserData->SuiteMask & VER_SUITE_BLADE) 168 { 169 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't."); 170 } 171 172 /* Actually, fuck it, don't block anything, we're open source */ 173 return STATUS_SUCCESS; 174 } 175 176 NTSTATUS 177 NTAPI 178 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List, 179 IN PWCHAR ComponentName, 180 IN PWCHAR DllName) 181 { 182 /* Pretty much the only thing this key is used for, is malware */ 183 UNIMPLEMENTED; 184 return STATUS_NOT_IMPLEMENTED; 185 } 186 187 NTSTATUS 188 NTAPI 189 BasepConfigureAppCertDlls(IN PWSTR ValueName, 190 IN ULONG ValueType, 191 IN PVOID ValueData, 192 IN ULONG ValueLength, 193 IN PVOID Context, 194 IN PVOID EntryContext) 195 { 196 /* Add this to the certification list */ 197 return BasepSaveAppCertRegistryValue(Context, ValueName, ValueData); 198 } 199 200 NTSTATUS 201 WINAPI 202 BasepIsProcessAllowed(IN LPWSTR ApplicationName) 203 { 204 NTSTATUS Status, Status1; 205 PWCHAR Buffer; 206 UINT Length; 207 HMODULE TrustLibrary; 208 PBASEP_APPCERT_ENTRY Entry; 209 ULONG CertFlag; 210 PLIST_ENTRY NextEntry; 211 HANDLE KeyHandle; 212 UNICODE_STRING CertKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls"); 213 OBJECT_ATTRIBUTES KeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey, OBJ_CASE_INSENSITIVE); 214 215 /* Try to initialize the certification subsystem */ 216 while (!g_AppCertInitialized) 217 { 218 /* Defaults */ 219 Status = STATUS_SUCCESS; 220 Buffer = NULL; 221 222 /* Acquire the lock while initializing and see if we lost a race */ 223 RtlEnterCriticalSection(&gcsAppCert); 224 if (g_AppCertInitialized) break; 225 226 /* On embedded, there is a special DLL */ 227 if (SharedUserData->SuiteMask & VER_SUITE_EMBEDDEDNT) 228 { 229 /* Allocate a buffer for the name */ 230 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 231 0, 232 MAX_PATH * sizeof(WCHAR) + 233 sizeof(UNICODE_NULL)); 234 if (!Buffer) 235 { 236 /* Fail if no memory */ 237 Status = STATUS_NO_MEMORY; 238 } 239 else 240 { 241 /* Now get the system32 directory in our buffer, make sure it fits */ 242 Length = GetSystemDirectoryW(Buffer, MAX_PATH - sizeof("EmbdTrst.DLL")); 243 if ((Length) && (Length <= MAX_PATH - sizeof("EmbdTrst.DLL"))) 244 { 245 /* Add a slash if needed, and add the embedded cert DLL name */ 246 if (Buffer[Length - 1] != '\\') Buffer[Length++] = '\\'; 247 RtlCopyMemory(&Buffer[Length], 248 L"EmbdTrst.DLL", 249 sizeof(L"EmbdTrst.DLL")); 250 251 /* Try to load it */ 252 TrustLibrary = LoadLibraryW(Buffer); 253 if (TrustLibrary) 254 { 255 /* And extract the special function out of it */ 256 fEmbeddedCertFunc = (PVOID)GetProcAddress(TrustLibrary, 257 "ImageOkToRunOnEmbeddedNT"); 258 } 259 } 260 261 /* If we didn't get this far, set a failure code */ 262 if (!fEmbeddedCertFunc) Status = STATUS_UNSUCCESSFUL; 263 } 264 } 265 else 266 { 267 /* Other systems have a registry entry for this */ 268 Status1 = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes); 269 if (NT_SUCCESS(Status1)) 270 { 271 /* Close it, we'll query it through Rtl */ 272 NtClose(KeyHandle); 273 274 /* Do the query, which will call a special callback */ 275 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 276 L"Session Manager", 277 BasepAppCertTable, 278 NULL, 279 NULL); 280 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 281 { 282 Status = STATUS_SUCCESS; 283 } 284 } 285 } 286 287 /* Free any buffer if we had one */ 288 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 289 290 /* Check for errors, or a missing embedded/custom certification DLL */ 291 if (!NT_SUCCESS(Status) || 292 (!(fEmbeddedCertFunc) && (IsListEmpty(&BasepAppCertDllsList)))) 293 { 294 /* The subsystem is not active on this machine, so give up */ 295 g_HaveAppCerts = FALSE; 296 g_AppCertStatus = Status; 297 } 298 else 299 { 300 /* We have certification DLLs active, remember this */ 301 g_HaveAppCerts = TRUE; 302 } 303 304 /* We are done the initialization phase, release the lock */ 305 g_AppCertInitialized = TRUE; 306 RtlLeaveCriticalSection(&gcsAppCert); 307 } 308 309 /* If there's no certification DLLs present, return the failure code */ 310 if (!g_HaveAppCerts) return g_AppCertStatus; 311 312 /* Otherwise, assume success and make sure we have *something* */ 313 ASSERT(fEmbeddedCertFunc || !IsListEmpty(&BasepAppCertDllsList)); 314 Status = STATUS_SUCCESS; 315 316 /* If the something is an embedded certification DLL, call it and return */ 317 if (fEmbeddedCertFunc) return fEmbeddedCertFunc(ApplicationName); 318 319 /* Otherwise we have custom certification DLLs, parse them */ 320 NextEntry = BasepAppCertDllsList.Flink; 321 CertFlag = 2; 322 while (NextEntry != &BasepAppCertDllsList) 323 { 324 /* Make sure the entry has a callback */ 325 Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry); 326 ASSERT(Entry->fPluginCertFunc != NULL); 327 328 /* Call it and check if it failed */ 329 Status = Entry->fPluginCertFunc(ApplicationName, 1); 330 if (!NT_SUCCESS(Status)) CertFlag = 3; 331 332 /* Move on */ 333 NextEntry = NextEntry->Flink; 334 } 335 336 /* Now loop them again */ 337 NextEntry = BasepAppCertDllsList.Flink; 338 while (NextEntry != &BasepAppCertDllsList) 339 { 340 /* Make sure the entry has a callback */ 341 Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry); 342 ASSERT(Entry->fPluginCertFunc != NULL); 343 344 /* Call it, this time with the flag from the loop above */ 345 Status = Entry->fPluginCertFunc(ApplicationName, CertFlag); 346 } 347 348 /* All done, return the status */ 349 return Status; 350 } 351 352 NTSTATUS 353 WINAPI 354 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle, 355 IN HANDLE ProcessHandle, 356 IN HANDLE ThreadHandle) 357 { 358 NTSTATUS Status; 359 ANSI_STRING SaferiReplaceProcessThreadTokens = RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens"); 360 361 /* Enter the application certification lock */ 362 RtlEnterCriticalSection(&gcsAppCert); 363 364 /* Check if we already know the function */ 365 if (g_SaferReplaceProcessThreadTokens) 366 { 367 /* Call it */ 368 Status = g_SaferReplaceProcessThreadTokens(TokenHandle, 369 ProcessHandle, 370 ThreadHandle) ? 371 STATUS_SUCCESS : 372 STATUS_UNSUCCESSFUL; 373 } 374 else 375 { 376 /* Check if the app certification DLL isn't loaded */ 377 if (!(gSaferHandle) || 378 (gSaferHandle == (HMODULE)-1) || 379 (gSaferHandle == (HMODULE)-2)) 380 { 381 /* Then we can't call the function */ 382 Status = STATUS_ENTRYPOINT_NOT_FOUND; 383 } 384 else 385 { 386 /* We have the DLL, find the address of the Safer function */ 387 Status = LdrGetProcedureAddress(gSaferHandle, 388 &SaferiReplaceProcessThreadTokens, 389 0, 390 (PVOID*)&g_SaferReplaceProcessThreadTokens); 391 if (NT_SUCCESS(Status)) 392 { 393 /* Found it, now call it */ 394 Status = g_SaferReplaceProcessThreadTokens(TokenHandle, 395 ProcessHandle, 396 ThreadHandle) ? 397 STATUS_SUCCESS : 398 STATUS_UNSUCCESSFUL; 399 } 400 else 401 { 402 /* We couldn't find it, so this must be an unsupported DLL */ 403 LdrUnloadDll(gSaferHandle); 404 gSaferHandle = NULL; 405 Status = STATUS_ENTRYPOINT_NOT_FOUND; 406 } 407 } 408 } 409 410 /* Release the lock and return the result */ 411 RtlLeaveCriticalSection(&gcsAppCert); 412 return Status; 413 } 414 415 VOID 416 WINAPI 417 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles) 418 { 419 NTSTATUS Status; 420 421 /* Sanity checks */ 422 ASSERT(Handles != NULL); 423 ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess()); 424 425 /* Close the file handle */ 426 if (Handles->File) 427 { 428 Status = NtClose(Handles->File); 429 ASSERT(NT_SUCCESS(Status)); 430 } 431 432 /* Close the section handle */ 433 if (Handles->Section) 434 { 435 Status = NtClose(Handles->Section); 436 ASSERT(NT_SUCCESS(Status)); 437 } 438 439 /* Unmap the section view */ 440 if (Handles->ViewBase.QuadPart) 441 { 442 Status = NtUnmapViewOfSection(NtCurrentProcess(), 443 (PVOID)(ULONG_PTR)Handles->ViewBase.QuadPart); 444 ASSERT(NT_SUCCESS(Status)); 445 } 446 } 447 448 DECLSPEC_NORETURN 449 VOID 450 WINAPI 451 BaseProcessStartup( 452 _In_ PPROCESS_START_ROUTINE lpStartAddress) 453 { 454 _SEH2_TRY 455 { 456 /* Set our Start Address */ 457 NtSetInformationThread(NtCurrentThread(), 458 ThreadQuerySetWin32StartAddress, 459 &lpStartAddress, 460 sizeof(PPROCESS_START_ROUTINE)); 461 462 /* Call the Start Routine */ 463 ExitThread(lpStartAddress()); 464 } 465 _SEH2_EXCEPT(UnhandledExceptionFilter(_SEH2_GetExceptionInformation())) 466 { 467 /* Get the Exit code from the SEH Handler */ 468 if (!BaseRunningInServerProcess) 469 { 470 /* Kill the whole process, usually */ 471 ExitProcess(_SEH2_GetExceptionCode()); 472 } 473 else 474 { 475 /* If running inside CSRSS, kill just this thread */ 476 ExitThread(_SEH2_GetExceptionCode()); 477 } 478 } 479 _SEH2_END; 480 } 481 482 BOOLEAN 483 WINAPI 484 BasePushProcessParameters(IN ULONG ParameterFlags, 485 IN HANDLE ProcessHandle, 486 IN PPEB RemotePeb, 487 IN LPCWSTR ApplicationPathName, 488 IN LPWSTR lpCurrentDirectory, 489 IN LPWSTR lpCommandLine, 490 IN LPVOID lpEnvironment, 491 IN LPSTARTUPINFOW StartupInfo, 492 IN DWORD CreationFlags, 493 IN BOOL InheritHandles, 494 IN ULONG ImageSubsystem, 495 IN PVOID AppCompatData, 496 IN ULONG AppCompatDataSize) 497 { 498 WCHAR FullPath[MAX_PATH + 5]; 499 PWCHAR Remaining, DllPathString, ScanChar; 500 PRTL_USER_PROCESS_PARAMETERS ProcessParameters, RemoteParameters; 501 PVOID RemoteAppCompatData; 502 UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory; 503 UNICODE_STRING Desktop, Shell, Runtime, Title; 504 NTSTATUS Status; 505 ULONG EnviroSize; 506 SIZE_T Size; 507 BOOLEAN HavePebLock = FALSE, Result; 508 PPEB Peb = NtCurrentPeb(); 509 510 /* Get the full path name */ 511 Size = GetFullPathNameW(ApplicationPathName, 512 MAX_PATH + 4, 513 FullPath, 514 &Remaining); 515 if ((Size) && (Size <= (MAX_PATH + 4))) 516 { 517 /* Get the DLL Path */ 518 DllPathString = BaseComputeProcessDllPath(FullPath, lpEnvironment); 519 if (!DllPathString) 520 { 521 /* Fail */ 522 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 523 return FALSE; 524 } 525 526 /* Initialize Strings */ 527 RtlInitUnicodeString(&DllPath, DllPathString); 528 RtlInitUnicodeString(&ImageName, FullPath); 529 } 530 else 531 { 532 /* Couldn't get the path name. Just take the original path */ 533 DllPathString = BaseComputeProcessDllPath((LPWSTR)ApplicationPathName, 534 lpEnvironment); 535 if (!DllPathString) 536 { 537 /* Fail */ 538 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 539 return FALSE; 540 } 541 542 /* Initialize Strings */ 543 RtlInitUnicodeString(&DllPath, DllPathString); 544 RtlInitUnicodeString(&ImageName, ApplicationPathName); 545 } 546 547 /* Initialize Strings */ 548 RtlInitUnicodeString(&CommandLine, lpCommandLine); 549 RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory); 550 551 /* Initialize more Strings from the Startup Info */ 552 if (StartupInfo->lpDesktop) 553 { 554 RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop); 555 } 556 else 557 { 558 RtlInitUnicodeString(&Desktop, L""); 559 } 560 if (StartupInfo->lpReserved) 561 { 562 RtlInitUnicodeString(&Shell, StartupInfo->lpReserved); 563 } 564 else 565 { 566 RtlInitUnicodeString(&Shell, L""); 567 } 568 if (StartupInfo->lpTitle) 569 { 570 RtlInitUnicodeString(&Title, StartupInfo->lpTitle); 571 } 572 else 573 { 574 RtlInitUnicodeString(&Title, ApplicationPathName); 575 } 576 577 /* This one is special because the length can differ */ 578 Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2; 579 Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2; 580 581 /* Enforce no app compat data if the pointer was NULL */ 582 if (!AppCompatData) AppCompatDataSize = 0; 583 584 /* Create the Parameter Block */ 585 ProcessParameters = NULL; 586 DPRINT("ImageName: '%wZ'\n", &ImageName); 587 DPRINT("DllPath : '%wZ'\n", &DllPath); 588 DPRINT("CurDir : '%wZ'\n", &CurrentDirectory); 589 DPRINT("CmdLine : '%wZ'\n", &CommandLine); 590 DPRINT("Title : '%wZ'\n", &Title); 591 DPRINT("Desktop : '%wZ'\n", &Desktop); 592 DPRINT("Shell : '%wZ'\n", &Shell); 593 DPRINT("Runtime : '%wZ'\n", &Runtime); 594 Status = RtlCreateProcessParameters(&ProcessParameters, 595 &ImageName, 596 &DllPath, 597 lpCurrentDirectory ? 598 &CurrentDirectory : NULL, 599 &CommandLine, 600 lpEnvironment, 601 &Title, 602 &Desktop, 603 &Shell, 604 &Runtime); 605 if (!NT_SUCCESS(Status)) goto FailPath; 606 607 /* Clear the current directory handle if not inheriting */ 608 if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL; 609 610 /* Check if the user passed in an environment */ 611 if (lpEnvironment) 612 { 613 /* We should've made it part of the parameters block, enforce this */ 614 ASSERT(ProcessParameters->Environment == lpEnvironment); 615 lpEnvironment = ProcessParameters->Environment; 616 } 617 else 618 { 619 /* The user did not, so use the one from the current PEB */ 620 HavePebLock = TRUE; 621 RtlAcquirePebLock(); 622 lpEnvironment = Peb->ProcessParameters->Environment; 623 } 624 625 /* Save pointer and start lookup */ 626 ScanChar = lpEnvironment; 627 if (lpEnvironment) 628 { 629 /* Find the environment size */ 630 while (*ScanChar++) while (*ScanChar++); 631 EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)lpEnvironment); 632 633 /* Allocate and Initialize new Environment Block */ 634 Size = EnviroSize; 635 ProcessParameters->Environment = NULL; 636 Status = NtAllocateVirtualMemory(ProcessHandle, 637 (PVOID*)&ProcessParameters->Environment, 638 0, 639 &Size, 640 MEM_COMMIT, 641 PAGE_READWRITE); 642 if (!NT_SUCCESS(Status)) goto FailPath; 643 644 /* Write the Environment Block */ 645 Status = NtWriteVirtualMemory(ProcessHandle, 646 ProcessParameters->Environment, 647 lpEnvironment, 648 EnviroSize, 649 NULL); 650 651 /* No longer need the PEB lock anymore */ 652 if (HavePebLock) 653 { 654 /* Release it */ 655 RtlReleasePebLock(); 656 HavePebLock = FALSE; 657 } 658 659 /* Check if the write failed */ 660 if (!NT_SUCCESS(Status)) goto FailPath; 661 } 662 663 /* Write new parameters */ 664 ProcessParameters->StartingX = StartupInfo->dwX; 665 ProcessParameters->StartingY = StartupInfo->dwY; 666 ProcessParameters->CountX = StartupInfo->dwXSize; 667 ProcessParameters->CountY = StartupInfo->dwYSize; 668 ProcessParameters->CountCharsX = StartupInfo->dwXCountChars; 669 ProcessParameters->CountCharsY = StartupInfo->dwYCountChars; 670 ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute; 671 ProcessParameters->WindowFlags = StartupInfo->dwFlags; 672 ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow; 673 674 /* Write the handles only if we have to */ 675 if (StartupInfo->dwFlags & 676 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)) 677 { 678 ProcessParameters->StandardInput = StartupInfo->hStdInput; 679 ProcessParameters->StandardOutput = StartupInfo->hStdOutput; 680 ProcessParameters->StandardError = StartupInfo->hStdError; 681 } 682 683 /* Use Special Flags for ConDllInitialize in Kernel32 */ 684 if (CreationFlags & DETACHED_PROCESS) 685 { 686 ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS; 687 } 688 else if (CreationFlags & CREATE_NEW_CONSOLE) 689 { 690 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE; 691 } 692 else if (CreationFlags & CREATE_NO_WINDOW) 693 { 694 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW; 695 } 696 else 697 { 698 /* Inherit our Console Handle */ 699 ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle; 700 701 /* Make sure that the shell isn't trampling on our handles first */ 702 if (!(StartupInfo->dwFlags & 703 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))) 704 { 705 /* Copy the handle if we are inheriting or if it's a console handle */ 706 if ((InheritHandles) || 707 (IsConsoleHandle(Peb->ProcessParameters->StandardInput))) 708 { 709 ProcessParameters->StandardInput = Peb->ProcessParameters->StandardInput; 710 } 711 if ((InheritHandles) || 712 (IsConsoleHandle(Peb->ProcessParameters->StandardOutput))) 713 { 714 ProcessParameters->StandardOutput = Peb->ProcessParameters->StandardOutput; 715 } 716 if ((InheritHandles) || 717 (IsConsoleHandle(Peb->ProcessParameters->StandardError))) 718 { 719 ProcessParameters->StandardError = Peb->ProcessParameters->StandardError; 720 } 721 } 722 } 723 724 /* Also set the Console Flag */ 725 if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) && 726 (!(CreationFlags & CREATE_NEW_CONSOLE))) 727 { 728 ProcessParameters->ConsoleFlags = 1; 729 } 730 731 /* Check if there's a .local file present */ 732 if (ParameterFlags & 1) 733 { 734 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH; 735 } 736 737 /* Check if we failed to open the IFEO key */ 738 if (ParameterFlags & 2) 739 { 740 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING; 741 } 742 743 /* Allocate memory for the parameter block */ 744 Size = ProcessParameters->Length; 745 RemoteParameters = NULL; 746 Status = NtAllocateVirtualMemory(ProcessHandle, 747 (PVOID*)&RemoteParameters, 748 0, 749 &Size, 750 MEM_COMMIT, 751 PAGE_READWRITE); 752 if (!NT_SUCCESS(Status)) goto FailPath; 753 754 /* Set the allocated size */ 755 ProcessParameters->MaximumLength = Size; 756 757 /* Handle some Parameter Flags */ 758 ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ? 759 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER : 0; 760 ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ? 761 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL : 0; 762 ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ? 763 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER : 0; 764 ProcessParameters->Flags |= (Peb->ProcessParameters->Flags & 765 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS); 766 767 /* Write the Parameter Block */ 768 Status = NtWriteVirtualMemory(ProcessHandle, 769 RemoteParameters, 770 ProcessParameters, 771 ProcessParameters->Length, 772 NULL); 773 if (!NT_SUCCESS(Status)) goto FailPath; 774 775 /* Write the PEB Pointer */ 776 Status = NtWriteVirtualMemory(ProcessHandle, 777 &RemotePeb->ProcessParameters, 778 &RemoteParameters, 779 sizeof(PVOID), 780 NULL); 781 if (!NT_SUCCESS(Status)) goto FailPath; 782 783 /* Check if there's any app compat data to write */ 784 RemoteAppCompatData = NULL; 785 if (AppCompatData) 786 { 787 /* Allocate some space for the application compatibility data */ 788 Size = AppCompatDataSize; 789 Status = NtAllocateVirtualMemory(ProcessHandle, 790 &RemoteAppCompatData, 791 0, 792 &Size, 793 MEM_COMMIT, 794 PAGE_READWRITE); 795 if (!NT_SUCCESS(Status)) goto FailPath; 796 797 /* Write the application compatibility data */ 798 Status = NtWriteVirtualMemory(ProcessHandle, 799 RemoteAppCompatData, 800 AppCompatData, 801 AppCompatDataSize, 802 NULL); 803 if (!NT_SUCCESS(Status)) goto FailPath; 804 } 805 806 /* Write the PEB Pointer to the app compat data (might be NULL) */ 807 Status = NtWriteVirtualMemory(ProcessHandle, 808 &RemotePeb->pShimData, 809 &RemoteAppCompatData, 810 sizeof(PVOID), 811 NULL); 812 if (!NT_SUCCESS(Status)) goto FailPath; 813 814 /* Now write Peb->ImageSubSystem */ 815 if (ImageSubsystem) 816 { 817 NtWriteVirtualMemory(ProcessHandle, 818 &RemotePeb->ImageSubsystem, 819 &ImageSubsystem, 820 sizeof(ImageSubsystem), 821 NULL); 822 } 823 824 /* Success path */ 825 Result = TRUE; 826 827 Quickie: 828 /* Cleanup */ 829 if (HavePebLock) RtlReleasePebLock(); 830 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer); 831 if (ProcessParameters) RtlDestroyProcessParameters(ProcessParameters); 832 return Result; 833 FailPath: 834 DPRINT1("Failure to create process parameters: %lx\n", Status); 835 BaseSetLastNTError(Status); 836 Result = FALSE; 837 goto Quickie; 838 } 839 840 VOID 841 WINAPI 842 InitCommandLines(VOID) 843 { 844 NTSTATUS Status; 845 846 /* Read the UNICODE_STRING from the PEB */ 847 BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine; 848 849 /* Convert to ANSI_STRING for the *A callers */ 850 Status = RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine, 851 &BaseUnicodeCommandLine, 852 TRUE); 853 if (!NT_SUCCESS(Status)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine, 0, 0); 854 } 855 856 /* PUBLIC FUNCTIONS ***********************************************************/ 857 858 /* 859 * @implemented 860 */ 861 BOOL 862 WINAPI 863 GetProcessAffinityMask(IN HANDLE hProcess, 864 OUT PDWORD_PTR lpProcessAffinityMask, 865 OUT PDWORD_PTR lpSystemAffinityMask) 866 { 867 PROCESS_BASIC_INFORMATION ProcessInfo; 868 NTSTATUS Status; 869 870 /* Query information on the process from the kernel */ 871 Status = NtQueryInformationProcess(hProcess, 872 ProcessBasicInformation, 873 &ProcessInfo, 874 sizeof(ProcessInfo), 875 NULL); 876 if (!NT_SUCCESS(Status)) 877 { 878 /* Fail */ 879 BaseSetLastNTError(Status); 880 return FALSE; 881 } 882 883 /* Copy the affinity mask, and get the system one from our shared data */ 884 *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask; 885 *lpSystemAffinityMask = (DWORD)BaseStaticServerData->SysInfo.ActiveProcessorsAffinityMask; 886 return TRUE; 887 } 888 889 /* 890 * @implemented 891 */ 892 BOOL 893 WINAPI 894 SetProcessAffinityMask(IN HANDLE hProcess, 895 IN DWORD_PTR dwProcessAffinityMask) 896 { 897 NTSTATUS Status; 898 899 /* Directly set the affinity mask */ 900 Status = NtSetInformationProcess(hProcess, 901 ProcessAffinityMask, 902 (PVOID)&dwProcessAffinityMask, 903 sizeof(dwProcessAffinityMask)); 904 if (!NT_SUCCESS(Status)) 905 { 906 /* Handle failure */ 907 BaseSetLastNTError(Status); 908 return FALSE; 909 } 910 911 /* Everything was ok */ 912 return TRUE; 913 } 914 915 /* 916 * @implemented 917 */ 918 BOOL 919 WINAPI 920 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel, 921 OUT LPDWORD lpdwFlags) 922 { 923 BASE_API_MESSAGE ApiMessage; 924 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &ApiMessage.Data.ShutdownParametersRequest; 925 926 /* Ask CSRSS for shutdown information */ 927 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 928 NULL, 929 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetProcessShutdownParam), 930 sizeof(*ShutdownParametersRequest)); 931 if (!NT_SUCCESS(ApiMessage.Status)) 932 { 933 /* Return the failure from CSRSS */ 934 BaseSetLastNTError(ApiMessage.Status); 935 return FALSE; 936 } 937 938 /* Get the data back */ 939 *lpdwLevel = ShutdownParametersRequest->ShutdownLevel; 940 *lpdwFlags = ShutdownParametersRequest->ShutdownFlags; 941 return TRUE; 942 } 943 944 /* 945 * @implemented 946 */ 947 BOOL 948 WINAPI 949 SetProcessShutdownParameters(IN DWORD dwLevel, 950 IN DWORD dwFlags) 951 { 952 BASE_API_MESSAGE ApiMessage; 953 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &ApiMessage.Data.ShutdownParametersRequest; 954 955 /* Write the data into the CSRSS request and send it */ 956 ShutdownParametersRequest->ShutdownLevel = dwLevel; 957 ShutdownParametersRequest->ShutdownFlags = dwFlags; 958 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 959 NULL, 960 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetProcessShutdownParam), 961 sizeof(*ShutdownParametersRequest)); 962 if (!NT_SUCCESS(ApiMessage.Status)) 963 { 964 /* Return the failure from CSRSS */ 965 BaseSetLastNTError(ApiMessage.Status); 966 return FALSE; 967 } 968 969 /* All went well */ 970 return TRUE; 971 } 972 973 /* 974 * @implemented 975 */ 976 BOOL 977 WINAPI 978 GetProcessWorkingSetSizeEx(IN HANDLE hProcess, 979 OUT PSIZE_T lpMinimumWorkingSetSize, 980 OUT PSIZE_T lpMaximumWorkingSetSize, 981 OUT PDWORD Flags) 982 { 983 QUOTA_LIMITS_EX QuotaLimits; 984 NTSTATUS Status; 985 986 /* Query the kernel about this */ 987 Status = NtQueryInformationProcess(hProcess, 988 ProcessQuotaLimits, 989 &QuotaLimits, 990 sizeof(QuotaLimits), 991 NULL); 992 if (!NT_SUCCESS(Status)) 993 { 994 /* Return error */ 995 BaseSetLastNTError(Status); 996 return FALSE; 997 } 998 999 /* Copy the quota information out */ 1000 *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize; 1001 *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize; 1002 *Flags = QuotaLimits.Flags; 1003 return TRUE; 1004 } 1005 1006 /* 1007 * @implemented 1008 */ 1009 BOOL 1010 WINAPI 1011 GetProcessWorkingSetSize(IN HANDLE hProcess, 1012 OUT PSIZE_T lpMinimumWorkingSetSize, 1013 OUT PSIZE_T lpMaximumWorkingSetSize) 1014 { 1015 DWORD Dummy; 1016 return GetProcessWorkingSetSizeEx(hProcess, 1017 lpMinimumWorkingSetSize, 1018 lpMaximumWorkingSetSize, 1019 &Dummy); 1020 } 1021 1022 /* 1023 * @implemented 1024 */ 1025 BOOL 1026 WINAPI 1027 SetProcessWorkingSetSizeEx(IN HANDLE hProcess, 1028 IN SIZE_T dwMinimumWorkingSetSize, 1029 IN SIZE_T dwMaximumWorkingSetSize, 1030 IN DWORD Flags) 1031 { 1032 QUOTA_LIMITS_EX QuotaLimits; 1033 NTSTATUS Status, ReturnStatus; 1034 BOOL Result; 1035 PVOID State; 1036 ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE; 1037 1038 /* Zero out the input structure */ 1039 RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits)); 1040 1041 /* Check if the caller sent any limits */ 1042 if ((dwMinimumWorkingSetSize) && (dwMaximumWorkingSetSize)) 1043 { 1044 /* Write the quota information */ 1045 QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize; 1046 QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize; 1047 QuotaLimits.Flags = Flags; 1048 1049 /* Acquire the required privilege */ 1050 Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State); 1051 1052 /* Request the new quotas */ 1053 ReturnStatus = NtSetInformationProcess(hProcess, 1054 ProcessQuotaLimits, 1055 &QuotaLimits, 1056 sizeof(QuotaLimits)); 1057 Result = NT_SUCCESS(ReturnStatus); 1058 if (NT_SUCCESS(Status)) 1059 { 1060 /* Release the privilege and set succes code */ 1061 ASSERT(State != NULL); 1062 RtlReleasePrivilege(State); 1063 State = NULL; 1064 } 1065 } 1066 else 1067 { 1068 /* No limits, fail the call */ 1069 ReturnStatus = STATUS_INVALID_PARAMETER; 1070 Result = FALSE; 1071 } 1072 1073 /* Return result code, set error code if this was a failure */ 1074 if (!Result) BaseSetLastNTError(ReturnStatus); 1075 return Result; 1076 } 1077 1078 /* 1079 * @implemented 1080 */ 1081 BOOL 1082 WINAPI 1083 SetProcessWorkingSetSize(IN HANDLE hProcess, 1084 IN SIZE_T dwMinimumWorkingSetSize, 1085 IN SIZE_T dwMaximumWorkingSetSize) 1086 { 1087 /* Call the newer API */ 1088 return SetProcessWorkingSetSizeEx(hProcess, 1089 dwMinimumWorkingSetSize, 1090 dwMaximumWorkingSetSize, 1091 0); 1092 } 1093 1094 /* 1095 * @implemented 1096 */ 1097 BOOL 1098 WINAPI 1099 GetProcessTimes(IN HANDLE hProcess, 1100 IN LPFILETIME lpCreationTime, 1101 IN LPFILETIME lpExitTime, 1102 IN LPFILETIME lpKernelTime, 1103 IN LPFILETIME lpUserTime) 1104 { 1105 KERNEL_USER_TIMES Kut; 1106 NTSTATUS Status; 1107 1108 /* Query the times */ 1109 Status = NtQueryInformationProcess(hProcess, 1110 ProcessTimes, 1111 &Kut, 1112 sizeof(Kut), 1113 NULL); 1114 if (!NT_SUCCESS(Status)) 1115 { 1116 /* Handle failure */ 1117 BaseSetLastNTError(Status); 1118 return FALSE; 1119 } 1120 1121 /* Copy all the times and return success */ 1122 lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart; 1123 lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart; 1124 lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart; 1125 lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart; 1126 lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart; 1127 lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart; 1128 lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart; 1129 lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart; 1130 return TRUE; 1131 } 1132 1133 /* 1134 * @implemented 1135 */ 1136 HANDLE 1137 WINAPI 1138 GetCurrentProcess(VOID) 1139 { 1140 return (HANDLE)NtCurrentProcess(); 1141 } 1142 1143 /* 1144 * @implemented 1145 */ 1146 HANDLE 1147 WINAPI 1148 GetCurrentThread(VOID) 1149 { 1150 return (HANDLE)NtCurrentThread(); 1151 } 1152 1153 /* 1154 * @implemented 1155 */ 1156 DWORD 1157 WINAPI 1158 GetCurrentProcessId(VOID) 1159 { 1160 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess); 1161 } 1162 1163 /* 1164 * @implemented 1165 */ 1166 BOOL 1167 WINAPI 1168 GetExitCodeProcess(IN HANDLE hProcess, 1169 IN LPDWORD lpExitCode) 1170 { 1171 PROCESS_BASIC_INFORMATION ProcessBasic; 1172 NTSTATUS Status; 1173 1174 /* Ask the kernel */ 1175 Status = NtQueryInformationProcess(hProcess, 1176 ProcessBasicInformation, 1177 &ProcessBasic, 1178 sizeof(ProcessBasic), 1179 NULL); 1180 if (!NT_SUCCESS(Status)) 1181 { 1182 /* We failed, was this because this is a VDM process? */ 1183 if (BaseCheckForVDM(hProcess, lpExitCode) != FALSE) return TRUE; 1184 1185 /* Not a VDM process, fail the call */ 1186 BaseSetLastNTError(Status); 1187 return FALSE; 1188 } 1189 1190 /* Succes case, return the exit code */ 1191 *lpExitCode = (DWORD)ProcessBasic.ExitStatus; 1192 return TRUE; 1193 } 1194 1195 /* 1196 * @implemented 1197 */ 1198 DWORD 1199 WINAPI 1200 GetProcessId(IN HANDLE Process) 1201 { 1202 PROCESS_BASIC_INFORMATION ProcessBasic; 1203 NTSTATUS Status; 1204 1205 /* Query the kernel */ 1206 Status = NtQueryInformationProcess(Process, 1207 ProcessBasicInformation, 1208 &ProcessBasic, 1209 sizeof(ProcessBasic), 1210 NULL); 1211 if (!NT_SUCCESS(Status)) 1212 { 1213 /* Handle failure */ 1214 BaseSetLastNTError(Status); 1215 return 0; 1216 } 1217 1218 /* Return the PID */ 1219 return (DWORD)ProcessBasic.UniqueProcessId; 1220 } 1221 1222 /* 1223 * @implemented 1224 */ 1225 HANDLE 1226 WINAPI 1227 OpenProcess(IN DWORD dwDesiredAccess, 1228 IN BOOL bInheritHandle, 1229 IN DWORD dwProcessId) 1230 { 1231 NTSTATUS Status; 1232 HANDLE ProcessHandle; 1233 OBJECT_ATTRIBUTES ObjectAttributes; 1234 CLIENT_ID ClientId; 1235 1236 /* Setup the input client ID structure */ 1237 ClientId.UniqueProcess = UlongToHandle(dwProcessId); 1238 ClientId.UniqueThread = 0; 1239 1240 /* This is needed just to define the inheritance flags */ 1241 InitializeObjectAttributes(&ObjectAttributes, 1242 NULL, 1243 (bInheritHandle ? OBJ_INHERIT : 0), 1244 NULL, 1245 NULL); 1246 1247 /* Now try to open the process */ 1248 Status = NtOpenProcess(&ProcessHandle, 1249 dwDesiredAccess, 1250 &ObjectAttributes, 1251 &ClientId); 1252 if (!NT_SUCCESS(Status)) 1253 { 1254 /* Handle failure */ 1255 BaseSetLastNTError(Status); 1256 return NULL; 1257 } 1258 1259 /* Otherwise return a handle to the process */ 1260 return ProcessHandle; 1261 } 1262 1263 /* 1264 * @implemented 1265 */ 1266 VOID 1267 WINAPI 1268 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle) 1269 { 1270 /* Write the global function pointer */ 1271 UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle; 1272 } 1273 1274 /* 1275 * @implemented 1276 */ 1277 VOID 1278 WINAPI 1279 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo) 1280 { 1281 PRTL_USER_PROCESS_PARAMETERS Params; 1282 1283 /* Get the process parameters */ 1284 Params = NtCurrentPeb()->ProcessParameters; 1285 1286 /* Copy the data out of there */ 1287 lpStartupInfo->cb = sizeof(STARTUPINFOW); 1288 lpStartupInfo->lpReserved = Params->ShellInfo.Buffer; 1289 lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer; 1290 lpStartupInfo->lpTitle = Params->WindowTitle.Buffer; 1291 lpStartupInfo->dwX = Params->StartingX; 1292 lpStartupInfo->dwY = Params->StartingY; 1293 lpStartupInfo->dwXSize = Params->CountX; 1294 lpStartupInfo->dwYSize = Params->CountY; 1295 lpStartupInfo->dwXCountChars = Params->CountCharsX; 1296 lpStartupInfo->dwYCountChars = Params->CountCharsY; 1297 lpStartupInfo->dwFillAttribute = Params->FillAttribute; 1298 lpStartupInfo->dwFlags = Params->WindowFlags; 1299 lpStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags; 1300 lpStartupInfo->cbReserved2 = Params->RuntimeData.Length; 1301 lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer; 1302 1303 /* Check if the standard handles are being used for other features */ 1304 if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | 1305 STARTF_USEHOTKEY | 1306 STARTF_SHELLPRIVATE)) 1307 { 1308 /* These are, so copy the standard handles too */ 1309 lpStartupInfo->hStdInput = Params->StandardInput; 1310 lpStartupInfo->hStdOutput = Params->StandardOutput; 1311 lpStartupInfo->hStdError = Params->StandardError; 1312 } 1313 } 1314 1315 /* 1316 * @implemented 1317 */ 1318 VOID 1319 WINAPI 1320 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo) 1321 { 1322 PRTL_USER_PROCESS_PARAMETERS Params; 1323 ANSI_STRING TitleString, ShellString, DesktopString; 1324 LPSTARTUPINFOA StartupInfo; 1325 NTSTATUS Status; 1326 1327 /* Get the cached information as well as the PEB parameters */ 1328 StartupInfo = BaseAnsiStartupInfo; 1329 Params = NtCurrentPeb()->ProcessParameters; 1330 1331 /* Check if this is the first time we have to get the cached version */ 1332 while (!StartupInfo) 1333 { 1334 /* Create new ANSI startup info */ 1335 StartupInfo = RtlAllocateHeap(RtlGetProcessHeap(), 1336 0, 1337 sizeof(*StartupInfo)); 1338 if (StartupInfo) 1339 { 1340 /* Zero out string pointers in case we fail to create them */ 1341 StartupInfo->lpReserved = NULL; 1342 StartupInfo->lpDesktop = NULL; 1343 StartupInfo->lpTitle = NULL; 1344 1345 /* Set the size */ 1346 StartupInfo->cb = sizeof(*StartupInfo); 1347 1348 /* Copy what's already stored in the PEB */ 1349 StartupInfo->dwX = Params->StartingX; 1350 StartupInfo->dwY = Params->StartingY; 1351 StartupInfo->dwXSize = Params->CountX; 1352 StartupInfo->dwYSize = Params->CountY; 1353 StartupInfo->dwXCountChars = Params->CountCharsX; 1354 StartupInfo->dwYCountChars = Params->CountCharsY; 1355 StartupInfo->dwFillAttribute = Params->FillAttribute; 1356 StartupInfo->dwFlags = Params->WindowFlags; 1357 StartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags; 1358 StartupInfo->cbReserved2 = Params->RuntimeData.Length; 1359 StartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer; 1360 StartupInfo->hStdInput = Params->StandardInput; 1361 StartupInfo->hStdOutput = Params->StandardOutput; 1362 StartupInfo->hStdError = Params->StandardError; 1363 1364 /* Copy shell info string */ 1365 Status = RtlUnicodeStringToAnsiString(&ShellString, 1366 &Params->ShellInfo, 1367 TRUE); 1368 if (NT_SUCCESS(Status)) 1369 { 1370 /* Save it */ 1371 StartupInfo->lpReserved = ShellString.Buffer; 1372 1373 /* Copy desktop info string */ 1374 Status = RtlUnicodeStringToAnsiString(&DesktopString, 1375 &Params->DesktopInfo, 1376 TRUE); 1377 if (NT_SUCCESS(Status)) 1378 { 1379 /* Save it */ 1380 StartupInfo->lpDesktop = DesktopString.Buffer; 1381 1382 /* Copy window title string */ 1383 Status = RtlUnicodeStringToAnsiString(&TitleString, 1384 &Params->WindowTitle, 1385 TRUE); 1386 if (NT_SUCCESS(Status)) 1387 { 1388 /* Save it */ 1389 StartupInfo->lpTitle = TitleString.Buffer; 1390 1391 /* We finished with the ANSI version, try to cache it */ 1392 if (!InterlockedCompareExchangePointer((PVOID*)&BaseAnsiStartupInfo, 1393 StartupInfo, 1394 NULL)) 1395 { 1396 /* We were the first thread through, use the data */ 1397 break; 1398 } 1399 1400 /* Someone beat us to it, use their data instead */ 1401 StartupInfo = BaseAnsiStartupInfo; 1402 Status = STATUS_SUCCESS; 1403 1404 /* We're going to free our own stuff, but not raise */ 1405 RtlFreeAnsiString(&TitleString); 1406 } 1407 RtlFreeAnsiString(&DesktopString); 1408 } 1409 RtlFreeAnsiString(&ShellString); 1410 } 1411 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo); 1412 } 1413 else 1414 { 1415 /* No memory, fail */ 1416 Status = STATUS_NO_MEMORY; 1417 } 1418 1419 /* Raise an error unless we got here due to the race condition */ 1420 if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status); 1421 } 1422 1423 /* Now copy from the cached ANSI version */ 1424 lpStartupInfo->cb = StartupInfo->cb; 1425 lpStartupInfo->lpReserved = StartupInfo->lpReserved; 1426 lpStartupInfo->lpDesktop = StartupInfo->lpDesktop; 1427 lpStartupInfo->lpTitle = StartupInfo->lpTitle; 1428 lpStartupInfo->dwX = StartupInfo->dwX; 1429 lpStartupInfo->dwY = StartupInfo->dwY; 1430 lpStartupInfo->dwXSize = StartupInfo->dwXSize; 1431 lpStartupInfo->dwYSize = StartupInfo->dwYSize; 1432 lpStartupInfo->dwXCountChars = StartupInfo->dwXCountChars; 1433 lpStartupInfo->dwYCountChars = StartupInfo->dwYCountChars; 1434 lpStartupInfo->dwFillAttribute = StartupInfo->dwFillAttribute; 1435 lpStartupInfo->dwFlags = StartupInfo->dwFlags; 1436 lpStartupInfo->wShowWindow = StartupInfo->wShowWindow; 1437 lpStartupInfo->cbReserved2 = StartupInfo->cbReserved2; 1438 lpStartupInfo->lpReserved2 = StartupInfo->lpReserved2; 1439 1440 /* Check if the shell is hijacking the handles for other features */ 1441 if (lpStartupInfo->dwFlags & 1442 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)) 1443 { 1444 /* It isn't, so we can return the raw values */ 1445 lpStartupInfo->hStdInput = StartupInfo->hStdInput; 1446 lpStartupInfo->hStdOutput = StartupInfo->hStdOutput; 1447 lpStartupInfo->hStdError = StartupInfo->hStdError; 1448 } 1449 else 1450 { 1451 /* It is, so make sure nobody uses these as console handles */ 1452 lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE; 1453 lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE; 1454 lpStartupInfo->hStdError = INVALID_HANDLE_VALUE; 1455 } 1456 } 1457 1458 /* 1459 * @implemented 1460 */ 1461 BOOL 1462 WINAPI 1463 FlushInstructionCache(IN HANDLE hProcess, 1464 IN LPCVOID lpBaseAddress, 1465 IN SIZE_T nSize) 1466 { 1467 NTSTATUS Status; 1468 1469 /* Call the native function */ 1470 Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, nSize); 1471 if (!NT_SUCCESS(Status)) 1472 { 1473 /* Handle failure case */ 1474 BaseSetLastNTError(Status); 1475 return FALSE; 1476 } 1477 1478 /* All good */ 1479 return TRUE; 1480 } 1481 1482 /* 1483 * @implemented 1484 */ 1485 VOID 1486 WINAPI 1487 ExitProcess(IN UINT uExitCode) 1488 { 1489 BASE_API_MESSAGE ApiMessage; 1490 PBASE_EXIT_PROCESS ExitProcessRequest = &ApiMessage.Data.ExitProcessRequest; 1491 1492 ASSERT(!BaseRunningInServerProcess); 1493 1494 _SEH2_TRY 1495 { 1496 /* Acquire the PEB lock */ 1497 RtlAcquirePebLock(); 1498 1499 /* Kill all the threads */ 1500 NtTerminateProcess(NULL, uExitCode); 1501 1502 /* Unload all DLLs */ 1503 LdrShutdownProcess(); 1504 1505 /* Notify Base Server of process termination */ 1506 ExitProcessRequest->uExitCode = uExitCode; 1507 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1508 NULL, 1509 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitProcess), 1510 sizeof(*ExitProcessRequest)); 1511 1512 /* Now do it again */ 1513 NtTerminateProcess(NtCurrentProcess(), uExitCode); 1514 } 1515 _SEH2_FINALLY 1516 { 1517 /* Release the PEB lock */ 1518 RtlReleasePebLock(); 1519 } 1520 _SEH2_END; 1521 1522 /* should never get here */ 1523 ASSERT(0); 1524 while(1); 1525 } 1526 1527 /* 1528 * @implemented 1529 */ 1530 BOOL 1531 WINAPI 1532 TerminateProcess(IN HANDLE hProcess, 1533 IN UINT uExitCode) 1534 { 1535 NTSTATUS Status; 1536 1537 /* Check if no handle was passed in */ 1538 if (!hProcess) 1539 { 1540 /* Set error code */ 1541 SetLastError(ERROR_INVALID_HANDLE); 1542 } 1543 else 1544 { 1545 /* Otherwise, try to terminate the process */ 1546 Status = NtTerminateProcess(hProcess, uExitCode); 1547 if (NT_SUCCESS(Status)) return TRUE; 1548 1549 /* It failed, convert error code */ 1550 BaseSetLastNTError(Status); 1551 } 1552 1553 /* This is the failure path */ 1554 return FALSE; 1555 } 1556 1557 /* 1558 * @implemented 1559 */ 1560 VOID 1561 WINAPI 1562 FatalAppExitA(UINT uAction, 1563 LPCSTR lpMessageText) 1564 { 1565 PUNICODE_STRING MessageTextU; 1566 ANSI_STRING MessageText; 1567 NTSTATUS Status; 1568 1569 /* Initialize the string using the static TEB pointer */ 1570 MessageTextU = &NtCurrentTeb()->StaticUnicodeString; 1571 RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText); 1572 1573 /* Convert to unicode, or just exit normally if this failed */ 1574 Status = RtlAnsiStringToUnicodeString(MessageTextU, &MessageText, FALSE); 1575 if (!NT_SUCCESS(Status)) ExitProcess(0); 1576 1577 /* Call the Wide function */ 1578 FatalAppExitW(uAction, MessageTextU->Buffer); 1579 } 1580 1581 /* 1582 * @implemented 1583 */ 1584 VOID 1585 WINAPI 1586 FatalAppExitW(IN UINT uAction, 1587 IN LPCWSTR lpMessageText) 1588 { 1589 UNICODE_STRING UnicodeString; 1590 ULONG Response; 1591 NTSTATUS Status; 1592 1593 /* Setup the string to print out */ 1594 RtlInitUnicodeString(&UnicodeString, lpMessageText); 1595 1596 /* Display the hard error no matter what */ 1597 Status = NtRaiseHardError(STATUS_FATAL_APP_EXIT | HARDERROR_OVERRIDE_ERRORMODE, 1598 1, 1599 1, 1600 (PULONG_PTR)&UnicodeString, 1601 #if DBG 1602 /* On Checked builds, Windows allows the user to cancel the operation */ 1603 OptionOkCancel, 1604 #else 1605 OptionOk, 1606 #endif 1607 &Response); 1608 1609 /* Give the user a chance to abort */ 1610 if ((NT_SUCCESS(Status)) && (Response == ResponseCancel)) 1611 { 1612 return; 1613 } 1614 1615 /* Otherwise kill the process */ 1616 ExitProcess(0); 1617 } 1618 1619 /* 1620 * @implemented 1621 */ 1622 VOID 1623 WINAPI 1624 FatalExit(IN int ExitCode) 1625 { 1626 #if DBG 1627 /* On Checked builds, Windows gives the user a nice little debugger UI */ 1628 CHAR Action[2]; 1629 DbgPrint("FatalExit...\n\n"); 1630 1631 while (TRUE) 1632 { 1633 DbgPrompt("A (Abort), B (Break), I (Ignore)? ", Action, sizeof(Action)); 1634 switch (Action[0]) 1635 { 1636 case 'B': case 'b': 1637 DbgBreakPoint(); 1638 break; 1639 1640 case 'A': case 'a': 1641 ExitProcess(ExitCode); 1642 1643 case 'I': case 'i': 1644 return; 1645 } 1646 } 1647 #endif 1648 /* On other builds, just kill the process */ 1649 ExitProcess(ExitCode); 1650 } 1651 1652 /* 1653 * @implemented 1654 */ 1655 DWORD 1656 WINAPI 1657 GetPriorityClass(IN HANDLE hProcess) 1658 { 1659 NTSTATUS Status; 1660 PROCESS_PRIORITY_CLASS DECLSPEC_ALIGN(4) PriorityClass; 1661 1662 /* Query the kernel */ 1663 Status = NtQueryInformationProcess(hProcess, 1664 ProcessPriorityClass, 1665 &PriorityClass, 1666 sizeof(PriorityClass), 1667 NULL); 1668 if (NT_SUCCESS(Status)) 1669 { 1670 /* Handle the conversion from NT to Win32 classes */ 1671 switch (PriorityClass.PriorityClass) 1672 { 1673 case PROCESS_PRIORITY_CLASS_IDLE: return IDLE_PRIORITY_CLASS; 1674 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS; 1675 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS; 1676 case PROCESS_PRIORITY_CLASS_HIGH: return HIGH_PRIORITY_CLASS; 1677 case PROCESS_PRIORITY_CLASS_REALTIME: return REALTIME_PRIORITY_CLASS; 1678 case PROCESS_PRIORITY_CLASS_NORMAL: default: return NORMAL_PRIORITY_CLASS; 1679 } 1680 } 1681 1682 /* Failure path */ 1683 BaseSetLastNTError(Status); 1684 return 0; 1685 } 1686 1687 /* 1688 * @implemented 1689 */ 1690 BOOL 1691 WINAPI 1692 SetPriorityClass(IN HANDLE hProcess, 1693 IN DWORD dwPriorityClass) 1694 { 1695 NTSTATUS Status; 1696 PVOID State = NULL; 1697 PROCESS_PRIORITY_CLASS PriorityClass; 1698 1699 /* Handle conversion from Win32 to NT priority classes */ 1700 switch (dwPriorityClass) 1701 { 1702 case IDLE_PRIORITY_CLASS: 1703 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; 1704 break; 1705 1706 case BELOW_NORMAL_PRIORITY_CLASS: 1707 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; 1708 break; 1709 1710 case NORMAL_PRIORITY_CLASS: 1711 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; 1712 break; 1713 1714 case ABOVE_NORMAL_PRIORITY_CLASS: 1715 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; 1716 break; 1717 1718 case HIGH_PRIORITY_CLASS: 1719 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 1720 break; 1721 1722 case REALTIME_PRIORITY_CLASS: 1723 /* Try to acquire the privilege. If it fails, just use HIGH */ 1724 State = BasepIsRealtimeAllowed(TRUE); 1725 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 1726 PriorityClass.PriorityClass += (State != NULL); 1727 break; 1728 1729 default: 1730 /* Unrecognized priority classes don't make it to the kernel */ 1731 SetLastError(ERROR_INVALID_PARAMETER); 1732 return FALSE; 1733 } 1734 1735 /* Send the request to the kernel, and don't touch the foreground flag */ 1736 PriorityClass.Foreground = FALSE; 1737 Status = NtSetInformationProcess(hProcess, 1738 ProcessPriorityClass, 1739 &PriorityClass, 1740 sizeof(PROCESS_PRIORITY_CLASS)); 1741 1742 /* Release the privilege if we had it */ 1743 if (State) RtlReleasePrivilege(State); 1744 if (!NT_SUCCESS(Status)) 1745 { 1746 /* Handle error path */ 1747 BaseSetLastNTError(Status); 1748 return FALSE; 1749 } 1750 1751 /* All done */ 1752 return TRUE; 1753 } 1754 1755 /* 1756 * @implemented 1757 */ 1758 DWORD 1759 WINAPI 1760 GetProcessVersion(IN DWORD ProcessId) 1761 { 1762 DWORD Version = 0; 1763 PIMAGE_NT_HEADERS NtHeader; 1764 PIMAGE_DOS_HEADER DosHeader; 1765 PPEB Peb; 1766 PROCESS_BASIC_INFORMATION ProcessBasicInfo; 1767 PVOID BaseAddress; 1768 ULONG e_lfanew; 1769 HANDLE ProcessHandle = NULL; 1770 NTSTATUS Status; 1771 USHORT VersionData[2]; 1772 BOOLEAN Result; 1773 1774 /* We'll be accessing stuff that can fault, so protect everything with SEH */ 1775 _SEH2_TRY 1776 { 1777 /* It this an in-process or out-of-process request? */ 1778 if (!(ProcessId) || (GetCurrentProcessId() == ProcessId)) 1779 { 1780 /* It's in-process, so just read our own header */ 1781 NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 1782 if (!NtHeader) 1783 { 1784 /* Unable to read the NT header, something is wrong here... */ 1785 Status = STATUS_INVALID_IMAGE_FORMAT; 1786 goto Error; 1787 } 1788 1789 /* Get the version straight out of the NT header */ 1790 Version = MAKELONG(NtHeader->OptionalHeader.MinorSubsystemVersion, 1791 NtHeader->OptionalHeader.MajorSubsystemVersion); 1792 } 1793 else 1794 { 1795 /* Out-of-process, so open it */ 1796 ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 1797 FALSE, 1798 ProcessId); 1799 if (!ProcessHandle) _SEH2_YIELD(return 0); 1800 1801 /* Try to find out where its PEB lives */ 1802 Status = NtQueryInformationProcess(ProcessHandle, 1803 ProcessBasicInformation, 1804 &ProcessBasicInfo, 1805 sizeof(ProcessBasicInfo), 1806 NULL); 1807 1808 if (!NT_SUCCESS(Status)) goto Error; 1809 Peb = ProcessBasicInfo.PebBaseAddress; 1810 1811 /* Now that we have the PEB, read the image base address out of it */ 1812 Result = ReadProcessMemory(ProcessHandle, 1813 &Peb->ImageBaseAddress, 1814 &BaseAddress, 1815 sizeof(BaseAddress), 1816 NULL); 1817 if (!Result) goto Error; 1818 1819 /* Now read the e_lfanew (offset to NT header) from the base */ 1820 DosHeader = BaseAddress; 1821 Result = ReadProcessMemory(ProcessHandle, 1822 &DosHeader->e_lfanew, 1823 &e_lfanew, 1824 sizeof(e_lfanew), 1825 NULL); 1826 if (!Result) goto Error; 1827 1828 /* And finally, read the NT header itself by adding the offset */ 1829 NtHeader = (PVOID)((ULONG_PTR)BaseAddress + e_lfanew); 1830 Result = ReadProcessMemory(ProcessHandle, 1831 &NtHeader->OptionalHeader.MajorSubsystemVersion, 1832 &VersionData, 1833 sizeof(VersionData), 1834 NULL); 1835 if (!Result) goto Error; 1836 1837 /* Get the version straight out of the NT header */ 1838 Version = MAKELONG(VersionData[0], VersionData[1]); 1839 1840 Error: 1841 /* If there was an error anywhere, set the last error */ 1842 if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status); 1843 } 1844 } 1845 _SEH2_FINALLY 1846 { 1847 /* Close the process handle */ 1848 if (ProcessHandle) CloseHandle(ProcessHandle); 1849 } 1850 _SEH2_END; 1851 1852 /* And return the version data */ 1853 return Version; 1854 } 1855 1856 /* 1857 * @implemented 1858 */ 1859 BOOL 1860 WINAPI 1861 GetProcessIoCounters(IN HANDLE hProcess, 1862 OUT PIO_COUNTERS lpIoCounters) 1863 { 1864 NTSTATUS Status; 1865 1866 /* Query the kernel. Structures are identical, so let it do the copy too. */ 1867 Status = NtQueryInformationProcess(hProcess, 1868 ProcessIoCounters, 1869 lpIoCounters, 1870 sizeof(IO_COUNTERS), 1871 NULL); 1872 if (!NT_SUCCESS(Status)) 1873 { 1874 /* Handle error path */ 1875 BaseSetLastNTError(Status); 1876 return FALSE; 1877 } 1878 1879 /* All done */ 1880 return TRUE; 1881 } 1882 1883 /* 1884 * @implemented 1885 */ 1886 BOOL 1887 WINAPI 1888 GetProcessPriorityBoost(IN HANDLE hProcess, 1889 OUT PBOOL pDisablePriorityBoost) 1890 { 1891 NTSTATUS Status; 1892 ULONG PriorityBoost; 1893 1894 /* Query the kernel */ 1895 Status = NtQueryInformationProcess(hProcess, 1896 ProcessPriorityBoost, 1897 &PriorityBoost, 1898 sizeof(PriorityBoost), 1899 NULL); 1900 if (NT_SUCCESS(Status)) 1901 { 1902 /* Convert from ULONG to a BOOL */ 1903 *pDisablePriorityBoost = PriorityBoost ? TRUE : FALSE; 1904 return TRUE; 1905 } 1906 1907 /* Handle error path */ 1908 BaseSetLastNTError(Status); 1909 return FALSE; 1910 } 1911 1912 /* 1913 * @implemented 1914 */ 1915 BOOL 1916 WINAPI 1917 SetProcessPriorityBoost(IN HANDLE hProcess, 1918 IN BOOL bDisablePriorityBoost) 1919 { 1920 NTSTATUS Status; 1921 ULONG PriorityBoost; 1922 1923 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */ 1924 PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE); 1925 Status = NtSetInformationProcess(hProcess, 1926 ProcessPriorityBoost, 1927 &PriorityBoost, 1928 sizeof(ULONG)); 1929 if (!NT_SUCCESS(Status)) 1930 { 1931 /* Handle error path */ 1932 BaseSetLastNTError(Status); 1933 return FALSE; 1934 } 1935 1936 /* All done */ 1937 return TRUE; 1938 } 1939 1940 /* 1941 * @implemented 1942 */ 1943 BOOL 1944 WINAPI 1945 GetProcessHandleCount(IN HANDLE hProcess, 1946 OUT PDWORD pdwHandleCount) 1947 { 1948 ULONG phc; 1949 NTSTATUS Status; 1950 1951 /* Query the kernel */ 1952 Status = NtQueryInformationProcess(hProcess, 1953 ProcessHandleCount, 1954 &phc, 1955 sizeof(phc), 1956 NULL); 1957 if (NT_SUCCESS(Status)) 1958 { 1959 /* Copy the count and return success */ 1960 *pdwHandleCount = phc; 1961 return TRUE; 1962 } 1963 1964 /* Handle error path */ 1965 BaseSetLastNTError(Status); 1966 return FALSE; 1967 } 1968 1969 /* 1970 * @implemented 1971 */ 1972 BOOL 1973 WINAPI 1974 IsWow64Process(IN HANDLE hProcess, 1975 OUT PBOOL Wow64Process) 1976 { 1977 ULONG_PTR pbi; 1978 NTSTATUS Status; 1979 1980 /* Query the kernel */ 1981 Status = NtQueryInformationProcess(hProcess, 1982 ProcessWow64Information, 1983 &pbi, 1984 sizeof(pbi), 1985 NULL); 1986 if (!NT_SUCCESS(Status)) 1987 { 1988 /* Handle error path */ 1989 BaseSetLastNTError(Status); 1990 return FALSE; 1991 } 1992 1993 /* Enforce this is a BOOL, and return success */ 1994 *Wow64Process = (pbi != 0); 1995 return TRUE; 1996 } 1997 1998 /* 1999 * @implemented 2000 */ 2001 LPSTR 2002 WINAPI 2003 GetCommandLineA(VOID) 2004 { 2005 return BaseAnsiCommandLine.Buffer; 2006 } 2007 2008 /* 2009 * @implemented 2010 */ 2011 LPWSTR 2012 WINAPI 2013 GetCommandLineW(VOID) 2014 { 2015 return BaseUnicodeCommandLine.Buffer; 2016 } 2017 2018 /* 2019 * @implemented 2020 */ 2021 BOOL 2022 NTAPI 2023 ReadProcessMemory(IN HANDLE hProcess, 2024 IN LPCVOID lpBaseAddress, 2025 IN LPVOID lpBuffer, 2026 IN SIZE_T nSize, 2027 OUT SIZE_T* lpNumberOfBytesRead) 2028 { 2029 NTSTATUS Status; 2030 2031 /* Do the read */ 2032 Status = NtReadVirtualMemory(hProcess, 2033 (PVOID)lpBaseAddress, 2034 lpBuffer, 2035 nSize, 2036 &nSize); 2037 2038 /* In user-mode, this parameter is optional */ 2039 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize; 2040 if (!NT_SUCCESS(Status)) 2041 { 2042 /* We failed */ 2043 BaseSetLastNTError(Status); 2044 return FALSE; 2045 } 2046 2047 /* Return success */ 2048 return TRUE; 2049 } 2050 2051 /* 2052 * @implemented 2053 */ 2054 BOOL 2055 NTAPI 2056 WriteProcessMemory(IN HANDLE hProcess, 2057 IN LPVOID lpBaseAddress, 2058 IN LPCVOID lpBuffer, 2059 IN SIZE_T nSize, 2060 OUT SIZE_T *lpNumberOfBytesWritten) 2061 { 2062 NTSTATUS Status; 2063 ULONG OldValue; 2064 SIZE_T RegionSize; 2065 PVOID Base; 2066 BOOLEAN UnProtect; 2067 2068 /* Set parameters for protect call */ 2069 RegionSize = nSize; 2070 Base = lpBaseAddress; 2071 2072 /* Check the current status */ 2073 Status = NtProtectVirtualMemory(hProcess, 2074 &Base, 2075 &RegionSize, 2076 PAGE_EXECUTE_READWRITE, 2077 &OldValue); 2078 if (NT_SUCCESS(Status)) 2079 { 2080 /* Check if we are unprotecting */ 2081 UnProtect = OldValue & (PAGE_READWRITE | 2082 PAGE_WRITECOPY | 2083 PAGE_EXECUTE_READWRITE | 2084 PAGE_EXECUTE_WRITECOPY) ? FALSE : TRUE; 2085 if (!UnProtect) 2086 { 2087 /* Set the new protection */ 2088 Status = NtProtectVirtualMemory(hProcess, 2089 &Base, 2090 &RegionSize, 2091 OldValue, 2092 &OldValue); 2093 2094 /* Write the memory */ 2095 Status = NtWriteVirtualMemory(hProcess, 2096 lpBaseAddress, 2097 (LPVOID)lpBuffer, 2098 nSize, 2099 &nSize); 2100 2101 /* In Win32, the parameter is optional, so handle this case */ 2102 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize; 2103 2104 if (!NT_SUCCESS(Status)) 2105 { 2106 /* We failed */ 2107 BaseSetLastNTError(Status); 2108 return FALSE; 2109 } 2110 2111 /* Flush the ITLB */ 2112 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize); 2113 return TRUE; 2114 } 2115 else 2116 { 2117 /* Check if we were read only */ 2118 if (OldValue & (PAGE_NOACCESS | PAGE_READONLY)) 2119 { 2120 /* Restore protection and fail */ 2121 NtProtectVirtualMemory(hProcess, 2122 &Base, 2123 &RegionSize, 2124 OldValue, 2125 &OldValue); 2126 BaseSetLastNTError(STATUS_ACCESS_VIOLATION); 2127 2128 /* Note: This is what Windows returns and code depends on it */ 2129 return STATUS_ACCESS_VIOLATION; 2130 } 2131 2132 /* Otherwise, do the write */ 2133 Status = NtWriteVirtualMemory(hProcess, 2134 lpBaseAddress, 2135 (LPVOID)lpBuffer, 2136 nSize, 2137 &nSize); 2138 2139 /* In Win32, the parameter is optional, so handle this case */ 2140 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize; 2141 2142 /* And restore the protection */ 2143 NtProtectVirtualMemory(hProcess, 2144 &Base, 2145 &RegionSize, 2146 OldValue, 2147 &OldValue); 2148 if (!NT_SUCCESS(Status)) 2149 { 2150 /* We failed */ 2151 BaseSetLastNTError(STATUS_ACCESS_VIOLATION); 2152 2153 /* Note: This is what Windows returns and code depends on it */ 2154 return STATUS_ACCESS_VIOLATION; 2155 } 2156 2157 /* Flush the ITLB */ 2158 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize); 2159 return TRUE; 2160 } 2161 } 2162 else 2163 { 2164 /* We failed */ 2165 BaseSetLastNTError(Status); 2166 return FALSE; 2167 } 2168 } 2169 2170 /* 2171 * @implemented 2172 */ 2173 BOOL 2174 WINAPI 2175 ProcessIdToSessionId(IN DWORD dwProcessId, 2176 OUT PDWORD pSessionId) 2177 { 2178 PROCESS_SESSION_INFORMATION SessionInformation; 2179 OBJECT_ATTRIBUTES ObjectAttributes; 2180 CLIENT_ID ClientId; 2181 HANDLE ProcessHandle; 2182 NTSTATUS Status; 2183 2184 /* Do a quick check if the pointer is not writable */ 2185 if (IsBadWritePtr(pSessionId, sizeof(DWORD))) 2186 { 2187 /* Fail fast */ 2188 SetLastError(ERROR_INVALID_PARAMETER); 2189 return FALSE; 2190 } 2191 2192 /* Open the process passed in by ID */ 2193 ClientId.UniqueProcess = UlongToHandle(dwProcessId); 2194 ClientId.UniqueThread = 0; 2195 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2196 Status = NtOpenProcess(&ProcessHandle, 2197 PROCESS_QUERY_INFORMATION, 2198 &ObjectAttributes, 2199 &ClientId); 2200 if (NT_SUCCESS(Status)) 2201 { 2202 /* Query the session ID from the kernel */ 2203 Status = NtQueryInformationProcess(ProcessHandle, 2204 ProcessSessionInformation, 2205 &SessionInformation, 2206 sizeof(SessionInformation), 2207 NULL); 2208 2209 /* Close the handle and check if we succeeded */ 2210 NtClose(ProcessHandle); 2211 if (NT_SUCCESS(Status)) 2212 { 2213 /* Return the session ID */ 2214 *pSessionId = SessionInformation.SessionId; 2215 return TRUE; 2216 } 2217 } 2218 2219 /* Set error code and fail */ 2220 BaseSetLastNTError(Status); 2221 return FALSE; 2222 } 2223 2224 2225 #define AddToHandle(x,y) ((x) = (HANDLE)((ULONG_PTR)(x) | (y))) 2226 #define RemoveFromHandle(x,y) ((x) = (HANDLE)((ULONG_PTR)(x) & ~(y))) 2227 C_ASSERT(PROCESS_PRIORITY_CLASS_REALTIME == (PROCESS_PRIORITY_CLASS_HIGH + 1)); 2228 2229 /* 2230 * @implemented 2231 */ 2232 BOOL 2233 WINAPI 2234 CreateProcessInternalW(IN HANDLE hUserToken, 2235 IN LPCWSTR lpApplicationName, 2236 IN LPWSTR lpCommandLine, 2237 IN LPSECURITY_ATTRIBUTES lpProcessAttributes, 2238 IN LPSECURITY_ATTRIBUTES lpThreadAttributes, 2239 IN BOOL bInheritHandles, 2240 IN DWORD dwCreationFlags, 2241 IN LPVOID lpEnvironment, 2242 IN LPCWSTR lpCurrentDirectory, 2243 IN LPSTARTUPINFOW lpStartupInfo, 2244 IN LPPROCESS_INFORMATION lpProcessInformation, 2245 OUT PHANDLE hNewToken) 2246 { 2247 // 2248 // Core variables used for creating the initial process and thread 2249 // 2250 SECURITY_ATTRIBUTES LocalThreadAttributes, LocalProcessAttributes; 2251 OBJECT_ATTRIBUTES LocalObjectAttributes; 2252 POBJECT_ATTRIBUTES ObjectAttributes; 2253 SECTION_IMAGE_INFORMATION ImageInformation; 2254 IO_STATUS_BLOCK IoStatusBlock; 2255 CLIENT_ID ClientId; 2256 ULONG NoWindow, StackSize, ErrorCode, Flags; 2257 SIZE_T RegionSize; 2258 USHORT ImageMachine; 2259 ULONG ParameterFlags, PrivilegeValue, HardErrorMode, ErrorResponse; 2260 ULONG_PTR ErrorParameters[2]; 2261 BOOLEAN InJob, SaferNeeded, UseLargePages, HavePrivilege; 2262 BOOLEAN QuerySection, SkipSaferAndAppCompat; 2263 CONTEXT Context; 2264 BASE_API_MESSAGE CsrMsg[2]; 2265 PBASE_CREATE_PROCESS CreateProcessMsg; 2266 PCSR_CAPTURE_BUFFER CaptureBuffer; 2267 PVOID BaseAddress, PrivilegeState, RealTimePrivilegeState; 2268 HANDLE DebugHandle, TokenHandle, JobHandle, KeyHandle, ThreadHandle; 2269 HANDLE FileHandle, SectionHandle, ProcessHandle; 2270 ULONG ResumeCount; 2271 PROCESS_PRIORITY_CLASS PriorityClass; 2272 NTSTATUS Status, AppCompatStatus, SaferStatus, IFEOStatus, ImageDbgStatus; 2273 PPEB Peb, RemotePeb; 2274 PTEB Teb; 2275 INITIAL_TEB InitialTeb; 2276 PVOID TibValue; 2277 PIMAGE_NT_HEADERS NtHeaders; 2278 STARTUPINFOW StartupInfo; 2279 PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 2280 UNICODE_STRING DebuggerString; 2281 BOOL Result; 2282 // 2283 // Variables used for command-line and argument parsing 2284 // 2285 PCHAR pcScan; 2286 SIZE_T n; 2287 WCHAR SaveChar; 2288 ULONG Length, FileAttribs, CmdQuoteLength; 2289 ULONG ResultSize; 2290 SIZE_T EnvironmentLength, CmdLineLength; 2291 PWCHAR QuotedCmdLine, AnsiCmdCommand, ExtBuffer, CurrentDirectory; 2292 PWCHAR NullBuffer, ScanString, NameBuffer, SearchPath, DebuggerCmdLine; 2293 ANSI_STRING AnsiEnv; 2294 UNICODE_STRING UnicodeEnv, PathName; 2295 BOOLEAN SearchRetry, QuotesNeeded, CmdLineIsAppName, HasQuotes; 2296 2297 // 2298 // Variables used for Fusion/SxS (Side-by-Side Assemblies) 2299 // 2300 RTL_PATH_TYPE SxsPathType, PathType; 2301 #if _SXS_SUPPORT_ENABLED_ 2302 PRTL_BUFFER ByteBuffer; 2303 PRTL_UNICODE_STRING_BUFFER ThisBuffer, Buffer, SxsStaticBuffers[5]; 2304 PRTL_UNICODE_STRING_BUFFER* BufferHead, SxsStringBuffer; 2305 RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath, SxsNtManifestPath; 2306 RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath, SxsNtPolicyPath; 2307 RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory; 2308 BASE_MSG_SXS_HANDLES MappedHandles, Handles, FileHandles; 2309 PVOID CapturedStrings[3]; 2310 SXS_WIN32_NT_PATH_PAIR ExePathPair, ManifestPathPair, PolicyPathPair; 2311 SXS_OVERRIDE_MANIFEST OverrideManifest; 2312 UNICODE_STRING FreeString, SxsNtExePath; 2313 PWCHAR SxsConglomeratedBuffer, StaticBuffer; 2314 ULONG ConglomeratedBufferSizeBytes, StaticBufferSize, i; 2315 #endif 2316 ULONG FusionFlags; 2317 2318 // 2319 // Variables used for path conversion (and partially Fusion/SxS) 2320 // 2321 PWCHAR FilePart, PathBuffer, FreeBuffer; 2322 BOOLEAN TranslationStatus; 2323 RTL_RELATIVE_NAME_U SxsWin32RelativePath; 2324 UNICODE_STRING PathBufferString, SxsWin32ExePath; 2325 2326 // 2327 // Variables used by Application Compatibility (and partially Fusion/SxS) 2328 // 2329 PVOID AppCompatSxsData, AppCompatData; 2330 ULONG AppCompatSxsDataSize, AppCompatDataSize; 2331 // 2332 // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support) 2333 // 2334 ULONG BinarySubType, VdmBinaryType, VdmTask, VdmReserve; 2335 ULONG VdmUndoLevel; 2336 BOOLEAN UseVdmReserve; 2337 HANDLE VdmWaitObject; 2338 ANSI_STRING VdmAnsiEnv; 2339 UNICODE_STRING VdmString, VdmUnicodeEnv; 2340 BOOLEAN IsWowApp; 2341 PBASE_CHECK_VDM CheckVdmMsg; 2342 2343 /* Zero out the initial core variables and handles */ 2344 QuerySection = FALSE; 2345 InJob = FALSE; 2346 SkipSaferAndAppCompat = FALSE; 2347 ParameterFlags = 0; 2348 Flags = 0; 2349 DebugHandle = NULL; 2350 JobHandle = NULL; 2351 TokenHandle = NULL; 2352 FileHandle = NULL; 2353 SectionHandle = NULL; 2354 ProcessHandle = NULL; 2355 ThreadHandle = NULL; 2356 ClientId.UniqueProcess = ClientId.UniqueThread = 0; 2357 BaseAddress = (PVOID)1; 2358 2359 /* Zero out initial SxS and Application Compatibility state */ 2360 AppCompatData = NULL; 2361 AppCompatDataSize = 0; 2362 AppCompatSxsData = NULL; 2363 AppCompatSxsDataSize = 0; 2364 CaptureBuffer = NULL; 2365 #if _SXS_SUPPORT_ENABLED_ 2366 SxsConglomeratedBuffer = NULL; 2367 #endif 2368 FusionFlags = 0; 2369 2370 /* Zero out initial parsing variables -- others are initialized later */ 2371 DebuggerCmdLine = NULL; 2372 PathBuffer = NULL; 2373 SearchPath = NULL; 2374 NullBuffer = NULL; 2375 FreeBuffer = NULL; 2376 NameBuffer = NULL; 2377 CurrentDirectory = NULL; 2378 FilePart = NULL; 2379 DebuggerString.Buffer = NULL; 2380 HasQuotes = FALSE; 2381 QuotedCmdLine = NULL; 2382 2383 /* Zero out initial VDM state */ 2384 VdmAnsiEnv.Buffer = NULL; 2385 VdmUnicodeEnv.Buffer = NULL; 2386 VdmString.Buffer = NULL; 2387 VdmTask = 0; 2388 VdmUndoLevel = 0; 2389 VdmBinaryType = 0; 2390 VdmReserve = 0; 2391 VdmWaitObject = NULL; 2392 UseVdmReserve = FALSE; 2393 IsWowApp = FALSE; 2394 2395 /* Set message structures */ 2396 CreateProcessMsg = &CsrMsg[0].Data.CreateProcessRequest; 2397 CheckVdmMsg = &CsrMsg[1].Data.CheckVDMRequest; 2398 2399 /* Clear the more complex structures by zeroing out their entire memory */ 2400 RtlZeroMemory(&Context, sizeof(Context)); 2401 #if _SXS_SUPPORT_ENABLED_ 2402 RtlZeroMemory(&FileHandles, sizeof(FileHandles)); 2403 RtlZeroMemory(&MappedHandles, sizeof(MappedHandles)); 2404 RtlZeroMemory(&Handles, sizeof(Handles)); 2405 #endif 2406 RtlZeroMemory(&CreateProcessMsg->Sxs, sizeof(CreateProcessMsg->Sxs)); 2407 RtlZeroMemory(&LocalProcessAttributes, sizeof(LocalProcessAttributes)); 2408 RtlZeroMemory(&LocalThreadAttributes, sizeof(LocalThreadAttributes)); 2409 2410 /* Zero out output arguments as well */ 2411 RtlZeroMemory(lpProcessInformation, sizeof(*lpProcessInformation)); 2412 if (hNewToken) *hNewToken = NULL; 2413 2414 /* Capture the special window flag */ 2415 NoWindow = dwCreationFlags & CREATE_NO_WINDOW; 2416 dwCreationFlags &= ~CREATE_NO_WINDOW; 2417 2418 #if _SXS_SUPPORT_ENABLED_ 2419 /* Setup the SxS static string arrays and buffers */ 2420 SxsStaticBuffers[0] = &SxsWin32ManifestPath; 2421 SxsStaticBuffers[1] = &SxsWin32PolicyPath; 2422 SxsStaticBuffers[2] = &SxsWin32AssemblyDirectory; 2423 SxsStaticBuffers[3] = &SxsNtManifestPath; 2424 SxsStaticBuffers[4] = &SxsNtPolicyPath; 2425 ExePathPair.Win32 = &SxsWin32ExePath; 2426 ExePathPair.Nt = &SxsNtExePath; 2427 ManifestPathPair.Win32 = &SxsWin32ManifestPath.String; 2428 ManifestPathPair.Nt = &SxsNtManifestPath.String; 2429 PolicyPathPair.Win32 = &SxsWin32PolicyPath.String; 2430 PolicyPathPair.Nt = &SxsNtPolicyPath.String; 2431 #endif 2432 2433 DPRINT("CreateProcessInternalW: '%S' '%S' %lx\n", lpApplicationName, lpCommandLine, dwCreationFlags); 2434 2435 /* Finally, set our TEB and PEB */ 2436 Teb = NtCurrentTeb(); 2437 Peb = NtCurrentPeb(); 2438 2439 /* This combination is illegal (see MSDN) */ 2440 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) == 2441 (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) 2442 { 2443 DPRINT1("Invalid flag combo used\n"); 2444 SetLastError(ERROR_INVALID_PARAMETER); 2445 return FALSE; 2446 } 2447 2448 /* Convert the priority class */ 2449 if (dwCreationFlags & IDLE_PRIORITY_CLASS) 2450 { 2451 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; 2452 } 2453 else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS) 2454 { 2455 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; 2456 } 2457 else if (dwCreationFlags & NORMAL_PRIORITY_CLASS) 2458 { 2459 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; 2460 } 2461 else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS) 2462 { 2463 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; 2464 } 2465 else if (dwCreationFlags & HIGH_PRIORITY_CLASS) 2466 { 2467 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 2468 } 2469 else if (dwCreationFlags & REALTIME_PRIORITY_CLASS) 2470 { 2471 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 2472 PriorityClass.PriorityClass += (BasepIsRealtimeAllowed(FALSE) != NULL); 2473 } 2474 else 2475 { 2476 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_INVALID; 2477 } 2478 2479 /* Done with the priority masks, so get rid of them */ 2480 PriorityClass.Foreground = FALSE; 2481 dwCreationFlags &= ~(NORMAL_PRIORITY_CLASS | 2482 IDLE_PRIORITY_CLASS | 2483 HIGH_PRIORITY_CLASS | 2484 REALTIME_PRIORITY_CLASS | 2485 BELOW_NORMAL_PRIORITY_CLASS | 2486 ABOVE_NORMAL_PRIORITY_CLASS); 2487 2488 /* You cannot request both a shared and a separate WoW VDM */ 2489 if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) && 2490 (dwCreationFlags & CREATE_SHARED_WOW_VDM)) 2491 { 2492 /* Fail such nonsensical attempts */ 2493 DPRINT1("Invalid WOW flags\n"); 2494 SetLastError(ERROR_INVALID_PARAMETER); 2495 return FALSE; 2496 } 2497 else if (!(dwCreationFlags & CREATE_SHARED_WOW_VDM) && 2498 (BaseStaticServerData->DefaultSeparateVDM)) 2499 { 2500 /* A shared WoW VDM was not requested but system enforces separation */ 2501 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 2502 } 2503 2504 /* If a shared WoW VDM is used, make sure the process isn't in a job */ 2505 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM) && 2506 (NtIsProcessInJob(NtCurrentProcess(), NULL))) 2507 { 2508 /* Remove the shared flag and add the separate flag */ 2509 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) | 2510 CREATE_SEPARATE_WOW_VDM; 2511 } 2512 2513 /* Convert the environment */ 2514 if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) 2515 { 2516 /* Scan the environment to calculate its Unicode size */ 2517 AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment; 2518 while ((*pcScan) || (*(pcScan + 1))) ++pcScan; 2519 2520 /* Make sure the environment is not too large */ 2521 EnvironmentLength = (pcScan + sizeof(ANSI_NULL) - (PCHAR)lpEnvironment); 2522 if (EnvironmentLength > MAXUSHORT) 2523 { 2524 /* Fail */ 2525 SetLastError(ERROR_INVALID_PARAMETER); 2526 return FALSE; 2527 } 2528 2529 /* Create our ANSI String */ 2530 AnsiEnv.Length = (USHORT)EnvironmentLength; 2531 AnsiEnv.MaximumLength = AnsiEnv.Length + sizeof(ANSI_NULL); 2532 2533 /* Allocate memory for the Unicode Environment */ 2534 UnicodeEnv.Buffer = NULL; 2535 RegionSize = AnsiEnv.MaximumLength * sizeof(WCHAR); 2536 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 2537 (PVOID)&UnicodeEnv.Buffer, 2538 0, 2539 &RegionSize, 2540 MEM_COMMIT, 2541 PAGE_READWRITE); 2542 if (!NT_SUCCESS(Status)) 2543 { 2544 /* Fail */ 2545 BaseSetLastNTError(Status); 2546 return FALSE; 2547 } 2548 2549 /* Use the allocated size and convert */ 2550 UnicodeEnv.MaximumLength = (USHORT)RegionSize; 2551 Status = RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE); 2552 if (!NT_SUCCESS(Status)) 2553 { 2554 /* Fail */ 2555 NtFreeVirtualMemory(NtCurrentProcess(), 2556 (PVOID)&UnicodeEnv.Buffer, 2557 &RegionSize, 2558 MEM_RELEASE); 2559 BaseSetLastNTError(Status); 2560 return FALSE; 2561 } 2562 2563 /* Now set the Unicode environment as the environment string pointer */ 2564 lpEnvironment = UnicodeEnv.Buffer; 2565 } 2566 2567 /* Make a copy of the caller's startup info since we'll modify it */ 2568 StartupInfo = *lpStartupInfo; 2569 2570 /* Check if private data is being sent on the same channel as std handles */ 2571 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) && 2572 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))) 2573 { 2574 /* Cannot use the std handles since we have monitor/hotkey values */ 2575 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 2576 } 2577 2578 /* If there's a debugger, or we have to launch cmd.exe, we go back here */ 2579 AppNameRetry: 2580 /* New iteration -- free any existing name buffer */ 2581 if (NameBuffer) 2582 { 2583 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 2584 NameBuffer = NULL; 2585 } 2586 2587 /* New iteration -- free any existing free buffer */ 2588 if (FreeBuffer) 2589 { 2590 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer); 2591 FreeBuffer = NULL; 2592 } 2593 2594 /* New iteration -- close any existing file handle */ 2595 if (FileHandle) 2596 { 2597 NtClose(FileHandle); 2598 FileHandle = NULL; 2599 } 2600 2601 /* Set the initial parsing state. This code can loop -- don't move this! */ 2602 ErrorCode = 0; 2603 SearchRetry = TRUE; 2604 QuotesNeeded = FALSE; 2605 CmdLineIsAppName = FALSE; 2606 2607 /* First check if we don't have an application name */ 2608 if (!lpApplicationName) 2609 { 2610 /* This should be the first time we attempt creating one */ 2611 ASSERT(NameBuffer == NULL); 2612 2613 /* Allocate a buffer to hold it */ 2614 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 2615 0, 2616 MAX_PATH * sizeof(WCHAR)); 2617 if (!NameBuffer) 2618 { 2619 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2620 Result = FALSE; 2621 goto Quickie; 2622 } 2623 2624 /* Initialize the application name and our parsing parameters */ 2625 lpApplicationName = NullBuffer = ScanString = lpCommandLine; 2626 2627 /* Check for an initial quote*/ 2628 if (*lpCommandLine == L'\"') 2629 { 2630 /* We found a quote, keep searching for another one */ 2631 SearchRetry = FALSE; 2632 ScanString++; 2633 lpApplicationName = ScanString; 2634 while (*ScanString) 2635 { 2636 /* Have we found the terminating quote? */ 2637 if (*ScanString == L'\"') 2638 { 2639 /* We're done, get out of here */ 2640 NullBuffer = ScanString; 2641 HasQuotes = TRUE; 2642 break; 2643 } 2644 2645 /* Keep searching for the quote */ 2646 ScanString++; 2647 NullBuffer = ScanString; 2648 } 2649 } 2650 else 2651 { 2652 StartScan: 2653 /* We simply make the application name be the command line*/ 2654 lpApplicationName = lpCommandLine; 2655 while (*ScanString) 2656 { 2657 /* Check if it starts with a space or tab */ 2658 if ((*ScanString == L' ') || (*ScanString == L'\t')) 2659 { 2660 /* Break out of the search loop */ 2661 NullBuffer = ScanString; 2662 break; 2663 } 2664 2665 /* Keep searching for a space or tab */ 2666 ScanString++; 2667 NullBuffer = ScanString; 2668 } 2669 } 2670 2671 /* We have found the end of the application name, terminate it */ 2672 SaveChar = *NullBuffer; 2673 *NullBuffer = UNICODE_NULL; 2674 2675 /* New iteration -- free any existing saved path */ 2676 if (SearchPath) 2677 { 2678 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath); 2679 SearchPath = NULL; 2680 } 2681 2682 /* Now compute the final EXE path based on the name */ 2683 SearchPath = BaseComputeProcessExePath((LPWSTR)lpApplicationName); 2684 DPRINT("Search Path: %S\n", SearchPath); 2685 if (!SearchPath) 2686 { 2687 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2688 Result = FALSE; 2689 goto Quickie; 2690 } 2691 2692 /* And search for the executable in the search path */ 2693 Length = SearchPathW(SearchPath, 2694 lpApplicationName, 2695 L".exe", 2696 MAX_PATH, 2697 NameBuffer, 2698 NULL); 2699 2700 /* Did we find it? */ 2701 if ((Length) && (Length < MAX_PATH)) 2702 { 2703 /* Get file attributes */ 2704 FileAttribs = GetFileAttributesW(NameBuffer); 2705 if ((FileAttribs != INVALID_FILE_ATTRIBUTES) && 2706 (FileAttribs & FILE_ATTRIBUTE_DIRECTORY)) 2707 { 2708 /* This was a directory, fail later on */ 2709 Length = 0; 2710 } 2711 else 2712 { 2713 /* It's a file! */ 2714 Length++; 2715 } 2716 } 2717 2718 DPRINT("Length: %lu Buffer: %S\n", Length, NameBuffer); 2719 2720 /* Check if there was a failure in SearchPathW */ 2721 if ((Length) && (Length < MAX_PATH)) 2722 { 2723 /* Everything looks good, restore the name */ 2724 *NullBuffer = SaveChar; 2725 lpApplicationName = NameBuffer; 2726 } 2727 else 2728 { 2729 /* Check if this was a relative path, which would explain it */ 2730 PathType = RtlDetermineDosPathNameType_U(lpApplicationName); 2731 if (PathType != RtlPathTypeRelative) 2732 { 2733 /* This should fail, and give us a detailed LastError */ 2734 FileHandle = CreateFileW(lpApplicationName, 2735 GENERIC_READ, 2736 FILE_SHARE_READ | 2737 FILE_SHARE_WRITE, 2738 NULL, 2739 OPEN_EXISTING, 2740 FILE_ATTRIBUTE_NORMAL, 2741 NULL); 2742 if (FileHandle != INVALID_HANDLE_VALUE) 2743 { 2744 /* It worked? Return a generic error */ 2745 CloseHandle(FileHandle); 2746 FileHandle = NULL; 2747 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND); 2748 } 2749 } 2750 else 2751 { 2752 /* Path was absolute, which means it doesn't exist */ 2753 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND); 2754 } 2755 2756 /* Did we already fail once? */ 2757 if (ErrorCode) 2758 { 2759 /* Set the error code */ 2760 SetLastError(ErrorCode); 2761 } 2762 else 2763 { 2764 /* Not yet, cache it */ 2765 ErrorCode = GetLastError(); 2766 } 2767 2768 /* Put back the command line */ 2769 *NullBuffer = SaveChar; 2770 lpApplicationName = NameBuffer; 2771 2772 /* It's possible there's whitespace in the directory name */ 2773 if (!(*ScanString) || !(SearchRetry)) 2774 { 2775 /* Not the case, give up completely */ 2776 Result = FALSE; 2777 goto Quickie; 2778 } 2779 2780 /* There are spaces, so keep trying the next possibility */ 2781 ScanString++; 2782 NullBuffer = ScanString; 2783 2784 /* We will have to add a quote, since there is a space */ 2785 QuotesNeeded = TRUE; 2786 HasQuotes = TRUE; 2787 goto StartScan; 2788 } 2789 } 2790 else if (!(lpCommandLine) || !(*lpCommandLine)) 2791 { 2792 /* We don't have a command line, so just use the application name */ 2793 CmdLineIsAppName = TRUE; 2794 lpCommandLine = (LPWSTR)lpApplicationName; 2795 } 2796 2797 /* Convert the application name to its NT path */ 2798 TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(lpApplicationName, 2799 &PathName, 2800 NULL, 2801 &SxsWin32RelativePath); 2802 if (!TranslationStatus) 2803 { 2804 /* Path must be invalid somehow, bail out */ 2805 DPRINT1("Path translation for SxS failed\n"); 2806 SetLastError(ERROR_PATH_NOT_FOUND); 2807 Result = FALSE; 2808 goto Quickie; 2809 } 2810 2811 /* Setup the buffer that needs to be freed at the end */ 2812 ASSERT(FreeBuffer == NULL); 2813 FreeBuffer = PathName.Buffer; 2814 2815 /* Check what kind of path the application is, for SxS (Fusion) purposes */ 2816 RtlInitUnicodeString(&SxsWin32ExePath, lpApplicationName); 2817 SxsPathType = RtlDetermineDosPathNameType_U(lpApplicationName); 2818 if ((SxsPathType != RtlPathTypeDriveAbsolute) && 2819 (SxsPathType != RtlPathTypeLocalDevice) && 2820 (SxsPathType != RtlPathTypeRootLocalDevice) && 2821 (SxsPathType != RtlPathTypeUncAbsolute)) 2822 { 2823 /* Relative-type path, get the full path */ 2824 RtlInitEmptyUnicodeString(&PathBufferString, NULL, 0); 2825 Status = RtlGetFullPathName_UstrEx(&SxsWin32ExePath, 2826 NULL, 2827 &PathBufferString, 2828 NULL, 2829 NULL, 2830 NULL, 2831 &SxsPathType, 2832 NULL); 2833 if (!NT_SUCCESS(Status)) 2834 { 2835 /* Fail the rest of the create */ 2836 RtlReleaseRelativeName(&SxsWin32RelativePath); 2837 BaseSetLastNTError(Status); 2838 Result = FALSE; 2839 goto Quickie; 2840 } 2841 2842 /* Use this full path as the SxS path */ 2843 SxsWin32ExePath = PathBufferString; 2844 PathBuffer = PathBufferString.Buffer; 2845 PathBufferString.Buffer = NULL; 2846 DPRINT("SxS Path: %S\n", PathBuffer); 2847 } 2848 2849 /* Also set the .EXE path based on the path name */ 2850 #if _SXS_SUPPORT_ENABLED_ 2851 SxsNtExePath = PathName; 2852 #endif 2853 if (SxsWin32RelativePath.RelativeName.Length) 2854 { 2855 /* If it's relative, capture the relative name */ 2856 PathName = SxsWin32RelativePath.RelativeName; 2857 } 2858 else 2859 { 2860 /* Otherwise, it's absolute, make sure no relative dir is used */ 2861 SxsWin32RelativePath.ContainingDirectory = NULL; 2862 } 2863 2864 /* Now use the path name, and the root path, to try opening the app */ 2865 DPRINT("Path: %wZ. Dir: %p\n", &PathName, SxsWin32RelativePath.ContainingDirectory); 2866 InitializeObjectAttributes(&LocalObjectAttributes, 2867 &PathName, 2868 OBJ_CASE_INSENSITIVE, 2869 SxsWin32RelativePath.ContainingDirectory, 2870 NULL); 2871 Status = NtOpenFile(&FileHandle, 2872 SYNCHRONIZE | 2873 FILE_READ_ATTRIBUTES | 2874 FILE_READ_DATA | 2875 FILE_EXECUTE, 2876 &LocalObjectAttributes, 2877 &IoStatusBlock, 2878 FILE_SHARE_READ | FILE_SHARE_DELETE, 2879 FILE_SYNCHRONOUS_IO_NONALERT | 2880 FILE_NON_DIRECTORY_FILE); 2881 if (!NT_SUCCESS(Status)) 2882 { 2883 /* Try to open the app just for execute purposes instead */ 2884 Status = NtOpenFile(&FileHandle, 2885 SYNCHRONIZE | FILE_EXECUTE, 2886 &LocalObjectAttributes, 2887 &IoStatusBlock, 2888 FILE_SHARE_READ | FILE_SHARE_DELETE, 2889 FILE_SYNCHRONOUS_IO_NONALERT | 2890 FILE_NON_DIRECTORY_FILE); 2891 } 2892 2893 /* Failure path, display which file failed to open */ 2894 if (!NT_SUCCESS(Status)) 2895 DPRINT1("Open file failed: %lx (%wZ)\n", Status, &PathName); 2896 2897 /* Cleanup in preparation for failure or success */ 2898 RtlReleaseRelativeName(&SxsWin32RelativePath); 2899 2900 if (!NT_SUCCESS(Status)) 2901 { 2902 /* Failure path, try to understand why */ 2903 if (RtlIsDosDeviceName_U(lpApplicationName)) 2904 { 2905 /* If a device is being executed, return this special error code */ 2906 SetLastError(ERROR_BAD_DEVICE); 2907 Result = FALSE; 2908 goto Quickie; 2909 } 2910 else 2911 { 2912 /* Otherwise return the converted NT error code */ 2913 BaseSetLastNTError(Status); 2914 Result = FALSE; 2915 goto Quickie; 2916 } 2917 } 2918 2919 /* Did the caller specify a desktop? */ 2920 if (!StartupInfo.lpDesktop) 2921 { 2922 /* Use the one from the current process */ 2923 StartupInfo.lpDesktop = Peb->ProcessParameters->DesktopInfo.Buffer; 2924 } 2925 2926 /* Create a section for this file */ 2927 Status = NtCreateSection(&SectionHandle, 2928 SECTION_ALL_ACCESS, 2929 NULL, 2930 NULL, 2931 PAGE_EXECUTE, 2932 SEC_IMAGE, 2933 FileHandle); 2934 DPRINT("Section status: %lx\n", Status); 2935 if (NT_SUCCESS(Status)) 2936 { 2937 /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */ 2938 if (SharedUserData->SuiteMask & (VER_SUITE_EMBEDDEDNT | 2939 VER_SUITE_DATACENTER | 2940 VER_SUITE_PERSONAL | 2941 VER_SUITE_BLADE)) 2942 { 2943 /* These SKUs do not allow running certain applications */ 2944 Status = BasepCheckWebBladeHashes(FileHandle); 2945 if (Status == STATUS_ACCESS_DENIED) 2946 { 2947 /* And this is one of them! */ 2948 DPRINT1("Invalid Blade hashes!\n"); 2949 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE); 2950 Result = FALSE; 2951 goto Quickie; 2952 } 2953 2954 /* Did we get some other failure? */ 2955 if (!NT_SUCCESS(Status)) 2956 { 2957 /* If we couldn't check the hashes, assume nefariousness */ 2958 DPRINT1("Tampered Blade hashes!\n"); 2959 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER); 2960 Result = FALSE; 2961 goto Quickie; 2962 } 2963 } 2964 2965 /* Now do Winsafer, etc, checks */ 2966 Status = BasepIsProcessAllowed((LPWSTR)lpApplicationName); 2967 if (!NT_SUCCESS(Status)) 2968 { 2969 /* Fail if we're not allowed to launch the process */ 2970 DPRINT1("Process not allowed to launch: %lx\n", Status); 2971 BaseSetLastNTError(Status); 2972 if (SectionHandle) 2973 { 2974 NtClose(SectionHandle); 2975 SectionHandle = NULL; 2976 } 2977 Result = FALSE; 2978 goto Quickie; 2979 } 2980 2981 /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */ 2982 if ((dwCreationFlags & CREATE_FORCEDOS) && 2983 (BaseStaticServerData->IsWowTaskReady)) 2984 { 2985 /* This request can't be satisfied, instead, a separate VDM is needed */ 2986 dwCreationFlags &= ~(CREATE_FORCEDOS | CREATE_SHARED_WOW_VDM); 2987 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 2988 2989 /* Set a failure code, ask for VDM reservation */ 2990 Status = STATUS_INVALID_IMAGE_WIN_16; 2991 UseVdmReserve = TRUE; 2992 2993 /* Close the current handle */ 2994 NtClose(SectionHandle); 2995 SectionHandle = NULL; 2996 2997 /* Don't query the section later */ 2998 QuerySection = FALSE; 2999 } 3000 } 3001 3002 /* Did we already do these checks? */ 3003 if (!SkipSaferAndAppCompat) 3004 { 3005 /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */ 3006 if ((NT_SUCCESS(Status)) || 3007 ((Status == STATUS_INVALID_IMAGE_NOT_MZ) && 3008 !(BaseIsDosApplication(&PathName, Status)))) 3009 { 3010 /* Clear the machine type in case of failure */ 3011 ImageMachine = 0; 3012 3013 /* Clean any app compat data that may have accumulated */ 3014 BasepFreeAppCompatData(AppCompatData, AppCompatSxsData); 3015 AppCompatData = NULL; 3016 AppCompatSxsData = NULL; 3017 3018 /* Do we have a section? */ 3019 if (SectionHandle) 3020 { 3021 /* Have we already queried it? */ 3022 if (QuerySection) 3023 { 3024 /* Nothing to do */ 3025 AppCompatStatus = STATUS_SUCCESS; 3026 } 3027 else 3028 { 3029 /* Get some information about the executable */ 3030 AppCompatStatus = NtQuerySection(SectionHandle, 3031 SectionImageInformation, 3032 &ImageInformation, 3033 sizeof(ImageInformation), 3034 NULL); 3035 } 3036 3037 /* Do we have section information now? */ 3038 if (NT_SUCCESS(AppCompatStatus)) 3039 { 3040 /* Don't ask for it again, save the machine type */ 3041 QuerySection = TRUE; 3042 ImageMachine = ImageInformation.Machine; 3043 } 3044 } 3045 3046 /* Is there a reason/Shim we shouldn't run this application? */ 3047 AppCompatStatus = BasepCheckBadapp(FileHandle, 3048 FreeBuffer, 3049 lpEnvironment, 3050 ImageMachine, 3051 &AppCompatData, 3052 &AppCompatDataSize, 3053 &AppCompatSxsData, 3054 &AppCompatSxsDataSize, 3055 &FusionFlags); 3056 if (!NT_SUCCESS(AppCompatStatus)) 3057 { 3058 /* This is usually the status we get back */ 3059 DPRINT1("App compat launch failure: %lx\n", AppCompatStatus); 3060 if (AppCompatStatus == STATUS_ACCESS_DENIED) 3061 { 3062 /* Convert it to something more Win32-specific */ 3063 SetLastError(ERROR_CANCELLED); 3064 } 3065 else 3066 { 3067 /* Some other error */ 3068 BaseSetLastNTError(AppCompatStatus); 3069 } 3070 3071 /* Did we have a section? */ 3072 if (SectionHandle) 3073 { 3074 /* Clean it up */ 3075 NtClose(SectionHandle); 3076 SectionHandle = NULL; 3077 } 3078 3079 /* Fail the call */ 3080 Result = FALSE; 3081 goto Quickie; 3082 } 3083 } 3084 } 3085 3086 //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0); 3087 3088 /* Have we already done, and do we need to do, SRP (WinSafer) checks? */ 3089 if (!(SkipSaferAndAppCompat) && 3090 ~(dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)) 3091 { 3092 /* Assume yes */ 3093 SaferNeeded = TRUE; 3094 switch (Status) 3095 { 3096 case STATUS_INVALID_IMAGE_NE_FORMAT: 3097 case STATUS_INVALID_IMAGE_PROTECT: 3098 case STATUS_INVALID_IMAGE_WIN_16: 3099 case STATUS_FILE_IS_OFFLINE: 3100 /* For all DOS, 16-bit, OS/2 images, we do*/ 3101 break; 3102 3103 case STATUS_INVALID_IMAGE_NOT_MZ: 3104 /* For invalid files, we don't, unless it's a .BAT file */ 3105 if (BaseIsDosApplication(&PathName, Status)) break; 3106 3107 default: 3108 /* Any other error codes we also don't */ 3109 if (!NT_SUCCESS(Status)) 3110 { 3111 SaferNeeded = FALSE; 3112 } 3113 3114 /* But for success, we do */ 3115 break; 3116 } 3117 3118 /* Okay, so what did the checks above result in? */ 3119 if (SaferNeeded) 3120 { 3121 /* We have to call into the WinSafer library and actually check */ 3122 SaferStatus = BasepCheckWinSaferRestrictions(hUserToken, 3123 (LPWSTR)lpApplicationName, 3124 FileHandle, 3125 &InJob, 3126 &TokenHandle, 3127 &JobHandle); 3128 if (SaferStatus == 0xFFFFFFFF) 3129 { 3130 /* Back in 2003, they didn't have an NTSTATUS for this... */ 3131 DPRINT1("WinSafer blocking process launch\n"); 3132 SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY); 3133 Result = FALSE; 3134 goto Quickie; 3135 } 3136 3137 /* Other status codes are not-Safer related, just convert them */ 3138 if (!NT_SUCCESS(SaferStatus)) 3139 { 3140 DPRINT1("Error checking WinSafer: %lx\n", SaferStatus); 3141 BaseSetLastNTError(SaferStatus); 3142 Result = FALSE; 3143 goto Quickie; 3144 } 3145 } 3146 } 3147 3148 /* The last step is to figure out why the section object was not created */ 3149 switch (Status) 3150 { 3151 case STATUS_INVALID_IMAGE_WIN_16: 3152 { 3153 /* 16-bit binary. Should we use WOW or does the caller force VDM? */ 3154 if (!(dwCreationFlags & CREATE_FORCEDOS)) 3155 { 3156 /* Remember that we're launching WOW */ 3157 IsWowApp = TRUE; 3158 3159 /* Create the VDM environment, it's valid for WOW too */ 3160 Result = BaseCreateVDMEnvironment(lpEnvironment, 3161 &VdmAnsiEnv, 3162 &VdmUnicodeEnv); 3163 if (!Result) 3164 { 3165 DPRINT1("VDM environment for WOW app failed\n"); 3166 goto Quickie; 3167 } 3168 3169 /* We're going to try this twice, so do a loop */ 3170 while (TRUE) 3171 { 3172 /* Pick which kind of WOW mode we want to run in */ 3173 VdmBinaryType = (dwCreationFlags & 3174 CREATE_SEPARATE_WOW_VDM) ? 3175 BINARY_TYPE_SEPARATE_WOW : BINARY_TYPE_WOW; 3176 3177 /* Get all the VDM settings and current status */ 3178 Status = BaseCheckVDM(VdmBinaryType, 3179 lpApplicationName, 3180 lpCommandLine, 3181 lpCurrentDirectory, 3182 &VdmAnsiEnv, 3183 &CsrMsg[1], 3184 &VdmTask, 3185 dwCreationFlags, 3186 &StartupInfo, 3187 hUserToken); 3188 3189 /* If it worked, no need to try again */ 3190 if (NT_SUCCESS(Status)) break; 3191 3192 /* Check if it's disallowed or if it's our second time */ 3193 BaseSetLastNTError(Status); 3194 if ((Status == STATUS_VDM_DISALLOWED) || 3195 (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW) || 3196 (GetLastError() == ERROR_ACCESS_DENIED)) 3197 { 3198 /* Fail the call -- we won't try again */ 3199 DPRINT1("VDM message failure for WOW: %lx\n", Status); 3200 Result = FALSE; 3201 goto Quickie; 3202 } 3203 3204 /* Try one more time, but with a separate WOW instance */ 3205 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 3206 } 3207 3208 /* Check which VDM state we're currently in */ 3209 switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED | 3210 VDM_NOT_READY | 3211 VDM_READY)) 3212 { 3213 case VDM_NOT_LOADED: 3214 /* VDM is not fully loaded, so not that much to undo */ 3215 VdmUndoLevel = VDM_UNDO_PARTIAL; 3216 3217 /* Reset VDM reserve if needed */ 3218 if (UseVdmReserve) VdmReserve = 1; 3219 3220 /* Get the required parameters and names for launch */ 3221 Result = BaseGetVdmConfigInfo(lpCommandLine, 3222 VdmTask, 3223 VdmBinaryType, 3224 &VdmString, 3225 &VdmReserve); 3226 if (!Result) 3227 { 3228 DPRINT1("VDM Configuration failed for WOW\n"); 3229 BaseSetLastNTError(Status); 3230 goto Quickie; 3231 } 3232 3233 /* Update the command-line with the VDM one instead */ 3234 lpCommandLine = VdmString.Buffer; 3235 lpApplicationName = NULL; 3236 3237 /* We don't want a console, detachment, nor a window */ 3238 dwCreationFlags |= CREATE_NO_WINDOW; 3239 dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS); 3240 3241 /* Force feedback on */ 3242 StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK; 3243 break; 3244 3245 3246 case VDM_READY: 3247 /* VDM is ready, so we have to undo everything */ 3248 VdmUndoLevel = VDM_UNDO_REUSE; 3249 3250 /* Check if CSRSS wants us to wait on VDM */ 3251 VdmWaitObject = CheckVdmMsg->WaitObjectForParent; 3252 break; 3253 3254 case VDM_NOT_READY: 3255 /* Something is wrong with VDM, we'll fail the call */ 3256 DPRINT1("VDM is not ready for WOW\n"); 3257 SetLastError(ERROR_NOT_READY); 3258 Result = FALSE; 3259 goto Quickie; 3260 3261 default: 3262 break; 3263 } 3264 3265 /* Since to get NULL, we allocate from 0x1, account for this */ 3266 VdmReserve--; 3267 3268 /* This implies VDM is ready, so skip everything else */ 3269 if (VdmWaitObject) goto VdmShortCircuit; 3270 3271 /* Don't inherit handles since we're doing VDM now */ 3272 bInheritHandles = FALSE; 3273 3274 /* Had the user passed in environment? If so, destroy it */ 3275 if ((lpEnvironment) && 3276 !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) 3277 { 3278 RtlDestroyEnvironment(lpEnvironment); 3279 } 3280 3281 /* We've already done all these checks, don't do them again */ 3282 SkipSaferAndAppCompat = TRUE; 3283 goto AppNameRetry; 3284 } 3285 3286 // There is no break here on purpose, so FORCEDOS drops down! 3287 } 3288 3289 case STATUS_INVALID_IMAGE_PROTECT: 3290 case STATUS_INVALID_IMAGE_NOT_MZ: 3291 case STATUS_INVALID_IMAGE_NE_FORMAT: 3292 { 3293 /* We're launching an executable application */ 3294 BinarySubType = BINARY_TYPE_EXE; 3295 3296 /* We can drop here from other "cases" above too, so check */ 3297 if ((Status == STATUS_INVALID_IMAGE_PROTECT) || 3298 (Status == STATUS_INVALID_IMAGE_NE_FORMAT) || 3299 (BinarySubType = BaseIsDosApplication(&PathName, Status))) 3300 { 3301 /* We're launching a DOS application */ 3302 VdmBinaryType = BINARY_TYPE_DOS; 3303 3304 /* Based on the caller environment, create a VDM one */ 3305 Result = BaseCreateVDMEnvironment(lpEnvironment, 3306 &VdmAnsiEnv, 3307 &VdmUnicodeEnv); 3308 if (!Result) 3309 { 3310 DPRINT1("VDM environment for DOS failed\n"); 3311 goto Quickie; 3312 } 3313 3314 /* Check the current state of the VDM subsystem */ 3315 Status = BaseCheckVDM(VdmBinaryType | BinarySubType, 3316 lpApplicationName, 3317 lpCommandLine, 3318 lpCurrentDirectory, 3319 &VdmAnsiEnv, 3320 &CsrMsg[1], 3321 &VdmTask, 3322 dwCreationFlags, 3323 &StartupInfo, 3324 NULL); 3325 if (!NT_SUCCESS(Status)) 3326 { 3327 /* Failed to inquire about VDM, fail the call */ 3328 DPRINT1("VDM message failure for DOS: %lx\n", Status); 3329 BaseSetLastNTError(Status); 3330 Result = FALSE; 3331 goto Quickie; 3332 }; 3333 3334 /* Handle possible VDM states */ 3335 switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED | 3336 VDM_NOT_READY | 3337 VDM_READY)) 3338 { 3339 case VDM_NOT_LOADED: 3340 /* If VDM is not loaded, we'll do a partial undo */ 3341 VdmUndoLevel = VDM_UNDO_PARTIAL; 3342 3343 /* A VDM process can't also be detached, so fail */ 3344 if (dwCreationFlags & DETACHED_PROCESS) 3345 { 3346 DPRINT1("Detached process but no VDM, not allowed\n"); 3347 SetLastError(ERROR_ACCESS_DENIED); 3348 return FALSE; 3349 } 3350 3351 /* Get the required parameters and names for launch */ 3352 Result = BaseGetVdmConfigInfo(lpCommandLine, 3353 VdmTask, 3354 VdmBinaryType, 3355 &VdmString, 3356 &VdmReserve); 3357 if (!Result) 3358 { 3359 DPRINT1("VDM Configuration failed for DOS\n"); 3360 BaseSetLastNTError(Status); 3361 goto Quickie; 3362 } 3363 3364 /* Update the command-line to launch VDM instead */ 3365 lpCommandLine = VdmString.Buffer; 3366 lpApplicationName = NULL; 3367 break; 3368 3369 case VDM_READY: 3370 /* VDM is ready, so we have to undo everything */ 3371 VdmUndoLevel = VDM_UNDO_REUSE; 3372 3373 /* Check if CSRSS wants us to wait on VDM */ 3374 VdmWaitObject = CheckVdmMsg->WaitObjectForParent; 3375 break; 3376 3377 case VDM_NOT_READY: 3378 /* Something is wrong with VDM, we'll fail the call */ 3379 DPRINT1("VDM is not ready for DOS\n"); 3380 SetLastError(ERROR_NOT_READY); 3381 Result = FALSE; 3382 goto Quickie; 3383 3384 default: 3385 break; 3386 } 3387 3388 /* Since to get NULL, we allocate from 0x1, account for this */ 3389 VdmReserve--; 3390 3391 /* This implies VDM is ready, so skip everything else */ 3392 if (VdmWaitObject) goto VdmShortCircuit; 3393 3394 /* Don't inherit handles since we're doing VDM now */ 3395 bInheritHandles = FALSE; 3396 3397 /* Had the user passed in environment? If so, destroy it */ 3398 if ((lpEnvironment) && 3399 !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) 3400 { 3401 RtlDestroyEnvironment(lpEnvironment); 3402 } 3403 3404 /* Use our VDM Unicode environment instead */ 3405 lpEnvironment = VdmUnicodeEnv.Buffer; 3406 } 3407 else 3408 { 3409 /* It's a batch file, get the extension */ 3410 ExtBuffer = &PathName.Buffer[PathName.Length / sizeof(WCHAR) - 4]; 3411 3412 /* Make sure the extensions are correct */ 3413 if ((PathName.Length < (4 * sizeof(WCHAR))) || 3414 ((_wcsnicmp(ExtBuffer, L".bat", 4)) && 3415 (_wcsnicmp(ExtBuffer, L".cmd", 4)))) 3416 { 3417 DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName); 3418 SetLastError(ERROR_BAD_EXE_FORMAT); 3419 Result = FALSE; 3420 goto Quickie; 3421 } 3422 3423 /* Check if we need to account for quotes around the path */ 3424 CmdQuoteLength = CmdLineIsAppName || HasQuotes; 3425 if (!CmdLineIsAppName) 3426 { 3427 if (HasQuotes) CmdQuoteLength++; 3428 } 3429 else 3430 { 3431 CmdQuoteLength++; 3432 } 3433 3434 /* Calculate the length of the command line */ 3435 CmdLineLength = wcslen(lpCommandLine); 3436 CmdLineLength += wcslen(CMD_STRING); 3437 CmdLineLength += CmdQuoteLength + sizeof(ANSI_NULL); 3438 CmdLineLength *= sizeof(WCHAR); 3439 3440 /* Allocate space for the new command line */ 3441 AnsiCmdCommand = RtlAllocateHeap(RtlGetProcessHeap(), 3442 0, 3443 CmdLineLength); 3444 if (!AnsiCmdCommand) 3445 { 3446 BaseSetLastNTError(STATUS_NO_MEMORY); 3447 Result = FALSE; 3448 goto Quickie; 3449 } 3450 3451 /* Build it */ 3452 wcscpy(AnsiCmdCommand, CMD_STRING); 3453 if ((CmdLineIsAppName) || (HasQuotes)) 3454 { 3455 wcscat(AnsiCmdCommand, L"\""); 3456 } 3457 wcscat(AnsiCmdCommand, lpCommandLine); 3458 if ((CmdLineIsAppName) || (HasQuotes)) 3459 { 3460 wcscat(AnsiCmdCommand, L"\""); 3461 } 3462 3463 /* Create it as a Unicode String */ 3464 RtlInitUnicodeString(&DebuggerString, AnsiCmdCommand); 3465 3466 /* Set the command line to this */ 3467 lpCommandLine = DebuggerString.Buffer; 3468 lpApplicationName = NULL; 3469 DPRINT1("Retrying with: %S\n", lpCommandLine); 3470 } 3471 3472 /* We've already done all these checks, don't do them again */ 3473 SkipSaferAndAppCompat = TRUE; 3474 goto AppNameRetry; 3475 } 3476 3477 case STATUS_INVALID_IMAGE_WIN_64: 3478 { 3479 /* 64-bit binaries are not allowed to run on 32-bit ReactOS */ 3480 DPRINT1("64-bit binary, failing\n"); 3481 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH); 3482 Result = FALSE; 3483 goto Quickie; 3484 } 3485 3486 case STATUS_FILE_IS_OFFLINE: 3487 { 3488 /* Set the correct last error for this */ 3489 DPRINT1("File is offline, failing\n"); 3490 SetLastError(ERROR_FILE_OFFLINE); 3491 break; 3492 } 3493 3494 default: 3495 { 3496 /* Any other error, convert it to a generic Win32 error */ 3497 if (!NT_SUCCESS(Status)) 3498 { 3499 DPRINT1("Failed to create section: %lx\n", Status); 3500 SetLastError(ERROR_BAD_EXE_FORMAT); 3501 Result = FALSE; 3502 goto Quickie; 3503 } 3504 3505 /* Otherwise, this must be success */ 3506 ASSERT(Status == STATUS_SUCCESS); 3507 break; 3508 } 3509 } 3510 3511 /* Is this not a WOW application, but a WOW32 VDM was requested for it? */ 3512 if (!(IsWowApp) && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) 3513 { 3514 /* Ignore the nonsensical request */ 3515 dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM; 3516 } 3517 3518 /* Did we already check information for the section? */ 3519 if (!QuerySection) 3520 { 3521 /* Get some information about the executable */ 3522 Status = NtQuerySection(SectionHandle, 3523 SectionImageInformation, 3524 &ImageInformation, 3525 sizeof(ImageInformation), 3526 NULL); 3527 if (!NT_SUCCESS(Status)) 3528 { 3529 /* We failed, bail out */ 3530 DPRINT1("Section query failed\n"); 3531 BaseSetLastNTError(Status); 3532 Result = FALSE; 3533 goto Quickie; 3534 } 3535 3536 /* Don't check this later */ 3537 QuerySection = TRUE; 3538 } 3539 3540 /* Check if this was linked as a DLL */ 3541 if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) 3542 { 3543 /* These aren't valid images to try to execute! */ 3544 DPRINT1("Trying to launch a DLL, failing\n"); 3545 SetLastError(ERROR_BAD_EXE_FORMAT); 3546 Result = FALSE; 3547 goto Quickie; 3548 } 3549 3550 /* Don't let callers pass in this flag -- we'll only get it from IFEO */ 3551 Flags &= ~PROCESS_CREATE_FLAGS_LARGE_PAGES; 3552 3553 /* Clear the IFEO-missing flag, before we know for sure... */ 3554 ParameterFlags &= ~2; 3555 3556 /* If the process is being debugged, only read IFEO if the PEB says so */ 3557 if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) || 3558 (Peb->ReadImageFileExecOptions)) 3559 { 3560 /* Let's do this! Attempt to open IFEO */ 3561 IFEOStatus = LdrOpenImageFileOptionsKey(&PathName, 0, &KeyHandle); 3562 if (!NT_SUCCESS(IFEOStatus)) 3563 { 3564 /* We failed, set the flag so we store this in the parameters */ 3565 if (IFEOStatus == STATUS_OBJECT_NAME_NOT_FOUND) ParameterFlags |= 2; 3566 } 3567 else 3568 { 3569 /* Was this our first time going through this path? */ 3570 if (!DebuggerCmdLine) 3571 { 3572 /* Allocate a buffer for the debugger path */ 3573 DebuggerCmdLine = RtlAllocateHeap(RtlGetProcessHeap(), 3574 0, 3575 MAX_PATH * sizeof(WCHAR)); 3576 if (!DebuggerCmdLine) 3577 { 3578 /* Close IFEO on failure */ 3579 IFEOStatus = NtClose(KeyHandle); 3580 ASSERT(NT_SUCCESS(IFEOStatus)); 3581 3582 /* Fail the call */ 3583 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3584 Result = FALSE; 3585 goto Quickie; 3586 } 3587 } 3588 3589 /* Now query for the debugger */ 3590 IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle, 3591 L"Debugger", 3592 REG_SZ, 3593 DebuggerCmdLine, 3594 MAX_PATH * sizeof(WCHAR), 3595 &ResultSize); 3596 if (!(NT_SUCCESS(IFEOStatus)) || 3597 (ResultSize < sizeof(WCHAR)) || 3598 (DebuggerCmdLine[0] == UNICODE_NULL)) 3599 { 3600 /* If it's not there, or too small, or invalid, ignore it */ 3601 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine); 3602 DebuggerCmdLine = NULL; 3603 } 3604 3605 /* Also query if we should map with large pages */ 3606 IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle, 3607 L"UseLargePages", 3608 REG_DWORD, 3609 &UseLargePages, 3610 sizeof(UseLargePages), 3611 NULL); 3612 if ((NT_SUCCESS(IFEOStatus)) && (UseLargePages)) 3613 { 3614 /* Do it! This is the only way this flag can be set */ 3615 Flags |= PROCESS_CREATE_FLAGS_LARGE_PAGES; 3616 } 3617 3618 /* We're done with IFEO, can close it now */ 3619 IFEOStatus = NtClose(KeyHandle); 3620 ASSERT(NT_SUCCESS(IFEOStatus)); 3621 } 3622 } 3623 3624 /* Make sure the image was compiled for this processor */ 3625 if ((ImageInformation.Machine < SharedUserData->ImageNumberLow) || 3626 (ImageInformation.Machine > SharedUserData->ImageNumberHigh)) 3627 { 3628 /* It was not -- raise a hard error */ 3629 ErrorResponse = ResponseOk; 3630 ErrorParameters[0] = (ULONG_PTR)&PathName; 3631 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, 3632 1, 3633 1, 3634 ErrorParameters, 3635 OptionOk, 3636 &ErrorResponse); 3637 if (Peb->ImageSubsystemMajorVersion <= 3) 3638 { 3639 /* If it's really old, return this error */ 3640 SetLastError(ERROR_BAD_EXE_FORMAT); 3641 } 3642 else 3643 { 3644 /* Otherwise, return a more modern error */ 3645 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH); 3646 } 3647 3648 /* Go to the failure path */ 3649 DPRINT1("Invalid image architecture: %lx\n", ImageInformation.Machine); 3650 Result = FALSE; 3651 goto Quickie; 3652 } 3653 3654 /* Check if this isn't a Windows image */ 3655 if ((ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI) && 3656 (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI)) 3657 { 3658 /* Get rid of section-related information since we'll retry */ 3659 NtClose(SectionHandle); 3660 SectionHandle = NULL; 3661 QuerySection = FALSE; 3662 3663 /* The only other non-Windows image type we support here is POSIX */ 3664 if (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_POSIX_CUI) 3665 { 3666 /* Bail out if it's something else */ 3667 SetLastError(ERROR_CHILD_NOT_COMPLETE); 3668 Result = FALSE; 3669 goto Quickie; 3670 } 3671 3672 /* Now build the command-line to have posix launch this image */ 3673 Result = BuildSubSysCommandLine(L"POSIX /P ", 3674 lpApplicationName, 3675 lpCommandLine, 3676 &DebuggerString); 3677 if (!Result) 3678 { 3679 /* Bail out if that failed */ 3680 DPRINT1("Subsystem command line failed\n"); 3681 goto Quickie; 3682 } 3683 3684 /* And re-try launching the process, with the new command-line now */ 3685 lpCommandLine = DebuggerString.Buffer; 3686 lpApplicationName = NULL; 3687 3688 /* We've already done all these checks, don't do them again */ 3689 SkipSaferAndAppCompat = TRUE; 3690 DPRINT1("Retrying with: %S\n", lpCommandLine); 3691 goto AppNameRetry; 3692 } 3693 3694 /* Was this image built for a version of Windows whose images we can run? */ 3695 Result = BasepIsImageVersionOk(ImageInformation.SubSystemMajorVersion, 3696 ImageInformation.SubSystemMinorVersion); 3697 if (!Result) 3698 { 3699 /* It was not, bail out */ 3700 DPRINT1("Invalid subsystem version: %hu.%hu\n", 3701 ImageInformation.SubSystemMajorVersion, 3702 ImageInformation.SubSystemMinorVersion); 3703 SetLastError(ERROR_BAD_EXE_FORMAT); 3704 goto Quickie; 3705 } 3706 3707 /* Check if there is a debugger associated with the application */ 3708 if (DebuggerCmdLine) 3709 { 3710 /* Get the length of the command line */ 3711 n = wcslen(lpCommandLine); 3712 if (!n) 3713 { 3714 /* There's no command line, use the application name instead */ 3715 lpCommandLine = (LPWSTR)lpApplicationName; 3716 n = wcslen(lpCommandLine); 3717 } 3718 3719 /* Protect against overflow */ 3720 if (n > UNICODE_STRING_MAX_CHARS) 3721 { 3722 BaseSetLastNTError(STATUS_NAME_TOO_LONG); 3723 Result = FALSE; 3724 goto Quickie; 3725 } 3726 3727 /* Now add the length of the debugger command-line */ 3728 n += wcslen(DebuggerCmdLine); 3729 3730 /* Again make sure we don't overflow */ 3731 if (n > UNICODE_STRING_MAX_CHARS) 3732 { 3733 BaseSetLastNTError(STATUS_NAME_TOO_LONG); 3734 Result = FALSE; 3735 goto Quickie; 3736 } 3737 3738 /* Account for the quotes and space between the two */ 3739 n += sizeof("\" \"") - sizeof(ANSI_NULL); 3740 3741 /* Convert to bytes, and make sure we don't overflow */ 3742 n *= sizeof(WCHAR); 3743 if (n > UNICODE_STRING_MAX_BYTES) 3744 { 3745 BaseSetLastNTError(STATUS_NAME_TOO_LONG); 3746 Result = FALSE; 3747 goto Quickie; 3748 } 3749 3750 /* Allocate space for the string */ 3751 DebuggerString.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, n); 3752 if (!DebuggerString.Buffer) 3753 { 3754 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3755 Result = FALSE; 3756 goto Quickie; 3757 } 3758 3759 /* Set the length */ 3760 RtlInitEmptyUnicodeString(&DebuggerString, 3761 DebuggerString.Buffer, 3762 (USHORT)n); 3763 3764 /* Now perform the command line creation */ 3765 ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, 3766 DebuggerCmdLine); 3767 ASSERT(NT_SUCCESS(ImageDbgStatus)); 3768 ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, L" "); 3769 ASSERT(NT_SUCCESS(ImageDbgStatus)); 3770 ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, lpCommandLine); 3771 ASSERT(NT_SUCCESS(ImageDbgStatus)); 3772 3773 /* Make sure it all looks nice */ 3774 DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString); 3775 3776 /* Update the command line and application name */ 3777 lpCommandLine = DebuggerString.Buffer; 3778 lpApplicationName = NULL; 3779 3780 /* Close all temporary state */ 3781 NtClose(SectionHandle); 3782 SectionHandle = NULL; 3783 QuerySection = FALSE; 3784 3785 /* Free all temporary memory */ 3786 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 3787 NameBuffer = NULL; 3788 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer); 3789 FreeBuffer = NULL; 3790 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine); 3791 DebuggerCmdLine = NULL; 3792 DPRINT1("Retrying with: %S\n", lpCommandLine); 3793 goto AppNameRetry; 3794 } 3795 3796 /* Initialize the process object attributes */ 3797 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 3798 lpProcessAttributes, 3799 NULL); 3800 if ((hUserToken) && (lpProcessAttributes)) 3801 { 3802 /* Augment them with information from the user */ 3803 3804 LocalProcessAttributes = *lpProcessAttributes; 3805 LocalProcessAttributes.lpSecurityDescriptor = NULL; 3806 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 3807 &LocalProcessAttributes, 3808 NULL); 3809 } 3810 3811 /* Check if we're going to be debugged */ 3812 if (dwCreationFlags & DEBUG_PROCESS) 3813 { 3814 /* Set process flag */ 3815 Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY; 3816 } 3817 3818 /* Check if we're going to be debugged */ 3819 if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) 3820 { 3821 /* Connect to DbgUi */ 3822 Status = DbgUiConnectToDbg(); 3823 if (!NT_SUCCESS(Status)) 3824 { 3825 DPRINT1("Failed to connect to DbgUI!\n"); 3826 BaseSetLastNTError(Status); 3827 Result = FALSE; 3828 goto Quickie; 3829 } 3830 3831 /* Get the debug object */ 3832 DebugHandle = DbgUiGetThreadDebugObject(); 3833 3834 /* Check if only this process will be debugged */ 3835 if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS) 3836 { 3837 /* Set process flag */ 3838 Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT; 3839 } 3840 } 3841 3842 /* Set inherit flag */ 3843 if (bInheritHandles) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES; 3844 3845 /* Check if the process should be created with large pages */ 3846 HavePrivilege = FALSE; 3847 PrivilegeState = NULL; 3848 if (Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) 3849 { 3850 /* Acquire the required privilege so that the kernel won't fail the call */ 3851 PrivilegeValue = SE_LOCK_MEMORY_PRIVILEGE; 3852 Status = RtlAcquirePrivilege(&PrivilegeValue, 1, 0, &PrivilegeState); 3853 if (NT_SUCCESS(Status)) 3854 { 3855 /* Remember to release it later */ 3856 HavePrivilege = TRUE; 3857 } 3858 } 3859 3860 /* Save the current TIB value since kernel overwrites it to store PEB */ 3861 TibValue = Teb->NtTib.ArbitraryUserPointer; 3862 3863 /* Tell the kernel to create the process */ 3864 Status = NtCreateProcessEx(&ProcessHandle, 3865 PROCESS_ALL_ACCESS, 3866 ObjectAttributes, 3867 NtCurrentProcess(), 3868 Flags, 3869 SectionHandle, 3870 DebugHandle, 3871 NULL, 3872 InJob); 3873 3874 /* Load the PEB address from the hacky location where the kernel stores it */ 3875 RemotePeb = Teb->NtTib.ArbitraryUserPointer; 3876 3877 /* And restore the old TIB value */ 3878 Teb->NtTib.ArbitraryUserPointer = TibValue; 3879 3880 /* Release the large page privilege if we had acquired it */ 3881 if (HavePrivilege) RtlReleasePrivilege(PrivilegeState); 3882 3883 /* And now check if the kernel failed to create the process */ 3884 if (!NT_SUCCESS(Status)) 3885 { 3886 /* Go to failure path */ 3887 DPRINT1("Failed to create process: %lx\n", Status); 3888 BaseSetLastNTError(Status); 3889 Result = FALSE; 3890 goto Quickie; 3891 } 3892 3893 /* Check if there is a priority class to set */ 3894 if (PriorityClass.PriorityClass) 3895 { 3896 /* Reset current privilege state */ 3897 RealTimePrivilegeState = NULL; 3898 3899 /* Is realtime priority being requested? */ 3900 if (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME) 3901 { 3902 /* Check if the caller has real-time access, and enable it if so */ 3903 RealTimePrivilegeState = BasepIsRealtimeAllowed(TRUE); 3904 } 3905 3906 /* Set the new priority class and release the privilege */ 3907 Status = NtSetInformationProcess(ProcessHandle, 3908 ProcessPriorityClass, 3909 &PriorityClass, 3910 sizeof(PROCESS_PRIORITY_CLASS)); 3911 if (RealTimePrivilegeState) RtlReleasePrivilege(RealTimePrivilegeState); 3912 3913 /* Check if we failed to set the priority class */ 3914 if (!NT_SUCCESS(Status)) 3915 { 3916 /* Bail out on failure */ 3917 DPRINT1("Failed to set priority class: %lx\n", Status); 3918 BaseSetLastNTError(Status); 3919 Result = FALSE; 3920 goto Quickie; 3921 } 3922 } 3923 3924 /* Check if the caller wants the default error mode */ 3925 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE) 3926 { 3927 /* Set Error Mode to only fail on critical errors */ 3928 HardErrorMode = SEM_FAILCRITICALERRORS; 3929 NtSetInformationProcess(ProcessHandle, 3930 ProcessDefaultHardErrorMode, 3931 &HardErrorMode, 3932 sizeof(ULONG)); 3933 } 3934 3935 /* Check if this was a VDM binary */ 3936 if (VdmBinaryType) 3937 { 3938 /* Update VDM by telling it the process has now been created */ 3939 VdmWaitObject = ProcessHandle; 3940 Result = BaseUpdateVDMEntry(VdmEntryUpdateProcess, 3941 &VdmWaitObject, 3942 VdmTask, 3943 VdmBinaryType); 3944 3945 if (!Result) 3946 { 3947 /* Bail out on failure */ 3948 DPRINT1("Failed to update VDM with wait object\n"); 3949 VdmWaitObject = NULL; 3950 goto Quickie; 3951 } 3952 3953 /* At this point, a failure means VDM has to undo all the state */ 3954 VdmUndoLevel |= VDM_UNDO_FULL; 3955 } 3956 3957 /* Check if VDM needed reserved low-memory */ 3958 if (VdmReserve) 3959 { 3960 /* Reserve the requested allocation */ 3961 RegionSize = VdmReserve; 3962 Status = NtAllocateVirtualMemory(ProcessHandle, 3963 &BaseAddress, 3964 0, 3965 &RegionSize, 3966 MEM_RESERVE, 3967 PAGE_EXECUTE_READWRITE); 3968 if (!NT_SUCCESS(Status)) 3969 { 3970 /* Bail out on failure */ 3971 DPRINT1("Failed to reserve memory for VDM: %lx\n", Status); 3972 BaseSetLastNTError(Status); 3973 Result = FALSE; 3974 goto Quickie; 3975 } 3976 3977 VdmReserve = (ULONG)RegionSize; 3978 } 3979 3980 /* Check if we've already queried information on the section */ 3981 if (!QuerySection) 3982 { 3983 /* We haven't, so get some information about the executable */ 3984 Status = NtQuerySection(SectionHandle, 3985 SectionImageInformation, 3986 &ImageInformation, 3987 sizeof(ImageInformation), 3988 NULL); 3989 if (!NT_SUCCESS(Status)) 3990 { 3991 /* Bail out on failure */ 3992 DPRINT1("Failed to query section: %lx\n", Status); 3993 BaseSetLastNTError(Status); 3994 Result = FALSE; 3995 goto Quickie; 3996 } 3997 3998 /* If we encounter a restart, don't re-query this information again */ 3999 QuerySection = TRUE; 4000 } 4001 4002 /* Do we need to apply SxS to this image? (On x86 this flag is set by PeFmtCreateSection) */ 4003 if (!(ImageInformation.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION)) 4004 { 4005 /* Too bad, we don't support this yet */ 4006 DPRINT("Image should receive SxS Fusion Isolation\n"); 4007 } 4008 4009 /* There's some SxS flag that we need to set if fusion flags have 1 set */ 4010 if (FusionFlags & 1) CreateProcessMsg->Sxs.Flags |= 0x10; 4011 4012 /* Check if we have a current directory */ 4013 if (lpCurrentDirectory) 4014 { 4015 /* Allocate a buffer so we can keep a Unicode copy */ 4016 DPRINT("Current directory: %S\n", lpCurrentDirectory); 4017 CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(), 4018 0, 4019 (MAX_PATH * sizeof(WCHAR)) + 4020 sizeof(UNICODE_NULL)); 4021 if (!CurrentDirectory) 4022 { 4023 /* Bail out if this failed */ 4024 BaseSetLastNTError(STATUS_NO_MEMORY); 4025 Result = FALSE; 4026 goto Quickie; 4027 } 4028 4029 /* Get the length in Unicode */ 4030 Length = GetFullPathNameW(lpCurrentDirectory, 4031 MAX_PATH, 4032 CurrentDirectory, 4033 &FilePart); 4034 if (Length > MAX_PATH) 4035 { 4036 /* The directory is too long, so bail out */ 4037 SetLastError(ERROR_DIRECTORY); 4038 Result = FALSE; 4039 goto Quickie; 4040 } 4041 4042 /* Make sure the directory is actually valid */ 4043 FileAttribs = GetFileAttributesW(CurrentDirectory); 4044 if ((FileAttribs == INVALID_FILE_ATTRIBUTES) || 4045 !(FileAttribs & FILE_ATTRIBUTE_DIRECTORY)) 4046 { 4047 /* It isn't, so bail out */ 4048 DPRINT1("Current directory is invalid\n"); 4049 SetLastError(ERROR_DIRECTORY); 4050 Result = FALSE; 4051 goto Quickie; 4052 } 4053 } 4054 4055 /* Insert quotes if needed */ 4056 if ((QuotesNeeded) || (CmdLineIsAppName)) 4057 { 4058 /* Allocate our buffer, plus enough space for quotes and a NULL */ 4059 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(), 4060 0, 4061 (wcslen(lpCommandLine) * sizeof(WCHAR)) + 4062 (2 * sizeof(L'\"') + sizeof(UNICODE_NULL))); 4063 if (QuotedCmdLine) 4064 { 4065 /* Copy the first quote */ 4066 wcscpy(QuotedCmdLine, L"\""); 4067 4068 /* Save the current null-character */ 4069 if (QuotesNeeded) 4070 { 4071 SaveChar = *NullBuffer; 4072 *NullBuffer = UNICODE_NULL; 4073 } 4074 4075 /* Copy the command line and the final quote */ 4076 wcscat(QuotedCmdLine, lpCommandLine); 4077 wcscat(QuotedCmdLine, L"\""); 4078 4079 /* Copy the null-char back */ 4080 if (QuotesNeeded) 4081 { 4082 *NullBuffer = SaveChar; 4083 wcscat(QuotedCmdLine, NullBuffer); 4084 } 4085 } 4086 else 4087 { 4088 /* We can't put quotes around the thing, so try it anyway */ 4089 if (QuotesNeeded) QuotesNeeded = FALSE; 4090 if (CmdLineIsAppName) CmdLineIsAppName = FALSE; 4091 } 4092 } 4093 4094 /* Use isolation if needed */ 4095 if (CreateProcessMsg->Sxs.Flags & 1) ParameterFlags |= 1; 4096 4097 /* Set the new command-line if needed */ 4098 if ((QuotesNeeded) || (CmdLineIsAppName)) lpCommandLine = QuotedCmdLine; 4099 4100 /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */ 4101 Result = BasePushProcessParameters(ParameterFlags, 4102 ProcessHandle, 4103 RemotePeb, 4104 lpApplicationName, 4105 CurrentDirectory, 4106 lpCommandLine, 4107 lpEnvironment, 4108 &StartupInfo, 4109 dwCreationFlags | NoWindow, 4110 bInheritHandles, 4111 IsWowApp ? IMAGE_SUBSYSTEM_WINDOWS_GUI: 0, 4112 AppCompatData, 4113 AppCompatDataSize); 4114 if (!Result) 4115 { 4116 /* The remote process would have an undefined state, so fail the call */ 4117 DPRINT1("BasePushProcessParameters failed\n"); 4118 goto Quickie; 4119 } 4120 4121 /* Free the VDM command line string as it's no longer needed */ 4122 RtlFreeUnicodeString(&VdmString); 4123 VdmString.Buffer = NULL; 4124 4125 /* Non-VDM console applications usually inherit handles unless specified */ 4126 if (!(VdmBinaryType) && 4127 !(bInheritHandles) && 4128 !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) && 4129 !(dwCreationFlags & (CREATE_NO_WINDOW | 4130 CREATE_NEW_CONSOLE | 4131 DETACHED_PROCESS)) && 4132 (ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)) 4133 { 4134 /* Get the remote parameters */ 4135 Status = NtReadVirtualMemory(ProcessHandle, 4136 &RemotePeb->ProcessParameters, 4137 &ProcessParameters, 4138 sizeof(PRTL_USER_PROCESS_PARAMETERS), 4139 NULL); 4140 if (NT_SUCCESS(Status)) 4141 { 4142 /* Duplicate standard input unless it's a console handle */ 4143 if (!IsConsoleHandle(Peb->ProcessParameters->StandardInput)) 4144 { 4145 StuffStdHandle(ProcessHandle, 4146 Peb->ProcessParameters->StandardInput, 4147 &ProcessParameters->StandardInput); 4148 } 4149 4150 /* Duplicate standard output unless it's a console handle */ 4151 if (!IsConsoleHandle(Peb->ProcessParameters->StandardOutput)) 4152 { 4153 StuffStdHandle(ProcessHandle, 4154 Peb->ProcessParameters->StandardOutput, 4155 &ProcessParameters->StandardOutput); 4156 } 4157 4158 /* Duplicate standard error unless it's a console handle */ 4159 if (!IsConsoleHandle(Peb->ProcessParameters->StandardError)) 4160 { 4161 StuffStdHandle(ProcessHandle, 4162 Peb->ProcessParameters->StandardError, 4163 &ProcessParameters->StandardError); 4164 } 4165 } 4166 } 4167 4168 /* Create the Thread's Stack */ 4169 StackSize = max(256 * 1024, ImageInformation.MaximumStackSize); 4170 Status = BaseCreateStack(ProcessHandle, 4171 ImageInformation.CommittedStackSize, 4172 StackSize, 4173 &InitialTeb); 4174 if (!NT_SUCCESS(Status)) 4175 { 4176 DPRINT1("Creating the thread stack failed: %lx\n", Status); 4177 BaseSetLastNTError(Status); 4178 Result = FALSE; 4179 goto Quickie; 4180 } 4181 4182 /* Create the Thread's Context */ 4183 BaseInitializeContext(&Context, 4184 RemotePeb, 4185 ImageInformation.TransferAddress, 4186 InitialTeb.StackBase, 4187 0); 4188 4189 /* Convert the thread attributes */ 4190 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 4191 lpThreadAttributes, 4192 NULL); 4193 if ((hUserToken) && (lpThreadAttributes)) 4194 { 4195 /* If the caller specified a user token, zero the security descriptor */ 4196 LocalThreadAttributes = *lpThreadAttributes; 4197 LocalThreadAttributes.lpSecurityDescriptor = NULL; 4198 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 4199 &LocalThreadAttributes, 4200 NULL); 4201 } 4202 4203 /* Create the Kernel Thread Object */ 4204 Status = NtCreateThread(&ThreadHandle, 4205 THREAD_ALL_ACCESS, 4206 ObjectAttributes, 4207 ProcessHandle, 4208 &ClientId, 4209 &Context, 4210 &InitialTeb, 4211 TRUE); 4212 if (!NT_SUCCESS(Status)) 4213 { 4214 /* A process is not allowed to exist without a main thread, so fail */ 4215 DPRINT1("Creating the main thread failed: %lx\n", Status); 4216 BaseSetLastNTError(Status); 4217 Result = FALSE; 4218 goto Quickie; 4219 } 4220 4221 /* Begin filling out the CSRSS message, first with our IDs and handles */ 4222 CreateProcessMsg->ProcessHandle = ProcessHandle; 4223 CreateProcessMsg->ThreadHandle = ThreadHandle; 4224 CreateProcessMsg->ClientId = ClientId; 4225 4226 /* Write the remote PEB address and clear it locally, we no longer use it */ 4227 CreateProcessMsg->PebAddressNative = RemotePeb; 4228 #ifdef _WIN64 4229 DPRINT("TODO: WOW64 is not supported yet\n"); 4230 CreateProcessMsg->PebAddressWow64 = 0; 4231 #else 4232 CreateProcessMsg->PebAddressWow64 = (ULONG)RemotePeb; 4233 #endif 4234 RemotePeb = NULL; 4235 4236 /* Now check what kind of architecture this image was made for */ 4237 switch (ImageInformation.Machine) 4238 { 4239 /* IA32, IA64 and AMD64 are supported in Server 2003 */ 4240 case IMAGE_FILE_MACHINE_I386: 4241 CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; 4242 break; 4243 case IMAGE_FILE_MACHINE_IA64: 4244 CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64; 4245 break; 4246 case IMAGE_FILE_MACHINE_AMD64: 4247 CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; 4248 break; 4249 4250 /* Anything else results in image unknown -- but no failure */ 4251 default: 4252 DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n", 4253 ImageInformation.Machine); 4254 CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN; 4255 break; 4256 } 4257 4258 /* Write the input creation flags except any debugger-related flags */ 4259 CreateProcessMsg->CreationFlags = dwCreationFlags & 4260 ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS); 4261 4262 /* CSRSS needs to know if this is a GUI app or not */ 4263 if ((ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) || 4264 (IsWowApp)) 4265 { 4266 /* 4267 * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls 4268 * (basesrv in particular) to know whether or not this is a GUI or a 4269 * TUI application. 4270 */ 4271 AddToHandle(CreateProcessMsg->ProcessHandle, 2); 4272 4273 /* Also check if the parent is also a GUI process */ 4274 NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL)); 4275 if ((NtHeaders) && 4276 (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)) 4277 { 4278 /* Let it know that it should display the hourglass mouse cursor */ 4279 AddToHandle(CreateProcessMsg->ProcessHandle, 1); 4280 } 4281 } 4282 4283 /* For all apps, if this flag is on, the hourglass mouse cursor is shown. 4284 * Likewise, the opposite holds as well, and no-feedback has precedence. */ 4285 if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK) 4286 { 4287 AddToHandle(CreateProcessMsg->ProcessHandle, 1); 4288 } 4289 if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK) 4290 { 4291 RemoveFromHandle(CreateProcessMsg->ProcessHandle, 1); 4292 } 4293 4294 /* Also store which kind of VDM app (if any) this is */ 4295 CreateProcessMsg->VdmBinaryType = VdmBinaryType; 4296 4297 /* And if it really is a VDM app... */ 4298 if (VdmBinaryType) 4299 { 4300 /* Store the VDM console handle (none if inherited or WOW app) and the task ID */ 4301 CreateProcessMsg->hVDM = VdmTask ? NULL : Peb->ProcessParameters->ConsoleHandle; 4302 CreateProcessMsg->VdmTask = VdmTask; 4303 } 4304 else if (VdmReserve) 4305 { 4306 /* Extended VDM, set a flag */ 4307 CreateProcessMsg->VdmBinaryType |= BINARY_TYPE_WOW_EX; 4308 } 4309 4310 /* Check if there's side-by-side assembly data associated with the process */ 4311 if (CreateProcessMsg->Sxs.Flags) 4312 { 4313 /* This should not happen in ReactOS yet */ 4314 DPRINT1("This is an SxS Message -- should not happen yet\n"); 4315 BaseSetLastNTError(STATUS_NOT_IMPLEMENTED); 4316 NtTerminateProcess(ProcessHandle, STATUS_NOT_IMPLEMENTED); 4317 Result = FALSE; 4318 goto Quickie; 4319 } 4320 4321 /* We are finally ready to call CSRSS to tell it about our new process! */ 4322 CsrClientCallServer((PCSR_API_MESSAGE)&CsrMsg[0], 4323 CaptureBuffer, 4324 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, 4325 BasepCreateProcess), 4326 sizeof(*CreateProcessMsg)); 4327 4328 /* CSRSS has returned, free the capture buffer now if we had one */ 4329 if (CaptureBuffer) 4330 { 4331 CsrFreeCaptureBuffer(CaptureBuffer); 4332 CaptureBuffer = NULL; 4333 } 4334 4335 /* Check if CSRSS failed to accept ownership of the new Windows process */ 4336 if (!NT_SUCCESS(CsrMsg[0].Status)) 4337 { 4338 /* Terminate the process and enter failure path with the CSRSS status */ 4339 DPRINT1("Failed to tell csrss about new process\n"); 4340 BaseSetLastNTError(CsrMsg[0].Status); 4341 NtTerminateProcess(ProcessHandle, CsrMsg[0].Status); 4342 Result = FALSE; 4343 goto Quickie; 4344 } 4345 4346 /* Check if we have a token due to Authz/Safer, not passed by the user */ 4347 if ((TokenHandle) && !(hUserToken)) 4348 { 4349 /* Replace the process and/or thread token with the one from Safer */ 4350 Status = BasepReplaceProcessThreadTokens(TokenHandle, 4351 ProcessHandle, 4352 ThreadHandle); 4353 if (!NT_SUCCESS(Status)) 4354 { 4355 /* If this failed, kill the process and enter the failure path */ 4356 DPRINT1("Failed to update process token: %lx\n", Status); 4357 NtTerminateProcess(ProcessHandle, Status); 4358 BaseSetLastNTError(Status); 4359 Result = FALSE; 4360 goto Quickie; 4361 } 4362 } 4363 4364 /* Check if a job was associated with this process */ 4365 if (JobHandle) 4366 { 4367 /* Bind the process and job together now */ 4368 Status = NtAssignProcessToJobObject(JobHandle, ProcessHandle); 4369 if (!NT_SUCCESS(Status)) 4370 { 4371 /* Kill the process and enter the failure path if binding failed */ 4372 DPRINT1("Failed to assign process to job: %lx\n", Status); 4373 NtTerminateProcess(ProcessHandle, STATUS_ACCESS_DENIED); 4374 BaseSetLastNTError(Status); 4375 Result = FALSE; 4376 goto Quickie; 4377 } 4378 } 4379 4380 /* Finally, resume the thread to actually get the process started */ 4381 if (!(dwCreationFlags & CREATE_SUSPENDED)) 4382 { 4383 NtResumeThread(ThreadHandle, &ResumeCount); 4384 } 4385 4386 VdmShortCircuit: 4387 /* We made it this far, meaning we have a fully created process and thread */ 4388 Result = TRUE; 4389 4390 /* Anyone doing a VDM undo should now undo everything, since we are done */ 4391 if (VdmUndoLevel) VdmUndoLevel |= VDM_UNDO_COMPLETED; 4392 4393 /* Having a VDM wait object implies this must be a VDM process */ 4394 if (VdmWaitObject) 4395 { 4396 /* Check if it's a 16-bit separate WOW process */ 4397 if (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW) 4398 { 4399 /* OR-in the special flag to indicate this, and return to caller */ 4400 AddToHandle(VdmWaitObject, 2); 4401 lpProcessInformation->hProcess = VdmWaitObject; 4402 4403 /* Check if this was a re-used VDM */ 4404 if (VdmUndoLevel & VDM_UNDO_REUSE) 4405 { 4406 /* No Client ID should be returned in this case */ 4407 ClientId.UniqueProcess = 0; 4408 ClientId.UniqueThread = 0; 4409 } 4410 } 4411 else 4412 { 4413 /* OR-in the special flag to indicate this is not a separate VDM, 4414 * and return the handle to the caller */ 4415 AddToHandle(VdmWaitObject, 1); 4416 lpProcessInformation->hProcess = VdmWaitObject; 4417 } 4418 4419 /* Close the original process handle, since it's not needed for VDM */ 4420 if (ProcessHandle) NtClose(ProcessHandle); 4421 } 4422 else 4423 { 4424 /* This is a regular process, so return the real process handle */ 4425 lpProcessInformation->hProcess = ProcessHandle; 4426 } 4427 4428 /* Return the rest of the process information based on what we have so far */ 4429 lpProcessInformation->hThread = ThreadHandle; 4430 lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess); 4431 lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread); 4432 4433 /* NULL these out here so we know to treat this as a success scenario */ 4434 ProcessHandle = NULL; 4435 ThreadHandle = NULL; 4436 4437 Quickie: 4438 /* Free the debugger command line if one was allocated */ 4439 if (DebuggerCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine); 4440 4441 /* Check if an SxS full path as queried */ 4442 if (PathBuffer) 4443 { 4444 /* Reinitialize the executable path */ 4445 RtlInitEmptyUnicodeString(&SxsWin32ExePath, NULL, 0); 4446 SxsWin32ExePath.Length = 0; 4447 4448 /* Free the path buffer */ 4449 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer); 4450 } 4451 4452 #if _SXS_SUPPORT_ENABLED_ 4453 /* Check if this was a non-VDM process */ 4454 if (!VdmBinaryType) 4455 { 4456 /* Then it must've had SxS data, so close the handles used for it */ 4457 BasepSxsCloseHandles(&Handles); 4458 BasepSxsCloseHandles(&FileHandles); 4459 4460 /* Check if we built SxS byte buffers for this create process request */ 4461 if (SxsConglomeratedBuffer) 4462 { 4463 /* Loop all of them */ 4464 for (i = 0; i < 5; i++) 4465 { 4466 /* Check if this one was allocated */ 4467 ThisBuffer = SxsStaticBuffers[i]; 4468 if (ThisBuffer) 4469 { 4470 /* Get the underlying RTL_BUFFER structure */ 4471 ByteBuffer = &ThisBuffer->ByteBuffer; 4472 if ((ThisBuffer != (PVOID)-8) && (ByteBuffer->Buffer)) 4473 { 4474 /* Check if it was dynamic */ 4475 if (ByteBuffer->Buffer != ByteBuffer->StaticBuffer) 4476 { 4477 /* Free it from the heap */ 4478 FreeString.Buffer = (PWCHAR)ByteBuffer->Buffer; 4479 RtlFreeUnicodeString(&FreeString); 4480 } 4481 4482 /* Reset the buffer to its static data */ 4483 ByteBuffer->Buffer = ByteBuffer->StaticBuffer; 4484 ByteBuffer->Size = ByteBuffer->StaticSize; 4485 } 4486 4487 /* Reset the string to the static buffer */ 4488 RtlInitEmptyUnicodeString(&ThisBuffer->String, 4489 (PWCHAR)ByteBuffer->StaticBuffer, 4490 ByteBuffer->StaticSize); 4491 if (ThisBuffer->String.Buffer) 4492 { 4493 /* Also NULL-terminate it */ 4494 *ThisBuffer->String.Buffer = UNICODE_NULL; 4495 } 4496 } 4497 } 4498 } 4499 } 4500 #endif 4501 /* Check if an environment was passed in */ 4502 if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) 4503 { 4504 /* Destroy it */ 4505 RtlDestroyEnvironment(lpEnvironment); 4506 4507 /* If this was the VDM environment too, clear that as well */ 4508 if (VdmUnicodeEnv.Buffer == lpEnvironment) VdmUnicodeEnv.Buffer = NULL; 4509 lpEnvironment = NULL; 4510 } 4511 4512 /* Unconditionally free all the name parsing buffers we always allocate */ 4513 RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine); 4514 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 4515 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory); 4516 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer); 4517 4518 /* Close open file/section handles */ 4519 if (FileHandle) NtClose(FileHandle); 4520 if (SectionHandle) NtClose(SectionHandle); 4521 4522 /* If we have a thread handle, this was a failure path */ 4523 if (ThreadHandle) 4524 { 4525 /* So kill the process and close the thread handle */ 4526 NtTerminateProcess(ProcessHandle, STATUS_SUCCESS); 4527 NtClose(ThreadHandle); 4528 } 4529 4530 /* If we have a process handle, this was a failure path, so close it */ 4531 if (ProcessHandle) NtClose(ProcessHandle); 4532 4533 /* Thread/process handles, if any, are now processed. Now close this one. */ 4534 if (JobHandle) NtClose(JobHandle); 4535 4536 /* Check if we had created a token */ 4537 if (TokenHandle) 4538 { 4539 /* And if the user asked for one */ 4540 if (hUserToken) 4541 { 4542 /* Then return it */ 4543 *hNewToken = TokenHandle; 4544 } 4545 else 4546 { 4547 /* User didn't want it, so we used it temporarily -- close it */ 4548 NtClose(TokenHandle); 4549 } 4550 } 4551 4552 /* Free any temporary app compatibility data, it's no longer needed */ 4553 BasepFreeAppCompatData(AppCompatData, AppCompatSxsData); 4554 4555 /* Free a few strings. The API takes care of these possibly being NULL */ 4556 RtlFreeUnicodeString(&VdmString); 4557 RtlFreeUnicodeString(&DebuggerString); 4558 4559 /* Check if we had built any sort of VDM environment */ 4560 if ((VdmAnsiEnv.Buffer) || (VdmUnicodeEnv.Buffer)) 4561 { 4562 /* Free it */ 4563 BaseDestroyVDMEnvironment(&VdmAnsiEnv, &VdmUnicodeEnv); 4564 } 4565 4566 /* Check if this was any kind of VDM application that we ended up creating */ 4567 if ((VdmUndoLevel) && (!(VdmUndoLevel & VDM_UNDO_COMPLETED))) 4568 { 4569 /* Send an undo */ 4570 BaseUpdateVDMEntry(VdmEntryUndo, 4571 (PHANDLE)&VdmTask, 4572 VdmUndoLevel, 4573 VdmBinaryType); 4574 4575 /* And close whatever VDM handle we were using for notifications */ 4576 if (VdmWaitObject) NtClose(VdmWaitObject); 4577 } 4578 4579 /* Check if we ended up here with an allocated search path, and free it */ 4580 if (SearchPath) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath); 4581 4582 /* Finally, return the API's result */ 4583 return Result; 4584 } 4585 4586 /* 4587 * @implemented 4588 */ 4589 BOOL 4590 WINAPI 4591 DECLSPEC_HOTPATCH 4592 CreateProcessW(LPCWSTR lpApplicationName, 4593 LPWSTR lpCommandLine, 4594 LPSECURITY_ATTRIBUTES lpProcessAttributes, 4595 LPSECURITY_ATTRIBUTES lpThreadAttributes, 4596 BOOL bInheritHandles, 4597 DWORD dwCreationFlags, 4598 LPVOID lpEnvironment, 4599 LPCWSTR lpCurrentDirectory, 4600 LPSTARTUPINFOW lpStartupInfo, 4601 LPPROCESS_INFORMATION lpProcessInformation) 4602 { 4603 /* Call the internal (but exported) version */ 4604 return CreateProcessInternalW(NULL, 4605 lpApplicationName, 4606 lpCommandLine, 4607 lpProcessAttributes, 4608 lpThreadAttributes, 4609 bInheritHandles, 4610 dwCreationFlags, 4611 lpEnvironment, 4612 lpCurrentDirectory, 4613 lpStartupInfo, 4614 lpProcessInformation, 4615 NULL); 4616 } 4617 4618 /* 4619 * @implemented 4620 */ 4621 BOOL 4622 WINAPI 4623 CreateProcessInternalA(HANDLE hToken, 4624 LPCSTR lpApplicationName, 4625 LPSTR lpCommandLine, 4626 LPSECURITY_ATTRIBUTES lpProcessAttributes, 4627 LPSECURITY_ATTRIBUTES lpThreadAttributes, 4628 BOOL bInheritHandles, 4629 DWORD dwCreationFlags, 4630 LPVOID lpEnvironment, 4631 LPCSTR lpCurrentDirectory, 4632 LPSTARTUPINFOA lpStartupInfo, 4633 LPPROCESS_INFORMATION lpProcessInformation, 4634 PHANDLE hNewToken) 4635 { 4636 UNICODE_STRING CommandLine; 4637 UNICODE_STRING ApplicationName; 4638 UNICODE_STRING CurrentDirectory; 4639 BOOL bRetVal; 4640 STARTUPINFOW StartupInfo; 4641 4642 DPRINT("dwCreationFlags %x, lpEnvironment %p, lpCurrentDirectory %p, " 4643 "lpStartupInfo %p, lpProcessInformation %p\n", 4644 dwCreationFlags, lpEnvironment, lpCurrentDirectory, 4645 lpStartupInfo, lpProcessInformation); 4646 4647 /* Copy Startup Info */ 4648 RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo)); 4649 4650 /* Initialize all strings to nothing */ 4651 CommandLine.Buffer = NULL; 4652 ApplicationName.Buffer = NULL; 4653 CurrentDirectory.Buffer = NULL; 4654 StartupInfo.lpDesktop = NULL; 4655 StartupInfo.lpReserved = NULL; 4656 StartupInfo.lpTitle = NULL; 4657 4658 /* Convert the Command line */ 4659 if (lpCommandLine) 4660 { 4661 Basep8BitStringToDynamicUnicodeString(&CommandLine, 4662 lpCommandLine); 4663 } 4664 4665 /* Convert the Name and Directory */ 4666 if (lpApplicationName) 4667 { 4668 Basep8BitStringToDynamicUnicodeString(&ApplicationName, 4669 lpApplicationName); 4670 } 4671 if (lpCurrentDirectory) 4672 { 4673 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory, 4674 lpCurrentDirectory); 4675 } 4676 4677 /* Now convert Startup Strings */ 4678 if (lpStartupInfo->lpReserved) 4679 { 4680 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved, 4681 &StartupInfo.lpReserved); 4682 } 4683 if (lpStartupInfo->lpDesktop) 4684 { 4685 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop, 4686 &StartupInfo.lpDesktop); 4687 } 4688 if (lpStartupInfo->lpTitle) 4689 { 4690 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle, 4691 &StartupInfo.lpTitle); 4692 } 4693 4694 /* Call the Unicode function */ 4695 bRetVal = CreateProcessInternalW(hToken, 4696 ApplicationName.Buffer, 4697 CommandLine.Buffer, 4698 lpProcessAttributes, 4699 lpThreadAttributes, 4700 bInheritHandles, 4701 dwCreationFlags, 4702 lpEnvironment, 4703 CurrentDirectory.Buffer, 4704 &StartupInfo, 4705 lpProcessInformation, 4706 hNewToken); 4707 4708 /* Clean up */ 4709 RtlFreeUnicodeString(&ApplicationName); 4710 RtlFreeUnicodeString(&CommandLine); 4711 RtlFreeUnicodeString(&CurrentDirectory); 4712 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop); 4713 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved); 4714 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle); 4715 4716 /* Return what Unicode did */ 4717 return bRetVal; 4718 } 4719 4720 /* 4721 * FUNCTION: The CreateProcess function creates a new process and its 4722 * primary thread. The new process executes the specified executable file 4723 * ARGUMENTS: 4724 * 4725 * lpApplicationName = Pointer to name of executable module 4726 * lpCommandLine = Pointer to command line string 4727 * lpProcessAttributes = Process security attributes 4728 * lpThreadAttributes = Thread security attributes 4729 * bInheritHandles = Handle inheritance flag 4730 * dwCreationFlags = Creation flags 4731 * lpEnvironment = Pointer to new environment block 4732 * lpCurrentDirectory = Pointer to current directory name 4733 * lpStartupInfo = Pointer to startup info 4734 * lpProcessInformation = Pointer to process information 4735 * 4736 * @implemented 4737 */ 4738 BOOL 4739 WINAPI 4740 DECLSPEC_HOTPATCH 4741 CreateProcessA(LPCSTR lpApplicationName, 4742 LPSTR lpCommandLine, 4743 LPSECURITY_ATTRIBUTES lpProcessAttributes, 4744 LPSECURITY_ATTRIBUTES lpThreadAttributes, 4745 BOOL bInheritHandles, 4746 DWORD dwCreationFlags, 4747 LPVOID lpEnvironment, 4748 LPCSTR lpCurrentDirectory, 4749 LPSTARTUPINFOA lpStartupInfo, 4750 LPPROCESS_INFORMATION lpProcessInformation) 4751 { 4752 /* Call the internal (but exported) version */ 4753 return CreateProcessInternalA(NULL, 4754 lpApplicationName, 4755 lpCommandLine, 4756 lpProcessAttributes, 4757 lpThreadAttributes, 4758 bInheritHandles, 4759 dwCreationFlags, 4760 lpEnvironment, 4761 lpCurrentDirectory, 4762 lpStartupInfo, 4763 lpProcessInformation, 4764 NULL); 4765 } 4766 4767 /* 4768 * @implemented 4769 */ 4770 UINT 4771 WINAPI 4772 DECLSPEC_HOTPATCH 4773 WinExec(LPCSTR lpCmdLine, 4774 UINT uCmdShow) 4775 { 4776 STARTUPINFOA StartupInfo; 4777 PROCESS_INFORMATION ProcessInformation; 4778 DWORD dosErr; 4779 4780 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); 4781 StartupInfo.cb = sizeof(STARTUPINFOA); 4782 StartupInfo.wShowWindow = (WORD)uCmdShow; 4783 StartupInfo.dwFlags = 0; 4784 4785 if (!CreateProcessA(NULL, 4786 (PVOID)lpCmdLine, 4787 NULL, 4788 NULL, 4789 FALSE, 4790 0, 4791 NULL, 4792 NULL, 4793 &StartupInfo, 4794 &ProcessInformation)) 4795 { 4796 dosErr = GetLastError(); 4797 return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT; 4798 } 4799 4800 if (NULL != UserWaitForInputIdleRoutine) 4801 { 4802 UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 4803 10000); 4804 } 4805 4806 NtClose(ProcessInformation.hProcess); 4807 NtClose(ProcessInformation.hThread); 4808 4809 return 33; /* Something bigger than 31 means success. */ 4810 } 4811 4812 /* EOF */ 4813